From 4b68db6e186a2d8cb9c84d6b0cff2a8396d1f3ba Mon Sep 17 00:00:00 2001 From: Erwin Dondorp Date: Thu, 8 Aug 2024 11:56:12 +0200 Subject: [PATCH] use highlightjs --- saltgui/index.html | 1 + saltgui/static/scripts/output/Output.js | 36 +++++++++++++++ .../static/scripts/panels/BeaconsMinion.js | 44 ++++++++++++------- saltgui/static/scripts/panels/Events.js | 3 +- saltgui/static/scripts/panels/Grains.js | 7 ++- saltgui/static/scripts/panels/GrainsMinion.js | 3 +- saltgui/static/scripts/panels/Options.js | 27 ++++++++---- .../static/scripts/panels/PillarsMinion.js | 4 +- saltgui/static/scripts/panels/Reactors.js | 4 +- .../static/scripts/panels/SchedulesMinion.js | 4 +- saltgui/static/scripts/panels/Stats.js | 4 +- saltgui/static/stylesheets/beacons.css | 8 ---- saltgui/static/stylesheets/events.css | 4 -- saltgui/static/stylesheets/grains.css | 5 --- saltgui/static/stylesheets/options.css | 4 -- saltgui/static/stylesheets/pillars.css | 1 - saltgui/static/stylesheets/schedules.css | 4 -- 17 files changed, 99 insertions(+), 64 deletions(-) diff --git a/saltgui/index.html b/saltgui/index.html index c455b85af..1d0e27cff 100644 --- a/saltgui/index.html +++ b/saltgui/index.html @@ -18,6 +18,7 @@ + diff --git a/saltgui/static/scripts/output/Output.js b/saltgui/static/scripts/output/Output.js index f13b2a4fb..63dc4bd8d 100644 --- a/saltgui/static/scripts/output/Output.js +++ b/saltgui/static/scripts/output/Output.js @@ -8,6 +8,12 @@ import {OutputNested} from "./OutputNested.js"; import {OutputYaml} from "./OutputYaml.js"; import {ParseCommandLine} from "../ParseCommandLine.js"; import {Utils} from "../Utils.js"; +import hljs from "../../highlight/es/core.js"; +import json from "../../highlight/es/languages/json.js"; +import yaml from "../../highlight/es/languages/yaml.js"; + +hljs.registerLanguage("json", json); +hljs.registerLanguage("yaml", yaml); // Functions to turn responses from the salt system into visual information // The following variations exist: @@ -108,6 +114,36 @@ export class Output { return OutputJson.formatJSON(pObject); } + static setHighlightObject (pParent, pObject, pStyleWhiteSpace = "pre-wrap", pLanguage = null) { + const code = Utils.createElem("code"); + code.style.whiteSpace = pStyleWhiteSpace; + // light-yellow, but lighter + pParent.style.backgroundColor = "#FFFFF8"; + + if (pLanguage !== null) { + const outputFormats = Utils.getStorageItem("session", "output_formats"); + Utils.setStorageItem("session", "output_formats", pLanguage); + code.innerHTML = hljs.highlight(Output.formatObject(pObject), {language:pLanguage}).value; + Utils.setStorageItem("session", "output_formats", outputFormats); + } else if (Output.isOutputFormatAllowed("json")) { + code.innerHTML = hljs.highlight(Output.formatObject(pObject), {language:'json'}).value; + } else if (Output.isOutputFormatAllowed("nested")) { + // yes, yaml + code.innerHTML = hljs.highlight(Output.formatObject(pObject), {language:'yaml'}).value; + } else if (Output.isOutputFormatAllowed("yaml")) { + code.innerHTML = hljs.highlight(Output.formatObject(pObject), {language:'yaml'}).value; + } else { + code.innerText = Output.formatObject(pObject); + } + + if (pParent.firstElementChild) { + pParent.replaceChild(code, pParent.firstElementChild); + } else { + // empty or only a text-node + pParent.innerText = ""; + pParent.appendChild(code); + } + } // this is the default output form // just format the returned objects diff --git a/saltgui/static/scripts/panels/BeaconsMinion.js b/saltgui/static/scripts/panels/BeaconsMinion.js index 68c9096d0..b9cea1cd7 100644 --- a/saltgui/static/scripts/panels/BeaconsMinion.js +++ b/saltgui/static/scripts/panels/BeaconsMinion.js @@ -160,31 +160,44 @@ export class BeaconsMinionPanel extends Panel { this._addMenuItemBeaconsEnableBeaconWhenNeeded(beaconMenu, pMinionId, beaconName, beacon); this._addMenuItemBeaconsDelete(beaconMenu, pMinionId, beaconName); - // menu comes before this data on purpose - const beaconConfig = Output.formatObject(beacon); - const beaconConfigTd = Utils.createTd("beacon-config", beaconConfig); - let initialTimestamp = "(waiting)"; - let initialValue = "(waiting)"; + const beaconConfigTd = Utils.createTd(); + Output.setHighlightObject(beaconConfigTd, beacon, "pre"); + tr.appendChild(beaconConfigTd); + + let initialTimestamp; + let initialValue; + let initialClass; if (beacon.enabled === false) { - beaconConfigTd.classList.add("beacon-disabled"); + initialClass = "beacon-disabled"; initialTimestamp = Character.EM_DASH; initialValue = "(beacon" + Character.NO_BREAK_SPACE + "disabled)"; } else if (beacons.enabled === false) { - beaconConfigTd.classList.add("beacon-disabled"); + initialClass = "beacon-disabled"; initialTimestamp = Character.EM_DASH; initialValue = "(beacons" + Character.NO_BREAK_SPACE + "disabled)"; + } else { + initialClass = "beacon-waiting"; + initialTimestamp = "(waiting)"; + initialValue = "(waiting)"; } - tr.appendChild(beaconConfigTd); const beaconTimestampTd = Utils.createTd(); - const beaconTimestampSpan = Utils.createSpan(["beacon-timestamp", "beacon-waiting"], initialTimestamp); + const beaconTimestampSpan = Utils.createSpan(["beacon-timestamp", initialClass], initialTimestamp); beaconTimestampTd.appendChild(beaconTimestampSpan); tr.appendChild(beaconTimestampTd); tr.beaconTimestampSpan = beaconTimestampSpan; - const beaconValueTd = Utils.createTd(["beacon-value", "beacon-waiting"], initialValue); + const beaconValueTd = Utils.createTd(); + const beaconValueLabelDiv = Utils.createDiv(); + beaconValueLabelDiv.style.display = "none"; + beaconValueTd.appendChild(beaconValueLabelDiv); + const beaconValueValueDiv = Utils.createDiv(); + beaconValueValueDiv.innerText = initialValue; + beaconValueValueDiv.classList.add("beacon-value", initialClass); + beaconValueTd.appendChild(beaconValueValueDiv); tr.appendChild(beaconValueTd); - tr.beaconValueTd = beaconValueTd; + tr.beaconValueLabelDiv = beaconValueLabelDiv; + tr.beaconValueValueDiv = beaconValueValueDiv; const tbody = this.table.tBodies[0]; tbody.appendChild(tr); @@ -309,7 +322,6 @@ export class BeaconsMinionPanel extends Panel { return; } - let value = ""; let stamp = ""; if (pData["_stamp"]) { // keep timestamp for further logic @@ -321,13 +333,13 @@ export class BeaconsMinionPanel extends Panel { if (pTag !== prefix + beaconName + "/") { // Show the tag when it has extra information - value = pTag + "\n"; + tr.beaconValueLabelDiv.style.display = ""; + tr.beaconValueLabelDiv.innerText = pTag; } if (pData["id"] === minionId) { delete pData["id"]; } - value += Output.formatObject(pData); - tr.beaconValueTd.classList.remove("beacon-waiting"); + tr.beaconValueValueDiv.classList.remove("beacon-waiting"); // round down to 0.1 second // secondary events are close, but rarely exact on the same time @@ -366,7 +378,7 @@ export class BeaconsMinionPanel extends Panel { tr.helpButtonSpan.style.display = "none"; } - tr.beaconValueTd.innerText = value; + Output.setHighlightObject(tr.beaconValueValueDiv, pData, "pre"); tr.prevStamp = stamp; tr.prevTag = pTag; diff --git a/saltgui/static/scripts/panels/Events.js b/saltgui/static/scripts/panels/Events.js index 8ded134ba..249e87065 100644 --- a/saltgui/static/scripts/panels/Events.js +++ b/saltgui/static/scripts/panels/Events.js @@ -74,7 +74,8 @@ export class EventsPanel extends Panel { const pDataObj = {}; Object.assign(pDataObj, pData); delete pDataObj._stamp; - const dataTd = Utils.createTd("event-data", Output.formatObject(pDataObj)); + const dataTd = Utils.createTd(); + Output.setHighlightObject(dataTd, pDataObj); tr.append(dataTd); tbody.prepend(tr); diff --git a/saltgui/static/scripts/panels/Grains.js b/saltgui/static/scripts/panels/Grains.js index 55a07d4d7..0858ce56f 100644 --- a/saltgui/static/scripts/panels/Grains.js +++ b/saltgui/static/scripts/panels/Grains.js @@ -143,8 +143,8 @@ export class GrainsPanel extends Panel { // it is a json path const obj = jsonPath(pMinionData, previewGrainValue); if (Array.isArray(obj)) { - td.innerText = Output.formatObject(obj[0]); - td.classList.add("grain-value"); + // TODO: why [0] + Output.setHighlightObject(td, obj[0]); } } else { // a plain grain-name or a path in the grains.get style @@ -156,8 +156,7 @@ export class GrainsPanel extends Panel { } } if (obj) { - td.innerText = Output.formatObject(obj); - td.classList.add("grain-value"); + Output.setHighlightObject(td, obj); } } } else { diff --git a/saltgui/static/scripts/panels/GrainsMinion.js b/saltgui/static/scripts/panels/GrainsMinion.js index 99f0dcc50..8a1764bca 100644 --- a/saltgui/static/scripts/panels/GrainsMinion.js +++ b/saltgui/static/scripts/panels/GrainsMinion.js @@ -82,7 +82,8 @@ export class GrainsMinionPanel extends Panel { this._addMenuItemGrainsDelVal(grainMenu, pMinionId, grainName, grains[grainName]); // menu comes before this data on purpose - const grainValueTd = Utils.createTd("grain-value", grainValue); + const grainValueTd = Utils.createTd(); + Output.setHighlightObject(grainValueTd, grains[grainName]); grainTr.appendChild(grainValueTd); const tbody = this.table.tBodies[0]; diff --git a/saltgui/static/scripts/panels/Options.js b/saltgui/static/scripts/panels/Options.js index 38c0d3051..f50b0b7d4 100644 --- a/saltgui/static/scripts/panels/Options.js +++ b/saltgui/static/scripts/panels/Options.js @@ -3,7 +3,6 @@ import {Character} from "../Character.js"; import {LoginPanel} from "../panels/Login.js"; import {Output} from "../output/Output.js"; -import {OutputYaml} from "../output/OutputYaml.js"; import {Panel} from "./Panel.js"; import {Router} from "../Router.js"; import {Utils} from "../Utils.js"; @@ -324,11 +323,12 @@ export class OptionsPanel extends Panel { } else if (category === "session" && name === "expire") { OptionsPanel._enhanceSessionExpire(td, value, sessionStart); } else if (category === "session" && name === "perms") { - td.innerText = OutputYaml.formatYAML(value); + // because the "master" file is also in YAML + Output.setHighlightObject(td, value, null, "yaml"); } else if (category === "session") { td.innerText = value; } else { - td.innerText = this._parseAndFormat(name, value); + this._parseAndFormat(td, name, value); } if (category === "session" && name === "expire") { @@ -377,31 +377,40 @@ export class OptionsPanel extends Panel { } } - _parseAndFormat (id, valueStr) { + _parseAndFormat (pTd, id, valueStr) { /* eslint-disable curly */ if (valueStr === null) valueStr = undefined; if (valueStr === "undefined") valueStr = undefined; /* eslint-enable curly */ + if (valueStr === undefined) { const tr = this.div.querySelector("#option-" + id); if (tr.dataset.defaultValue) { - return "(undefined) " + Character.RIGHTWARDS_ARROW + " " + tr.dataset.defaultValue; + pTd.innerText = "(undefined) " + Character.RIGHTWARDS_ARROW + " " + tr.dataset.defaultValue; + return; } - return "(undefined)"; + pTd.innerText = "(undefined)"; + return; } + if (valueStr.length === 0) { - return "(empty string)"; + pTd.innerText = "(empty string)"; + return; } + if (valueStr[0] !== "{" && valueStr[0] !== "[") { - return valueStr; + pTd.innerText = valueStr; + return; } + let value; try { value = JSON.parse(valueStr); } catch (err) { value = err + " in \"" + valueStr + "\""; } - return OutputYaml.formatYAML(value); + // because the "master" file is also in YAML + Output.setHighlightObject(pTd, value, null, "yaml"); } _isSelected (pCategory, pRow, pName) { diff --git a/saltgui/static/scripts/panels/PillarsMinion.js b/saltgui/static/scripts/panels/PillarsMinion.js index 0b10a426f..05a6f2484 100644 --- a/saltgui/static/scripts/panels/PillarsMinion.js +++ b/saltgui/static/scripts/panels/PillarsMinion.js @@ -97,8 +97,8 @@ export class PillarsMinionPanel extends Panel { // initially use the hidden view pillarValueTd.appendChild(pillarHiddenDiv); - const pillarValueShown = Output.formatObject(pillars[pillarName]); - const pillarShownDiv = Utils.createDiv("pillar-shown", pillarValueShown); + const pillarShownDiv = Utils.createDiv("pillar-shown"); + Output.setHighlightObject(pillarShownDiv, pillars[pillarName]); // initially hide the normal view pillarShownDiv.style.display = "none"; Utils.addToolTip(pillarShownDiv, "Click to hide"); diff --git a/saltgui/static/scripts/panels/Reactors.js b/saltgui/static/scripts/panels/Reactors.js index 7da72f138..b4f4eb064 100644 --- a/saltgui/static/scripts/panels/Reactors.js +++ b/saltgui/static/scripts/panels/Reactors.js @@ -66,7 +66,9 @@ export class ReactorsPanel extends Panel { _addReactor (pEvent, pReactor) { const tr = Utils.createTr(); tr.appendChild(Utils.createTd("", pEvent)); - tr.appendChild(Utils.createTd("", Output.formatObject(pReactor))); + const td = Utils.createTd(); + Output.setHighlightObject(td, pReactor); + tr.appendChild(td); const tbody = this.table.tBodies[0]; tbody.appendChild(tr); diff --git a/saltgui/static/scripts/panels/SchedulesMinion.js b/saltgui/static/scripts/panels/SchedulesMinion.js index e83a988e3..7ef4b6b49 100644 --- a/saltgui/static/scripts/panels/SchedulesMinion.js +++ b/saltgui/static/scripts/panels/SchedulesMinion.js @@ -112,11 +112,11 @@ export class SchedulesMinionPanel extends Panel { this._addMenuItemScheduleRunJob(scheduleMenu, pMinionId, scheduleName, schedule); // menu comes before this data on purpose - const scheduleValue = Output.formatObject(schedule); - const scheduleValueTd = Utils.createTd("schedule-value", scheduleValue); + const scheduleValueTd = Utils.createTd(); if (schedule.enabled === false || schedules.enabled === false) { scheduleValueTd.classList.add("schedule-disabled"); } + Output.setHighlightObject(scheduleValueTd, schedule); tr.appendChild(scheduleValueTd); const tbody = this.table.tBodies[0]; diff --git a/saltgui/static/scripts/panels/Stats.js b/saltgui/static/scripts/panels/Stats.js index f4a2409dc..d46494d41 100644 --- a/saltgui/static/scripts/panels/Stats.js +++ b/saltgui/static/scripts/panels/Stats.js @@ -69,7 +69,7 @@ export class StatsPanel extends Panel { _handleStats (pStatsData) { if (this.showErrorRowInstead(pStatsData)) { - this.statsTd.innerHTML = "this error is typically caused by using the collect_stats: True setting in the master configuration file, which is broken in at least the recent versions of salt-api"; + this.statsTd.innerHTML = "This error is typically caused by using the collect_stats: True setting in the master configuration file, which is broken in at least the recent versions of salt-api"; window.clearInterval(this.updateStatsTimer); this.updateStatsTimer = null; return; @@ -141,6 +141,6 @@ export class StatsPanel extends Panel { } } - this.statsTd.innerText = Output.formatObject(pStatsData); + Output.setHighlightObject(this.statsTd, pStatsData); } } diff --git a/saltgui/static/stylesheets/beacons.css b/saltgui/static/stylesheets/beacons.css index 0a6c3f902..3f3c07243 100644 --- a/saltgui/static/stylesheets/beacons.css +++ b/saltgui/static/stylesheets/beacons.css @@ -1,11 +1,3 @@ -.beacon-config { - white-space: pre; -} - -.beacon-value { - white-space: pre; -} - #page-beacons { width: 100%; } diff --git a/saltgui/static/stylesheets/events.css b/saltgui/static/stylesheets/events.css index 086b067b9..9f21a0a07 100644 --- a/saltgui/static/stylesheets/events.css +++ b/saltgui/static/stylesheets/events.css @@ -1,7 +1,3 @@ -td.event-data { - white-space: pre-wrap; -} - #page-events { width: 100%; } diff --git a/saltgui/static/stylesheets/grains.css b/saltgui/static/stylesheets/grains.css index 5181fdcd0..1797a6d44 100644 --- a/saltgui/static/stylesheets/grains.css +++ b/saltgui/static/stylesheets/grains.css @@ -1,8 +1,3 @@ -td.grain-value { - white-space: pre-wrap; - word-break: keep-all; -} - #page-grains { width: 100%; } diff --git a/saltgui/static/stylesheets/options.css b/saltgui/static/stylesheets/options.css index 0c59421af..91d18a21b 100644 --- a/saltgui/static/stylesheets/options.css +++ b/saltgui/static/stylesheets/options.css @@ -15,7 +15,3 @@ label { white-space: pre-wrap; vertical-align: top; } - -#stats-table tr td { - white-space: pre-wrap; -} diff --git a/saltgui/static/stylesheets/pillars.css b/saltgui/static/stylesheets/pillars.css index faac22b7b..bdfdb0d1c 100644 --- a/saltgui/static/stylesheets/pillars.css +++ b/saltgui/static/stylesheets/pillars.css @@ -12,5 +12,4 @@ .pillar-shown { cursor: pointer; - white-space: pre; } diff --git a/saltgui/static/stylesheets/schedules.css b/saltgui/static/stylesheets/schedules.css index cfcbfdebb..ec0d1c1f2 100644 --- a/saltgui/static/stylesheets/schedules.css +++ b/saltgui/static/stylesheets/schedules.css @@ -2,10 +2,6 @@ width: 100%; } -td.schedule-value { - white-space: pre-wrap; -} - td.schedule-disabled { color: gray; }