diff --git a/css/backoffice/layout/activity-panel/_activity-panel.scss b/css/backoffice/layout/activity-panel/_activity-panel.scss index 796b508b3..1c5ac2044 100644 --- a/css/backoffice/layout/activity-panel/_activity-panel.scss +++ b/css/backoffice/layout/activity-panel/_activity-panel.scss @@ -48,7 +48,7 @@ $ibo-activity-panel--tab-title-decoration--height: $ibo-activity-panel--tab-titl $ibo-activity-panel--tab-title-decoration--margin-right: 8px !default; $ibo-activity-panel--tab-title-decoration--border-radius: $ibo-border-radius-300 !default; -$ibo-activity-panel--tab-title-draft-indicator--margin-right: $ibo-activity-panel--tab-title-decoration--margin-right !default; +$ibo-activity-panel--tab-title-draft-indicator--margin-x: $ibo-activity-panel--tab-title-decoration--margin-right !default; $ibo-activity-panel--tab-title-text--max-width: 100px !default; @@ -99,6 +99,9 @@ $ibo-activity-panel--add-caselog-entry-button--icon--width: $ibo-activity-panel- $ibo-activity-panel--add-caselog-entry-button--icon--font-size: 16px !default; $ibo-activity-panel--add-caselog-entry-button--icon--line-height: 33px !default; +$ibo-activity-panel--entry-forms-confirmation-explanation--spacing: 16px !default; +$ibo-activity-panel--entry-forms-confirmation-preference-input--spacing: 0.5rem !default; + /* Whole layout */ .ibo-activity-panel{ width: $ibo-activity-panel--width; @@ -192,7 +195,7 @@ $ibo-activity-panel--add-caselog-entry-button--icon--line-height: 33px !default; } .ibo-activity-panel--tab-title-draft-indicator{ display: none; - margin-right: $ibo-activity-panel--tab-title-draft-indicator--margin-right; + margin-left: $ibo-activity-panel--tab-title-draft-indicator--margin-x; @extend %ibo-font-ral-nor-50; } .ibo-activity-panel--tab-title-text{ @@ -300,6 +303,8 @@ $ibo-activity-panel--add-caselog-entry-button--icon--line-height: 33px !default; margin-right: $ibo-activity-panel--filter-option-input--margin-right; } + + /* Body */ .ibo-activity-panel--body{ flex-grow: 1; /* To occupy all the space not used by the header */ @@ -354,3 +359,19 @@ $ibo-activity-panel--add-caselog-entry-button--icon--line-height: 33px !default; display: none; } } + +/* Entry forms confirmation dialog */ +.ibo-activity-panel { + .ibo-activity-panel--entry-forms-confirmation-dialog { + display: none; /* Dialog will be moved elsewhere in the DOM on display so this rule won't apply anymore and it will be OK */ + } +} +.ibo-activity-panel--entry-forms-confirmation-explanation{ + margin-bottom: $ibo-activity-panel--entry-forms-confirmation-explanation--spacing; +} +.ibo-activity-panel--entry-forms-confirmation-preference{ + @extend %ibo-vertically-centered-content; +} +.ibo-activity-panel--entry-forms-confirmation-preference-input{ + margin-right: $ibo-activity-panel--entry-forms-confirmation-preference-input--spacing; +} diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index 0af91cec5..512fa6054 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -430,6 +430,7 @@ Dict::Add('EN US', 'English', 'English', array( 'UI:Button:Wait' => 'Please wait while updating fields', 'UI:Treeview:CollapseAll' => 'Collapse All', 'UI:Treeview:ExpandAll' => 'Expand All', + 'UI:UserPref:DoNotShowAgain' => 'Do not show again', 'UI:SearchToggle' => 'Search', 'UI:ClickToCreateNew' => 'Create a %1$s', diff --git a/dictionaries/ui/layouts/en.dictionary.itop.activity-panel.php b/dictionaries/ui/layouts/en.dictionary.itop.activity-panel.php index 5b7f7a256..80e350604 100644 --- a/dictionaries/ui/layouts/en.dictionary.itop.activity-panel.php +++ b/dictionaries/ui/layouts/en.dictionary.itop.activity-panel.php @@ -22,7 +22,7 @@ Dict::Add('EN US', 'English', 'English', array( 'UI:Layout:ActivityPanel:SizeToggler:Expand:Tooltip' => 'Expand', 'UI:Layout:ActivityPanel:SizeToggler:Collapse:Tooltip' => 'Reduce', - // Activity tab + // Tabs 'UI:Layout:ActivityPanel:Tab:Activity:Title' => 'Activity', 'UI:Layout:ActivityPanel:Tab:Caselog:DraftIndicator:Tooltip' => 'Draft entry', 'UI:Layout:ActivityPanel:Tab:Toolbar:Filter:Caselogs:Title' => 'Case logs', @@ -36,6 +36,11 @@ 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)', + // 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.', + 'UI:Layout:ActivityPanel:MutltipleEntriesSaveConfirmation:PrefLabel' => 'By pressing the "save" button, you will submit entries for all the edited case logs at once.', + // Placeholder 'UI:Layout:ActivityPanel:NoEntry:Placeholder:Hint' => 'It\'s calm up here, no activity yet', )); \ No newline at end of file diff --git a/js/layouts/activity-panel/activity-panel.js b/js/layouts/activity-panel/activity-panel.js index 79cfa401a..fbf3cb987 100644 --- a/js/layouts/activity-panel/activity-panel.js +++ b/js/layouts/activity-panel/activity-panel.js @@ -26,6 +26,7 @@ $(function() { datetime_format: null, datetimes_reformat_limit: 14, // In days + show_multiple_entries_submit_confirmation: true, }, css_classes: { @@ -42,6 +43,7 @@ $(function() 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"]', @@ -54,6 +56,8 @@ $(function() 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"]', @@ -82,6 +86,7 @@ $(function() this._UpdateMessagesCounters(); this._UpdateFiltersCheckboxesFromOptions(); this._ReformatDateTimes(); + this._PrepareEntriesSubmitConfirmationDialog(); // TODO 3.0.0: Modify PopoverMenu so we can pass it the ID of the block triggering the open/close //$(this.element).find(this.js_selectors.send_choices_picker).popover_menu({toggler: this.js_selectors.send_button}); @@ -297,25 +302,21 @@ $(function() { this._HideCaseLogsEntryForms(); }, + /** + * Called on submission request from a case log entry form, will display a confirmation dialog if multiple case logs have + * been edited and the user hasn't dismiss the dialog. + * @private + */ _onRequestSubmission: function() { - // TODO 3.0.0 - // Retrieve current value from each entry form - let oEntries = {}; - 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; - } - }); - console.log(oEntries); // If several entry forms filled, show a confirmation message - // Push data to the server - // Put entries in the feed - // Renew transaction ID for inline images - + if ((true === this.options.show_multiple_entries_submit_confirmation) && (Object.keys(this._GetEntriesFromAllForms()).length > 1)) { + this._ShowEntriesSubmitConfirmation(); + } + // Else push data directly to the server + else { + this._SendEntriesToServer(); + } }, _onCaseLogClosedMessageClick: function(oEntryElem) { @@ -567,6 +568,94 @@ $(function() // TODO 3.0.0: Release lock }, + /** + * @returns {Object} The case logs having a new entry and their values, format is {: , : } + * @private + */ + _GetEntriesFromAllForms: function() + { + let oEntries = {}; + 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; + } + }); + + return oEntries; + }, + /** + * Prepare the dialog for confirmation before submission when several case log entries have been edited. + * @private + */ + _PrepareEntriesSubmitConfirmationDialog: function() + { + const me = this; + + this.element.find(this.js_selectors.caselog_entry_forms_confirmation_dialog).dialog({ + autoOpen: false, + minWidth: 400, + modal:true, + position: { my: "center center", at: "center center", of: this.js_selectors.tabs_toolbars }, + buttons: [ + { + text: Dict.S('UI:Button:Cancel'), + class: 'ibo-is-alternative', + click: function() { + me._HideEntriesSubmitConfirmation(); + } + }, + { + text: Dict.S('UI:Button:Save'), + class: 'ibo-is-primary', + click: function() { + const bDoNotShowAgain = $(this).find(me.js_selectors.caselog_entry_forms_confirmation_preference_input).prop('checked'); + if (bDoNotShowAgain) { + me._SaveSubmitConfirmationPref(); + } + me._SendEntriesToServer(); + } + }, + ], + }); + }, + /** + * Show the confirmation dialog when multiple case log entries have been editied + * @private + */ + _ShowEntriesSubmitConfirmation: function() + { + $(this.js_selectors.caselog_entry_forms_confirmation_dialog).dialog('open'); + }, + /** + * Hide the confirmation dialog for multiple edited case log entries + * @private + */ + _HideEntriesSubmitConfirmation: function() + { + $(this.js_selectors.caselog_entry_forms_confirmation_dialog).dialog('close'); + }, + /** + * Save that the user don't want the confirmation dialog to be shown in the future + * @private + */ + _SaveSubmitConfirmationPref: function() + { + // Note: We have to send the value as a string because of the API limitation + SetUserPreference('activity_panel.show_multiple_entries_submit_confirmation', 'false', true); + }, + /** + * Send the edited case logs entries to the server + * @private + */ + _SendEntriesToServer: function() + { + const oEntries = this._GetEntriesFromAllForms(); + // Put entries in the feed + // Renew transaction ID for inline images + }, // - Helpers on messages _OpenMessage: function(oEntryElem) diff --git a/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php b/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php index a4cb55de9..c89f18508 100644 --- a/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php +++ b/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php @@ -20,6 +20,7 @@ namespace Combodo\iTop\Application\UI\Base\Layout\ActivityPanel; +use appUserPreferences; use AttributeDateTime; use cmdbAbstractObject; use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\ActivityEntry; @@ -48,6 +49,12 @@ class ActivityPanel extends UIBlock 'js/layouts/activity-panel/activity-panel.js', ]; + /** + * @var bool + * @see static::$bShowMultipleEntriesSubmitConfirmation + */ + public const DEFAULT_SHOW_MULTIPLE_ENTRIES_SUBMI_CONFIRMATION = true; + /** @var \DBObject $oObject The object for which the activity panel is for */ protected $oObject; /** @@ -68,6 +75,8 @@ class ActivityPanel extends UIBlock protected $bHasStates; /** @var \Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\CaseLogEntryForm\CaseLogEntryForm[] $aCaseLogTabsEntryForms */ protected $aCaseLogTabsEntryForms; + /** @var bool Whether a confirmation dialog should be prompt when multiple entries are about to be submitted at once */ + protected $bShowMultipleEntriesSubmitConfirmation; /** * ActivityPanel constructor. @@ -89,6 +98,7 @@ class ActivityPanel extends UIBlock $this->SetObjectMode(cmdbAbstractObject::DEFAULT_OBJECT_MODE); $this->SetEntries($aEntries); $this->bAreEntriesSorted = false; + $this->ComputedShowMultipleEntriesSubmitConfirmation(); } /** @@ -550,6 +560,15 @@ class ActivityPanel extends UIBlock return !empty($this->aCaseLogTabsEntryForms[$sCaseLogId]); } + /** + * @uses static::$bShowMultipleEntriesSubmitConfirmation + * @return bool + */ + public function GetShowMultipleEntriesSubmitConfirmation(): bool + { + return $this->bShowMultipleEntriesSubmitConfirmation; + } + /** * Whether the submission of the case logs present in the activity panel is autonomous or will be handled by another form * @@ -609,4 +628,19 @@ class ActivityPanel extends UIBlock return $aSubBlocks; } + + /** + * @see static::$bShowMultipleEntriesSubmitConfirmation + * @return $this + * @throws \CoreException + * @throws \CoreUnexpectedValue + * @throws \MySQLException + */ + protected function ComputedShowMultipleEntriesSubmitConfirmation() + { + // Note: Test on a string is necessary as we can only store strings from the JS API, not booleans. + // Note 2: Do not invert the test to "=== 'true'" as it won't work. Default value is a bool ("true"), values from the DB are strings (true|false) + $this->bShowMultipleEntriesSubmitConfirmation = appUserPreferences::GetPref('activity_panel.show_multiple_entries_submit_confirmation', static::DEFAULT_SHOW_MULTIPLE_ENTRIES_SUBMI_CONFIRMATION) !== 'false'; + return $this; + } } \ No newline at end of file diff --git a/templates/base/layouts/activity-panel/layout.html.twig b/templates/base/layouts/activity-panel/layout.html.twig index 14df7da74..7f4238166 100644 --- a/templates/base/layouts/activity-panel/layout.html.twig +++ b/templates/base/layouts/activity-panel/layout.html.twig @@ -1,6 +1,6 @@
-
+
{% for sCaseLogAttCode, aCaseLogData in oUIBlock.GetCaseLogTabs() %} {% set sExtraCSSClass = (loop.index == 1) ? 'ibo-is-active' : '' %}
-
+
{% for sCaseLogAttCode, aCaseLogData in oUIBlock.GetCaseLogTabs() %} {{ include('base/layouts/activity-panel/tab-toolbar/caselog.html.twig', {oUIBlock: oUIBlock, iRank: loop.index, bIsActive: (loop.index == 1), aFilteredCaseLogsAttCodes: [sCaseLogAttCode]}) }} {% endfor %} {{ include('base/layouts/activity-panel/tab-toolbar/activity.html.twig', {oUIBlock: oUIBlock, bIsActive: (oUIBlock.GetCaseLogTabs()|length == 0)}) }} +
+
By pressing the "save" button, you will submit entries for all the edited case logs at once.
+ +
{% if oUIBlock.HasAnEditableCaseLogTab() and oUIBlock.IsCaseLogsSubmitAutonomous() %} diff --git a/templates/base/layouts/activity-panel/layout.js.twig b/templates/base/layouts/activity-panel/layout.js.twig index 52e7f6f6a..e0fd87527 100644 --- a/templates/base/layouts/activity-panel/layout.js.twig +++ b/templates/base/layouts/activity-panel/layout.js.twig @@ -1,3 +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 }} });