From 44f8ecdc85ca623d048bc2c57c84d3f210381d35 Mon Sep 17 00:00:00 2001 From: "manuel.sowada" Date: Thu, 23 Apr 2026 15:40:07 +0200 Subject: [PATCH] fix .json overwriting --- public/javascript/JSON.js | 226 +++++++++++------------ public/views/integrated/serverinfo.hbs | 35 +--- public/views/plugindashboard.hbs | 6 +- src/models/integratedStartMenuItems.json | 24 +-- src/models/releasenotes.json | 7 + src/routes/indexRoutes.js | 2 +- utils.js | 2 +- 7 files changed, 130 insertions(+), 172 deletions(-) diff --git a/public/javascript/JSON.js b/public/javascript/JSON.js index 108ecd6..abc6033 100644 --- a/public/javascript/JSON.js +++ b/public/javascript/JSON.js @@ -2,7 +2,6 @@ createJsonTree({ container: domElement, data: jsonData, - expandInitially = true // optional: expand all nodes onChange: (data) => { }, // optional: callback on change onSave: (data) => { } // optional: if set, a save button will be added }); @@ -12,7 +11,7 @@ function createJsonTree({ data, onChange = () => {}, onSave = null, - expandInitially = true + readonly = false }) { container.innerHTML = ""; container.classList.add("json-tree-root"); @@ -22,8 +21,6 @@ function createJsonTree({ let lastSnapshot = clone(data); - const expandedPaths = new Set(); - function clone(obj) { return JSON.parse(JSON.stringify(obj)); } @@ -70,6 +67,7 @@ function createJsonTree({ } function undo() { + if (readonly) return; if (!history.length) return; redoStack.push(clone(data)); data = history.pop(); @@ -77,6 +75,7 @@ function createJsonTree({ } function redo() { + if (readonly) return; if (!redoStack.length) return; history.push(clone(data)); data = redoStack.pop(); @@ -84,6 +83,7 @@ function createJsonTree({ } function save() { + if (readonly) return; if (onSave) onSave(data); } @@ -93,6 +93,7 @@ function createJsonTree({ } function remove(key, parent) { + if (readonly) return; if (key === null || parent == null) return; if (!confirm("Wirklich löschen?")) return; @@ -109,28 +110,10 @@ function createJsonTree({ render(); } - function collectPaths(obj, path = "root") { - if (typeof obj !== "object" || obj === null) return; - - expandedPaths.add(path); - - const entries = Array.isArray(obj) - ? obj.map((v, i) => [i, v]) - : Object.entries(obj); - - for (const [k, v] of entries) { - collectPaths(v, `${path}.${k}`); - } - } - - if (expandInitially) { - collectPaths(data); - } - function render() { container.innerHTML = ""; - if (onSave) { + if (onSave && !readonly) { const controls = document.createElement("div"); controls.className = "json-controls"; @@ -174,10 +157,13 @@ function createJsonTree({ const removeBtn = document.createElement("span"); removeBtn.className = "json-remove"; removeBtn.textContent = " [x]"; - removeBtn.onclick = (evt) => { - evt.stopPropagation(); - remove(key, parent); - }; + + if (!readonly) { + removeBtn.onclick = (evt) => { + evt.stopPropagation(); + remove(key, parent); + }; + } // OBJECT / ARRAY if (typeof value === "object" && value !== null) { @@ -201,81 +187,67 @@ function createJsonTree({ const children = document.createElement("div"); children.className = "json-children"; - const toggleState = () => { - if (expandedPaths.has(path)) { - expandedPaths.delete(path); - children.classList.add("collapsed"); - } else { - expandedPaths.add(path); - children.classList.remove("collapsed"); - } + keyLabel.onclick = toggle.onclick = () => { + if (readonly) return; + children.classList.toggle("collapsed"); }; - keyLabel.onclick = toggle.onclick = toggleState; + if (!readonly) { + addBtn.onclick = () => { + let newKey = ""; + let newValue; - if (expandedPaths.has(path)) { - children.classList.remove("collapsed"); - } else { - children.classList.add("collapsed"); + feedbox({ + title: `Key hinzufügen`, + message: ` +
+ ${!isArray ? ` + + ` : ``} + +
+ `, + buttons: { + yes: { + text: 'Anlegen', + onClick: () => { + pushHistory(); + + if (!isArray) { + const input = document.querySelector('#newJsonKeyName'); + newKey = input?.value?.trim(); + if (!newKey) return; + } + + const selectedType = document.querySelector('#newJsonValueType').value; + + switch (selectedType) { + case "number": newValue = 0; break; + case "boolean": newValue = false; break; + case "object": newValue = {}; break; + case "array": newValue = []; break; + default: newValue = ""; + } + + if (isArray) value.push(newValue); + else value[newKey] = newValue; + + onChange(data); + render(); + } + }, + no: { text: "Abbrechen" } + } + }); + }; } - addBtn.onclick = () => { - let newKey = ""; - let newValue; - - feedbox({ - title: `Key hinzufügen`, - message: ` -
- ${!isArray ? ` - - ` : ``} - -
- `, - buttons: { - yes: { - text: 'Anlegen', - onClick: () => { - pushHistory(); - - if (!isArray) { - const input = document.querySelector('#newJsonKeyName'); - newKey = input?.value?.trim(); - if (!newKey) return; - } - - const selectedType = document.querySelector('#newJsonValueType').value; - - switch (selectedType) { - case "number": newValue = 0; break; - case "boolean": newValue = false; break; - case "object": newValue = {}; break; - case "array": newValue = []; break; - default: newValue = ""; - } - - if (isArray) { - value.push(newValue); - } else { - value[newKey] = newValue; - } - - onChange(data); - render(); - } - }, - no: { text: 'Abbrechen' } - } - }); - }; - const inner = document.createElement("div"); const entries = isArray @@ -292,9 +264,8 @@ function createJsonTree({ header.appendChild(keyLabel); header.appendChild(toggle); - header.appendChild(addBtn); - - if (key !== null) header.appendChild(removeBtn); + if (!readonly) header.appendChild(addBtn); + if (key !== null && !readonly) header.appendChild(removeBtn); wrapper.appendChild(header); wrapper.appendChild(children); @@ -308,18 +279,22 @@ function createJsonTree({ input.className = "json-input string"; input.value = value; - input.oninput = () => { - pushHistory(); - parent[key] = input.value; - autoResize(input); - onChange(data); - }; + if (readonly) { + input.disabled = true; + } else { + input.oninput = () => { + pushHistory(); + parent[key] = input.value; + autoResize(input); + onChange(data); + }; + } setTimeout(() => autoResize(input), 0); wrapper.appendChild(keySpan); wrapper.appendChild(input); - if (key !== null) wrapper.appendChild(removeBtn); + if (key !== null && !readonly) wrapper.appendChild(removeBtn); return wrapper; } @@ -330,18 +305,22 @@ function createJsonTree({ input.className = "json-input number"; input.value = value; - input.oninput = () => { - pushHistory(); - parent[key] = Number(input.value); - autoResize(input); - onChange(data); - }; + if (readonly) { + input.disabled = true; + } else { + input.oninput = () => { + pushHistory(); + parent[key] = Number(input.value); + autoResize(input); + onChange(data); + }; + } setTimeout(() => autoResize(input), 0); wrapper.appendChild(keySpan); wrapper.appendChild(input); - if (key !== null) wrapper.appendChild(removeBtn); + if (key !== null && !readonly) wrapper.appendChild(removeBtn); return wrapper; } @@ -351,15 +330,19 @@ function createJsonTree({ input.type = "checkbox"; input.checked = value; - input.onchange = () => { - pushHistory(); - parent[key] = input.checked; - onChange(data); - }; + if (readonly) { + input.disabled = true; + } else { + input.onchange = () => { + pushHistory(); + parent[key] = input.checked; + onChange(data); + }; + } wrapper.appendChild(keySpan); wrapper.appendChild(input); - if (key !== null) wrapper.appendChild(removeBtn); + if (key !== null && !readonly) wrapper.appendChild(removeBtn); return wrapper; } @@ -368,8 +351,7 @@ function createJsonTree({ wrapper.appendChild(keySpan); wrapper.appendChild(span); - - if (key !== null) wrapper.appendChild(removeBtn); + if (key !== null && !readonly) wrapper.appendChild(removeBtn); return wrapper; } diff --git a/public/views/integrated/serverinfo.hbs b/public/views/integrated/serverinfo.hbs index 32d0b59..7e2d12c 100644 --- a/public/views/integrated/serverinfo.hbs +++ b/public/views/integrated/serverinfo.hbs @@ -8,8 +8,8 @@ -
-
+
+
@@ -58,21 +58,6 @@ data: [], buffer: 5, rowHeight: 30, - filterConfig:{ - exceptedColumns: [ 'Erledigt' ], - columnModes: { - 'datetime': 'text', - 'sAMAccountName': 'text', - 'Note': 'text' - }, - checkboxFilter: { - column: 'finish', - rules: [ - { label: 'Nur erledigte', test: v => v === true }, - { label: 'Nur unerledigte', test: v => v === false }, - ] - } - }, customRender: (row, tr) => { createTd(tr, ` @@ -87,14 +72,14 @@ } }); - vt.addData(json.releaseNotes) - //document.querySelector('#package').innerHTML = JSON.stringify(json.package).split(',').join('
'); - - createJsonTree({ - container: document.getElementById("package"), - data: json.package, - expandInitially: true - }); + vt.addData(json.releaseNotes.sort((a, b) => new Date(b.datetime) - new Date(a.datetime))); + createJsonTree({ + container: document.getElementById("package"), + data: json.package, + expandInitially: true, + readonly: true }); + +}); \ No newline at end of file diff --git a/public/views/plugindashboard.hbs b/public/views/plugindashboard.hbs index 249b7cf..2467d53 100644 --- a/public/views/plugindashboard.hbs +++ b/public/views/plugindashboard.hbs @@ -97,7 +97,7 @@ pluginsTabWrapper.innerHTML = ''; const objectsContainer = document.createElement('div'); - objectsContainer.className = 'card static'; + objectsContainer.className = 'card static row'; objectsContainer.style = ``; const card = document.createElement('div'); card.className = 'card static row'; @@ -167,14 +167,14 @@ if(typeof value === 'object') { const objectCard = document.createElement('div'); objectCard.className = 'card static'; - objectCard.style = `min-height:400px;`; + objectCard.style = `flex:1;height:100%`; objectCard.innerHTML = `
`; objectsContainer.appendChild(objectCard); pluginsTabWrapper.appendChild(objectsContainer); - const menu = createJsonTree({ + createJsonTree({ container: document.getElementById(`${metaData.name}-${key}`), data: metaData[key], onChange: (data) => { }, diff --git a/src/models/integratedStartMenuItems.json b/src/models/integratedStartMenuItems.json index 2e9187e..d6a120f 100644 --- a/src/models/integratedStartMenuItems.json +++ b/src/models/integratedStartMenuItems.json @@ -18,15 +18,15 @@ "label": "Configs", "view": "serverconfig", "icon": "app.png", + "defaultSize": { + "width": "900px", + "height": "900px" + }, "permissions": [ "Administration" ] } ] - }, - "defaultSize": { - "width": 800, - "height": 600 } }, { @@ -49,10 +49,6 @@ ] } ] - }, - "defaultSize": { - "width": "1200px", - "height": "1200px" } }, { @@ -75,10 +71,6 @@ ] } ] - }, - "defaultSize": { - "width": "900px", - "height": "800px" } }, { @@ -101,10 +93,6 @@ ] } ] - }, - "defaultSize": { - "width": "900px", - "height": "500px" } }, { @@ -127,10 +115,6 @@ ] } ] - }, - "defaultSize": { - "width": "460px", - "height": "515px" } }, { diff --git a/src/models/releasenotes.json b/src/models/releasenotes.json index 22a4bac..d26dfb5 100644 --- a/src/models/releasenotes.json +++ b/src/models/releasenotes.json @@ -54,5 +54,12 @@ "datetime": "2026-04-21", "value": "Plugin-System + JSONtree bugfixes", "finish": true + }, + { + "sAMAccountName": "manuel.sowada", + "plugin": "System", + "datetime": "2026-04-23", + "value": "Neues Stylesheet, integratedStartMenuItems JS > JSON, JSONtree Updates, OS-Styles (Mauszeiger, Scrollbalken, Responsive Design, Window-Resize)", + "finish": true } ] diff --git a/src/routes/indexRoutes.js b/src/routes/indexRoutes.js index 1d66fad..45dab4c 100644 --- a/src/routes/indexRoutes.js +++ b/src/routes/indexRoutes.js @@ -28,7 +28,7 @@ module.exports = { let context = fs.existsSync(pluginPath) ? service.get('fileSystemManager').loadJSON(pluginPath) - : (global.json.startMenuItems.live).find(item => item.name == name); + : (JSON.parse(JSON.stringify(global.json.startMenuItems.live))).find(item => item.name == name); context.defaultSize = context.menu.items.find(item => item.label == viewLabel)?.defaultSize || diff --git a/utils.js b/utils.js index f2efa34..5a08e12 100644 --- a/utils.js +++ b/utils.js @@ -30,7 +30,7 @@ module.exports = startMenuItems = async function (app, sAMAccountName) { return JSON.parse(JSON.stringify(obj)); } - const integratedStartmenuItems = safeClone(global.json.startMenuItems.live); + const integratedStartmenuItems = safeClone(service.get('fileSystemManager').loadJSON(global.json.startMenuItems.filePath)); const plugins = service .get('pluginManager')