fix .json overwriting

This commit is contained in:
2026-04-23 15:40:07 +02:00
parent 31dd117d91
commit 44f8ecdc85
7 changed files with 130 additions and 172 deletions

View File

@@ -2,7 +2,6 @@
createJsonTree({ createJsonTree({
container: domElement, container: domElement,
data: jsonData, data: jsonData,
expandInitially = true // optional: expand all nodes
onChange: (data) => { }, // optional: callback on change onChange: (data) => { }, // optional: callback on change
onSave: (data) => { } // optional: if set, a save button will be added onSave: (data) => { } // optional: if set, a save button will be added
}); });
@@ -12,7 +11,7 @@ function createJsonTree({
data, data,
onChange = () => {}, onChange = () => {},
onSave = null, onSave = null,
expandInitially = true readonly = false
}) { }) {
container.innerHTML = ""; container.innerHTML = "";
container.classList.add("json-tree-root"); container.classList.add("json-tree-root");
@@ -22,8 +21,6 @@ function createJsonTree({
let lastSnapshot = clone(data); let lastSnapshot = clone(data);
const expandedPaths = new Set();
function clone(obj) { function clone(obj) {
return JSON.parse(JSON.stringify(obj)); return JSON.parse(JSON.stringify(obj));
} }
@@ -70,6 +67,7 @@ function createJsonTree({
} }
function undo() { function undo() {
if (readonly) return;
if (!history.length) return; if (!history.length) return;
redoStack.push(clone(data)); redoStack.push(clone(data));
data = history.pop(); data = history.pop();
@@ -77,6 +75,7 @@ function createJsonTree({
} }
function redo() { function redo() {
if (readonly) return;
if (!redoStack.length) return; if (!redoStack.length) return;
history.push(clone(data)); history.push(clone(data));
data = redoStack.pop(); data = redoStack.pop();
@@ -84,6 +83,7 @@ function createJsonTree({
} }
function save() { function save() {
if (readonly) return;
if (onSave) onSave(data); if (onSave) onSave(data);
} }
@@ -93,6 +93,7 @@ function createJsonTree({
} }
function remove(key, parent) { function remove(key, parent) {
if (readonly) return;
if (key === null || parent == null) return; if (key === null || parent == null) return;
if (!confirm("Wirklich löschen?")) return; if (!confirm("Wirklich löschen?")) return;
@@ -109,28 +110,10 @@ function createJsonTree({
render(); 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() { function render() {
container.innerHTML = ""; container.innerHTML = "";
if (onSave) { if (onSave && !readonly) {
const controls = document.createElement("div"); const controls = document.createElement("div");
controls.className = "json-controls"; controls.className = "json-controls";
@@ -174,10 +157,13 @@ function createJsonTree({
const removeBtn = document.createElement("span"); const removeBtn = document.createElement("span");
removeBtn.className = "json-remove"; removeBtn.className = "json-remove";
removeBtn.textContent = " [x]"; removeBtn.textContent = " [x]";
if (!readonly) {
removeBtn.onclick = (evt) => { removeBtn.onclick = (evt) => {
evt.stopPropagation(); evt.stopPropagation();
remove(key, parent); remove(key, parent);
}; };
}
// OBJECT / ARRAY // OBJECT / ARRAY
if (typeof value === "object" && value !== null) { if (typeof value === "object" && value !== null) {
@@ -201,24 +187,12 @@ function createJsonTree({
const children = document.createElement("div"); const children = document.createElement("div");
children.className = "json-children"; children.className = "json-children";
const toggleState = () => { keyLabel.onclick = toggle.onclick = () => {
if (expandedPaths.has(path)) { if (readonly) return;
expandedPaths.delete(path); children.classList.toggle("collapsed");
children.classList.add("collapsed");
} else {
expandedPaths.add(path);
children.classList.remove("collapsed");
}
}; };
keyLabel.onclick = toggle.onclick = toggleState; if (!readonly) {
if (expandedPaths.has(path)) {
children.classList.remove("collapsed");
} else {
children.classList.add("collapsed");
}
addBtn.onclick = () => { addBtn.onclick = () => {
let newKey = ""; let newKey = "";
let newValue; let newValue;
@@ -261,20 +235,18 @@ function createJsonTree({
default: newValue = ""; default: newValue = "";
} }
if (isArray) { if (isArray) value.push(newValue);
value.push(newValue); else value[newKey] = newValue;
} else {
value[newKey] = newValue;
}
onChange(data); onChange(data);
render(); render();
} }
}, },
no: { text: 'Abbrechen' } no: { text: "Abbrechen" }
} }
}); });
}; };
}
const inner = document.createElement("div"); const inner = document.createElement("div");
@@ -292,9 +264,8 @@ function createJsonTree({
header.appendChild(keyLabel); header.appendChild(keyLabel);
header.appendChild(toggle); header.appendChild(toggle);
header.appendChild(addBtn); if (!readonly) header.appendChild(addBtn);
if (key !== null && !readonly) header.appendChild(removeBtn);
if (key !== null) header.appendChild(removeBtn);
wrapper.appendChild(header); wrapper.appendChild(header);
wrapper.appendChild(children); wrapper.appendChild(children);
@@ -308,18 +279,22 @@ function createJsonTree({
input.className = "json-input string"; input.className = "json-input string";
input.value = value; input.value = value;
if (readonly) {
input.disabled = true;
} else {
input.oninput = () => { input.oninput = () => {
pushHistory(); pushHistory();
parent[key] = input.value; parent[key] = input.value;
autoResize(input); autoResize(input);
onChange(data); onChange(data);
}; };
}
setTimeout(() => autoResize(input), 0); setTimeout(() => autoResize(input), 0);
wrapper.appendChild(keySpan); wrapper.appendChild(keySpan);
wrapper.appendChild(input); wrapper.appendChild(input);
if (key !== null) wrapper.appendChild(removeBtn); if (key !== null && !readonly) wrapper.appendChild(removeBtn);
return wrapper; return wrapper;
} }
@@ -330,18 +305,22 @@ function createJsonTree({
input.className = "json-input number"; input.className = "json-input number";
input.value = value; input.value = value;
if (readonly) {
input.disabled = true;
} else {
input.oninput = () => { input.oninput = () => {
pushHistory(); pushHistory();
parent[key] = Number(input.value); parent[key] = Number(input.value);
autoResize(input); autoResize(input);
onChange(data); onChange(data);
}; };
}
setTimeout(() => autoResize(input), 0); setTimeout(() => autoResize(input), 0);
wrapper.appendChild(keySpan); wrapper.appendChild(keySpan);
wrapper.appendChild(input); wrapper.appendChild(input);
if (key !== null) wrapper.appendChild(removeBtn); if (key !== null && !readonly) wrapper.appendChild(removeBtn);
return wrapper; return wrapper;
} }
@@ -351,15 +330,19 @@ function createJsonTree({
input.type = "checkbox"; input.type = "checkbox";
input.checked = value; input.checked = value;
if (readonly) {
input.disabled = true;
} else {
input.onchange = () => { input.onchange = () => {
pushHistory(); pushHistory();
parent[key] = input.checked; parent[key] = input.checked;
onChange(data); onChange(data);
}; };
}
wrapper.appendChild(keySpan); wrapper.appendChild(keySpan);
wrapper.appendChild(input); wrapper.appendChild(input);
if (key !== null) wrapper.appendChild(removeBtn); if (key !== null && !readonly) wrapper.appendChild(removeBtn);
return wrapper; return wrapper;
} }
@@ -368,8 +351,7 @@ function createJsonTree({
wrapper.appendChild(keySpan); wrapper.appendChild(keySpan);
wrapper.appendChild(span); wrapper.appendChild(span);
if (key !== null && !readonly) wrapper.appendChild(removeBtn);
if (key !== null) wrapper.appendChild(removeBtn);
return wrapper; return wrapper;
} }

View File

@@ -8,8 +8,8 @@
<span class="copy-icon" onclick="copyToClipboard(`${document.getElementById('pid').textContent}`)">⧉</span> <span class="copy-icon" onclick="copyToClipboard(`${document.getElementById('pid').textContent}`)">⧉</span>
</div> </div>
</div> </div>
<div class="card" styles="max-height:350px;"> <div class="card">
<div class="table-wrapper"> <div class="table-wrapper" style="max-height:250px;height:100%">
<table id="releaseNotes"> <table id="releaseNotes">
<thead> <thead>
<tr> <tr>
@@ -58,21 +58,6 @@
data: [], data: [],
buffer: 5, buffer: 5,
rowHeight: 30, 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) => { customRender: (row, tr) => {
createTd(tr, createTd(tr,
` `
@@ -87,14 +72,14 @@
} }
}); });
vt.addData(json.releaseNotes) vt.addData(json.releaseNotes.sort((a, b) => new Date(b.datetime) - new Date(a.datetime)));
//document.querySelector('#package').innerHTML = JSON.stringify(json.package).split(',').join('<br>');
createJsonTree({ createJsonTree({
container: document.getElementById("package"), container: document.getElementById("package"),
data: json.package, data: json.package,
expandInitially: true expandInitially: true,
readonly: true
}); });
}); });
</script> </script>

View File

@@ -97,7 +97,7 @@
pluginsTabWrapper.innerHTML = ''; pluginsTabWrapper.innerHTML = '';
const objectsContainer = document.createElement('div'); const objectsContainer = document.createElement('div');
objectsContainer.className = 'card static'; objectsContainer.className = 'card static row';
objectsContainer.style = ``; objectsContainer.style = ``;
const card = document.createElement('div'); const card = document.createElement('div');
card.className = 'card static row'; card.className = 'card static row';
@@ -167,14 +167,14 @@
if(typeof value === 'object') { if(typeof value === 'object') {
const objectCard = document.createElement('div'); const objectCard = document.createElement('div');
objectCard.className = 'card static'; objectCard.className = 'card static';
objectCard.style = `min-height:400px;`; objectCard.style = `flex:1;height:100%`;
objectCard.innerHTML = ` objectCard.innerHTML = `
<label style="font-weight:bold">${key}</label> <label style="font-weight:bold">${key}</label>
<div style="overflow:auto" id="${metaData.name}-${key}"></div> <div style="overflow:auto" id="${metaData.name}-${key}"></div>
`; `;
objectsContainer.appendChild(objectCard); objectsContainer.appendChild(objectCard);
pluginsTabWrapper.appendChild(objectsContainer); pluginsTabWrapper.appendChild(objectsContainer);
const menu = createJsonTree({ createJsonTree({
container: document.getElementById(`${metaData.name}-${key}`), container: document.getElementById(`${metaData.name}-${key}`),
data: metaData[key], data: metaData[key],
onChange: (data) => { }, onChange: (data) => { },

View File

@@ -18,15 +18,15 @@
"label": "Configs", "label": "Configs",
"view": "serverconfig", "view": "serverconfig",
"icon": "app.png", "icon": "app.png",
"defaultSize": {
"width": "900px",
"height": "900px"
},
"permissions": [ "permissions": [
"Administration" "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"
} }
}, },
{ {

View File

@@ -54,5 +54,12 @@
"datetime": "2026-04-21", "datetime": "2026-04-21",
"value": "Plugin-System + JSONtree bugfixes", "value": "Plugin-System + JSONtree bugfixes",
"finish": true "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
} }
] ]

View File

@@ -28,7 +28,7 @@ module.exports = {
let context = fs.existsSync(pluginPath) let context = fs.existsSync(pluginPath)
? service.get('fileSystemManager').loadJSON(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.defaultSize =
context.menu.items.find(item => item.label == viewLabel)?.defaultSize || context.menu.items.find(item => item.label == viewLabel)?.defaultSize ||

View File

@@ -30,7 +30,7 @@ module.exports = startMenuItems = async function (app, sAMAccountName) {
return JSON.parse(JSON.stringify(obj)); 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 const plugins = service
.get('pluginManager') .get('pluginManager')