diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php index e79d94161..6c4fda610 100644 --- a/application/displayblock.class.inc.php +++ b/application/displayblock.class.inc.php @@ -1246,6 +1246,10 @@ JS } else { $oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, null, null, $aRefreshParams); } + $sClassDescription = MetaModel::GetClassDescription($sClass); + if (utils::IsNotNullOrEmptyString($sClassDescription)) { + $oBlock->SetClassDescription($sClassDescription); + } return $oBlock; } diff --git a/application/ui.linkswidget.class.inc.php b/application/ui.linkswidget.class.inc.php index b0c4f5255..0354a1a83 100644 --- a/application/ui.linkswidget.class.inc.php +++ b/application/ui.linkswidget.class.inc.php @@ -178,17 +178,18 @@ class UILinksWidget $oDisplayBlock = new DisplayBlock($oFilter, 'search', false); $oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}", - array( - 'menu' => false, + [ + 'menu' => false, 'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}", - 'table_id' => "add_{$sLinkedSetId}", - 'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}", - 'selection_mode' => true, - 'json' => $sJson, - 'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix, - 'query_params' => $oFilter->GetInternalParams(), - 'hidden_criteria' => $sAlreadyLinkedExpression, - ))); + 'table_id' => "add_{$sLinkedSetId}", + 'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}", + 'selection_mode' => true, + 'json' => $sJson, + 'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix, + 'query_params' => $oFilter->GetInternalParams(), + 'hidden_criteria' => $sAlreadyLinkedExpression, + 'submit_on_load' => false, + ])); $oBlock->AddForm(); } diff --git a/core/action.class.inc.php b/core/action.class.inc.php index 756f98a8f..53bf71865 100644 --- a/core/action.class.inc.php +++ b/core/action.class.inc.php @@ -650,6 +650,9 @@ class ActionEmail extends ActionNotification $aMessageContent['subject'] = 'TEST['.$aMessageContent['subject'].']'; $aMessageContent['body'] = $sTestBody; $aMessageContent['to'] = $this->Get('test_recipient'); + // N°6677 Ensure emails in test are never sent to cc'd and bcc'd addresses + $aMessageContent['cc'] = ''; + $aMessageContent['bcc'] = ''; } // Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification $aMessageContent['in_reply_to'] = $aMessageContent['references']; diff --git a/css/backoffice/components/dashlet/_dashlet-badge.scss b/css/backoffice/components/dashlet/_dashlet-badge.scss index eda128e97..f95a2cc1c 100644 --- a/css/backoffice/components/dashlet/_dashlet-badge.scss +++ b/css/backoffice/components/dashlet/_dashlet-badge.scss @@ -20,6 +20,8 @@ $ibo-dashlet-badge--icon--size: 48px !default; $ibo-dashlet-badge--action-icon--margin-right: $ibo-spacing-300 !default; +$ibo-dashlet-badge--body--tooltip-title--margin-bottom: $ibo-spacing-500 !default; + /* CSS variables (can be changed directly from the browser) */ :root { --ibo-dashlet-badge--min-width: #{$ibo-dashlet-badge--min-width}; @@ -74,18 +76,27 @@ $ibo-dashlet-badge--action-icon--margin-right: $ibo-spacing-300 !default; @extend %ibo-hyperlink-inherited-colors; } } -.ibo-dashlet-badge--action-list-count{ - margin-right: $ibo-dashlet-badge--action-list-count--margin-right; - @extend %ibo-font-ral-bol-450; + +.ibo-dashlet-badge--action-list-count { + margin-right: $ibo-dashlet-badge--action-list-count--margin-right; + @extend %ibo-font-ral-bol-450; } -.ibo-dashlet-badge--action-list-label{ - display: inline-block; - @extend %ibo-text-truncated-with-ellipsis; + +.ibo-dashlet-badge--action-list-label { + display: inline-block; + @extend %ibo-text-truncated-with-ellipsis; } -.ibo-dashlet-badge--action-create{ - @extend %ibo-baseline-centered-content; - @extend %ibo-font-size-150; + +.ibo-dashlet-badge--action-create { + @extend %ibo-baseline-centered-content; + @extend %ibo-font-size-150; } -.ibo-dashlet-badge--action-create-icon{ - margin-right: $ibo-dashlet-badge--action-icon--margin-right; + +.ibo-dashlet-badge--action-create-icon { + margin-right: $ibo-dashlet-badge--action-icon--margin-right; +} + +.ibo-dashlet-badge--body--tooltip-title { + @extend %ibo-font-weight-600; + margin-bottom: $ibo-dashlet-badge--body--tooltip-title--margin-bottom; } diff --git a/js/layouts/activity-panel/activity-panel.js b/js/layouts/activity-panel/activity-panel.js index ed9326589..f3669cadd 100644 --- a/js/layouts/activity-panel/activity-panel.js +++ b/js/layouts/activity-panel/activity-panel.js @@ -117,6 +117,7 @@ $(function() locked_by_someone_else: 'locked_by_someone_else', }, }, + release_lock_promise_resolve: null, // N°4494 - Resolve callback of the Promise used for the action following the log entry send, which must be done only once the lock is released // the constructor _create: function () { @@ -500,7 +501,7 @@ $(function() { // Hide all filters' options only if click wasn't on one of them if(($(oEvent.target).closest(this.js_selectors.activity_filter_options_toggler).length === 0) - && $(oEvent.target).closest(this.js_selectors.activity_filter_options).length === 0) { + && $(oEvent.target).closest(this.js_selectors.activity_filter_options).length === 0) { this._HideAllFiltersOptions(); } }, @@ -947,9 +948,9 @@ $(function() // Send request to server $.post( - GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', - oParams, - 'json' + GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', + oParams, + 'json' ) .fail(function (oXHR, sStatus, sErrorThrown) { CombodoModal.OpenErrorModal(sErrorThrown); @@ -972,12 +973,24 @@ $(function() // 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.caselog_entry_form.itop'); - // Redirect to stimulus // - Convert undefined, null and empty string to null sStimulusCode = ((sStimulusCode ?? '') === '') ? null : sStimulusCode; if (null !== sStimulusCode) { - window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+me._GetHostObjectClass()+'&id='+me._GetHostObjectID()+'&stimulus='+sStimulusCode; + if (me.options.lock_enabled) { + // Use a Promise to ensure that we redirect to the stimulus page ONLY when the lock is released, otherwise we might lock ourselves + const oPromise = new Promise(function(resolve) { + // Store the resolve callback so we can call it later from outside + me.release_lock_promise_resolve = resolve; + }); + oPromise.then(function () { + window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+me._GetHostObjectClass()+'&id='+me._GetHostObjectID()+'&stimulus='+sStimulusCode; + // Resolve callback is reinitialized in case the redirection fails for any reason and we might need to retry + me.release_lock_promise_resolve = null; + }); + } else { + window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+me._GetHostObjectClass()+'&id='+me._GetHostObjectID()+'&stimulus='+sStimulusCode; + } } }) .always(function () { @@ -995,7 +1008,7 @@ $(function() _IncreaseTabTogglerMessagesCounter: function(sCaseLogAttCode){ let oTabTogglerCounter = this._GetTabTogglerFromCaseLogAttCode(sCaseLogAttCode).find('[data-role="ibo-activity-panel--tab-title-messages-count"]'); let iNewCounterValue = parseInt(oTabTogglerCounter.attr('data-messages-count')) + 1; - + oTabTogglerCounter.attr('data-messages-count', iNewCounterValue).text(iNewCounterValue); }, /** @@ -1143,11 +1156,10 @@ $(function() else { oParams.operation = 'check_lock_state'; } - $.post( - this.options.lock_endpoint, - oParams, - 'json' + this.options.lock_endpoint, + oParams, + 'json' ) .fail(function (oXHR, sStatus, sErrorThrown) { // In case of HTTP request failure (not lock request), put the details in the JS console @@ -1196,6 +1208,9 @@ $(function() // Tried to release our lock else if ('release_lock' === oParams.operation) { sNewLockStatus = me.enums.lock_status.unknown; + if (me.release_lock_promise_resolve !== null) { + me.release_lock_promise_resolve(); + } } // Just checked if object was locked @@ -1430,9 +1445,9 @@ $(function() limit_results_length: bLimitResultsLength, }; $.post( - this.options.load_more_entries_endpoint, - oParams, - 'json' + this.options.load_more_entries_endpoint, + oParams, + 'json' ) .fail(function (oXHR, sStatus, sErroThrown) { CombodoModal.OpenErrorModal(sErrorThrown); diff --git a/js/links/links_widget.js b/js/links/links_widget.js index 6983e70c0..309918a88 100644 --- a/js/links/links_widget.js +++ b/js/links/links_widget.js @@ -153,16 +153,15 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH "dataType": "html" }) .done(function (data) { + /* N°6152 - Hide during data loading and before open */ + $('#dlg_'+me.id).hide(); $('#dlg_'+me.id).html(data); window[sPromiseId].then(function () { $('#dlg_'+me.id).dialog('open'); me.UpdateSizes(null, null); - if (me.bDoSearch) - { + if (me.bDoSearch) { me.SearchObjectsToAdd(); - } - else - { + } else { $('#count_'+me.id).change(function () { let c = this.value; me.UpdateButtons(c); diff --git a/pages/UniversalSearch.php b/pages/UniversalSearch.php index ac73a64c4..0597a36f4 100644 --- a/pages/UniversalSearch.php +++ b/pages/UniversalSearch.php @@ -105,7 +105,7 @@ if ($oFilter != null) $aExtraParams['action'] = utils::GetAbsoluteUrlAppRoot().'pages/UniversalSearch.php'; $aExtraParams['table_id'] = '1'; $aExtraParams['search_header_force_dropdown'] = $sSearchHeaderForceDropdown; - //$aExtraParams['class'] = $sClassName; + $aExtraParams['submit_on_load'] = false; $oBlock->Display($oP, 0, $aExtraParams); // Search results diff --git a/pages/tagadmin.php b/pages/tagadmin.php index 33da2ab8f..f52a37df3 100644 --- a/pages/tagadmin.php +++ b/pages/tagadmin.php @@ -109,6 +109,7 @@ try $aExtraParams['action'] = utils::GetAbsoluteUrlAppRoot().'pages/tagadmin.php'; $aExtraParams['table_id'] = '1'; $aExtraParams['search_header_force_dropdown'] = $sSearchHeaderForceDropdown; + $aExtraParams['submit_on_load'] = false; $oBlock->Display($oP, 0, $aExtraParams); // Search results diff --git a/sources/Application/UI/Base/Component/Dashlet/DashletBadge.php b/sources/Application/UI/Base/Component/Dashlet/DashletBadge.php index 12e2722cb..d92fb05f2 100644 --- a/sources/Application/UI/Base/Component/Dashlet/DashletBadge.php +++ b/sources/Application/UI/Base/Component/Dashlet/DashletBadge.php @@ -9,6 +9,7 @@ namespace Combodo\iTop\Application\UI\Base\Component\Dashlet; use Combodo\iTop\Application\UI\Base\tJSRefreshCallback; +use utils; class DashletBadge extends DashletContainer { @@ -29,6 +30,11 @@ class DashletBadge extends DashletContainer protected $iCount; /** @var string */ protected $sClassLabel; + /** + * @var string + * @since 3.1.1 3.2.0 + */ + protected $sClassDescription; /** @var string */ protected $sCreateActionUrl; @@ -62,6 +68,7 @@ class DashletBadge extends DashletContainer $this->sCreateActionUrl = $sCreateActionUrl; $this->sCreateActionLabel = $sCreateActionLabel; $this->aRefreshParams = $aRefreshParams; + $this->sClassDescription = ''; } @@ -185,6 +192,37 @@ class DashletBadge extends DashletContainer return $this; } + /** + * @return string + * @since 3.1.1 3.2.0 + */ + public function GetClassDescription(): string + { + return $this->sClassDescription; + } + + /** + * @param string $sClassDescription + * + * @return DashletBadge + * @since 3.1.1 3.2.0 + */ + public function SetClassDescription(string $sClassDescription) + { + $this->sClassDescription = $sClassDescription; + + return $this; + } + + /** + * @return bool + * @since 3.1.1 + */ + public function HasClassDescription(): bool + { + return utils::IsNotNullOrEmptyString($this->sClassDescription); + } + public function GetJSRefresh(): string { return "$('#".$this->sId."').block(); diff --git a/templates/base/components/dashlet/dashlet-badge.html.twig b/templates/base/components/dashlet/dashlet-badge.html.twig index 74096e9ee..52ea2d2de 100644 --- a/templates/base/components/dashlet/dashlet-badge.html.twig +++ b/templates/base/components/dashlet/dashlet-badge.html.twig @@ -3,7 +3,16 @@ {% apply spaceless %}