From 2f69b54c8395445ca2c3d47f0a2921fce5f92b0d Mon Sep 17 00:00:00 2001 From: RomainLvr Date: Thu, 12 Nov 2026 16:48:20 +0100 Subject: [PATCH] Fix - Slow display of pages showing alerts when many alerts exist --- CHANGELOG.md | 8 ++++++ hook.php | 3 ++ inc/alert.class.php | 18 ++++-------- inc/alert_target.class.php | 23 +++++++++++++-- public/css/styles.css | 14 +++++++++ public/js/news.js | 10 ++----- setup.php | 48 ++++++++++++++----------------- templates/display_alert.html.twig | 44 ++++------------------------ 8 files changed, 81 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e837b4..7da5135 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] + +### Fixed + +- Faster display of pages showing alerts (ticket form, central page, ticket list) when many alerts exist +- Faster display of the alert targets tab +- Closing an alert sent one request per tab previously opened on the page + ## [1.14.2] - 2026-10-06 ### Fixed diff --git a/hook.php b/hook.php index a700358..31ce553 100644 --- a/hook.php +++ b/hook.php @@ -157,6 +157,9 @@ function plugin_news_install() $migration->addKey($alert_table, 'is_active'); } + // index used to find the alerts to display, which would otherwise scan every past alert + $migration->addKey($alert_table, ['is_active', 'is_deleted', 'date_end'], 'is_active_is_deleted_date_end'); + // fix is_default default value $alert_fields = $DB->listFields($alert_table); if ($alert_fields['is_deleted']['Default'] !== '0') { diff --git a/inc/alert.class.php b/inc/alert.class.php index e9e5188..f1ff78e 100644 --- a/inc/alert.class.php +++ b/inc/alert.class.php @@ -227,24 +227,18 @@ public function rawSearchOptions() public function post_updateItem($history = true) { + /** @var DBmysql $DB */ + global $DB; + // force display of alerts after update regardless of their closable state - $alert_user = new PluginNewsAlert_User(); - //get all Alert_User for this alert where state is hidden - $all_alert = $alert_user->find( + $DB->update( + PluginNewsAlert_User::getTable(), + ['state' => PluginNewsAlert_User::VISIBLE], [ 'plugin_news_alerts_id' => $this->getID(), 'state' => PluginNewsAlert_User::HIDDEN, ], ); - foreach ($all_alert as $alert) { - //update state to force display - $alert_user->update( - [ - 'id' => $alert['id'], - 'state' => PluginNewsAlert_User::VISIBLE, - ], - ); - } } public static function findAllToNotify($params = []) diff --git a/inc/alert_target.class.php b/inc/alert_target.class.php index ded9ff2..213024f 100644 --- a/inc/alert_target.class.php +++ b/inc/alert_target.class.php @@ -120,8 +120,11 @@ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $ public static function showForAlert(PluginNewsAlert $alert) { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; + /** + * @var array $CFG_GLPI + * @var DBmysql $DB + */ + global $CFG_GLPI, $DB; $rand = mt_rand(); echo "
"; @@ -171,10 +174,24 @@ public static function showForAlert(PluginNewsAlert $alert) echo '' . __s('Recipient', 'news') . ''; echo ''; + // Load the targeted items with one query per itemtype instead of one per target + $ids_by_itemtype = []; + foreach ($found_target as $current_target) { + if (is_a($current_target['itemtype'], CommonDBTM::class, true) && $current_target['items_id'] > 0) { + $ids_by_itemtype[$current_target['itemtype']][] = $current_target['items_id']; + } + } + $rows_by_itemtype = []; + foreach ($ids_by_itemtype as $itemtype => $ids) { + foreach ($DB->request(['FROM' => getTableForItemType($itemtype),'WHERE' => ['id' => $ids]]) as $row) { + $rows_by_itemtype[$itemtype][$row['id']] = $row; + } + } + foreach ($found_target as $current_target) { if (is_a($current_target['itemtype'], CommonDBTM::class, true)) { $item = new $current_target['itemtype'](); - $item->getFromDB($current_target['items_id']); + $item->getFromResultSet($rows_by_itemtype[$current_target['itemtype']][$current_target['items_id']] ?? []); $name = ($current_target['all_items'] == 1 && $current_target['itemtype'] == 'Profile') ? __s('All', 'news') diff --git a/public/css/styles.css b/public/css/styles.css index c5d2c63..fd4a31a 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -26,10 +26,24 @@ * ------------------------------------------------------------------------- */ +/* Missing tabler variable */ +:root { + --tblr-lime: #74b816; +} + .plugin_news_alert-container { margin-bottom: 1rem; } +/* + * ITIL form has a specified layout, we must always display the full size alert. + * The "col-12" class can't be directly used for this purpose because a GLPI's core + * script will automatically replace it by "col-6" when expanding the sidebar. + */ +#itil-form .plugin_news_alert { + width: 100% !important; +} + /* Needed to have similar height for alerts on the same row */ .plugin_news_alert-container .alert { height: 100%; diff --git a/public/js/news.js b/public/js/news.js index 85450c5..cdad575 100644 --- a/public/js/news.js +++ b/public/js/news.js @@ -27,7 +27,7 @@ */ pluginNewsCloseAlerts = function() { - $(document).on("mousedown", ".plugin_news_alert .alert a[data-bs-dismiss=alert]", function(event) { + $(document).off("mousedown.pluginnews").on("mousedown.pluginnews", ".plugin_news_alert .alert a[data-bs-dismiss=alert]", function(event) { var alert = $(this).closest(".plugin_news_alert"); var id = alert.attr('data-id'); var a_url = CFG_GLPI.root_doc+"/plugins/news/ajax"; @@ -36,18 +36,14 @@ pluginNewsCloseAlerts = function() { }; pluginNewsToggleAlerts = function() { - $(document).on("click", ".plugin_news_alert-toggle",function() { + $(document).off("click.pluginnews").on("click.pluginnews", ".plugin_news_alert-toggle",function() { var alert = $(this).closest(".plugin_news_alert"); alert.toggleClass('expanded'); }); } +// Handlers are delegated on document: bound once, they also cover alerts loaded later in tabs $(function() { pluginNewsCloseAlerts(); pluginNewsToggleAlerts(); - - $(document).on('glpi.tab.loaded', function() { - pluginNewsCloseAlerts(); - pluginNewsToggleAlerts(); - }); }); diff --git a/setup.php b/setup.php index f795f10..a57a623 100644 --- a/setup.php +++ b/setup.php @@ -47,37 +47,31 @@ function plugin_init_news() $PLUGIN_HOOKS['csrf_compliant']['news'] = true; - $plugin = new Plugin(); - if ( - $plugin->isInstalled('news') - && $plugin->isActivated('news') - ) { - Plugin::registerClass('PluginNewsProfile', ['addtabon' => 'Profile']); + Plugin::registerClass('PluginNewsProfile', ['addtabon' => 'Profile']); - $PLUGIN_HOOKS['add_css']['news'] = 'css/styles.css'; - $PLUGIN_HOOKS['add_javascript']['news'][] = 'js/news.js'; - $PLUGIN_HOOKS['display_login']['news'] = [ - 'PluginNewsAlert', 'displayOnLogin', - ]; - $PLUGIN_HOOKS['display_central']['news'] = [ - 'PluginNewsAlert', 'displayOnCentral', - ]; - $PLUGIN_HOOKS['display_service_catalog']['news'] = [ - 'PluginNewsAlert', 'displayOnServiceCatalog', - ]; - $PLUGIN_HOOKS['pre_item_list']['news'] = ['PluginNewsAlert', 'preItemList']; + $PLUGIN_HOOKS['add_css']['news'] = 'css/styles.css'; + $PLUGIN_HOOKS['add_javascript']['news'][] = 'js/news.js'; + $PLUGIN_HOOKS['display_login']['news'] = [ + 'PluginNewsAlert', 'displayOnLogin', + ]; + $PLUGIN_HOOKS['display_central']['news'] = [ + 'PluginNewsAlert', 'displayOnCentral', + ]; + $PLUGIN_HOOKS['display_service_catalog']['news'] = [ + 'PluginNewsAlert', 'displayOnServiceCatalog', + ]; + $PLUGIN_HOOKS['pre_item_list']['news'] = ['PluginNewsAlert', 'preItemList']; - $PLUGIN_HOOKS['pre_item_form']['news'] = ['PluginNewsAlert', 'preItemForm']; + $PLUGIN_HOOKS['pre_item_form']['news'] = ['PluginNewsAlert', 'preItemForm']; - if (Session::haveRight(PluginNewsAlert::$rightname, READ)) { - $PLUGIN_HOOKS['menu_toadd']['news'] = [ - 'tools' => 'PluginNewsAlert', - ]; - $PLUGIN_HOOKS['config_page']['news'] = 'front/alert.php'; + if (Session::haveRight(PluginNewsAlert::$rightname, READ)) { + $PLUGIN_HOOKS['menu_toadd']['news'] = [ + 'tools' => 'PluginNewsAlert', + ]; + $PLUGIN_HOOKS['config_page']['news'] = 'front/alert.php'; - // require tinymce (for glpi >= 9.2) - $CFG_GLPI['javascript']['tools']['pluginnewsalert'] = ['tinymce']; - } + // require tinymce (for glpi >= 9.2) + $CFG_GLPI['javascript']['tools']['pluginnewsalert'] = ['tinymce']; } } diff --git a/templates/display_alert.html.twig b/templates/display_alert.html.twig index 23881c7..45c5179 100644 --- a/templates/display_alert.html.twig +++ b/templates/display_alert.html.twig @@ -26,24 +26,20 @@ # ------------------------------------------------------------------------- #} - - -{% set js_rand = random() %} +{# Accentuation color has a lower opacity, unless it is the background color (= no accent) #} +{% set accent = 'var(--tblr-' ~ alert_fields.emphasis_color ~ ')' %} +{% if alert_fields.emphasis_color != alert_fields.background_color %} + {% set accent = 'color-mix(in srgb, ' ~ accent ~ ' 60%, transparent)' %} +{% endif %}
@@ -82,31 +78,3 @@
-