Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ We suggest to upgrade the SaltStack installation when you are still using a vers
- Keyboard control to apply templates
- Choose between live info and cached info for grains/pillar
- View details of orchestrations and allow to start them
- Act on multiple minions by first selecting them
- Act on multiple minions/keys/nodegroups by first selecting them


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

## Minion selection
## Row selection
Pages that show a simple list of minions allow individual minions to be selected.
The Keys page allows individual keys to be selected.
The NodeGroups page allows individual nodegroups and/or minions to be selected.

Use panel button [✔] to show an extra column with checkboxes in the table.
Minions can be selected one-by-one or you can use select-all, select-none by clicking on the column header.
Rows can be selected one-by-one or you can use select-all, select-none by clicking on the column header.
The selection can be inverted by using CTRL-click.
The list of selected minions will be used in the command-box and for commands from a panel-menu.
The list of selected rows will be used in the command-box and for commands from a panel-menu.
When the column is hidden, the selection-values are just ignored.

## Command documentation
Expand Down
109 changes: 99 additions & 10 deletions saltgui/static/scripts/CommandBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,24 +423,93 @@
button.disabled = false;
}

static getSelectedMinionList () {
static _getNodegroupsSelection () {
const allNodeGroups = Utils.getStorageItemObject("session", "nodegroups");
const allNodeGroupsKeys = Object.keys(allNodeGroups);

let ret = "";
const lst_nodegroups = Utils.getStorageItem("session", "select_nodegroups", null);
if (lst_nodegroups) {
for (const nodegroup of lst_nodegroups.split(",")) {
if (nodegroup === "null") {
// the spaces around '(' and before ')' are mandatory
// salt-api returns 500-InternalServerError when missing
// see also https://docs.saltproject.io/en/latest/topics/targeting/compound.html#precedence-matching
ret += " or not ( "
let grplst = "";
for (const grp of allNodeGroupsKeys) {
grplst += " or N@" + grp;
}
// strip the prefix " or "
ret += grplst.substring(4) + " )";
} else if (nodegroup) {
ret += " or N@" + nodegroup;
}
}
}
return ret;
}

static _getMinionSelection () {
let ret = "";
const lst_minions = Utils.getStorageItem("session", "select_minions", null);
if (lst_minions) {
let minionlist = "";
for (const minion of lst_minions.split(",")) {
if (minion) {
minionlist += "," + minion;
}
}
if (minionlist) {
// substring removes the extra ","
ret += " or L@" + minionlist.substring(1);
}
}
return ret;
}

static getSelectedItemList (pSessionKeys) {
const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
if (!selectVisible) {
return null;
}

// only when the selection is visible
const selectMinions = Utils.getStorageItem("session", "select_minions", "");
const lst = selectMinions.split(",").sort();
while (lst.length > 0 && lst[0] === "") {
lst.shift();
let target = "";

if (pSessionKeys.includes("select_nodegroups")) {
target += CommandBox._getNodegroupsSelection();
}
// and only when there is a selection
if (lst.length == 0) {

if (pSessionKeys.includes("select_minions")) {
target += CommandBox._getMinionSelection();
}

if (pSessionKeys.includes("select_keys")) {
const lst_keys = Utils.getStorageItem("session", "select_keys", null);
if (lst_keys) {
let keylist = "";
for (const key of lst_keys.split(",")) {
if (key) {
keylist += "," + key;
}
}
// substring removes the extra ","
target += " or " + keylist.substring(1);
}
}

// remove the extra " or "
target = target.substring(4);
if (target.startsWith("L@")) {
// simplify when we only have the list of minions
target = target.substring(2);
}

if (target === "") {
return null;
}

return lst.join(",");
return target;
}

static showManualRun (pApi) {
Expand Down Expand Up @@ -498,7 +567,26 @@
CommandBox._populateTemplateTmplMenu();
CommandBox._populateTestProviders(pApi);

const lst = CommandBox.getSelectedMinionList()
let lst = null;
// different pages have different selection-types
// but run-command is available from every page
switch (window.location.hash) {

Check warning on line 573 in saltgui/static/scripts/CommandBox.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `globalThis` over `window`.

See more on https://sonarcloud.io/project/issues?id=erwindon_SaltGUI&issues=AZ16aA-Z1Rn55vnUNzDf&open=AZ16aA-Z1Rn55vnUNzDf&pullRequest=862
case "#minions":
case "#grains":
case "#schedules":
case "#pillars":
case "#beacons":
case "#highstate":
lst = CommandBox.getSelectedItemList(["select_minions"]);
break;
case "#keys":
lst = CommandBox.getSelectedItemList(["select_keys"]);
break;
case "#nodegroups":
lst = CommandBox.getSelectedItemList(["select_minions", "select_nodegroups"]);
break;
}

if (lst) {
const targetField = document.getElementById("target");
targetField.value = lst;
Expand Down Expand Up @@ -547,6 +635,7 @@

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export class OutputHighstateSummarySaltGui {
}

if (line) {
// strip the prefix ", "
const txtDiv = Utils.createDiv("", line.substring(2));
pDiv.append(txtDiv);
}
Expand Down
11 changes: 5 additions & 6 deletions saltgui/static/scripts/panels/Beacons.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {Utils} from "../Utils.js";
export class BeaconsPanel extends Panel {

constructor () {
super("beacons");
super("beacons", ["select_minions"]);

this.addTitle("Beacons");
this.addSearchButton();
Expand All @@ -18,12 +18,11 @@ export class BeaconsPanel extends Panel {
}

onShow () {
super.onShow();

const wheelKeyListAllPromise = this.api.getWheelKeyListAll();
const localBeaconsListPromise = this.api.getLocalBeaconsList(null);

const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
this.showSelectColumn(selectVisible);

this.nrMinions = 0;

wheelKeyListAllPromise.then((pWheelKeyListAllData) => {
Expand Down Expand Up @@ -108,7 +107,7 @@ export class BeaconsPanel extends Panel {
}

updateOfflineMinion (pMinionId, pMinionsDict) {
super.updateOfflineMinion(pMinionId, pMinionsDict, true);
super.updateOfflineMinion(pMinionId, pMinionsDict);

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

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

pMinionData = BeaconsPanel.fixBeaconsMinion(pMinionData);

super.updateMinion(null, pMinionId, pAllMinionsGrains, true);
super.updateMinion(null, pMinionId, pAllMinionsGrains);

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

Expand Down
11 changes: 5 additions & 6 deletions saltgui/static/scripts/panels/Grains.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {Utils} from "../Utils.js";
export class GrainsPanel extends Panel {

constructor () {
super("grains");
super("grains", ["select_minions"]);

this.addTitle("Grains");
this.addSearchButton();
Expand All @@ -27,8 +27,7 @@ export class GrainsPanel extends Panel {
}

onShow () {
const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
this.showSelectColumn(selectVisible);
super.onShow();

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

const minionIds = keys.minions.sort();
for (const minionId of minionIds) {
const minionTr = this.addMinion(minionId, true, this.previewGrains.length);
const minionTr = this.addMinion(minionId, this.previewGrains.length);

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

updateOfflineMinion (pMinionId, pMinionsDict) {
super.updateOfflineMinion(pMinionId, pMinionsDict, true);
super.updateOfflineMinion(pMinionId, pMinionsDict);

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

Expand All @@ -119,7 +118,7 @@ export class GrainsPanel extends Panel {
}

updateMinion (pMinionData, pMinionId, pAllMinionsGrains) {
super.updateMinion(pMinionData, pMinionId, pAllMinionsGrains, true);
super.updateMinion(pMinionData, pMinionId, pAllMinionsGrains);

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

Expand Down
13 changes: 6 additions & 7 deletions saltgui/static/scripts/panels/HighState.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {Utils} from "../Utils.js";
export class HighStatePanel extends Panel {

constructor () {
super("highstate");
super("highstate", ["select_minions"]);

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

onShow () {
const wheelKeyListAllPromise = this.api.getWheelKeyListAll();
super.onShow();

const selectVisible = Utils.getStorageItemBoolean("session", "select_visible", false);
this.showSelectColumn(selectVisible);
const wheelKeyListAllPromise = this.api.getWheelKeyListAll();

this.nrMinions = 0;

Expand Down Expand Up @@ -100,14 +99,14 @@ export class HighStatePanel extends Panel {
_addMenuItemStateApply (pMenu, pMinionId) {
pMenu.addMenuItem("Apply state...", () => {
const cmdArr = ["state.apply"];
this.runCommand("", pMinionId, cmdArr, true);
this.runCommand("", pMinionId, cmdArr, ["select_minions"]);
});
}

_addMenuItemStateApplyTest (pMenu, pMinionId) {
pMenu.addMenuItem("Test state...", () => {
const cmdArr = ["state.apply", "test=", true];
this.runCommand("", pMinionId, cmdArr, true);
this.runCommand("", pMinionId, cmdArr, ["select_minions"]);
});
}

Expand Down Expand Up @@ -366,7 +365,7 @@ export class HighStatePanel extends Panel {

// we already have the TR
// but this function also clears the row
this.getElement(trId, true);
this.getElement(trId, "select_minions", minionId);

// mark the TR as populated
minionTr.jid = pJobId;
Expand Down
4 changes: 4 additions & 0 deletions saltgui/static/scripts/panels/Job.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ export class JobPanel extends Panel {
return null;
}

// remove the first comma
return minionList.substring(1);
}

Expand Down Expand Up @@ -419,6 +420,7 @@ export class JobPanel extends Panel {
return null;
}

// remove the first comma
return minionList.substring(1);
}

Expand Down Expand Up @@ -452,6 +454,7 @@ export class JobPanel extends Panel {
return null;
}

// remove the first comma
return minionList.substring(1);
}

Expand Down Expand Up @@ -485,6 +488,7 @@ export class JobPanel extends Panel {
return null;
}

// remove the first comma
return minionList.substring(1);
}

Expand Down
Loading
Loading