From 821b57b1db32a34f58d8cc85187aad7a23e305f0 Mon Sep 17 00:00:00 2001 From: Erwin Dondorp Date: Tue, 11 Aug 2020 22:16:51 +0200 Subject: [PATCH] use new menus --- saltgui/static/scripts/Character.js | 1 + saltgui/static/scripts/CommandBox.js | 21 ++--- saltgui/static/scripts/Documentation.js | 20 ++--- saltgui/static/scripts/DropDown.js | 68 ++++++++------- saltgui/static/scripts/DropDownCheckBox.js | 38 ++++++++ saltgui/static/scripts/DropDownCmd.js | 14 +++ saltgui/static/scripts/DropDownRadio.js | 67 +++++++++++++++ saltgui/static/scripts/ParseCommandLine.js | 2 + saltgui/static/scripts/RunType.js | 45 ++-------- saltgui/static/scripts/Search.js | 80 +++++++++++++++++ saltgui/static/scripts/TargetType.js | 45 ++++------ saltgui/static/scripts/Utils.js | 86 ++----------------- saltgui/static/scripts/issues/Issues.js | 8 +- saltgui/static/scripts/panels/Beacons.js | 2 +- .../static/scripts/panels/BeaconsMinion.js | 20 ++--- saltgui/static/scripts/panels/Grains.js | 2 +- saltgui/static/scripts/panels/GrainsMinion.js | 16 ++-- saltgui/static/scripts/panels/HighState.js | 10 +-- saltgui/static/scripts/panels/Job.js | 31 +++---- saltgui/static/scripts/panels/JobsDetails.js | 18 ++-- saltgui/static/scripts/panels/JobsSummary.js | 8 +- saltgui/static/scripts/panels/Keys.js | 30 +++---- saltgui/static/scripts/panels/Minions.js | 12 +-- saltgui/static/scripts/panels/Nodegroups.js | 24 +++--- saltgui/static/scripts/panels/Panel.js | 13 +-- saltgui/static/scripts/panels/Pillars.js | 2 +- .../static/scripts/panels/PillarsMinion.js | 2 +- saltgui/static/scripts/panels/Schedules.js | 2 +- .../static/scripts/panels/SchedulesMinion.js | 24 +++--- saltgui/static/scripts/panels/Templates.js | 6 +- 30 files changed, 407 insertions(+), 310 deletions(-) create mode 100644 saltgui/static/scripts/DropDownCheckBox.js create mode 100644 saltgui/static/scripts/DropDownCmd.js create mode 100644 saltgui/static/scripts/DropDownRadio.js create mode 100644 saltgui/static/scripts/Search.js diff --git a/saltgui/static/scripts/Character.js b/saltgui/static/scripts/Character.js index 9759c0c3d..7491c8b6e 100644 --- a/saltgui/static/scripts/Character.js +++ b/saltgui/static/scripts/Character.js @@ -26,6 +26,7 @@ export class Character { Character.BLACK_RIGHT_POINTING_POINTER = "\u25BA"; Character.WHITE_DOWN_POINTING_TRIANGLE = "\u25BD"; Character.BLACK_DIAMOND = "\u25C6"; + Character.WHITE_CIRCLE = "\u25CB"; Character.BLACK_CIRCLE = "\u25CF"; Character.GEAR = "\u2699"; Character.WARNING_SIGN = "\u26A0" + Character._VARIATION_SELECTOR_16; diff --git a/saltgui/static/scripts/CommandBox.js b/saltgui/static/scripts/CommandBox.js index cdb6f4a46..c6998642d 100644 --- a/saltgui/static/scripts/CommandBox.js +++ b/saltgui/static/scripts/CommandBox.js @@ -2,7 +2,7 @@ import {Character} from "./Character.js"; import {Documentation} from "./Documentation.js"; -import {DropDownMenu} from "./DropDown.js"; +import {DropDownMenuCmd} from "./DropDownCmd.js"; import {Output} from "./output/Output.js"; import {ParseCommandLine} from "./ParseCommandLine.js"; import {Router} from "./Router.js"; @@ -18,14 +18,15 @@ export class CommandBox { this.api = pApi; const cmdbox = document.getElementById("cmd-box"); - this.cmdmenu = new DropDownMenu(cmdbox); + this.cmdmenu = new DropDownMenuCmd(cmdbox); - this.documentation = new Documentation(this.router, this); this._registerCommandBoxEventListeners(); RunType.createMenu(); TargetType.createMenu(); + this.documentation = new Documentation(pRouter, this); + const manualRun = document.getElementById("popup-run-command"); Utils.addTableHelp(manualRun, "Click for help", "bottom-center"); const helpButton = manualRun.querySelector("#help"); @@ -58,7 +59,7 @@ export class CommandBox { CommandBox.templateCatMenu.setTitle(""); return; } - const menu = new DropDownMenu(titleElement); + const menu = new DropDownMenuCmd(titleElement); menu.setTitle(""); menu.menuButton.classList.add("small-button-left"); CommandBox.templateCatMenu = menu; @@ -70,7 +71,7 @@ export class CommandBox { } categories.unshift(null); for (const category of categories) { - menu.addMenuItem( + menu.addMenuItemCmd( () => CommandBox._templateCatMenuItemTitle(category), () => { CommandBox.templateTmplMenu._templateCategory = category; @@ -120,7 +121,7 @@ export class CommandBox { CommandBox.templateTmplMenu._templateCategory = null; return; } - const menu = new DropDownMenu(titleElement); + const menu = new DropDownMenuCmd(titleElement); menu.menuButton.classList.add("small-button-left"); CommandBox.templateTmplMenu = menu; CommandBox.templateTmplMenu._templateCategory = null; @@ -132,7 +133,7 @@ export class CommandBox { if (!description) { description = "(" + key + ")"; } - menu.addMenuItem( + menu.addMenuItemCmd( () => CommandBox._templateTmplMenuItemTitle(template), () => { CommandBox.applyTemplateByTemplate(template); @@ -267,7 +268,7 @@ export class CommandBox { TargetType.setTargetType(pTargetType); } else { // not in the template, revert to default - TargetType.setTargetTypeDefault(); + TargetType.setTargetType(null); } if (pTarget) { @@ -341,7 +342,7 @@ export class CommandBox { const commandField = document.getElementById("command"); const commandValue = commandField.value; - const targetType = TargetType.menuTargetType._value; + const targetType = TargetType.menuTargetType.getValue(); const patWhitespaceAll = /\s/g; const commandValueNoTabs = commandValue.replace(patWhitespaceAll, " "); @@ -492,7 +493,7 @@ export class CommandBox { // reset to default, so that its value is initially hidden RunType.setRunTypeDefault(); - TargetType.setTargetTypeDefault(); + TargetType.setTargetType(null); if (Router.currentPage) { Router.currentPage.refreshPage(); diff --git a/saltgui/static/scripts/Documentation.js b/saltgui/static/scripts/Documentation.js index 98520538b..c7230b902 100644 --- a/saltgui/static/scripts/Documentation.js +++ b/saltgui/static/scripts/Documentation.js @@ -17,23 +17,23 @@ export class Documentation { this.router = pRouter; this.commandbox = pCommandBox; - pCommandBox.cmdmenu.addMenuItem( + Documentation.DOCUMENTATION_URL = "https://docs.saltproject.io/en/latest/ref/"; + Documentation.EXTERNAL_LINK = Character.NO_BREAK_SPACE + Character.EXTERNAL_LINK_IMG; + + Documentation.PROVIDERS = { }; + + pCommandBox.cmdmenu.addMenuItemCmd( () => Documentation._manualRunMenuSysDocPrepare(), () => this._manualRunMenuSysDocRun()); - pCommandBox.cmdmenu.addMenuItem( + pCommandBox.cmdmenu.addMenuItemCmd( () => Documentation._manualRunMenuHtmlDocPrepare(), () => Documentation._manualRunMenuHtmlDocRun()); - pCommandBox.cmdmenu.addMenuItem( + pCommandBox.cmdmenu.addMenuItemCmd( () => Documentation._manualRunMenuBeaconNamePrepare(), () => Documentation._manualRunMenuBeaconNameRun()); - pCommandBox.cmdmenu.addMenuItem( + pCommandBox.cmdmenu.addMenuItemCmd( () => Documentation._manualRunMenuCustomHelpPrepare(), () => Documentation._manualRunMenuCustomHelpRun()); - - Documentation.DOCUMENTATION_URL = "https://docs.saltproject.io/en/latest/ref/"; - Documentation.EXTERNAL_LINK = Character.NO_BREAK_SPACE + Character.EXTERNAL_LINK_IMG; - - Documentation.PROVIDERS = { }; } // INTERNAL DOCUMENTATION @@ -120,7 +120,7 @@ export class Documentation { dummyCommand = "sys.doc " + cmd; } - const targetType = TargetType.menuTargetType._value; + const targetType = TargetType.menuTargetType.getValue(); const func = this.commandbox.getRunParams(targetType, target, docCommand, true, false); if (func === null) { diff --git a/saltgui/static/scripts/DropDown.js b/saltgui/static/scripts/DropDown.js index beb853d8a..0fa4caab7 100644 --- a/saltgui/static/scripts/DropDown.js +++ b/saltgui/static/scripts/DropDown.js @@ -10,7 +10,7 @@ import {Utils} from "./Utils.js"; // a) sets the title using pMenuItem.innerText = "xyz" // b) arranges the visibility using pMenuItem.style.display = true/false // 2: the callback function -// called when the menu item is selected: (pClickEvent) => { ... } +// called when the menu item is selected: () => { ... } // all menu items are re-validated when the menu pops up // when all menu items are invisible, the menu-button must be made invisible // since this can happen at any time, this cannot be done when the menu is shown @@ -20,6 +20,8 @@ import {Utils} from "./Utils.js"; // the menu. when at least one item is visible, the menu is visible // remember to call verifyApp() when that is potentially the case +// superclass for DropDownMenuRadio, DropDownMenuCheckBox and DropDownMenuCmd + export class DropDownMenu { // Creates an empty dropdown menu @@ -87,10 +89,10 @@ export class DropDownMenu { continue; } - const verifyCallBack = chld.verifyCallBack; - if (verifyCallBack) { - const title = verifyCallBack(chld); - if (title === null) { + const titleCallBack = chld._titleCallBack; + if (titleCallBack) { + const title = titleCallBack.bind(this)(chld); + if (!title) { chld.style.display = "none"; continue; } @@ -106,6 +108,7 @@ export class DropDownMenu { itemsBeforeSeparator += 1; } } + // hide the menu when it has no visible menu-items const displayVisible = this.menuDropdown.tagName === "TD" ? "table-cell" : "inline-block"; const displayInvisible = "none"; @@ -125,25 +128,49 @@ export class DropDownMenu { // function is called each time the menu opens // This allows dynamic menuitem titles (use menuitem.innerText) // or visibility (use menuitem.style.display = "none"/"inline-block") - addMenuItem (pTitle, pCallBack, pValue) { + addMenuItem (pValue, pTitle, pSystemCallBack, pUserCallBack) { + const button = Utils.createDiv("run-command-button", Character.HORIZONTAL_ELLIPSIS); - if (pValue) { - button._value = pValue; - } + + button._value = pValue; + if (typeof pTitle === "string") { button.innerText = DropDownMenu._sanitizeMenuItemTitle(pTitle); } else { - button.verifyCallBack = pTitle; + button._titleCallBack = pTitle; } + button.addEventListener("click", (pClickEvent) => { + + // hide the menu pClickEvent.target.parentElement.style.display = "none"; + + // "show" the menu again after a short delay + // but because the mouse is no longer hovering it, + // it will actually remain invisible window.setTimeout(() => { pClickEvent.target.parentElement.style.display = ""; }, 500); - this._callback(pClickEvent, pCallBack, pValue); + + this._value = pValue; + + if (pSystemCallBack) { + pSystemCallBack.bind(this)(pClickEvent.target); + } + + if (pUserCallBack) { + pUserCallBack.bind(this)(pClickEvent.target); + } + + // all menu items may have become invisible + this.verifyAll(); + pClickEvent.stopPropagation(); }); + this.menuDropdownContent.appendChild(button); + + // the menu might have become populated enough to get visible this.verifyAll(); return button; } @@ -157,11 +184,6 @@ export class DropDownMenu { this.menuDropdownContent.appendChild(div); } - _callback (pClickEvent, pCallBack, pValue) { - this._value = pValue; - pCallBack(pClickEvent); - } - setTitle (pTitle) { // Setting the title implies that we are interested // in the menu values, rather than their actions. @@ -172,18 +194,4 @@ export class DropDownMenu { pTitle += Character.GEAR; this.menuButton.innerText = DropDownMenu._sanitizeMenuItemTitle(pTitle); } - - __showMenu () { - this.menuDropdown.style.display = "inline-block"; - } - - __hideMenu () { - this.menuDropdown.style.display = "none"; - } - - clearMenu () { - while (this.menuDropdownContent.firstChild) { - this.menuDropdownContent.removeChild(this.menuDropdownContent.firstChild); - } - } } diff --git a/saltgui/static/scripts/DropDownCheckBox.js b/saltgui/static/scripts/DropDownCheckBox.js new file mode 100644 index 000000000..aacbabb27 --- /dev/null +++ b/saltgui/static/scripts/DropDownCheckBox.js @@ -0,0 +1,38 @@ +/* global */ + +import {Character} from "./Character.js"; +import {DropDownMenu} from "./DropDown.js"; + +export class DropDownMenuCheckBox extends DropDownMenu { + + static _menuItemTitleCallBack (pMenuItem) { + let prefix = ""; + if (pMenuItem._selected === true) { + prefix = Character.HEAVY_CHECK_MARK + Character.NO_BREAK_SPACE; + } + return prefix + pMenuItem._title; + } + + static _menuItemActionCallBack (pMenuItem) { + pMenuItem._selected = !pMenuItem._selected; + } + + addMenuItemCheckBox (pValue, pTitle, pUserCallBack) { + const menuItem = super.addMenuItem( + pValue, + DropDownMenuCheckBox._menuItemTitleCallBack, + DropDownMenuCheckBox._menuItemActionCallBack, + pUserCallBack); + menuItem._title = pTitle; + return menuItem; + } + + isSet (pValue) { + for (const menuItem of this.menuDropdownContent.childNodes) { + if (menuItem._selected === true && menuItem._value === pValue) { + return true; + } + } + return false; + } +} diff --git a/saltgui/static/scripts/DropDownCmd.js b/saltgui/static/scripts/DropDownCmd.js new file mode 100644 index 000000000..69669daac --- /dev/null +++ b/saltgui/static/scripts/DropDownCmd.js @@ -0,0 +1,14 @@ +/* global */ + +import {DropDownMenu} from "./DropDown.js"; + +export class DropDownMenuCmd extends DropDownMenu { + + addMenuItemCmd (pTitle, pUserCallBack) { + return super.addMenuItem( + null, + pTitle, + pUserCallBack + ); + } +} diff --git a/saltgui/static/scripts/DropDownRadio.js b/saltgui/static/scripts/DropDownRadio.js new file mode 100644 index 000000000..b0620febc --- /dev/null +++ b/saltgui/static/scripts/DropDownRadio.js @@ -0,0 +1,67 @@ +/* global */ + +import {Character} from "./Character.js"; +import {DropDownMenu} from "./DropDown.js"; + +export class DropDownMenuRadio extends DropDownMenu { + constructor (pParentElement) { + super(pParentElement); + this._value = null; + this._defaultValue = null; + } + + getValue () { + if (this._value === null) { + return this._defaultValue; + } + return this._value; + } + + setValue (pValue) { + this._value = pValue; + } + + setDefaultValue (pDefaultValue) { + this._defaultValue = pDefaultValue; + } + + _menuItemTitleCallBack (pMenuItem) { + let title; + if (!pMenuItem._title) { + title = "..."; + } else if (typeof pMenuItem._title === "string") { + title = pMenuItem._title; + } else { + title = pMenuItem._title.bind(this)(pMenuItem); + } + + if (title === null) { + // menu item will be hidden + } else if (pMenuItem._value === this._value) { + title = Character.BLACK_CIRCLE + Character.NO_BREAK_SPACE + title; + } else if (this._value === null && pMenuItem._value === this._defaultValue) { + title = Character.WHITE_CIRCLE + Character.NO_BREAK_SPACE + title; + } + return title; + } + + _menuItemActionCallBack (pMenuItem) { + this._value = pMenuItem._value; + let menuTitle = pMenuItem._title; + if (menuTitle && typeof menuTitle !== "string") { + menuTitle = menuTitle.bind(this)(pMenuItem); + } + this.setTitle(menuTitle); + } + + addMenuItemRadio (pValue, pTitle, pUserCallBack) { + const menuItem = super.addMenuItem( + pValue, + this._menuItemTitleCallBack, + this._menuItemActionCallBack, + pUserCallBack); + menuItem._value = pValue; + menuItem._title = pTitle; + return menuItem; + } +} diff --git a/saltgui/static/scripts/ParseCommandLine.js b/saltgui/static/scripts/ParseCommandLine.js index 467352056..f4cab882f 100644 --- a/saltgui/static/scripts/ParseCommandLine.js +++ b/saltgui/static/scripts/ParseCommandLine.js @@ -1,3 +1,5 @@ +/* global */ + // Function to parse a commandline // The line is broken into individual tokens // Each token that is recognized as a JS type will get that type diff --git a/saltgui/static/scripts/RunType.js b/saltgui/static/scripts/RunType.js index 85ef464c8..48d495c7a 100644 --- a/saltgui/static/scripts/RunType.js +++ b/saltgui/static/scripts/RunType.js @@ -1,65 +1,36 @@ /* global */ -import {Character} from "./Character.js"; -import {DropDownMenu} from "./DropDown.js"; +import {DropDownMenuRadio} from "./DropDownRadio.js"; import {Utils} from "./Utils.js"; export class RunType { static createMenu () { const runblock = document.getElementById("run-block"); - RunType.menuRunType = new DropDownMenu(runblock); + RunType.menuRunType = new DropDownMenuRadio(runblock); // do not show the menu title at first RunType.menuRunType.setTitle(""); - RunType.menuRunType.addMenuItem("Normal", RunType._updateRunTypeText, "normal"); - RunType.menuRunType.addMenuItem("Async", RunType._updateRunTypeText, "async"); - RunType._updateRunTypeText(); - } - - static _updateRunTypeText () { - const runType = RunType.getRunType(); - - switch (runType) { - case "normal": - // now that the menu is used show the menu title - RunType.menuRunType.setTitle("Normal"); - break; - case "async": - RunType.menuRunType.setTitle("Async"); - break; - default: - Utils.error("runType", runType); - } - - // Store last used runType - Utils.setStorageItem("local", "runtype", runType); - - const menuItems = RunType.menuRunType.menuDropdownContent.children; - for (const menuItem of menuItems) { - let menuItemText = menuItem.innerText; - menuItemText = menuItemText.replace(/^. /, ""); - if (menuItem._value === runType) { - menuItemText = Character.BLACK_CIRCLE + " " + menuItemText; - } - menuItem.innerText = menuItemText; - } + RunType.menuRunType.setDefaultValue("normal"); + RunType.menuRunType.addMenuItemRadio("normal", "Normal"); + RunType.menuRunType.addMenuItemRadio("async", "Async"); } static setRunTypeDefault () { + RunType.menuRunType.setValue(null); // Retrieve last used runType let runType = Utils.getStorageItem("local", "runtype"); // Set default if previous runtype not stored if (runType !== "normal" && runType !== "async") { runType = "normal"; } - RunType._updateRunTypeText(); + RunType.menuRunType.setDefaultValue(runType); // reset the title to the absolute minimum // so that the menu does not stand out in trivial situations RunType.menuRunType.setTitle(""); } static getRunType () { - let runType = RunType.menuRunType._value; + let runType = RunType.menuRunType.getValue(); if (runType === undefined || runType === "") { runType = Utils.getStorageItem("local", "runtype", "normal"); } diff --git a/saltgui/static/scripts/Search.js b/saltgui/static/scripts/Search.js new file mode 100644 index 000000000..f5ee28dd1 --- /dev/null +++ b/saltgui/static/scripts/Search.js @@ -0,0 +1,80 @@ +/* global */ + +import {Character} from "./Character.js"; +import {DropDownMenuCheckBox} from "./DropDownCheckBox.js"; +import {Utils} from "./Utils.js"; + +export class Search { + + static makeSearchBox (pSearchButton, pTable, pFieldList = null) { + + const div = Utils.createDiv("search-box", ""); + div.style.display = "none"; + + const menuAndFieldDiv = Utils.createDiv("search-menu-and-field", ""); + + const searchOptionsMenu = new DropDownMenuCheckBox(menuAndFieldDiv, true); + + const input = document.createElement("input"); + input.type = "text"; + input.classList.add("filter-text"); + input.placeholder = Character.LEFT_POINTING_MAGNIFYING_GLASS; + if (pFieldList) { + input.setAttribute("list", pFieldList); + } + menuAndFieldDiv.append(input); + + div.append(menuAndFieldDiv); + + const errorDiv = Utils.createDiv("search-error", ""); + errorDiv.style.display = "none"; + div.append(errorDiv); + + searchOptionsMenu.addMenuItemCheckBox( + "cs", + "Case sensitive", + () => { + Search._updateSearchOption(pTable, searchOptionsMenu, input); + }); + searchOptionsMenu.addMenuItemCheckBox( + "re", + "Regular expression", + () => { + Search._updateSearchOption(pTable, searchOptionsMenu, input); + }); + searchOptionsMenu.addMenuItemCheckBox( + "is", + "Invert search", + () => { + Search._updateSearchOption(pTable, searchOptionsMenu, input); + }); + + // make the search function active + pSearchButton.onclick = () => { + Utils.hideShowTableSearchBar(div, pTable); + }; + + div.searchOptionsMenu = searchOptionsMenu; + + return div; + } + + static _updateSearchOption (pTable, pSearchOptionsMenu, pInput) { + Utils._updateTableFilter( + pTable, + pInput.value, + pSearchOptionsMenu); + + let placeholder = Character.LEFT_POINTING_MAGNIFYING_GLASS; + if (pSearchOptionsMenu.isSet("cs")) { + placeholder += " caseSensitive"; + } + if (pSearchOptionsMenu.isSet("re")) { + placeholder += " regExp"; + } + if (pSearchOptionsMenu.isSet("is")) { + placeholder += " invertSearch"; + } + pInput.placeholder = placeholder; + } +} diff --git a/saltgui/static/scripts/TargetType.js b/saltgui/static/scripts/TargetType.js index f57ae8f4f..8b0a44790 100644 --- a/saltgui/static/scripts/TargetType.js +++ b/saltgui/static/scripts/TargetType.js @@ -1,34 +1,32 @@ /* global */ import {Character} from "./Character.js"; -import {DropDownMenu} from "./DropDown.js"; +import {DropDownMenuRadio} from "./DropDownRadio.js"; import {Utils} from "./Utils.js"; export class TargetType { static createMenu () { const targetbox = document.getElementById("target-box"); - TargetType.menuTargetType = new DropDownMenu(targetbox); + TargetType.menuTargetType = new DropDownMenuRadio(targetbox); // do not show the menu title at first - TargetType.menuTargetType.addMenuItem("Normal", TargetType._manualUpdateTargetTypeText, "glob"); - TargetType.menuTargetType.addMenuItem("List", TargetType._manualUpdateTargetTypeText, "list"); - TargetType.menuTargetType.addMenuItem(TargetType._targetTypeNodeGroupPrepare, TargetType._manualUpdateTargetTypeText, "nodegroup"); - TargetType.menuTargetType.addMenuItem("Compound", TargetType._manualUpdateTargetTypeText, "compound"); - TargetType.setTargetTypeDefault(); + TargetType.menuTargetType.setTitle(""); + TargetType.menuTargetType.setDefaultValue("glob"); + TargetType.menuTargetType.addMenuItemRadio("glob", "Normal"); + TargetType.menuTargetType.addMenuItemRadio("list", "List"); + TargetType.menuTargetType.addMenuItemRadio("nodegroup", () => TargetType._targetTypeNodeGroupPrepare()); + TargetType.menuTargetType.addMenuItemRadio("compound", "Compound"); + TargetType.autoSelectTargetType(""); } // It takes a while before we known the list of nodegroups // so this conclusion must be re-evaluated each time - static _targetTypeNodeGroupPrepare (pMenuItem) { + static _targetTypeNodeGroupPrepare () { const nodeGroups = Utils.getStorageItemObject("session", "nodegroups"); if (!nodeGroups || Object.keys(nodeGroups).length === 0) { return null; } - // optimization as the list of nodegroups will not change until the next login - // but mainly to preserve the highlight marker - pMenuItem.verifyCallBack = null; - return "Nodegroup"; } @@ -85,10 +83,10 @@ export class TargetType { } menuItem.innerText = menuItemText; } + return null; } static autoSelectTargetType (pTarget) { - if (!TargetType.menuTargetType._system) { // user has selected the value, do not touch it return; @@ -100,34 +98,25 @@ export class TargetType { pTarget.includes("(") || pTarget.includes(")")) { // "@" is a strong indicator for compound target // but "space", "(" and ")" are also typical for compound target - TargetType.menuTargetType._value = "compound"; + TargetType.menuTargetType.setDefaultValue("compound"); } else if (pTarget.includes(",")) { // "," is a strong indicator for list target (when it is also not compound) - TargetType.menuTargetType._value = "list"; + TargetType.menuTargetType.setDefaultValue("list"); } else if (pTarget.startsWith("#")) { // "#" at the start of a line is a strong indicator for nodegroup target // this is not a SALTSTACK standard, but our own invention - TargetType.menuTargetType._value = "nodegroup"; + TargetType.menuTargetType.setDefaultValue("nodegroup"); } else { - TargetType.menuTargetType._value = "glob"; + TargetType.menuTargetType.setDefaultValue("glob"); } - - // show the new title - TargetType._updateTargetTypeText(); } static setTargetType (pTargetType) { - TargetType.menuTargetType._value = pTargetType; - TargetType.menuTargetType._system = true; - TargetType._updateTargetTypeText(); + TargetType.menuTargetType.setValue(pTargetType); } static _getTargetType () { - const targetType = TargetType.menuTargetType._value; - if (targetType === undefined || targetType === "") { - return "glob"; - } - return targetType; + return TargetType.menuTargetType.getValue(); } static makeTargetText (pObj) { diff --git a/saltgui/static/scripts/Utils.js b/saltgui/static/scripts/Utils.js index 2d1e170da..9bf288742 100644 --- a/saltgui/static/scripts/Utils.js +++ b/saltgui/static/scripts/Utils.js @@ -1,7 +1,6 @@ /* global Hilitor */ import {Character} from "./Character.js"; -import {DropDownMenu} from "./DropDown.js"; export class Utils { @@ -250,80 +249,6 @@ export class Utils { return regs[0].length > 0 ? 1 : 2; } - static makeSearchBox (pSearchButton, pTable, pFieldList = null) { - - const div = Utils.createDiv("search-box", ""); - div.style.display = "none"; - - const menuAndFieldDiv = Utils.createDiv("search-menu-and-field", ""); - - const searchOptionsMenu = new DropDownMenu(menuAndFieldDiv, "smaller"); - - const input = Utils.createElem("input", "filter-text"); - input.type = "text"; - input.spellcheck = false; - input.placeholder = Character.LEFT_POINTING_MAGNIFYING_GLASS; - if (pFieldList) { - input.setAttribute("list", pFieldList); - } - menuAndFieldDiv.append(input); - - div.append(menuAndFieldDiv); - - const errorDiv = Utils.createDiv("search-error", ""); - errorDiv.style.display = "none"; - div.append(errorDiv); - - searchOptionsMenu.addMenuItem( - "Case sensitive", (ev) => { - Utils._updateSearchOption(ev, pTable, searchOptionsMenu, input); - }); - searchOptionsMenu.addMenuItem( - "Regular expression", (ev) => { - Utils._updateSearchOption(ev, pTable, searchOptionsMenu, input); - }); - searchOptionsMenu.addMenuItem( - "Invert search", (ev) => { - Utils._updateSearchOption(ev, pTable, searchOptionsMenu, input); - }); - - // make the search function active - pSearchButton.addEventListener("click", (pClickEvent) => { - Utils.hideShowTableSearchBar(div, pTable); - pClickEvent.stopPropagation(); - }); - - return div; - } - - static _updateSearchOption (ev, pTable, pSearchOptionsMenu, pInput) { - ev.target._value = !ev.target._value; - - let menuItemText = ev.target.innerText; - menuItemText = menuItemText.replace(/^. /, ""); - if (ev.target._value === true) { - menuItemText = Character.HEAVY_CHECK_MARK + " " + menuItemText; - } - ev.target.innerText = menuItemText; - - Utils._updateTableFilter( - pTable, - pInput.value, - pSearchOptionsMenu.menuDropdownContent); - - let placeholder = Character.LEFT_POINTING_MAGNIFYING_GLASS; - if (pSearchOptionsMenu.menuDropdownContent.childNodes[0]._value === true) { - placeholder += " caseSensitive"; - } - if (pSearchOptionsMenu.menuDropdownContent.childNodes[1]._value === true) { - placeholder += " regExp"; - } - if (pSearchOptionsMenu.menuDropdownContent.childNodes[2]._value === true) { - placeholder += " invertSearch"; - } - pInput.placeholder = placeholder; - } - static addTableHelp (pStartElement, pHelpText, pStyle = "bottom-right") { const helpButton = pStartElement.querySelector("#help"); helpButton.classList.add("search-button"); @@ -331,7 +256,6 @@ export class Utils { } static hideShowTableSearchBar (pSearchBlock, pTable, pAction = "toggle") { - const startElement = pTable.parentElement; // remove all highlights const searchInSelector = pTable.tagName === "TABLE" ? "tbody" : ""; @@ -344,7 +268,7 @@ export class Utils { fm.classList.remove("no-filter-match"); } - const menuItems = startElement.querySelector(".search-box .menu-dropdown-content"); + const menuItems = pSearchBlock.searchOptionsMenu; // hide/show search box (the block may become more complicated later) const input = pSearchBlock.querySelector("input"); @@ -377,7 +301,7 @@ export class Utils { input.focus(); } - static _updateTableFilter (pTable, pSearchText, pMenuItems) { + static _updateTableFilter (pTable, pSearchText, pSearchMenu) { // remove highlighting before re-comparing // as it affects the texts const searchInSelector = pTable.tagName === "TABLE" ? "tbody" : ""; @@ -385,9 +309,9 @@ export class Utils { hilitor.remove(); // values may be undefined, so convert to proper boolean - const caseSensitiveFlag = pMenuItems.childNodes[0]._value === true; - const regExpFlag = pMenuItems.childNodes[1]._value === true; - let invertFlag = pMenuItems.childNodes[2]._value === true; + const caseSensitiveFlag = pSearchMenu.isSet("cs"); + const regExpFlag = pSearchMenu.isSet("re"); + let invertFlag = pSearchMenu.isSet("is"); // otherwise everything is immediatelly hidden if (invertFlag && !pSearchText) { diff --git a/saltgui/static/scripts/issues/Issues.js b/saltgui/static/scripts/issues/Issues.js index cd08181f5..c922bd2ae 100644 --- a/saltgui/static/scripts/issues/Issues.js +++ b/saltgui/static/scripts/issues/Issues.js @@ -1,6 +1,6 @@ /* global */ -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {Utils} from "../Utils.js"; export class Issues { @@ -49,7 +49,7 @@ export class Issues { const theTr = Utils.createTr(); - const menu = new DropDownMenu(theTr, "smaller"); + const menu = new DropDownMenuCmd(theTr, "smaller"); theTr.menu = menu; const descTd = Utils.createTd(); @@ -77,7 +77,7 @@ export class Issues { } static addIssueCmd (pTr, pTitle, pTarget, pCommand) { - pTr.menu.addMenuItem(pTitle + "...", () => { + pTr.menu.addMenuItemCmd(pTitle + "...", () => { pTr.panel.runCommand("", pTarget, pCommand); }); @@ -98,7 +98,7 @@ export class Issues { } else { title = "Go to " + pPage + " page"; } - pTr.menu.addMenuItem(title, (pClickEvent) => { + pTr.menu.addMenuItemCmd(title, (pClickEvent) => { pTr.panel.router.goTo(pPage, pArgs, undefined, pClickEvent); }); diff --git a/saltgui/static/scripts/panels/Beacons.js b/saltgui/static/scripts/panels/Beacons.js index aef746058..c31ad6d77 100644 --- a/saltgui/static/scripts/panels/Beacons.js +++ b/saltgui/static/scripts/panels/Beacons.js @@ -140,7 +140,7 @@ export class BeaconsPanel extends Panel { } _addMenuItemShowBeacons (pMenu, pMinionId) { - pMenu.addMenuItem("Show beacons", (pClickEvent) => { + pMenu.addMenuItemCmd("Show beacons", (pClickEvent) => { this.router.goTo("beacons-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } diff --git a/saltgui/static/scripts/panels/BeaconsMinion.js b/saltgui/static/scripts/panels/BeaconsMinion.js index 68c9096d0..ff1ce100b 100644 --- a/saltgui/static/scripts/panels/BeaconsMinion.js +++ b/saltgui/static/scripts/panels/BeaconsMinion.js @@ -2,7 +2,7 @@ import {BeaconsPanel} from "./Beacons.js"; import {Character} from "../Character.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {Output} from "../output/Output.js"; import {Panel} from "./Panel.js"; import {Utils} from "../Utils.js"; @@ -141,7 +141,7 @@ export class BeaconsMinionPanel extends Panel { for (const beaconName of keys) { const tr = Utils.createTr("", "", "beacon-" + beaconName); - const beaconMenu = new DropDownMenu(tr, "smaller"); + const beaconMenu = new DropDownMenuCmd(tr, "smaller"); const nameTd = Utils.createTd("beacon-name", beaconName); tr.appendChild(nameTd); @@ -214,7 +214,7 @@ export class BeaconsMinionPanel extends Panel { } _addPanelMenuItemBeaconsDisableWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.beaconsEnabled) { return null; } @@ -227,7 +227,7 @@ export class BeaconsMinionPanel extends Panel { } _addPanelMenuItemBeaconsEnableWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.beaconsEnabled) { return null; } @@ -240,7 +240,7 @@ export class BeaconsMinionPanel extends Panel { } _addPanelMenuItemBeaconsAdd () { - this.panelMenu.addMenuItem("Add beacon...", () => { + this.panelMenu.addMenuItemCmd("Add beacon...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = ["beacons.add", "", ""]; this.runCommand("", minionId, cmdArr); @@ -248,7 +248,7 @@ export class BeaconsMinionPanel extends Panel { } _addPanelMenuItemBeaconsReset () { - this.panelMenu.addMenuItem("Reset beacons...", () => { + this.panelMenu.addMenuItemCmd("Reset beacons...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = ["beacons.reset"]; this.runCommand("", minionId, cmdArr); @@ -256,7 +256,7 @@ export class BeaconsMinionPanel extends Panel { } _addPanelMenuItemBeaconsSave () { - this.panelMenu.addMenuItem("Save beacons...", () => { + this.panelMenu.addMenuItemCmd("Save beacons...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = ["beacons.save"]; this.runCommand("", minionId, cmdArr); @@ -267,7 +267,7 @@ export class BeaconsMinionPanel extends Panel { if (beacon.enabled === false) { return; } - pMenu.addMenuItem("Disable beacon...", () => { + pMenu.addMenuItemCmd("Disable beacon...", () => { const cmdArr = ["beacons.disable_beacon", key]; this.runCommand("", pMinionId, cmdArr); }); @@ -277,14 +277,14 @@ export class BeaconsMinionPanel extends Panel { if (beacon.enabled !== false) { return; } - pMenu.addMenuItem("Enable beacon...", () => { + pMenu.addMenuItemCmd("Enable beacon...", () => { const cmdArr = ["beacons.enable_beacon", key]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemBeaconsDelete (pMenu, pMinionId, key) { - pMenu.addMenuItem("Delete beacon...", () => { + pMenu.addMenuItemCmd("Delete beacon...", () => { const cmdArr = ["beacons.delete", key]; this.runCommand("", pMinionId, cmdArr); }); diff --git a/saltgui/static/scripts/panels/Grains.js b/saltgui/static/scripts/panels/Grains.js index 55a07d4d7..4452a95d7 100644 --- a/saltgui/static/scripts/panels/Grains.js +++ b/saltgui/static/scripts/panels/Grains.js @@ -169,7 +169,7 @@ export class GrainsPanel extends Panel { } _addMenuItemShowGrains (pMenu, pMinionId) { - pMenu.addMenuItem("Show grains", (pClickEvent) => { + pMenu.addMenuItemCmd("Show grains", (pClickEvent) => { this.router.goTo("grains-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } diff --git a/saltgui/static/scripts/panels/GrainsMinion.js b/saltgui/static/scripts/panels/GrainsMinion.js index 99f0dcc50..8b2fd3e08 100644 --- a/saltgui/static/scripts/panels/GrainsMinion.js +++ b/saltgui/static/scripts/panels/GrainsMinion.js @@ -1,7 +1,7 @@ /* global */ import {Character} from "../Character.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {Output} from "../output/Output.js"; import {Panel} from "./Panel.js"; import {Utils} from "../Utils.js"; @@ -69,7 +69,7 @@ export class GrainsMinionPanel extends Panel { for (const grainName of grainNames) { const grainTr = Utils.createTr(); - const grainMenu = new DropDownMenu(grainTr, "smaller"); + const grainMenu = new DropDownMenuCmd(grainTr, "smaller"); const grainNameTd = Utils.createTd("grain-name", grainName); grainTr.appendChild(grainNameTd); @@ -101,7 +101,7 @@ export class GrainsMinionPanel extends Panel { } _addPanelMenuItemGrainsSetValAdd () { - this.panelMenu.addMenuItem("Add grain...", () => { + this.panelMenu.addMenuItemCmd("Add grain...", () => { // use placeholders for name and value const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = ["grains.setval", "", ""]; @@ -110,7 +110,7 @@ export class GrainsMinionPanel extends Panel { } _addPanelMenuItemSaltUtilRefreshGrains () { - this.panelMenu.addMenuItem("Refresh grains...", () => { + this.panelMenu.addMenuItemCmd("Refresh grains...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = ["saltutil.refresh_grains"]; this.runCommand("", minionId, cmdArr); @@ -118,7 +118,7 @@ export class GrainsMinionPanel extends Panel { } _addMenuItemGrainsSetValUpdate (pMenu, pMinionId, key, grains) { - pMenu.addMenuItem("Edit grain...", () => { + pMenu.addMenuItemCmd("Edit grain...", () => { const cmdArr = ["grains.setval", key, grains[key]]; this.runCommand("", pMinionId, cmdArr); }); @@ -128,7 +128,7 @@ export class GrainsMinionPanel extends Panel { if (!pGrainValue.startsWith("[")) { return; } - pMenu.addMenuItem("Add value...", () => { + pMenu.addMenuItemCmd("Add value...", () => { const cmdArr = ["grains.append", key, ""]; this.runCommand("", pMinionId, cmdArr); }); @@ -140,7 +140,7 @@ export class GrainsMinionPanel extends Panel { cmdArr.push("force=", true); } cmdArr.push(pKey); - pMenu.addMenuItem("Delete key...", () => { + pMenu.addMenuItemCmd("Delete key...", () => { this.runCommand("", pMinionId, cmdArr); }); } @@ -151,7 +151,7 @@ export class GrainsMinionPanel extends Panel { cmdArr.push("force=", true); } cmdArr.push(pKey); - pMenu.addMenuItem("Delete value...", () => { + pMenu.addMenuItemCmd("Delete value...", () => { this.runCommand("", pMinionId, cmdArr); }); } diff --git a/saltgui/static/scripts/panels/HighState.js b/saltgui/static/scripts/panels/HighState.js index 154ac45b2..c20f6abc2 100644 --- a/saltgui/static/scripts/panels/HighState.js +++ b/saltgui/static/scripts/panels/HighState.js @@ -94,21 +94,21 @@ export class HighStatePanel extends Panel { } _addMenuItemStateApply (pMenu, pMinionId) { - pMenu.addMenuItem("Apply state...", () => { + pMenu.addMenuItemCmd("Apply state...", () => { const cmdArr = ["state.apply"]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemStateApplyTest (pMenu, pMinionId) { - pMenu.addMenuItem("Test state...", () => { + pMenu.addMenuItemCmd("Test state...", () => { const cmdArr = ["state.apply", "test=", true]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemUseStateHighstate () { - this.settingsMenu.addMenuItem( + this.settingsMenu.addMenuItemCmd( () => { const stateHighstateFlag = Utils.getStorageItem("local", "use_state_highstate", "true"); return (stateHighstateFlag === "true" ? Character.HEAVY_CHECK_MARK + Character.NO_BREAK_SPACE : "") + "Include state.highstate"; @@ -121,7 +121,7 @@ export class HighStatePanel extends Panel { } _addMenuItemUseStateApply () { - this.settingsMenu.addMenuItem( + this.settingsMenu.addMenuItemCmd( () => { const stateApplyFlag = Utils.getStorageItem("local", "use_state_apply", "true"); return (stateApplyFlag === "true" ? Character.HEAVY_CHECK_MARK + Character.NO_BREAK_SPACE : "") + "Include state.apply"; @@ -535,7 +535,7 @@ export class HighStatePanel extends Panel { } _addJobsMenuItemShowDetails (pMenu, pJob, pMinionId) { - pMenu.addMenuItem("Show details", (pClickEvent) => { + pMenu.addMenuItemCmd("Show details", (pClickEvent) => { this.router.goTo("job", {"id": pJob.jid, "minionid": pMinionId}, undefined, pClickEvent); }); } diff --git a/saltgui/static/scripts/panels/Job.js b/saltgui/static/scripts/panels/Job.js index 3ac0cfc0f..e4df3d67f 100644 --- a/saltgui/static/scripts/panels/Job.js +++ b/saltgui/static/scripts/panels/Job.js @@ -1,10 +1,11 @@ /* global */ import {Character} from "../Character.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {Output} from "../output/Output.js"; import {Panel} from "./Panel.js"; import {ParseCommandLine} from "../ParseCommandLine.js"; +import {Search} from "../Search.js"; import {TargetType} from "../TargetType.js"; import {Utils} from "../Utils.js"; @@ -52,7 +53,7 @@ export class JobPanel extends Panel { const output = Utils.createElem("pre", "output", "", "job-table"); this.output = output; - const searchBox = Utils.makeSearchBox(this.searchButton, this.output, "data-list-job"); + const searchBox = Search.makeSearchBox(this.searchButton, this.output, "data-list-job"); this.div.appendChild(searchBox); this.div.append(this.output); @@ -342,7 +343,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemJobRerunJob () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.target && !this.commandtext) { return null; } @@ -376,7 +377,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemRerunJobOnAllMinionsWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { const lst = this._listForRerunJobOnAllMinions(); if (!lst) { return null; @@ -423,7 +424,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemRerunJobOnUnsuccessfulMinionsWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { const lst = this._listForRerunJobOnUnsuccessfulMinions(); if (!lst) { return null; @@ -456,7 +457,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemRerunJobOnFailedMinionsWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { const lst = this._listForRerunJobOnFailedMinions(); if (!lst) { return null; @@ -489,7 +490,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemRerunJobOnNonRespondingMinionsWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { const lst = this._listForRerunJobOnNonRespondingMinions(); if (!lst) { return null; @@ -502,7 +503,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemTerminateJob () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.jobIsTerminated !== false) { return null; } @@ -514,7 +515,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemKillJob () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.jobIsTerminated !== false) { return null; } @@ -526,7 +527,7 @@ export class JobPanel extends Panel { } _addPanelMenuItemSignalJob () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.jobIsTerminated !== false) { return null; } @@ -585,20 +586,20 @@ export class JobPanel extends Panel { // show that this minion is still active on the request noResponseSpan.innerText = "(active) "; - const menu = new DropDownMenu(noResponseSpan, "verysmall"); - menu.addMenuItem("Show process info...", () => { + const menu = new DropDownMenuCmd(noResponseSpan, "verysmall"); + menu.addMenuItemCmd("Show process info...", () => { const cmdArr = ["ps.proc_info", pid]; this.runCommand("", minionId, cmdArr); }); - menu.addMenuItem("Terminate process...", () => { + menu.addMenuItemCmd("Terminate process...", () => { const cmdArr = ["ps.kill_pid", pid, "signal=", 15]; this.runCommand("", minionId, cmdArr); }); - menu.addMenuItem("Kill process...", () => { + menu.addMenuItemCmd("Kill process...", () => { const cmdArr = ["ps.kill_pid", pid, "signal=", 9]; this.runCommand("", minionId, cmdArr); }); - menu.addMenuItem("Signal process...", () => { + menu.addMenuItemCmd("Signal process...", () => { const cmdArr = ["ps.kill_pid", pid, "signal=", ""]; this.runCommand("", minionId, cmdArr); }); diff --git a/saltgui/static/scripts/panels/JobsDetails.js b/saltgui/static/scripts/panels/JobsDetails.js index aab538a7e..f12cd1e01 100644 --- a/saltgui/static/scripts/panels/JobsDetails.js +++ b/saltgui/static/scripts/panels/JobsDetails.js @@ -1,7 +1,7 @@ /* global */ import {Character} from "../Character.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {JobPanel} from "./Job.js"; import {JobsPanel} from "./Jobs.js"; import {Output} from "../output/Output.js"; @@ -88,7 +88,7 @@ export class JobsDetailsPanel extends JobsPanel { } _addSettingsMenuItemShowSome () { - this.settingsMenu.addMenuItem(() => { + this.settingsMenu.addMenuItemCmd(() => { let title = "Show first " + MAX_JOBS_DETAILS + " jobs"; const cnt = decodeURIComponent(Utils.getQueryParam("cnt")); if (cnt === "undefined" || cnt === String(MAX_JOBS_DETAILS)) { @@ -101,7 +101,7 @@ export class JobsDetailsPanel extends JobsPanel { } _addSettingsMenuItemShowEligible () { - this.settingsMenu.addMenuItem(() => { + this.settingsMenu.addMenuItemCmd(() => { const cnt = decodeURIComponent(Utils.getQueryParam("cnt")); let title = "Show eligible jobs"; if (cnt === "eligible") { @@ -114,7 +114,7 @@ export class JobsDetailsPanel extends JobsPanel { } _addSettingsMenuItemShowAll () { - this.settingsMenu.addMenuItem(() => { + this.settingsMenu.addMenuItemCmd(() => { const cnt = decodeURIComponent(Utils.getQueryParam("cnt")); let title = "Show all jobs"; if (cnt === "all") { @@ -346,7 +346,7 @@ export class JobsDetailsPanel extends JobsPanel { tr.id = Utils.getIdFromJobId(job.id); tr.dataset.jobid = job.id; - const menu = new DropDownMenu(tr, "smaller"); + const menu = new DropDownMenuCmd(tr, "smaller"); tr.appendChild(Utils.createTd("", job.id)); @@ -419,20 +419,20 @@ export class JobsDetailsPanel extends JobsPanel { } _addJobsMenuItemShowDetails (pMenu, job) { - pMenu.addMenuItem("Show details", (pClickEvent) => { + pMenu.addMenuItemCmd("Show details", (pClickEvent) => { this.router.goTo("job", {"id": job.id}, undefined, pClickEvent); }); } _addMenuItemJobsRerunJob (pMenu, job, argumentsText) { - pMenu.addMenuItem("Re-run job...", () => { + pMenu.addMenuItemCmd("Re-run job...", () => { const cmdStr = job.Function + argumentsText; this.runCommand(job["Target-type"], job.Target, cmdStr); }); } _addJobsMenuItemUpdateStatus (pMenu, pStatusSpan) { - pMenu.addMenuItem("Update status", () => { + pMenu.addMenuItemCmd("Update status", () => { pStatusSpan.classList.add("no-job-status"); pStatusSpan.innerText = "loading" + Character.HORIZONTAL_ELLIPSIS; this.startRunningJobs(); @@ -440,7 +440,7 @@ export class JobsDetailsPanel extends JobsPanel { } _addMenuItemUpdateDetails (pMenu, pDetailsSpan, job) { - pMenu.addMenuItem("Update details", () => { + pMenu.addMenuItemCmd("Update details", () => { pDetailsSpan.classList.add("no-job-details"); pDetailsSpan.innerText = "loading" + Character.HORIZONTAL_ELLIPSIS; this._getJobDetails(job.id); diff --git a/saltgui/static/scripts/panels/JobsSummary.js b/saltgui/static/scripts/panels/JobsSummary.js index 17f23f056..4d13a17be 100644 --- a/saltgui/static/scripts/panels/JobsSummary.js +++ b/saltgui/static/scripts/panels/JobsSummary.js @@ -1,7 +1,7 @@ /* global */ import {Character} from "../Character.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {JobsPanel} from "./Jobs.js"; import {Output} from "../output/Output.js"; import {TargetType} from "../TargetType.js"; @@ -37,7 +37,7 @@ export class JobsSummaryPanel extends JobsPanel { tr.id = Utils.getIdFromJobId(job.id); // menu on left side to prevent it from going past end of window - const menu = new DropDownMenu(tr, "smaller"); + const menu = new DropDownMenuCmd(tr, "smaller"); const td = Utils.createTd(); @@ -87,13 +87,13 @@ export class JobsSummaryPanel extends JobsPanel { } _addMenuItemShowDetails (pMenu, job) { - pMenu.addMenuItem("Show details", (pClickEvent) => { + pMenu.addMenuItemCmd("Show details", (pClickEvent) => { this.router.goTo("job", {"id": job.id}, undefined, pClickEvent); }); } _addMenuItemUpdateStatus (pMenu, statusSpan) { - pMenu.addMenuItem("Update status", () => { + pMenu.addMenuItemCmd("Update status", () => { statusSpan.classList.add("no-job-status"); statusSpan.innerText = "loading" + Character.HORIZONTAL_ELLIPSIS; this.startRunningJobs(); diff --git a/saltgui/static/scripts/panels/Keys.js b/saltgui/static/scripts/panels/Keys.js index 753c65383..957f36e38 100644 --- a/saltgui/static/scripts/panels/Keys.js +++ b/saltgui/static/scripts/panels/Keys.js @@ -412,7 +412,7 @@ export class KeysPanel extends Panel { } _addMenuItemWheelKeyAccept1 (pMenu, pMinionId, pStatusField) { - pMenu.addMenuItem(() => { + pMenu.addMenuItemCmd(() => { const status = pStatusField.innerText; if (status === "denied" || status === "unaccepted") { return "Accept key..."; @@ -431,7 +431,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyAcceptAllUnaccepted () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.nrUnaccepted > 0) { return "Accept all unaccepted keys..."; } @@ -443,7 +443,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyAcceptAllUnacceptedRejected () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.nrRejected) { return null; } @@ -458,7 +458,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyAcceptAllUnacceptedDenied () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.nrDenied) { return null; } @@ -473,7 +473,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyAcceptAllUnacceptedRejectedDenied () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.nrRejected || !this.nrDenied) { return null; } @@ -488,7 +488,7 @@ export class KeysPanel extends Panel { } _addMenuItemWheelKeyAccept2 (pMenu, pMinionId, pStatusField) { - pMenu.addMenuItem(() => { + pMenu.addMenuItemCmd(() => { const status = pStatusField.innerText; if (status === "rejected") { return "Accept key..."; @@ -507,7 +507,7 @@ export class KeysPanel extends Panel { } _addMenuItemWheelKeyReject (pMenu, pMinionId, pStatusField) { - pMenu.addMenuItem(() => { + pMenu.addMenuItemCmd(() => { const status = pStatusField.innerText; if (status === "accepted" || status === "denied" || status === "unaccepted") { return "Reject key..."; @@ -526,7 +526,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyRejectAllUnaccepted () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.nrUnaccepted > 0) { return "Reject all unaccepted keys..."; } @@ -538,7 +538,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyRejectAllUnacceptedAccepted () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.nrAccepted) { return null; } @@ -553,7 +553,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyRejectAllUnacceptedDenied () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.nrDenied) { return null; } @@ -568,7 +568,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyRejectAllUnacceptedAcceptedDenied () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.nrAccepted || !this.nrDenied) { return null; } @@ -582,9 +582,9 @@ export class KeysPanel extends Panel { }); } - _addMenuItemWheelKeyDelete (pMenu, pMinionId, pStatusField) { - pMenu.addMenuItem(() => { - const status = pStatusField.innerText; + _addMenuItemWheelKeyDelete (pMenu, pMinionId, pMinionTr) { + pMenu.addMenuItemCmd(() => { + const status = pMinionTr.dataset.status; if (status === "accepted" || status === "rejected" || status === "unaccepted" || status === "denied") { return "Delete key..."; } @@ -596,7 +596,7 @@ export class KeysPanel extends Panel { } _addPanelMenuItemWheelKeyDeleteAll () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.nrAccepted > 0 || this.nrUnaccepted > 0 || this.nrRejected > 0 || this.nrDenied > 0) { return "Delete all keys..."; } diff --git a/saltgui/static/scripts/panels/Minions.js b/saltgui/static/scripts/panels/Minions.js index 117cc49d5..a97a13e1a 100644 --- a/saltgui/static/scripts/panels/Minions.js +++ b/saltgui/static/scripts/panels/Minions.js @@ -202,39 +202,39 @@ export class MinionsPanel extends Panel { } _addMenuItemStateApply (pMenu, pMinionId) { - pMenu.addMenuItem("Apply state...", () => { + pMenu.addMenuItemCmd("Apply state...", () => { const cmdArr = ["state.apply"]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemStateApplyTest (pMenu, pMinionId) { - pMenu.addMenuItem("Test state...", () => { + pMenu.addMenuItemCmd("Test state...", () => { const cmdArr = ["state.apply", "test=", true]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemShowGrains (pMenu, pMinionId) { - pMenu.addMenuItem("Show grains", (pClickEvent) => { + pMenu.addMenuItemCmd("Show grains", (pClickEvent) => { this.router.goTo("grains-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } _addMenuItemShowSchedules (pMenu, pMinionId) { - pMenu.addMenuItem("Show schedules", (pClickEvent) => { + pMenu.addMenuItemCmd("Show schedules", (pClickEvent) => { this.router.goTo("schedules-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } _addMenuItemShowPillars (pMenu, pMinionId) { - pMenu.addMenuItem("Show pillars", (pClickEvent) => { + pMenu.addMenuItemCmd("Show pillars", (pClickEvent) => { this.router.goTo("pillars-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } _addMenuItemShowBeacons (pMenu, pMinionId) { - pMenu.addMenuItem("Show beacons", (pClickEvent) => { + pMenu.addMenuItemCmd("Show beacons", (pClickEvent) => { this.router.goTo("beacons-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } diff --git a/saltgui/static/scripts/panels/Nodegroups.js b/saltgui/static/scripts/panels/Nodegroups.js index 410476bf3..69902cf94 100644 --- a/saltgui/static/scripts/panels/Nodegroups.js +++ b/saltgui/static/scripts/panels/Nodegroups.js @@ -1,7 +1,7 @@ /* global */ import {Character} from "../Character.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {Panel} from "./Panel.js"; import {Utils} from "../Utils.js"; @@ -157,7 +157,7 @@ export class NodegroupsPanel extends Panel { oldMenuButton.parentElement.remove(); const newMenuButton = Utils.createTd(); minionTr2.insertBefore(newMenuButton, minionTr2.firstChild); - minionTr2.dropdownmenu = new DropDownMenu(newMenuButton, "smaller"); + minionTr2.dropdownmenu = new DropDownMenuCmd(newMenuButton, "smaller"); if (minionIsOk) { this._addMenuItemStateApplyMinion(minionTr2.dropdownmenu, pMinionId); this._addMenuItemStateApplyTestMinion(minionTr2.dropdownmenu, pMinionId); @@ -311,7 +311,7 @@ export class NodegroupsPanel extends Panel { tr.style.borderTop = "4px double #ddd"; const menuTd = Utils.createTd(); - tr.dropdownmenu = new DropDownMenu(menuTd, "smaller"); + tr.dropdownmenu = new DropDownMenuCmd(menuTd, "smaller"); tr.appendChild(menuTd); const titleTd = Utils.createTd(); @@ -396,59 +396,59 @@ export class NodegroupsPanel extends Panel { } _addMenuItemStateApplyGroup (pMenu, pNodegroup, pAllNodegroups) { - pMenu.addMenuItem("Apply state...", () => { + pMenu.addMenuItemCmd("Apply state...", () => { const cmdArr = ["state.apply"]; this.runCommand("", NodegroupsPanel._getGroupTarget(pNodegroup, pAllNodegroups), cmdArr); }); } _addMenuItemStateApplyTestGroup (pMenu, pNodegroup, pAllNodegroups) { - pMenu.addMenuItem("Test state...", () => { + pMenu.addMenuItemCmd("Test state...", () => { const cmdArr = ["state.apply", "test=", true]; this.runCommand("", NodegroupsPanel._getGroupTarget(pNodegroup, pAllNodegroups), cmdArr); }); } _addMenuItemStateApplyMinion (pMenu, pMinionId) { - pMenu.addMenuItem("Apply state...", () => { + pMenu.addMenuItemCmd("Apply state...", () => { const cmdArr = ["state.apply"]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemStateApplyTestMinion (pMenu, pMinionId) { - pMenu.addMenuItem("Test state...", () => { + pMenu.addMenuItemCmd("Test state...", () => { const cmdArr = ["state.apply", "test=", true]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemShowKeys (pMenu) { - pMenu.addMenuItem("Show keys", (pClickEvent) => { + pMenu.addMenuItemCmd("Show keys", (pClickEvent) => { this.router.goTo("keys", undefined, undefined, pClickEvent); }); } _addMenuItemShowGrains (pMenu, pMinionId) { - pMenu.addMenuItem("Show grains", (pClickEvent) => { + pMenu.addMenuItemCmd("Show grains", (pClickEvent) => { this.router.goTo("grains-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } _addMenuItemShowSchedules (pMenu, pMinionId) { - pMenu.addMenuItem("Show schedules", (pClickEvent) => { + pMenu.addMenuItemCmd("Show schedules", (pClickEvent) => { this.router.goTo("schedules-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } _addMenuItemShowPillars (pMenu, pMinionId) { - pMenu.addMenuItem("Show pillars", (pClickEvent) => { + pMenu.addMenuItemCmd("Show pillars", (pClickEvent) => { this.router.goTo("pillars-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } _addMenuItemShowBeacons (pMenu, pMinionId) { - pMenu.addMenuItem("Show beacons", (pClickEvent) => { + pMenu.addMenuItemCmd("Show beacons", (pClickEvent) => { this.router.goTo("beacons-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } diff --git a/saltgui/static/scripts/panels/Panel.js b/saltgui/static/scripts/panels/Panel.js index 9018a1680..0c6c6e49c 100644 --- a/saltgui/static/scripts/panels/Panel.js +++ b/saltgui/static/scripts/panels/Panel.js @@ -2,7 +2,8 @@ import {Character} from "../Character.js"; import {CommandBox} from "../CommandBox.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; +import {Search} from "../Search.js"; import {SortTable} from "../../sorttable/sorttable.js"; import {TargetType} from "../TargetType.js"; import {Utils} from "../Utils.js"; @@ -47,7 +48,7 @@ export class Panel { addPanelMenu () { const span = Utils.createSpan(); span.id = this.key + "-menu"; - const menu = new DropDownMenu(span); + const menu = new DropDownMenuCmd(span); menu.menuButton.classList.add("small-button-left", "no-print"); this.div.appendChild(span); this.panelMenu = menu; @@ -56,7 +57,7 @@ export class Panel { addSettingsMenu () { const span = Utils.createSpan(); span.id = this.key + "-settings"; - const menu = new DropDownMenu(span); + const menu = new DropDownMenuCmd(span); menu.menuButton.classList.add("small-button-left"); this.div.appendChild(span); this.settingsMenu = menu; @@ -208,7 +209,7 @@ export class Panel { // most tables are searchable (but not all) // when it is, we already prepared the search button for it if (this.div.querySelector(".search-button") !== null) { - const searchBox = Utils.makeSearchBox(this.searchButton, table, pFieldList); + const searchBox = Search.makeSearchBox(this.searchButton, table, pFieldList); this.div.appendChild(searchBox); this.searchBox = searchBox; } @@ -394,7 +395,7 @@ export class Panel { // drop down menu const menuTd = Utils.createTd(); - const menu = new DropDownMenu(menuTd, "smaller"); + const menu = new DropDownMenuCmd(menuTd, "smaller"); minionTr.dropdownmenu = menu; minionTr.appendChild(menuTd); @@ -434,7 +435,7 @@ export class Panel { // drop down menu const menuTd = Utils.createTd(); - const menu = new DropDownMenu(menuTd, "smaller"); + const menu = new DropDownMenuCmd(menuTd, "smaller"); minionTr.dropdownmenu = menu; minionTr.appendChild(menuTd); diff --git a/saltgui/static/scripts/panels/Pillars.js b/saltgui/static/scripts/panels/Pillars.js index 8e063859c..cd3a83015 100644 --- a/saltgui/static/scripts/panels/Pillars.js +++ b/saltgui/static/scripts/panels/Pillars.js @@ -104,7 +104,7 @@ export class PillarsPanel extends Panel { } _addMenuItemShowPillars (pMenu, pMinionId) { - pMenu.addMenuItem("Show pillars", (pClickEvent) => { + pMenu.addMenuItemCmd("Show pillars", (pClickEvent) => { this.router.goTo("pillars-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } diff --git a/saltgui/static/scripts/panels/PillarsMinion.js b/saltgui/static/scripts/panels/PillarsMinion.js index 0b10a426f..2421d78bf 100644 --- a/saltgui/static/scripts/panels/PillarsMinion.js +++ b/saltgui/static/scripts/panels/PillarsMinion.js @@ -139,7 +139,7 @@ export class PillarsMinionPanel extends Panel { } _addPanelMenuItemSaltUtilRefreshPillar () { - this.panelMenu.addMenuItem("Refresh pillar...", () => { + this.panelMenu.addMenuItemCmd("Refresh pillar...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = ["saltutil.refresh_pillar"]; this.runCommand("", minionId, cmdArr); diff --git a/saltgui/static/scripts/panels/Schedules.js b/saltgui/static/scripts/panels/Schedules.js index 65baee7ca..67b9e8cf8 100644 --- a/saltgui/static/scripts/panels/Schedules.js +++ b/saltgui/static/scripts/panels/Schedules.js @@ -147,7 +147,7 @@ export class SchedulesPanel extends Panel { } _addMenuItemShowSchedules (pMenu, pMinionId) { - pMenu.addMenuItem("Show schedules", (pClickEvent) => { + pMenu.addMenuItemCmd("Show schedules", (pClickEvent) => { this.router.goTo("schedules-minion", {"minionid": pMinionId}, undefined, pClickEvent); }); } diff --git a/saltgui/static/scripts/panels/SchedulesMinion.js b/saltgui/static/scripts/panels/SchedulesMinion.js index e83a988e3..6624f6a13 100644 --- a/saltgui/static/scripts/panels/SchedulesMinion.js +++ b/saltgui/static/scripts/panels/SchedulesMinion.js @@ -1,7 +1,7 @@ /* global */ import {Character} from "../Character.js"; -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {Output} from "../output/Output.js"; import {Panel} from "./Panel.js"; import {SchedulesPanel} from "./Schedules.js"; @@ -95,7 +95,7 @@ export class SchedulesMinionPanel extends Panel { const tr = Utils.createTr(); - const scheduleMenu = new DropDownMenu(tr, "smaller"); + const scheduleMenu = new DropDownMenuCmd(tr, "smaller"); const nameTd = Utils.createTd("schedule-name", scheduleName); tr.appendChild(nameTd); @@ -134,7 +134,7 @@ export class SchedulesMinionPanel extends Panel { } _addPanelMenuItemScheduleEnableWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (this.schedulesEnabled) { return null; } @@ -147,7 +147,7 @@ export class SchedulesMinionPanel extends Panel { } _addPanelMenuItemScheduleDisableWhenNeeded () { - this.panelMenu.addMenuItem(() => { + this.panelMenu.addMenuItemCmd(() => { if (!this.schedulesEnabled) { return null; } @@ -160,7 +160,7 @@ export class SchedulesMinionPanel extends Panel { } _addPanelMenuItemScheduleAddInterval () { - this.panelMenu.addMenuItem("Add interval schedule...", () => { + this.panelMenu.addMenuItemCmd("Add interval schedule...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = [ "schedule.add", @@ -176,7 +176,7 @@ export class SchedulesMinionPanel extends Panel { } _addPanelMenuItemScheduleAddCron () { - this.panelMenu.addMenuItem("Add cron schedule...", () => { + this.panelMenu.addMenuItemCmd("Add cron schedule...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = [ "schedule.add", @@ -189,7 +189,7 @@ export class SchedulesMinionPanel extends Panel { } _addPanelMenuItemScheduleAddOnce () { - this.panelMenu.addMenuItem("Add once schedule...", () => { + this.panelMenu.addMenuItemCmd("Add once schedule...", () => { const minionId = decodeURIComponent(Utils.getQueryParam("minionid")); const cmdArr = [ "schedule.add", @@ -204,7 +204,7 @@ export class SchedulesMinionPanel extends Panel { } _addMenuItemModifyJob (pMenu, pMinionId, scheduleModifyCmdArr) { - pMenu.addMenuItem("Modify job...", () => { + pMenu.addMenuItemCmd("Modify job...", () => { this.runCommand("", pMinionId, scheduleModifyCmdArr); }); } @@ -213,7 +213,7 @@ export class SchedulesMinionPanel extends Panel { if (schedule.enabled !== false) { return; } - pMenu.addMenuItem("Enable job...", () => { + pMenu.addMenuItemCmd("Enable job...", () => { const cmdArr = ["schedule.enable_job", pJobName]; this.runCommand("", pMinionId, cmdArr); }); @@ -223,21 +223,21 @@ export class SchedulesMinionPanel extends Panel { if (schedule.enabled === false) { return; } - pMenu.addMenuItem("Disable job...", () => { + pMenu.addMenuItemCmd("Disable job...", () => { const cmdArr = ["schedule.disable_job", pJobName]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemScheduleDeleteJob (pMenu, pMinionId, pJobName) { - pMenu.addMenuItem("Delete job...", () => { + pMenu.addMenuItemCmd("Delete job...", () => { const cmdArr = ["schedule.delete", pJobName]; this.runCommand("", pMinionId, cmdArr); }); } _addMenuItemScheduleRunJob (pMenu, pMinionId, pJobName, schedule) { - pMenu.addMenuItem("Run job...", () => { + pMenu.addMenuItemCmd("Run job...", () => { const scheduleRunJobCmdArr = ["schedule.run_job"]; if (schedule.enabled === false) { scheduleRunJobCmdArr.push("force=", true); diff --git a/saltgui/static/scripts/panels/Templates.js b/saltgui/static/scripts/panels/Templates.js index 152bc1e31..bbe27d069 100644 --- a/saltgui/static/scripts/panels/Templates.js +++ b/saltgui/static/scripts/panels/Templates.js @@ -1,6 +1,6 @@ /* global */ -import {DropDownMenu} from "../DropDown.js"; +import {DropDownMenuCmd} from "../DropDownCmd.js"; import {Panel} from "./Panel.js"; import {Router} from "../Router.js"; import {Utils} from "../Utils.js"; @@ -113,7 +113,7 @@ export class TemplatesPanel extends Panel { _addTemplate (pTemplateName, template) { const tr = Utils.createTr(); - const menu = new DropDownMenu(tr, "smaller"); + const menu = new DropDownMenuCmd(tr, "smaller"); tr.appendChild(Utils.createTd("name", pTemplateName)); @@ -180,7 +180,7 @@ export class TemplatesPanel extends Panel { } _addMenuItemApplyTemplate (pMenu, pTargetType, target, pCommand) { - pMenu.addMenuItem("Apply template...", () => { + pMenu.addMenuItemCmd("Apply template...", () => { this.runCommand(pTargetType, target, pCommand); }); }