diff --git a/packages/web/management/js/fog/fog.common.js b/packages/web/management/js/fog/fog.common.js index 1a04a1b757..5d2d29e156 100644 --- a/packages/web/management/js/fog/fog.common.js +++ b/packages/web/management/js/fog/fog.common.js @@ -5417,6 +5417,12 @@ function setupInfoCard() { * clicking a host name, and one stray click would deploy over a running * machine -- or, from a group, over all of them. The text is built server * side (FOGPageRender::renderQuickTaskActions) because it is translated. + * + * The confirmation is the page's own modal rather than window.confirm(): the + * browser dialog cannot be styled, ignores the dark theme, and prefixes the + * page URL, so it reads as something outside the application. Every button + * shares the one modal, which carries the clicked button's data-confirm as + * its body and remembers which button opened it. */ function setupInfoCardActions() { // Guards the window between the click and the server's answer. Per button @@ -5427,39 +5433,59 @@ function setupInfoCardActions() { // otherwise be two identical taskings. var running = {}; - // Delegated and namespaced: the card is torn down and rebuilt with the - // page on every AJAX nav, so a direct binding would be lost on the first - // one and doPageLoad() would stack a new one per visit. + // Which button opened the modal. Cleared on every open so a dismissed + // confirmation cannot be committed by the next one. + var pending = null; + + function fire(btn) { + var node = btn.data('node'), + id = btn.data('id'), + type = btn.data('type'), + key = node + ':' + id + ':' + type; + if (running[key]) { + return; + } + running[key] = true; + $.apiCall( + 'post', + '../management/index.php?node=' + encodeURIComponent(node) + + '&sub=deploy&id=' + encodeURIComponent(id) + + '&type=' + encodeURIComponent(type), + {scheduleType: 'instant'}, + function() { + // Both outcomes land here and both only need the lock released. + // apiCall has already drawn the toast, and there is nothing on + // this page to repaint: the card's Last Deployed is the date the + // last task FINISHED, which a task just queued has not. + running[key] = false; + } + ); + } + + // Delegated and namespaced: the card and its modal are torn down and + // rebuilt with the page on every AJAX nav, so a direct binding would be + // lost on the first one and doPageLoad() would stack a new one per visit. + // Both handlers share the one namespace so the .off() clears the pair. $(document) .off('click.fogQuickTask') .on('click.fogQuickTask', '.fog-quicktask', function(e) { e.preventDefault(); - var btn = $(this), - node = btn.data('node'), - id = btn.data('id'), - type = btn.data('type'), - key = node + ':' + id + ':' + type; - if (running[key]) { - return; - } - if (!window.confirm(btn.data('confirm'))) { - return; + pending = $(this); + // .text(), never .html(): data-confirm carries a host or group name, + // which is admin-supplied. + $('#quicktask-confirm-text').text(pending.data('confirm')); + $('#quicktask-confirm-modal').modal('show'); + }) + .on('click.fogQuickTask', '#quicktask-confirm-go', function(e) { + e.preventDefault(); + var btn = pending; + // Taken before the request so a second click during the hide + // animation has nothing left to commit. + pending = null; + $('#quicktask-confirm-modal').modal('hide'); + if (btn) { + fire(btn); } - running[key] = true; - $.apiCall( - 'post', - '../management/index.php?node=' + encodeURIComponent(node) - + '&sub=deploy&id=' + encodeURIComponent(id) - + '&type=' + encodeURIComponent(type), - {scheduleType: 'instant'}, - function() { - // Both outcomes land here and both only need the lock released. - // apiCall has already drawn the toast, and there is nothing on - // this page to repaint: the card's Last Deployed is the date the - // last task FINISHED, which a task just queued has not. - running[key] = false; - } - ); }); } diff --git a/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po index 40cc95fc47..d47ed9c2a9 100644 --- a/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/de_DE.UTF-8/LC_MESSAGES/messages.po @@ -2437,6 +2437,10 @@ msgstr "Benutzer erstellen fehlgeschlagen" msgid "Create task form success" msgstr "Benutzer erfolgreich erstellt" +#, fuzzy +msgid "Create tasking" +msgstr "Neues Snapin erstellen" + msgid "Create tasking succeeded" msgstr "" @@ -10420,7 +10424,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po index 1681a995ed..3d3c730a0c 100644 --- a/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/en_US.UTF-8/LC_MESSAGES/messages.po @@ -2440,6 +2440,10 @@ msgstr "User created" msgid "Create task form success" msgstr "User created" +#, fuzzy +msgid "Create tasking" +msgstr "Create New %s" + msgid "Create tasking succeeded" msgstr "" @@ -10429,7 +10433,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po index 3ee7b9f6e8..0d18efc9d5 100644 --- a/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/es_ES.UTF-8/LC_MESSAGES/messages.po @@ -2458,6 +2458,10 @@ msgstr "creado por el usuario" msgid "Create task form success" msgstr "creado por el usuario" +#, fuzzy +msgid "Create tasking" +msgstr "Crear nuevo grupo" + msgid "Create tasking succeeded" msgstr "" @@ -10587,7 +10591,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/eu_ES.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/eu_ES.UTF-8/LC_MESSAGES/messages.po index e0fc0180d9..c7e7dd915b 100644 --- a/packages/web/management/languages/eu_ES.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/eu_ES.UTF-8/LC_MESSAGES/messages.po @@ -2437,6 +2437,10 @@ msgstr "Benutzer erstellen fehlgeschlagen" msgid "Create task form success" msgstr "Benutzer erfolgreich erstellt" +#, fuzzy +msgid "Create tasking" +msgstr "Neues Snapin erstellen" + msgid "Create tasking succeeded" msgstr "" @@ -10421,7 +10425,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po index 3b00b8e97a..2ced59edc7 100644 --- a/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/fr_FR.UTF-8/LC_MESSAGES/messages.po @@ -2440,6 +2440,10 @@ msgstr "utilisateur créé" msgid "Create task form success" msgstr "utilisateur créé" +#, fuzzy +msgid "Create tasking" +msgstr "Créer un nouveau %s" + msgid "Create tasking succeeded" msgstr "" @@ -10413,7 +10417,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po index a204c10efa..1118ae0608 100644 --- a/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/it_IT.UTF-8/LC_MESSAGES/messages.po @@ -2382,6 +2382,10 @@ msgstr "Creazione utente fallita" msgid "Create task form success" msgstr "Creazione utente riuscita" +#, fuzzy +msgid "Create tasking" +msgstr "Crea nuovo snapin" + msgid "Create tasking succeeded" msgstr "" @@ -10136,7 +10140,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po index ed897e43b5..7fa50c2fc5 100644 --- a/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/ja_JP.UTF-8/LC_MESSAGES/messages.po @@ -2367,6 +2367,10 @@ msgstr "タスク作成対象" msgid "Create task form success" msgstr "タスク状態を作成" +#, fuzzy +msgid "Create tasking" +msgstr "新しいスナップインを作成" + #, fuzzy msgid "Create tasking succeeded" msgstr "タスク状態を作成" @@ -10093,7 +10097,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/messages.pot b/packages/web/management/languages/messages.pot index 660d09f7f0..93bf06b48e 100644 --- a/packages/web/management/languages/messages.pot +++ b/packages/web/management/languages/messages.pot @@ -2106,6 +2106,9 @@ msgstr "" msgid "Create task form success" msgstr "" +msgid "Create tasking" +msgstr "" + msgid "Create tasking succeeded" msgstr "" @@ -8932,7 +8935,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po index 101f14bfb6..fcb06dc94a 100644 --- a/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/pt_BR.UTF-8/LC_MESSAGES/messages.po @@ -2440,6 +2440,10 @@ msgstr "usuário criado" msgid "Create task form success" msgstr "usuário criado" +#, fuzzy +msgid "Create tasking" +msgstr "Criar novo %s" + msgid "Create tasking succeeded" msgstr "" @@ -10416,7 +10420,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po b/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po index 07863ee01c..a80e973b10 100644 --- a/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po +++ b/packages/web/management/languages/zh_CN.UTF-8/LC_MESSAGES/messages.po @@ -2440,6 +2440,10 @@ msgstr "用户创建" msgid "Create task form success" msgstr "用户创建" +#, fuzzy +msgid "Create tasking" +msgstr "新建%s" + msgid "Create tasking succeeded" msgstr "" @@ -10416,7 +10420,6 @@ msgstr "" msgid "The term goes in q. limit caps results PER CLASS, not overall, and this route is not paged -- there is no nextUrl to follow. Within a class, names that start with the term sort first. Both fields may also be sent as POST body fields. Also reachable as /search." msgstr "" -#, php-format msgid "The term. Because it is a path segment, a term containing / ? # or % cannot travel this way; use /unisearch?q= instead." msgstr "" diff --git a/packages/web/src/Base/FOGPageRender.php b/packages/web/src/Base/FOGPageRender.php index 01b5f320da..ac3bfc334f 100644 --- a/packages/web/src/Base/FOGPageRender.php +++ b/packages/web/src/Base/FOGPageRender.php @@ -566,7 +566,7 @@ protected static function noteSourceAttrs($source) * commit action -- the General tab's Update is -- so these are two * shortcuts in a header strip, not a decision cluster in a form footer, * and the weight a red button would carry is carried by the - * confirmation instead. It is also what the list grid's own quick + * confirmation modal instead. It is also what the list grid's own quick * buttons are, since DataTables draws its button bar that way. * * Filled, NOT btn-outline-secondary, and that is a contrast decision @@ -636,9 +636,43 @@ public static function renderQuickTaskActions( return ''; } + // The confirmation is a modal, not window.confirm(). The browser's + // own dialog cannot be styled, ignores the dark theme entirely, and + // announces itself with the page's URL -- next to AdminLTE it reads + // as something the site got wrong. Same shape as assocDelModal(), + // which is what every other "are you sure" in this app looks like. + // + // ONE modal for the whole card, filled in by the script from the + // clicked button's data-confirm, rather than one per button: two + // would eventually say the same thing in two different wordings. + // + // Emitted next to the buttons, the way assocDelModal() sits in its + // card-footer. A .modal is position:fixed and display:none until + // shown, so it adds nothing to the flex row it nominally lives in. + $modal = self::makeModal( + 'quicktask-confirm-modal', + '