mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 15:22:17 +02:00
N°3649 - Activity panel: Add tooltip on compose button
This commit is contained in:
@@ -36,6 +36,9 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Layout:ActivityPanel:Tab:Toolbar:Info:AuthorsCount:Tooltip' => 'Number of persons interacting in the visible entries',
|
||||
'UI:Layout:ActivityPanel:Tab:Toolbar:Info:MessagesCount:Tooltip' => 'Number of messages in the visible log(s)',
|
||||
|
||||
// Compose button
|
||||
'UI:Layout:ActivityPanel:ComposeButton:Tooltip' => 'Compose a new case log entry',
|
||||
|
||||
// Case log entry
|
||||
'UI:Layout:ActivityPanel:MutltipleEntriesSaveConfirmation:Title' => 'Multiple case logs save',
|
||||
'UI:Layout:ActivityPanel:MutltipleEntriesSaveConfirmation:Explanation' => 'By pressing the "save" button, you will submit entries for all the edited case logs at once.',
|
||||
|
||||
@@ -23,49 +23,52 @@ $(function()
|
||||
{
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
datetime_format: null,
|
||||
datetimes_reformat_limit: 14, // In days
|
||||
show_multiple_entries_submit_confirmation: true,
|
||||
},
|
||||
{
|
||||
datetime_format: null,
|
||||
datetimes_reformat_limit: 14, // In days
|
||||
transaction_id: null, // Null until the user gets the lock on the object
|
||||
show_multiple_entries_submit_confirmation: true,
|
||||
},
|
||||
css_classes:
|
||||
{
|
||||
is_expanded: 'ibo-is-expanded',
|
||||
is_opened: 'ibo-is-opened',
|
||||
is_closed: 'ibo-is-closed',
|
||||
is_active: 'ibo-is-active',
|
||||
is_visible: 'ibo-is-visible',
|
||||
is_hidden: 'ibo-is-hidden',
|
||||
is_draft: 'ibo-is-draft',
|
||||
},
|
||||
{
|
||||
is_expanded: 'ibo-is-expanded',
|
||||
is_opened: 'ibo-is-opened',
|
||||
is_closed: 'ibo-is-closed',
|
||||
is_active: 'ibo-is-active',
|
||||
is_visible: 'ibo-is-visible',
|
||||
is_hidden: 'ibo-is-hidden',
|
||||
is_draft: 'ibo-is-draft',
|
||||
is_current_user: 'ibo-is-current-user',
|
||||
},
|
||||
js_selectors:
|
||||
{
|
||||
panel_size_toggler: '[data-role="ibo-activity-panel--size-toggler"]',
|
||||
tab_toggler: '[data-role="ibo-activity-panel--tab-toggler"]',
|
||||
tab_title: '[data-role="ibo-activity-panel--tab-title"]',
|
||||
tabs_toolbars: '[data-role="ibo-activity-panel--tabs-toolbars"]',
|
||||
tab_toolbar: '[data-role="ibo-activity-panel--tab-toolbar"]',
|
||||
tab_toolbar_action: '[data-role="ibo-activity-panel--tab-toolbar-action"]',
|
||||
caselog_tab_open_all: '[data-role="ibo-activity-panel--caselog-open-all"]',
|
||||
caselog_tab_close_all: '[data-role="ibo-activity-panel--caselog-close-all"]',
|
||||
activity_filter: '[data-role="ibo-activity-panel--filter"]',
|
||||
activity_filter_options: '[data-role="ibo-activity-panel--filter-options"]',
|
||||
activity_filter_options_toggler: '[data-role="ibo-activity-panel--filter-options-toggler"]',
|
||||
activity_filter_option_input: '[data-role="ibo-activity-panel--filter-option-input"]',
|
||||
authors_count: '[data-role="ibo-activity-panel--tab-toolbar-info-authors-count"]',
|
||||
messages_count: '[data-role="ibo-activity-panel--tab-toolbar-info-messages-count"]',
|
||||
compose_button: '[data-role="ibo-activity-panel--add-caselog-entry-button"]',
|
||||
caselog_entry_form: '[data-role="ibo-caselog-entry-form"]',
|
||||
caselog_entry_forms_confirmation_dialog: '[data-role="ibo-activity-panel--entry-forms-confirmation-dialog"]',
|
||||
caselog_entry_forms_confirmation_preference_input: '[data-role="ibo-activity-panel--entry-forms-confirmation-preference-input"]',
|
||||
entry_group: '[data-role="ibo-activity-panel--entry-group"]',
|
||||
entry: '[data-role="ibo-activity-entry"]',
|
||||
entry_medallion: '[data-role="ibo-activity-entry--medallion"]',
|
||||
entry_main_information: '[data-role="ibo-activity-entry--main-information"]',
|
||||
entry_datetime: '[data-role="ibo-activity-entry--datetime"]',
|
||||
edits_entry_long_description: '[data-role="ibo-edits-entry--long-description"]',
|
||||
edits_entry_long_description_toggler: '[data-role="ibo-edits-entry--long-description-toggler"]',
|
||||
},
|
||||
{
|
||||
panel_size_toggler: '[data-role="ibo-activity-panel--size-toggler"]',
|
||||
tab_toggler: '[data-role="ibo-activity-panel--tab-toggler"]',
|
||||
tab_title: '[data-role="ibo-activity-panel--tab-title"]',
|
||||
tabs_toolbars: '[data-role="ibo-activity-panel--tabs-toolbars"]',
|
||||
tab_toolbar: '[data-role="ibo-activity-panel--tab-toolbar"]',
|
||||
tab_toolbar_action: '[data-role="ibo-activity-panel--tab-toolbar-action"]',
|
||||
caselog_tab_open_all: '[data-role="ibo-activity-panel--caselog-open-all"]',
|
||||
caselog_tab_close_all: '[data-role="ibo-activity-panel--caselog-close-all"]',
|
||||
activity_filter: '[data-role="ibo-activity-panel--filter"]',
|
||||
activity_filter_options: '[data-role="ibo-activity-panel--filter-options"]',
|
||||
activity_filter_options_toggler: '[data-role="ibo-activity-panel--filter-options-toggler"]',
|
||||
activity_filter_option_input: '[data-role="ibo-activity-panel--filter-option-input"]',
|
||||
authors_count: '[data-role="ibo-activity-panel--tab-toolbar-info-authors-count"]',
|
||||
messages_count: '[data-role="ibo-activity-panel--tab-toolbar-info-messages-count"]',
|
||||
compose_button: '[data-role="ibo-activity-panel--add-caselog-entry-button"]',
|
||||
caselog_entry_form: '[data-role="ibo-caselog-entry-form"]',
|
||||
caselog_entry_forms_confirmation_dialog: '[data-role="ibo-activity-panel--entry-forms-confirmation-dialog"]',
|
||||
caselog_entry_forms_confirmation_preference_input: '[data-role="ibo-activity-panel--entry-forms-confirmation-preference-input"]',
|
||||
body: '[data-role="ibo-activity-panel--body"]',
|
||||
entry_group: '[data-role="ibo-activity-panel--entry-group"]',
|
||||
entry: '[data-role="ibo-activity-entry"]',
|
||||
entry_medallion: '[data-role="ibo-activity-entry--medallion"]',
|
||||
entry_main_information: '[data-role="ibo-activity-entry--main-information"]',
|
||||
entry_datetime: '[data-role="ibo-activity-entry--datetime"]',
|
||||
edits_entry_long_description: '[data-role="ibo-edits-entry--long-description"]',
|
||||
edits_entry_long_description_toggler: '[data-role="ibo-edits-entry--long-description-toggler"]',
|
||||
},
|
||||
enums: {
|
||||
tab_types: {
|
||||
caselog: 'caselog',
|
||||
@@ -79,9 +82,9 @@ $(function()
|
||||
},
|
||||
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
_create: function () {
|
||||
this.element.addClass('ibo-activity-panel');
|
||||
|
||||
this._bindEvents();
|
||||
this._UpdateMessagesCounters();
|
||||
this._UpdateFiltersCheckboxesFromOptions();
|
||||
@@ -561,26 +564,36 @@ $(function()
|
||||
* @return {void}
|
||||
* @private
|
||||
*/
|
||||
_HideCaseLogsEntryForms: function()
|
||||
{
|
||||
_HideCaseLogsEntryForms: function () {
|
||||
this.element.find(this.js_selectors.caselog_entry_form).trigger('hide_form.caselog_entry_form.itop');
|
||||
this.element.find(this.js_selectors.compose_button).removeClass(this.css_classes.is_hidden);
|
||||
|
||||
// TODO 3.0.0: Release lock
|
||||
},
|
||||
_FreezeCaseLogsEntryForms: function () {
|
||||
this.element.find(this.js_selectors.caselog_entry_form).trigger('enter_pending_submission_state.caselog_entry_form.itop');
|
||||
},
|
||||
_UnfreezeCaseLogsEntryForms: function () {
|
||||
this.element.find(this.js_selectors.caselog_entry_form).trigger('leave_pending_submission_state.caselog_entry_form.itop');
|
||||
},
|
||||
/**
|
||||
* @returns {Object} The case logs having a new entry and their values, format is {<ATT_CODE_1>: <HTML_VALUE_1>, <ATT_CODE_2>: <HTML_VALUE_2>}
|
||||
* @private
|
||||
*/
|
||||
_GetEntriesFromAllForms: function()
|
||||
{
|
||||
_GetEntriesFromAllForms: function () {
|
||||
const me = this;
|
||||
|
||||
let oEntries = {};
|
||||
this.element.find(this.js_selectors.caselog_entry_form).each(function(){
|
||||
this.element.find(this.js_selectors.caselog_entry_form).each(function () {
|
||||
const oEntryFormElem = $(this);
|
||||
const sEntryFormValue = oEntryFormElem.triggerHandler('get_entry.caselog_entry_form.itop');
|
||||
|
||||
if('' !== sEntryFormValue) {
|
||||
oEntries[oEntryFormElem.attr('data-attribute-code')] = sEntryFormValue;
|
||||
if ('' !== sEntryFormValue) {
|
||||
const sCaseLogAttCode = oEntryFormElem.attr('data-attribute-code');
|
||||
oEntries[sCaseLogAttCode] = {
|
||||
value: sEntryFormValue,
|
||||
rank: me.element.find(me.js_selectors.tab_toggler+'[data-tab-type="caselog"][data-caselog-attribute-code="'+sCaseLogAttCode+'"]').attr('data-caselog-rank'),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -615,6 +628,7 @@ $(function()
|
||||
if (bDoNotShowAgain) {
|
||||
me._SaveSubmitConfirmationPref();
|
||||
}
|
||||
me._HideEntriesSubmitConfirmation();
|
||||
me._SendEntriesToServer();
|
||||
}
|
||||
},
|
||||
@@ -650,11 +664,67 @@ $(function()
|
||||
* Send the edited case logs entries to the server
|
||||
* @private
|
||||
*/
|
||||
_SendEntriesToServer: function()
|
||||
{
|
||||
_SendEntriesToServer: function () {
|
||||
const me = this;
|
||||
const oEntries = this._GetEntriesFromAllForms();
|
||||
// Put entries in the feed
|
||||
// Renew transaction ID for inline images
|
||||
|
||||
// Proceed only if entries to send
|
||||
if (Object.keys(oEntries).length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare parameters
|
||||
let oParams = {
|
||||
operation: 'add_caselog_entries',
|
||||
object_class: this._GetHostObjectClass(),
|
||||
object_id: this._GetHostObjectID(),
|
||||
transaction_id: this.options.transaction_id,
|
||||
entries: oEntries,
|
||||
};
|
||||
|
||||
// Freeze case logs
|
||||
this._FreezeCaseLogsEntryForms();
|
||||
|
||||
// Send request to server
|
||||
$.post(
|
||||
GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
oParams,
|
||||
'json'
|
||||
)
|
||||
.fail(function (oXHR, sStatus, sErrorThrown) {
|
||||
// TODO 3.0.0: Maybe we could have a centralized dialog to display error messages?
|
||||
alert(sErrorThrown);
|
||||
})
|
||||
.done(function (oData) {
|
||||
if (false === oData.success) {
|
||||
// TODO 3.0.0: Same comment as the fail() callback
|
||||
alert(oData.error_message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the feed
|
||||
for (let sCaseLogAttCode in oData.entries) {
|
||||
me._AddEntry(sCaseLogAttCode, oData.entries[sCaseLogAttCode]);
|
||||
}
|
||||
me._ApplyEntriesFilters();
|
||||
|
||||
// For now, we don't hide the forms as the user may want to add something else
|
||||
me.element.find(me.js_selectors.caselog_entry_form).trigger('clear_entry.case_entry_form.itop');
|
||||
|
||||
// TODO 3.0.0: Redirect to transition page if necessary (buttons need to be added)
|
||||
// // Redirect to stimulus
|
||||
// if(sStimulusCode !== null){
|
||||
// window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+sObjClass+'&id='+sObjId+'&stimulus='+sStimulusCode;
|
||||
// }
|
||||
|
||||
// TODO 3.0.0: If no stimulus
|
||||
// On done, lock was release, remove message
|
||||
// On done, renew transaction ID
|
||||
})
|
||||
.always(function () {
|
||||
// Always, unfreeze case logs
|
||||
me._UnfreezeCaseLogsEntryForms();
|
||||
});
|
||||
},
|
||||
|
||||
// - Helpers on messages
|
||||
@@ -787,7 +857,7 @@ $(function()
|
||||
|
||||
// ... except the selected
|
||||
for (let sCaseLogAttCode of aOptions) {
|
||||
this.element.find(sEntrySelector + '[data-entry-caselog-attribute-code="' + sCaseLogAttCode + '"]').removeClass(this.css_classes.is_hidden);
|
||||
this.element.find(sEntrySelector+'[data-entry-caselog-attribute-code="'+sCaseLogAttCode+'"]').removeClass(this.css_classes.is_hidden);
|
||||
}
|
||||
}
|
||||
// General case
|
||||
@@ -797,49 +867,63 @@ $(function()
|
||||
|
||||
this._UpdateEntryGroupsVisibility();
|
||||
},
|
||||
_UpdateEntryGroupsVisibility: function()
|
||||
{
|
||||
_UpdateEntryGroupsVisibility: function () {
|
||||
const me = this;
|
||||
|
||||
this.element.find(this.js_selectors.entry_group).each(function(){
|
||||
if($(this).find(me.js_selectors.entry + ':not(.' + me.css_classes.is_hidden + ')').length === 0)
|
||||
{
|
||||
this.element.find(this.js_selectors.entry_group).each(function () {
|
||||
if ($(this).find(me.js_selectors.entry+':not(.'+me.css_classes.is_hidden+')').length === 0) {
|
||||
$(this).addClass(me.css_classes.is_hidden);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$(this).removeClass(me.css_classes.is_hidden);
|
||||
}
|
||||
});
|
||||
},
|
||||
_GetNewEntryGroup: function()
|
||||
{
|
||||
let AjaxNewEntryGroupDeferred = jQuery.Deferred();
|
||||
const me = this;
|
||||
var oParams = {
|
||||
'operation' : 'new_entry_group',
|
||||
'caselog_new_entry': sData,
|
||||
'caselog_attcode' : sCaselog,
|
||||
/**
|
||||
* Add an entry represented by its oData to the case log with the sCaseLogAttCode
|
||||
*
|
||||
* @param sCaseLogAttCode {string}
|
||||
* @param oData {Object} Structured data of the entry: {html_rendering: <HTML_DATA>}
|
||||
* @private
|
||||
*/
|
||||
_AddEntry: function (sCaseLogAttCode, oData) {
|
||||
// Info about the new entry
|
||||
const oNewEntryElem = $(oData.html_rendering);
|
||||
const sNewEntryAuthorLogin = oNewEntryElem.attr('data-entry-author-login');
|
||||
const sNewEntryOrigin = oNewEntryElem.attr('data-entry-group-origin');
|
||||
|
||||
// Info about the last entry group to see the entry to add should be in this one or a new one
|
||||
const oLastEntryGroupElem = this.element.find(this.js_selectors.entry_group+':first');
|
||||
const sLastEntryAuthorLogin = oLastEntryGroupElem.length > 0 ? oLastEntryGroupElem.attr('data-entry-author-login') : null;
|
||||
const sLastEntryOrigin = oLastEntryGroupElem.length > 0 ? oLastEntryGroupElem.attr('data-entry-group-origin') : null;
|
||||
|
||||
let oTargetEntryGroup = null;
|
||||
if ((sLastEntryAuthorLogin === sNewEntryAuthorLogin) && (sLastEntryOrigin && sNewEntryOrigin)) {
|
||||
oTargetEntryGroup = oLastEntryGroupElem;
|
||||
} else {
|
||||
oTargetEntryGroup = this._CreateEntryGroup(sNewEntryAuthorLogin, sNewEntryOrigin);
|
||||
}
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data){
|
||||
AjaxNewEntryGroupDeferred.resolve(data);
|
||||
});
|
||||
return AjaxNewEntryGroupDeferred.promise();
|
||||
oTargetEntryGroup.prepend(oNewEntryElem);
|
||||
this._ReformatDateTimes();
|
||||
},
|
||||
/**
|
||||
* Create an entry group and add it to the activity panel
|
||||
*
|
||||
* @param sAuthorLogin {string}
|
||||
* @param sOrigin {string}
|
||||
* @returns {Object} jQuery object representing the created entry group
|
||||
* @private
|
||||
*/
|
||||
_CreateEntryGroup: function (sAuthorLogin, sOrigin) {
|
||||
// Note: When using the ActivityPanel, there should always be at least one entry group already, the one from the object creation
|
||||
let oEntryGroupElem = this.element.find(this.js_selectors.entry_group+':first')
|
||||
.clone()
|
||||
.attr('data-entry-author-login', sAuthorLogin)
|
||||
.attr('data-entry-group-origin', sOrigin)
|
||||
.addClass(this.css_classes.is_current_user)
|
||||
.html('')
|
||||
.prependTo(this.element.find(this.js_selectors.body));
|
||||
|
||||
return oEntryGroupElem;
|
||||
},
|
||||
AddEntry: function(sEntry, sOrigin)
|
||||
{
|
||||
let aEntryGroup = this.element.find(this.js_selectors.entry_group)
|
||||
let sAuthorLogin = $(sEntry).attr('data-entry-author-login');
|
||||
if (aEntryGroup.length > 0 && $(aEntryGroup[0]).attr('data-entry-group-author-login') === sAuthorLogin && $(aEntryGroup[0]).attr('data-entry-group-origin') === sOrigin)
|
||||
{
|
||||
$(aEntryGroup[0]).prepend(sEntry);
|
||||
this._ReformatDateTimes();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO 3.0.0 Create a new entry group
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,8 +60,8 @@ $(function() {
|
||||
const aMandatoryOptions = ['object_class', 'object_id', 'attribute_code'];
|
||||
for (let sOption of aMandatoryOptions) {
|
||||
if (null === this.options[sOption]) {
|
||||
CombodoGlobalToolbox.Trace('CaseLogEntryForm: Could not initialize widget, make sure that the following options' +
|
||||
' are passed: ' + aMandatoryOptions.join(' / '), 'error');
|
||||
CombodoJSConsole.Error('CaseLogEntryForm: Could not initialize widget, make sure that the following options'+
|
||||
' are passed: '+aMandatoryOptions.join(' / '), 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -88,17 +88,16 @@ $(function() {
|
||||
CKEDITOR.on('instanceReady', function(oEvent){
|
||||
// Handle only the current CKEditor instance
|
||||
if(oEvent.editor.name === me.options.text_input_id) {
|
||||
CKEDITOR.instances[me.options.text_input_id].on('change', function(){
|
||||
me._GetCKEditorInstance().on('change', function () {
|
||||
const bWasDraftBefore = me.is_draft;
|
||||
const bIsDraftNow = !me._IsInputEmpty();
|
||||
|
||||
if(bWasDraftBefore !== bIsDraftNow) {
|
||||
if (bWasDraftBefore !== bIsDraftNow) {
|
||||
me.is_draft = bIsDraftNow;
|
||||
me._UpdateEditingVisualHint();
|
||||
if(me._IsSubmitAutonomous()) {
|
||||
if (me._IsSubmitAutonomous()) {
|
||||
me._UpdateSubmitButtonState();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
me._UpdateBridgeInput();
|
||||
}
|
||||
}
|
||||
@@ -107,10 +106,10 @@ $(function() {
|
||||
});
|
||||
|
||||
// Form buttons
|
||||
this.element.find(this.js_selectors.cancel_button).on('click', function(oEvent){
|
||||
this.element.find(this.js_selectors.cancel_button).on('click', function (oEvent) {
|
||||
me.element.trigger('cancelled_form.caselog_entry_form.itop');
|
||||
});
|
||||
this.element.find(this.js_selectors.save_button).on('click', function(oEvent){
|
||||
this.element.find(this.js_selectors.save_button).on('click', function (oEvent) {
|
||||
// Avoid form being submitted
|
||||
oEvent.preventDefault();
|
||||
|
||||
@@ -118,58 +117,39 @@ $(function() {
|
||||
});
|
||||
|
||||
// Form show/hide
|
||||
this.element.on('show_form.caselog_entry_form.itop', function(){
|
||||
this.element.on('show_form.caselog_entry_form.itop', function () {
|
||||
me._ShowEntryForm();
|
||||
});
|
||||
this.element.on('hide_form.caselog_entry_form.itop', function(){
|
||||
this.element.on('hide_form.caselog_entry_form.itop', function () {
|
||||
me._HideEntryForm();
|
||||
});
|
||||
|
||||
// Form pending submission states
|
||||
this.element.on('enter_pending_submission_state.caselog_entry_form.itop', function () {
|
||||
me._EnterPendingSubmissionState();
|
||||
});
|
||||
this.element.on('leave_pending_submission_state.caselog_entry_form.itop', function () {
|
||||
me._LeavePendingSubmissionState();
|
||||
});
|
||||
|
||||
// Get the entry value
|
||||
this.element.on('get_entry.caselog_entry_form.itop', function(){
|
||||
this.element.on('get_entry.caselog_entry_form.itop', function () {
|
||||
return me._GetInputData();
|
||||
});
|
||||
|
||||
// Caselog selection
|
||||
// TODO 3.0.0: Remove this as it is no longer useful
|
||||
this.element.on('add_to_caselog.caselog_entry_form.itop', function(oEvent, oData){
|
||||
const sCaseLogAttCode = oData.caselog_att_code;
|
||||
const sStimulusCode = oData.stimulus_code !== undefined ? oData.stimulus_code : null;
|
||||
|
||||
me._SubmitEntryToCaselog(me._GetInputData(), sCaseLogAttCode, sStimulusCode);
|
||||
});
|
||||
},
|
||||
_SubmitEntryToCaselog: function(sEntryContent, sCaselogAttCode, sStimulusCode = null){
|
||||
const me = this;
|
||||
const sObjClass = this.element.closest(this.js_selectors.activity_panel).attr('data-object-class');
|
||||
const sObjId = this.element.closest(this.js_selectors.activity_panel).attr('data-object-id');
|
||||
|
||||
let oParams = {
|
||||
'operation' : 'add_caselog_entry',
|
||||
'class' : sObjClass,
|
||||
'id' : sObjId,
|
||||
'caselog_new_entry': sEntryContent,
|
||||
'caselog_attcode' : sCaselogAttCode,
|
||||
'caselog_rank' : this.element.closest(this.js_selectors.activity_panel).activity_panel('GetCaseLogRank', sCaselogAttCode),
|
||||
}
|
||||
//TODO 3.0.0 Handle errors
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(sNewEntry){
|
||||
me.element.closest(me.js_selectors.activity_panel).activity_panel('AddEntry', sNewEntry, 'caselog:' + sCaselogAttCode)
|
||||
// Clear the entry value
|
||||
this.element.on('clear_entry.case_entry_form.itop', function () {
|
||||
me._EmptyInput();
|
||||
me._HideEntryForm();
|
||||
|
||||
// Redirect to stimulus
|
||||
if(sStimulusCode !== null){
|
||||
window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+sObjClass+'&id='+sObjId+'&stimulus='+sStimulusCode;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helpers
|
||||
_IsSubmitAutonomous: function() {
|
||||
_IsSubmitAutonomous: function () {
|
||||
return this.options.submit_mode === this.enums.submit_mode.autonomous;
|
||||
},
|
||||
// - Form
|
||||
_GetCKEditorInstance: function () {
|
||||
return CKEDITOR.instances[this.options.text_input_id];
|
||||
},
|
||||
_ShowEntryForm: function () {
|
||||
this.element.closest(this.js_selectors.activity_panel).find(this.js_selectors.form).removeClass(this.css_classes.is_closed);
|
||||
},
|
||||
@@ -178,6 +158,16 @@ $(function() {
|
||||
|
||||
// TODO 3.0.0: This should also clear the form (input, lock, send button, ...)
|
||||
},
|
||||
_EnterPendingSubmissionState: function () {
|
||||
this._GetCKEditorInstance().setReadOnly(true);
|
||||
this.element.find(this.js_selectors.cancel_button).prop('disabled', true);
|
||||
this.element.find(this.js_selectors.save_button).prop('disabled', true);
|
||||
},
|
||||
_LeavePendingSubmissionState: function () {
|
||||
this._GetCKEditorInstance().setReadOnly(false);
|
||||
this.element.find(this.js_selectors.cancel_button).prop('disabled', false);
|
||||
this.element.find(this.js_selectors.save_button).prop('disabled', false);
|
||||
},
|
||||
// - Bridged form input
|
||||
/**
|
||||
* Return the general object form element.
|
||||
@@ -186,7 +176,7 @@ $(function() {
|
||||
* @returns {null|jQuery.fn.init|jQuery|HTMLElement}
|
||||
* @private
|
||||
*/
|
||||
_GetGeneralFormElement: function() {
|
||||
_GetGeneralFormElement: function () {
|
||||
const oActivityPanelElem = this.element.closest(this.js_selectors.activity_panel);
|
||||
const sHostObjClass = oActivityPanelElem.attr('data-object-class');
|
||||
const sHostObjId = oActivityPanelElem.attr('data-object-id');
|
||||
@@ -194,7 +184,7 @@ $(function() {
|
||||
const oGeneralFormElem = $('.object-details[data-object-class="'+sHostObjClass+'"][data-object-id="'+sHostObjId+'"] > form');
|
||||
|
||||
// Protection in case this is called with non editable general form
|
||||
if(oGeneralFormElem.length === 0) {
|
||||
if (oGeneralFormElem.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -212,9 +202,7 @@ $(function() {
|
||||
const oGeneralFormElem = this._GetGeneralFormElement();
|
||||
|
||||
if(oGeneralFormElem === null) {
|
||||
if(window.console && window.console.error){
|
||||
console.error('Could not add bridge input as there is no general form');
|
||||
}
|
||||
CombodoJSConsole.Error('CaseLogEntryForm: Could not add bridge input as there is no general form');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\ActivityEntryFactory;
|
||||
use Combodo\iTop\Controller\AjaxRenderController;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
|
||||
@@ -2650,27 +2649,20 @@ EOF
|
||||
}
|
||||
$oPage->add(json_encode($aResult));
|
||||
break;
|
||||
case 'add_caselog_entry':
|
||||
// TODO 3.0.0: Handle errors & rights
|
||||
$sClass = utils::ReadPostedParam('class', '', 'class');
|
||||
$sClassLabel = MetaModel::GetName($sClass);
|
||||
$id = utils::ReadPostedParam('id', '');
|
||||
// TODO 3.0.0 Handle transactions token which is not passed yet
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
|
||||
$sCaseLogAttCode = utils::ReadPostedParam('caselog_attcode', '');
|
||||
$sCaseLogNewEntry = utils::ReadPostedParam('caselog_new_entry', '', 'raw');
|
||||
$iCaseLogRank = utils::ReadPostedParam('caselog_rank', 0, 'integer');
|
||||
if($id !== 0 && MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($sClass, $id);
|
||||
$oObj->Set($sCaseLogAttCode, $sCaseLogNewEntry);
|
||||
$oObj->DBWrite();
|
||||
|
||||
// Activity panel
|
||||
case 'add_caselog_entries':
|
||||
$oPage->SetContentType('application/json');
|
||||
try {
|
||||
$aResult = AjaxRenderController::AddCaseLogsEntries();
|
||||
}
|
||||
$oNewEntry = ActivityEntryFactory::MakeFromCaseLogEntryArray($sCaseLogAttCode, $oObj->Get($sCaseLogAttCode)->GetAsArray()[0]);
|
||||
$oNewEntry->SetCaseLogRank($iCaseLogRank);
|
||||
$oPage->AddUiBlock($oNewEntry);
|
||||
break;
|
||||
case 'new_entry_group':
|
||||
catch (Exception $oException) {
|
||||
$aResult = [
|
||||
'success' => false,
|
||||
'error_message' => $oException->getMessage(),
|
||||
];
|
||||
}
|
||||
$oPage->add(json_encode($aResult));
|
||||
break;
|
||||
|
||||
case 'get_menus_count':
|
||||
|
||||
@@ -13,12 +13,15 @@ use BulkExport;
|
||||
use BulkExportException;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\ActivityEntryFactory;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use DBSearch;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use ExecutionKPI;
|
||||
use InlineImage;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
|
||||
@@ -367,4 +370,85 @@ class AjaxRenderController
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new entries to some of the object's (identified by posted parameters) case logs
|
||||
*
|
||||
* @return array The status of the update, a renewed transaction ID and the entries as HTML so they can be append to the front.
|
||||
* [
|
||||
* 'success' => true,
|
||||
* 'entries' => [
|
||||
* '<ATT_CODE_1>' => [
|
||||
* html_rendering => '<HTML_RENDERING_TO_BE_APPEND_IN_FRONT_END>',
|
||||
* ],
|
||||
* '<ATT_CODE_2>' => [
|
||||
* html_rendering => '<HTML_RENDERING_TO_BE_APPEND_IN_FRONT_END>',
|
||||
* ],
|
||||
* ...
|
||||
* ],
|
||||
* 'renewed_transaction_id' => '<RENEWED_TRANSACTION_ID>',
|
||||
* ]
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*/
|
||||
public static function AddCaseLogsEntries(): array
|
||||
{
|
||||
$sObjectClass = utils::ReadPostedParam('object_class', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$sObjectId = utils::ReadPostedParam('object_id', 0);
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', null, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
|
||||
// TODO 3.0.0: Remove this line when transaction handled
|
||||
$sTransactionId = 'foo';
|
||||
$aEntries = utils::ReadPostedParam('entries', [], utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
|
||||
// Consistency checks
|
||||
// - Mandatory parameters
|
||||
if (empty($sObjectClass) || empty($sObjectId) || empty($sTransactionId) || empty($aEntries)) {
|
||||
throw new Exception('Missing mandatory parameters object_class / object_id / transaction_id / entries');
|
||||
}
|
||||
// - Transaction ID
|
||||
// TODO 3.0.0: Uncomment when transaction ID is passed (retrieved from the upcoming lock system)
|
||||
// if (!utils::IsTransactionValid($sTransactionId)) {
|
||||
// throw new Exception(Dict::S('iTopUpdate:Error:InvalidToken'));
|
||||
// }
|
||||
|
||||
$aResults = [
|
||||
'success' => true,
|
||||
'entries' => [],
|
||||
];
|
||||
|
||||
// Note: Will trigger an exception if object does not exists or not accessible to the user
|
||||
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId);
|
||||
foreach ($aEntries as $sAttCode => $aData) {
|
||||
// Add entry to object
|
||||
$oObject->Set($sAttCode, $aData['value']);
|
||||
|
||||
// Make entry rendering to send back to the front
|
||||
$aEntryAsArray = $oObject->Get($sAttCode)->GetAsArray()[0];
|
||||
$oEntryBlock = ActivityEntryFactory::MakeFromCaseLogEntryArray($sAttCode, $aEntryAsArray);
|
||||
$oEntryBlock->SetCaseLogRank((int)$aData['rank']);
|
||||
$sEntryAsHtml = BlockRenderer::RenderBlockTemplates($oEntryBlock);
|
||||
|
||||
$aResults['entries'][$sAttCode] = [
|
||||
'html_rendering' => $sEntryAsHtml,
|
||||
];
|
||||
}
|
||||
$oObject->DBWrite();
|
||||
|
||||
// Finalize inline images
|
||||
InlineImage::FinalizeInlineImages($oObject);
|
||||
|
||||
// Renew transaction ID
|
||||
utils::RemoveTransaction($sTransactionId);
|
||||
$aResults['renewed_transaction_id'] = utils::GetNewTransactionId();
|
||||
|
||||
return $aResults;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div id="{{ oUIBlock.GetId() }}" class="ibo-activity-panel" data-role="ibo-activity-panel" data-object-class="{{ oUIBlock.GetObjectClass() }}" data-object-id="{{ oUIBlock.GetObjectId() }}" data-object-mode="{{ oUIBlock.GetObjectMode() }}">
|
||||
<div class="ibo-activity-panel--header">
|
||||
<div class="ibo-activity-panel--tabs-togglers" data-role="ibo-activity-panel--tabs-togglers">
|
||||
{% for sCaseLogAttCode, aCaseLogData in oUIBlock.GetCaseLogTabs() %}
|
||||
<div class="ibo-activity-panel--header" data-role="ibo-activity-panel--header">
|
||||
<div class="ibo-activity-panel--tabs-togglers" data-role="ibo-activity-panel--tabs-togglers">
|
||||
{% for sCaseLogAttCode, aCaseLogData in oUIBlock.GetCaseLogTabs() %}
|
||||
{% set sExtraCSSClass = (loop.index == 1) ? 'ibo-is-active' : '' %}
|
||||
<div class="ibo-activity-panel--tab-toggler ibo-activity-panel--tab-toggler-for-caselog ibo-activity-panel--tab-toggler-for-caselog-{{ loop.index }} {{ sExtraCSSClass }}"
|
||||
data-role="ibo-activity-panel--tab-toggler"
|
||||
@@ -55,10 +55,13 @@
|
||||
</div>
|
||||
</div>
|
||||
{% if oUIBlock.HasAnEditableCaseLogTab() and oUIBlock.IsCaseLogsSubmitAutonomous() %}
|
||||
<a href="#" class="ibo-activity-panel--add-caselog-entry-button" data-role="ibo-activity-panel--add-caselog-entry-button"><i class="fas fa-feather"></i></a>
|
||||
{% endif %}
|
||||
<div class="ibo-activity-panel--body">
|
||||
{% if oUIBlock.GetGroupedEntries()|length > 0 %}
|
||||
<a href="#" class="ibo-activity-panel--add-caselog-entry-button" data-role="ibo-activity-panel--add-caselog-entry-button"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:ComposeButton:Tooltip'|dict_s }}">
|
||||
<i class="fas fa-feather"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="ibo-activity-panel--body" data-role="ibo-activity-panel--body">
|
||||
{% if oUIBlock.GetGroupedEntries()|length > 0 %}
|
||||
{% for aEntryGroup in oUIBlock.GetGroupedEntries() %}
|
||||
{{ include('base/layouts/activity-panel/entry-group.html.twig', {aEntryGroup: aEntryGroup}) }}
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
$('#{{ oUIBlock.GetId() }}').activity_panel({
|
||||
datetime_format: {{ oUIBlock.GetDateTimeFormatForJSWidget()|json_encode|raw }},
|
||||
datetime_format: {{ oUIBlock.GetDateTimeFormatForJSWidget()|json_encode|raw }},
|
||||
show_multiple_entries_submit_confirmation: {{ oUIBlock.GetShowMultipleEntriesSubmitConfirmation()|var_export }}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user