diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php index 41afb394e..0cc5a5e0f 100644 --- a/application/displayblock.class.inc.php +++ b/application/displayblock.class.inc.php @@ -2216,11 +2216,25 @@ class MenuBlock extends DisplayBlock $oActionsToolbar->AddSubBlock($oActionButton); } - // - Search if ($this->m_sStyle == 'details') { + // - Search $oActionButton = ButtonUIBlockFactory::MakeIconLink('fas fa-search', Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass)), "{$sRootUrl}pages/UI.php?operation=search_form&do_search=0&class=$sClass{$sContext}", '', 'UI:SearchFor_Class'); $oActionButton->AddCSSClasses(['ibo-action-button', 'ibo-regular-action-button']); $oActionsToolbar->AddSubBlock($oActionButton); + } else { + // - Filter list + $sSearchUrl = utils::GetDataTableSearchUrl($this->m_oFilter); + if (!empty($sSearchUrl)) { + $oActionButton = ButtonUIBlockFactory::MakeIconLink( + 'fas fa-filter', + Dict::S('UI:Menu:FilterList'), + $sSearchUrl, + '', + 'UI:Menu:FilterList' + ); + $oActionButton->AddCSSClasses(['ibo-action-button', 'ibo-regular-action-button']); + $oActionsToolbar->AddSubBlock($oActionButton); + } } // - Others diff --git a/application/utils.inc.php b/application/utils.inc.php index 315013ded..e28e1c5bb 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -1462,6 +1462,7 @@ class utils } $aResult[] = new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL', '$sContext')"); $aResult[] = new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sDataTableId', '$sContext')"); + break; case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS: @@ -1515,32 +1516,24 @@ class utils default: // Unknown type of menu, do nothing } - foreach ($aResult as $oMenuItem) - { + foreach ($aResult as $oMenuItem) { $aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem(); } // Invoke the plugins // /** @var \iPopupMenuExtension $oExtensionInstance */ - foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance) - { - if (is_object($param) && !($param instanceof DBObject)) - { + foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance) { + if (is_object($param) && !($param instanceof DBObject)) { $tmpParam = clone $param; // In case the parameter is an DBObjectSet, clone it to prevent alterations - } - else - { + } else { $tmpParam = $param; } - foreach($oExtensionInstance->EnumItems($iMenuId, $tmpParam) as $oMenuItem) - { - if (is_object($oMenuItem)) - { + foreach ($oExtensionInstance->EnumItems($iMenuId, $tmpParam) as $oMenuItem) { + if (is_object($oMenuItem)) { $aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem(); - - foreach($oMenuItem->GetLinkedScripts() as $sLinkedScript) - { + + foreach ($oMenuItem->GetLinkedScripts() as $sLinkedScript) { $oContainerBlock->AddJsFileRelPath($sLinkedScript); } } @@ -1548,6 +1541,53 @@ class utils } } + /** + * We cannot use iMenuId (corresponding values in iPopupMenuExtension constants) as value is always \iPopupMenuExtension::MENU_OBJLIST_TOOLKIT + * whenever we are in a datatable, whereas it is included in a object tab, a dashlet or a search. + * + * So a {@see \ContextTag} is set on the corresponding calls. + * + * @return bool true if we are in a search page context, either directly or by the datatable ajax call + * + * @since 3.0.0 + * + * @uses \ContextTag::TAG_SEARCH + */ + public static function IsCurrentPageASearch(): bool + { + if (ContextTag::Check(ContextTag::TAG_SEARCH)) { + return true; + } + + return false; + } + + /** + * @param \DBObjectSearch $oFilter object list + * + * @return string|null null if we are already in a search, otherwise the URL to open this list in a search + * + * @throws \ArchivedObjectException + * @throws \CoreException + * + * @uses utils::IsCurrentPageASearch() + * + * @since 3.0.0 + */ + public static function GetDataTableSearchUrl(DBSearch $oFilter): ?string + { + if (static::IsCurrentPageASearch()) { + // we don't want to add the link when already in a search page ! + return null; + } + + $sAppRootUrl = static::GetAbsoluteUrlAppRoot(); + $oAppContext = new ApplicationContext(); + $sUrl = $sAppRootUrl.'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($oFilter->serialize()); + + return $sUrl; + } + /** * @param string $sEnvironment * @@ -1555,10 +1595,10 @@ class utils */ public static function GetConfigFilePath($sEnvironment = null) { - if (is_null($sEnvironment)) - { + if (is_null($sEnvironment)) { $sEnvironment = self::GetCurrentEnvironment(); } + return APPCONF.$sEnvironment.'/'.ITOP_CONFIG_FILE; } diff --git a/core/contexttag.class.inc.php b/core/contexttag.class.inc.php index 6fe9a6590..064082d03 100644 --- a/core/contexttag.class.inc.php +++ b/core/contexttag.class.inc.php @@ -52,17 +52,19 @@ */ class ContextTag { - const TAG_PORTAL = 'GUI:Portal'; - const TAG_CRON = 'CRON'; - const TAG_CONSOLE = 'GUI:Console'; - const TAG_SETUP = 'Setup'; - const TAG_SYNCHRO = 'Synchro'; - const TAG_REST = 'REST/JSON'; + public const TAG_PORTAL = 'GUI:Portal'; + public const TAG_CRON = 'CRON'; + public const TAG_CONSOLE = 'GUI:Console'; + public const TAG_SETUP = 'Setup'; + public const TAG_SYNCHRO = 'Synchro'; + public const TAG_REST = 'REST/JSON'; + public const TAG_SEARCH = 'Search'; protected static $aStack = array(); /** * Store a context tag on the stack + * * @param string $sTag */ public function __construct($sTag) diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index 0d6f93156..f40a2b438 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -1422,6 +1422,7 @@ When associated with a trigger, each action is given an "order" number, specifyi 'Calendar-FirstDayOfWeek' => 0,// 0 = Sunday, 1 = Monday, etc... 'UI:Menu:ShortcutList' => 'Create a Shortcut...', + 'UI:Menu:FilterList' => 'Filter list...', 'UI:ShortcutRenameDlg:Title' => 'Rename the shortcut', 'UI:ShortcutListDlg:Title' => 'Create a shortcut for the list', 'UI:ShortcutDelete:Confirm' => 'Please confirm that wou wish to delete the shortcut(s).', diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index 1f4d7225c..cdf1fd651 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -1402,6 +1402,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé 'Calendar-FirstDayOfWeek' => '1',// 0 = Sunday, 1 = Monday, etc... 'UI:Menu:ShortcutList' => 'Créer un Raccourci...', + 'UI:Menu:FilterList' => 'Filtrer la liste...', 'UI:ShortcutRenameDlg:Title' => 'Renommer le raccourci', 'UI:ShortcutListDlg:Title' => 'Créer un raccourci pour la liste', 'UI:ShortcutDelete:Confirm' => 'Veuillez confirmer la suppression du ou des raccourci(s)', diff --git a/pages/UI.php b/pages/UI.php index 6f03879f6..d0c4c7527 100644 --- a/pages/UI.php +++ b/pages/UI.php @@ -519,6 +519,7 @@ try /////////////////////////////////////////////////////////////////////////////////////////// case 'search': // Serialized DBSearch + $oSearchContext = new ContextTag(ContextTag::TAG_SEARCH); $sFilter = utils::ReadParam('filter', '', false, 'raw_data'); $sFormat = utils::ReadParam('format', ''); $bSearchForm = utils::ReadParam('search_form', true); diff --git a/pages/ajax.searchform.php b/pages/ajax.searchform.php index 82ba670bf..0f4a816bf 100644 --- a/pages/ajax.searchform.php +++ b/pages/ajax.searchform.php @@ -29,6 +29,7 @@ try throw new AjaxSearchException("Invalid query (empty filter)", 400); } + $oSearchContext = new ContextTag(ContextTag::TAG_SEARCH); $oPage = new AjaxPage(""); $oPage->SetContentType('text/html');