Skip to content

Commit e69e6b4

Browse files
author
Erwin Dondorp
committed
Also allow selection of keys and nodegroups
1 parent 9a2ff35 commit e69e6b4

14 files changed

Lines changed: 535 additions & 145 deletions

File tree

docs/README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ We suggest to upgrade the SaltStack installation when you are still using a vers
4949
- Keyboard control to apply templates
5050
- Choose between live info and cached info for grains/pillar
5151
- View details of orchestrations and allow to start them
52-
- Act on multiple minions by first selecting them
52+
- Act on multiple minions/keys/nodegroups by first selecting them
5353

5454

5555
## Quick start using PAM as authentication method
@@ -401,12 +401,15 @@ Each issue has its own dropdown-menu, which typically contains:
401401
But note that there might be more possible solutions, some of which may actually be more preferred.
402402
* A navigation-command to go to a page for more details.
403403

404-
## Minion selection
404+
## Row selection
405405
Pages that show a simple list of minions allow individual minions to be selected.
406+
The Keys page allows individual keys to be selected.
407+
The NodeGroups page allows individual nodegroups and/or minions to be selected.
408+
406409
Use panel button [] to show an extra column with checkboxes in the table.
407-
Minions can be selected one-by-one or you can use select-all, select-none by clicking on the column header.
410+
Rows can be selected one-by-one or you can use select-all, select-none by clicking on the column header.
408411
The selection can be inverted by using CTRL-click.
409-
The list of selected minions will be used in the command-box and for commands from a panel-menu.
412+
The list of selected rows will be used in the command-box and for commands from a panel-menu.
410413
When the column is hidden, the selection-values are just ignored.
411414

412415
## Command documentation

saltgui/static/scripts/CommandBox.js

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -423,24 +423,93 @@ export class CommandBox {
423423
button.disabled = false;
424424
}
425425

426-
static getSelectedMinionList () {
426+
static _getNodegroupsSelection () {
427+
const allNodeGroups = Utils.getStorageItemObject("session", "nodegroups");
428+
const allNodeGroupsKeys = Object.keys(allNodeGroups);
429+
430+
let ret = "";
431+
const lst_nodegroups = Utils.getStorageItem("session", "select_nodegroups", null);
432+
if (lst_nodegroups) {
433+
for (const nodegroup of lst_nodegroups.split(",")) {
434+
if (nodegroup === "null") {
435+
// the spaces around '(' and before ')' are mandatory
436+
// salt-api returns 500-InternalServerError when missing
437+
// see also https://docs.saltproject.io/en/latest/topics/targeting/compound.html#precedence-matching
438+
ret += " or not ( "
439+
let grplst = "";
440+
for (const grp of allNodeGroupsKeys) {
441+
grplst += " or N@" + grp;
442+
}
443+
// strip the prefix " or "
444+
ret += grplst.substring(4) + " )";
445+
} else if (nodegroup) {
446+
ret += " or N@" + nodegroup;
447+
}
448+
}
449+
}
450+
return ret;
451+
}
452+
453+
static _getMinionSelection () {
454+
let ret = "";
455+
const lst_minions = Utils.getStorageItem("session", "select_minions", null);
456+
if (lst_minions) {
457+
let minionlist = "";
458+
for (const minion of lst_minions.split(",")) {
459+
if (minion) {
460+
minionlist += "," + minion;
461+
}
462+
}
463+
if (minionlist) {
464+
// substring removes the extra ","
465+
ret += " or L@" + minionlist.substring(1);
466+
}
467+
}
468+
return ret;
469+
}
470+
471+
static getSelectedItemList (pSessionKeys) {
427472
const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
428473
if (!selectVisible) {
429474
return null;
430475
}
431476

432-
// only when the selection is visible
433-
const selectMinions = Utils.getStorageItem("session", "select_minions", "");
434-
const lst = selectMinions.split(",").sort();
435-
while (lst.length > 0 && lst[0] === "") {
436-
lst.shift();
477+
let target = "";
478+
479+
if (pSessionKeys.includes("select_nodegroups")) {
480+
target += CommandBox._getNodegroupsSelection();
437481
}
438-
// and only when there is a selection
439-
if (lst.length == 0) {
482+
483+
if (pSessionKeys.includes("select_minions")) {
484+
target += CommandBox._getMinionSelection();
485+
}
486+
487+
if (pSessionKeys.includes("select_keys")) {
488+
const lst_keys = Utils.getStorageItem("session", "select_keys", null);
489+
if (lst_keys) {
490+
let keylist = "";
491+
for (const key of lst_keys.split(",")) {
492+
if (key) {
493+
keylist += "," + key;
494+
}
495+
}
496+
// substring removes the extra ","
497+
target += " or " + keylist.substring(1);
498+
}
499+
}
500+
501+
// remove the extra " or "
502+
target = target.substring(4);
503+
if (target.startsWith("L@")) {
504+
// simplify when we only have the list of minions
505+
target = target.substring(2);
506+
}
507+
508+
if (target === "") {
440509
return null;
441510
}
442511

443-
return lst.join(",");
512+
return target;
444513
}
445514

446515
static showManualRun (pApi) {
@@ -498,7 +567,26 @@ export class CommandBox {
498567
CommandBox._populateTemplateTmplMenu();
499568
CommandBox._populateTestProviders(pApi);
500569

501-
const lst = CommandBox.getSelectedMinionList()
570+
let lst = null;
571+
// different pages have different selection-types
572+
// but run-command is available from every page
573+
switch (window.location.hash) {
574+
case "#minions":
575+
case "#grains":
576+
case "#schedules":
577+
case "#pillars":
578+
case "#beacons":
579+
case "#highstate":
580+
lst = CommandBox.getSelectedItemList(["select_minions"]);
581+
break;
582+
case "#keys":
583+
lst = CommandBox.getSelectedItemList(["select_keys"]);
584+
break;
585+
case "#nodegroups":
586+
lst = CommandBox.getSelectedItemList(["select_minions", "select_nodegroups"]);
587+
break;
588+
}
589+
502590
if (lst) {
503591
const targetField = document.getElementById("target");
504592
targetField.value = lst;
@@ -547,6 +635,7 @@ export class CommandBox {
547635

548636
// The leading # was used to indicate a nodegroup
549637
if (pTargetType === "nodegroup" && pTarget.startsWith("#")) {
638+
// remove the leading "#" as that is not part of the syntax for nodegroups
550639
pTarget = pTarget.substring(1);
551640
}
552641

saltgui/static/scripts/output/OutputHighstateSummarySaltGui.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export class OutputHighstateSummarySaltGui {
4848
}
4949

5050
if (line) {
51+
// strip the prefix ", "
5152
const txtDiv = Utils.createDiv("", line.substring(2));
5253
pDiv.append(txtDiv);
5354
}

saltgui/static/scripts/panels/Beacons.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {Utils} from "../Utils.js";
66
export class BeaconsPanel extends Panel {
77

88
constructor () {
9-
super("beacons");
9+
super("beacons", ["select_minions"]);
1010

1111
this.addTitle("Beacons");
1212
this.addSearchButton();
@@ -18,12 +18,11 @@ export class BeaconsPanel extends Panel {
1818
}
1919

2020
onShow () {
21+
super.onShow();
22+
2123
const wheelKeyListAllPromise = this.api.getWheelKeyListAll();
2224
const localBeaconsListPromise = this.api.getLocalBeaconsList(null);
2325

24-
const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
25-
this.showSelectColumn(selectVisible);
26-
2726
this.nrMinions = 0;
2827

2928
wheelKeyListAllPromise.then((pWheelKeyListAllData) => {
@@ -108,7 +107,7 @@ export class BeaconsPanel extends Panel {
108107
}
109108

110109
updateOfflineMinion (pMinionId, pMinionsDict) {
111-
super.updateOfflineMinion(pMinionId, pMinionsDict, true);
110+
super.updateOfflineMinion(pMinionId, pMinionsDict);
112111

113112
const minionTr = this.table.querySelector("#" + Utils.getIdFromMinionId(pMinionId));
114113

@@ -120,7 +119,7 @@ export class BeaconsPanel extends Panel {
120119

121120
pMinionData = BeaconsPanel.fixBeaconsMinion(pMinionData);
122121

123-
super.updateMinion(null, pMinionId, pAllMinionsGrains, true);
122+
super.updateMinion(null, pMinionId, pAllMinionsGrains);
124123

125124
const minionTr = this.table.querySelector("#" + Utils.getIdFromMinionId(pMinionId));
126125

saltgui/static/scripts/panels/Grains.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {Utils} from "../Utils.js";
77
export class GrainsPanel extends Panel {
88

99
constructor () {
10-
super("grains");
10+
super("grains", ["select_minions"]);
1111

1212
this.addTitle("Grains");
1313
this.addSearchButton();
@@ -27,8 +27,7 @@ export class GrainsPanel extends Panel {
2727
}
2828

2929
onShow () {
30-
const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
31-
this.showSelectColumn(selectVisible);
30+
super.onShow();
3231

3332
if (this.previewColumsAdded !== true) {
3433
// collect the list of displayed extra grains
@@ -86,7 +85,7 @@ export class GrainsPanel extends Panel {
8685

8786
const minionIds = keys.minions.sort();
8887
for (const minionId of minionIds) {
89-
const minionTr = this.addMinion(minionId, true, this.previewGrains.length);
88+
const minionTr = this.addMinion(minionId, this.previewGrains.length);
9089

9190
// preliminary dropdown menu
9291
this._addMenuItemShowGrains(minionTr.dropdownmenu, minionId);
@@ -105,7 +104,7 @@ export class GrainsPanel extends Panel {
105104
}
106105

107106
updateOfflineMinion (pMinionId, pMinionsDict) {
108-
super.updateOfflineMinion(pMinionId, pMinionsDict, true);
107+
super.updateOfflineMinion(pMinionId, pMinionsDict);
109108

110109
const minionTr = this.table.querySelector("#" + Utils.getIdFromMinionId(pMinionId));
111110

@@ -119,7 +118,7 @@ export class GrainsPanel extends Panel {
119118
}
120119

121120
updateMinion (pMinionData, pMinionId, pAllMinionsGrains) {
122-
super.updateMinion(pMinionData, pMinionId, pAllMinionsGrains, true);
121+
super.updateMinion(pMinionData, pMinionId, pAllMinionsGrains);
123122

124123
const minionTr = this.table.querySelector("#" + Utils.getIdFromMinionId(pMinionId));
125124

saltgui/static/scripts/panels/HighState.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {Utils} from "../Utils.js";
1212
export class HighStatePanel extends Panel {
1313

1414
constructor () {
15-
super("highstate");
15+
super("highstate", ["select_minions"]);
1616

1717
// only consider this number of latest highstate jobs
1818
this._maxShowHighstates = Utils.getStorageItem("session", "max_show_highstates", 10);
@@ -47,10 +47,9 @@ export class HighStatePanel extends Panel {
4747
}
4848

4949
onShow () {
50-
const wheelKeyListAllPromise = this.api.getWheelKeyListAll();
50+
super.onShow();
5151

52-
const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
53-
this.showSelectColumn(selectVisible);
52+
const wheelKeyListAllPromise = this.api.getWheelKeyListAll();
5453

5554
this.nrMinions = 0;
5655

@@ -100,14 +99,14 @@ export class HighStatePanel extends Panel {
10099
_addMenuItemStateApply (pMenu, pMinionId) {
101100
pMenu.addMenuItem("Apply state...", () => {
102101
const cmdArr = ["state.apply"];
103-
this.runCommand("", pMinionId, cmdArr, true);
102+
this.runCommand("", pMinionId, cmdArr, ["select_minions"]);
104103
});
105104
}
106105

107106
_addMenuItemStateApplyTest (pMenu, pMinionId) {
108107
pMenu.addMenuItem("Test state...", () => {
109108
const cmdArr = ["state.apply", "test=", true];
110-
this.runCommand("", pMinionId, cmdArr, true);
109+
this.runCommand("", pMinionId, cmdArr, ["select_minions"]);
111110
});
112111
}
113112

@@ -366,7 +365,7 @@ export class HighStatePanel extends Panel {
366365

367366
// we already have the TR
368367
// but this function also clears the row
369-
this.getElement(trId, true);
368+
this.getElement(trId, "select_minions", minionId);
370369

371370
// mark the TR as populated
372371
minionTr.jid = pJobId;

saltgui/static/scripts/panels/Job.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ export class JobPanel extends Panel {
372372
return null;
373373
}
374374

375+
// remove the first comma
375376
return minionList.substring(1);
376377
}
377378

@@ -419,6 +420,7 @@ export class JobPanel extends Panel {
419420
return null;
420421
}
421422

423+
// remove the first comma
422424
return minionList.substring(1);
423425
}
424426

@@ -452,6 +454,7 @@ export class JobPanel extends Panel {
452454
return null;
453455
}
454456

457+
// remove the first comma
455458
return minionList.substring(1);
456459
}
457460

@@ -485,6 +488,7 @@ export class JobPanel extends Panel {
485488
return null;
486489
}
487490

491+
// remove the first comma
488492
return minionList.substring(1);
489493
}
490494

0 commit comments

Comments
 (0)