@codyswann/lisa 4.56.4 → 4.57.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/cli-load-diagnostic.d.ts +8 -0
- package/dist/cli-load-diagnostic.d.ts.map +1 -0
- package/dist/cli-load-diagnostic.js +83 -0
- package/dist/cli-load-diagnostic.js.map +1 -0
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +6 -2
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/ui/README.md +6 -5
- package/ui/index.html +235 -37
package/ui/index.html
CHANGED
|
@@ -1835,14 +1835,15 @@
|
|
|
1835
1835
|
id="saveBtn"
|
|
1836
1836
|
type="button"
|
|
1837
1837
|
disabled
|
|
1838
|
-
title="
|
|
1838
|
+
title="Open this console with lisa ui to save changes"
|
|
1839
1839
|
aria-describedby="saveReadonlyReason"
|
|
1840
1840
|
>
|
|
1841
1841
|
Save changes
|
|
1842
1842
|
</button>
|
|
1843
1843
|
<span class="status-why readonly-reason" id="saveReadonlyReason">
|
|
1844
|
-
|
|
1844
|
+
Open this console with lisa ui to save changes
|
|
1845
1845
|
</span>
|
|
1846
|
+
<span id="saveError" role="alert" hidden></span>
|
|
1846
1847
|
</div>
|
|
1847
1848
|
<div class="toast" id="toast"></div>
|
|
1848
1849
|
<script>
|
|
@@ -11053,14 +11054,16 @@
|
|
|
11053
11054
|
/* LISA_UI_CATALOG_END */
|
|
11054
11055
|
|
|
11055
11056
|
/* ------------------------------------------------------------------ *
|
|
11056
|
-
* Rendering + interactions
|
|
11057
|
+
* Rendering + interactions
|
|
11057
11058
|
* ------------------------------------------------------------------ */
|
|
11058
11059
|
|
|
11059
11060
|
const $nav = document.getElementById("nav");
|
|
11060
11061
|
const $main = document.getElementById("main");
|
|
11061
11062
|
const $savebar = document.getElementById("savebar");
|
|
11062
11063
|
const $toast = document.getElementById("toast");
|
|
11063
|
-
const dirty = new
|
|
11064
|
+
const dirty = new Map();
|
|
11065
|
+
const initialControls = new Map();
|
|
11066
|
+
let saving = false;
|
|
11064
11067
|
let lisaLiveMode = false;
|
|
11065
11068
|
let lisaCatalogAudit = null;
|
|
11066
11069
|
let lisaCatalogPreparation = null;
|
|
@@ -11160,16 +11163,41 @@
|
|
|
11160
11163
|
.replace(/"/g, """);
|
|
11161
11164
|
}
|
|
11162
11165
|
|
|
11163
|
-
function markDirty(id, rowEl) {
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
+
function markDirty(id, rowEl, value) {
|
|
11167
|
+
const baseline = lisaLiveMode
|
|
11168
|
+
? liveConfigEntry(window.LISA_LIVE_CONFIG, id)
|
|
11169
|
+
: { present: false };
|
|
11170
|
+
if (
|
|
11171
|
+
baseline.present &&
|
|
11172
|
+
JSON.stringify(baseline.value) === JSON.stringify(value)
|
|
11173
|
+
)
|
|
11174
|
+
dirty.delete(id);
|
|
11175
|
+
else dirty.set(id, value);
|
|
11176
|
+
if (rowEl)
|
|
11177
|
+
rowEl.classList.toggle(
|
|
11178
|
+
"modified",
|
|
11179
|
+
isDirtyRow(rowEl.dataset.configKey || id)
|
|
11180
|
+
);
|
|
11181
|
+
document.getElementById("saveError").hidden = true;
|
|
11166
11182
|
updateSavebar();
|
|
11167
11183
|
}
|
|
11184
|
+
function isDirtyRow(key) {
|
|
11185
|
+
return [...dirty.keys()].some(
|
|
11186
|
+
changed => changed === key || changed.startsWith(key + ".")
|
|
11187
|
+
);
|
|
11188
|
+
}
|
|
11168
11189
|
function updateSavebar() {
|
|
11169
11190
|
const n = dirty.size;
|
|
11170
11191
|
document.getElementById("dirtyCount").textContent = n;
|
|
11171
11192
|
document.getElementById("dirtyPlural").textContent = n === 1 ? "" : "s";
|
|
11172
11193
|
$savebar.classList.toggle("show", n > 0);
|
|
11194
|
+
document.getElementById("saveBtn").disabled =
|
|
11195
|
+
!lisaLiveMode || saving || n === 0;
|
|
11196
|
+
document.getElementById("saveBtn").textContent = saving
|
|
11197
|
+
? "Saving…"
|
|
11198
|
+
: "Save changes";
|
|
11199
|
+
document.getElementById("discardBtn").disabled = saving;
|
|
11200
|
+
$main.inert = saving;
|
|
11173
11201
|
}
|
|
11174
11202
|
const toastState = { timer: 0 };
|
|
11175
11203
|
function showToast(message) {
|
|
@@ -11186,6 +11214,98 @@
|
|
|
11186
11214
|
updateSavebar();
|
|
11187
11215
|
}
|
|
11188
11216
|
|
|
11217
|
+
/** Visit existing config rows, including rows inside provider tabs. */
|
|
11218
|
+
function forEachConfigRow(visit) {
|
|
11219
|
+
const walk = blocks =>
|
|
11220
|
+
(blocks || []).forEach(block => {
|
|
11221
|
+
if (block.type === "tabs")
|
|
11222
|
+
(block.tabs || []).forEach(tab => walk(tab.blocks));
|
|
11223
|
+
if (!block.type)
|
|
11224
|
+
(block.rows || []).forEach(row => {
|
|
11225
|
+
if (row.key && row.control) visit(row);
|
|
11226
|
+
});
|
|
11227
|
+
});
|
|
11228
|
+
Object.values(DATA.sections).forEach(section => walk(section.blocks));
|
|
11229
|
+
}
|
|
11230
|
+
|
|
11231
|
+
/** Restore config controls without resetting separately loaded probe results. */
|
|
11232
|
+
function restoreConfigControls() {
|
|
11233
|
+
forEachConfigRow(row => {
|
|
11234
|
+
const original = initialControls.get(row.key);
|
|
11235
|
+
if (!original) return;
|
|
11236
|
+
const entry = lisaLiveMode
|
|
11237
|
+
? liveConfigEntry(window.LISA_LIVE_CONFIG, row.key)
|
|
11238
|
+
: null;
|
|
11239
|
+
row.control = { ...original };
|
|
11240
|
+
if (entry) {
|
|
11241
|
+
const hydrated =
|
|
11242
|
+
entry.present && hydrateControl(original, entry.value);
|
|
11243
|
+
if (hydrated) row.control = hydrated;
|
|
11244
|
+
else
|
|
11245
|
+
unknownControl(
|
|
11246
|
+
row,
|
|
11247
|
+
entry.present
|
|
11248
|
+
? "invalid live config value"
|
|
11249
|
+
: "missing live config key"
|
|
11250
|
+
);
|
|
11251
|
+
}
|
|
11252
|
+
});
|
|
11253
|
+
clearDirty();
|
|
11254
|
+
document.getElementById("saveError").hidden = true;
|
|
11255
|
+
renderAll();
|
|
11256
|
+
showSection(activeSection);
|
|
11257
|
+
}
|
|
11258
|
+
|
|
11259
|
+
async function saveConfig() {
|
|
11260
|
+
if (!lisaLiveMode || saving || dirty.size === 0) return;
|
|
11261
|
+
const errorNode = document.getElementById("saveError");
|
|
11262
|
+
saving = true;
|
|
11263
|
+
updateSavebar();
|
|
11264
|
+
errorNode.hidden = true;
|
|
11265
|
+
$toast.classList.remove("show");
|
|
11266
|
+
try {
|
|
11267
|
+
if (
|
|
11268
|
+
[...dirty.values()].some(
|
|
11269
|
+
value => typeof value === "number" && !Number.isFinite(value)
|
|
11270
|
+
)
|
|
11271
|
+
)
|
|
11272
|
+
throw new Error("Enter a valid number before saving.");
|
|
11273
|
+
const response = await fetch("/api/config", {
|
|
11274
|
+
method: "POST",
|
|
11275
|
+
headers: {
|
|
11276
|
+
"content-type": "application/json",
|
|
11277
|
+
accept: "application/json",
|
|
11278
|
+
},
|
|
11279
|
+
body: JSON.stringify({ changes: Object.fromEntries(dirty) }),
|
|
11280
|
+
});
|
|
11281
|
+
const result = await response.json();
|
|
11282
|
+
if (!response.ok)
|
|
11283
|
+
throw new Error(
|
|
11284
|
+
result.error ||
|
|
11285
|
+
"Unable to save changes (HTTP " + response.status + ")"
|
|
11286
|
+
);
|
|
11287
|
+
if (
|
|
11288
|
+
result.ok !== true ||
|
|
11289
|
+
!result.config ||
|
|
11290
|
+
typeof result.config !== "object" ||
|
|
11291
|
+
Array.isArray(result.config)
|
|
11292
|
+
)
|
|
11293
|
+
throw new Error(
|
|
11294
|
+
"The server did not confirm the saved configuration. Your changes are still pending."
|
|
11295
|
+
);
|
|
11296
|
+
window.LISA_LIVE_CONFIG = result.config;
|
|
11297
|
+
restoreConfigControls();
|
|
11298
|
+
showToast("Saved changes");
|
|
11299
|
+
} catch (error) {
|
|
11300
|
+
errorNode.textContent =
|
|
11301
|
+
error instanceof Error ? error.message : String(error);
|
|
11302
|
+
errorNode.hidden = false;
|
|
11303
|
+
} finally {
|
|
11304
|
+
saving = false;
|
|
11305
|
+
updateSavebar();
|
|
11306
|
+
}
|
|
11307
|
+
}
|
|
11308
|
+
|
|
11189
11309
|
/** Mark the DOM owner of a catalog value with its audited provenance. */
|
|
11190
11310
|
function markRenderedValue(node, value) {
|
|
11191
11311
|
if (!node || !value) return node;
|
|
@@ -11216,6 +11336,17 @@
|
|
|
11216
11336
|
table cells ({t, v, syncKey}) and card rows ({control:{value,
|
|
11217
11337
|
syncKey}}). */
|
|
11218
11338
|
function syncControlValue(syncKey, value) {
|
|
11339
|
+
forEachConfigRow(row => {
|
|
11340
|
+
if (row.key === syncKey) {
|
|
11341
|
+
const hydrated = hydrateControl(row.control, value);
|
|
11342
|
+
if (hydrated) row.control = hydrated;
|
|
11343
|
+
} else if (
|
|
11344
|
+
row.control.type === "envmap" &&
|
|
11345
|
+
syncKey.startsWith(row.key + ".")
|
|
11346
|
+
) {
|
|
11347
|
+
row.control[syncKey.slice(row.key.length + 1)] = value;
|
|
11348
|
+
}
|
|
11349
|
+
});
|
|
11219
11350
|
Object.values(DATA.sections).forEach(section => {
|
|
11220
11351
|
(section.blocks || []).forEach(block => {
|
|
11221
11352
|
if (!Array.isArray(block.rows)) return;
|
|
@@ -11229,7 +11360,11 @@
|
|
|
11229
11360
|
row.control &&
|
|
11230
11361
|
(row.control.syncKey === syncKey || row.key === syncKey)
|
|
11231
11362
|
) {
|
|
11232
|
-
|
|
11363
|
+
if (
|
|
11364
|
+
row.control.type !== "envmap" &&
|
|
11365
|
+
row.control.type !== "tags"
|
|
11366
|
+
)
|
|
11367
|
+
row.control.value = value;
|
|
11233
11368
|
}
|
|
11234
11369
|
});
|
|
11235
11370
|
});
|
|
@@ -11237,28 +11372,65 @@
|
|
|
11237
11372
|
document
|
|
11238
11373
|
.querySelectorAll('[data-sync-key="' + syncKey + '"]')
|
|
11239
11374
|
.forEach(node => {
|
|
11240
|
-
if (node.
|
|
11375
|
+
if (node.type === "checkbox") {
|
|
11376
|
+
node.checked = value;
|
|
11377
|
+
node.dispatchEvent(new Event("lisa-sync"));
|
|
11378
|
+
} else if (node.value !== String(value)) node.value = value;
|
|
11241
11379
|
});
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
input.dataset.syncKey = control.syncKey;
|
|
11248
|
-
input.addEventListener("change", () =>
|
|
11249
|
-
syncControlValue(control.syncKey, input.value)
|
|
11250
|
-
);
|
|
11380
|
+
document
|
|
11381
|
+
.querySelectorAll(".row[data-config-key]")
|
|
11382
|
+
.forEach(row =>
|
|
11383
|
+
row.classList.toggle("modified", isDirtyRow(row.dataset.configKey))
|
|
11384
|
+
);
|
|
11251
11385
|
}
|
|
11252
11386
|
|
|
11253
11387
|
function buildControl(control, dirtyId) {
|
|
11254
11388
|
const id = dirtyId || "ctl-" + ++ctlSeq;
|
|
11389
|
+
const configKey = dirtyId || (control && control.syncKey);
|
|
11255
11390
|
const wrap = el("div", "control");
|
|
11256
|
-
const
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
)
|
|
11391
|
+
const changed = (value, owner, key = configKey) => {
|
|
11392
|
+
if (lisaLiveMode && configKey && control.type === "envmap") {
|
|
11393
|
+
const baseline = liveConfigEntry(
|
|
11394
|
+
window.LISA_LIVE_CONFIG,
|
|
11395
|
+
configKey
|
|
11396
|
+
);
|
|
11397
|
+
if (typeof baseline.value === "string") {
|
|
11398
|
+
// A legacy scalar means production. Expanding it must retain
|
|
11399
|
+
// that value when the user edits another environment.
|
|
11400
|
+
const expanded = {
|
|
11401
|
+
production: baseline.value,
|
|
11402
|
+
...(dirty.get(configKey) || {}),
|
|
11403
|
+
[key.slice(configKey.length + 1)]: value,
|
|
11404
|
+
};
|
|
11405
|
+
const restored =
|
|
11406
|
+
Object.keys(expanded).length === 1 &&
|
|
11407
|
+
expanded.production === baseline.value;
|
|
11408
|
+
const next = restored ? baseline.value : expanded;
|
|
11409
|
+
markDirty(configKey, owner, next);
|
|
11410
|
+
syncControlValue(configKey, next);
|
|
11411
|
+
return;
|
|
11412
|
+
}
|
|
11413
|
+
}
|
|
11414
|
+
markDirty(key || id, owner, value);
|
|
11415
|
+
if (key) syncControlValue(key, value);
|
|
11416
|
+
};
|
|
11417
|
+
const bind = (input, rowFinder, key = configKey) => {
|
|
11418
|
+
if (key) input.dataset.syncKey = key;
|
|
11419
|
+
if (lisaLiveMode && !key) input.disabled = true;
|
|
11420
|
+
input.addEventListener(
|
|
11421
|
+
input.type === "text" || input.type === "number"
|
|
11422
|
+
? "input"
|
|
11423
|
+
: "change",
|
|
11424
|
+
() =>
|
|
11425
|
+
changed(
|
|
11426
|
+
input.type === "checkbox"
|
|
11427
|
+
? input.checked
|
|
11428
|
+
: input.type === "number"
|
|
11429
|
+
? input.valueAsNumber
|
|
11430
|
+
: input.value,
|
|
11431
|
+
rowFinder ? rowFinder(input) : input.closest(".row"),
|
|
11432
|
+
key
|
|
11433
|
+
)
|
|
11262
11434
|
);
|
|
11263
11435
|
};
|
|
11264
11436
|
if (!control) return wrap;
|
|
@@ -11278,6 +11450,7 @@
|
|
|
11278
11450
|
};
|
|
11279
11451
|
paintState();
|
|
11280
11452
|
input.addEventListener("change", paintState);
|
|
11453
|
+
input.addEventListener("lisa-sync", paintState);
|
|
11281
11454
|
bind(input, i => i.closest(".row") || i.closest("tr"));
|
|
11282
11455
|
box.appendChild(label);
|
|
11283
11456
|
box.appendChild(state);
|
|
@@ -11304,7 +11477,6 @@
|
|
|
11304
11477
|
s.appendChild(opt);
|
|
11305
11478
|
});
|
|
11306
11479
|
bind(s, i => i.closest(".row") || i.closest("tr"));
|
|
11307
|
-
bindSync(s, control);
|
|
11308
11480
|
wrap.appendChild(s);
|
|
11309
11481
|
} else if (control.type === "text") {
|
|
11310
11482
|
const i = document.createElement("input");
|
|
@@ -11321,9 +11493,11 @@
|
|
|
11321
11493
|
const i = document.createElement("input");
|
|
11322
11494
|
i.type = "number";
|
|
11323
11495
|
i.className = "ctl num";
|
|
11324
|
-
|
|
11496
|
+
const pendingValue = dirty.has(configKey)
|
|
11497
|
+
? dirty.get(configKey)
|
|
11498
|
+
: control.value;
|
|
11499
|
+
i.value = Number.isNaN(pendingValue) ? "" : pendingValue;
|
|
11325
11500
|
bind(i);
|
|
11326
|
-
bindSync(i, control);
|
|
11327
11501
|
wrap.appendChild(i);
|
|
11328
11502
|
if (control.unit)
|
|
11329
11503
|
wrap.appendChild(el("span", "unit", esc(control.unit)));
|
|
@@ -11352,7 +11526,7 @@
|
|
|
11352
11526
|
if (cb.checked) values.add(o);
|
|
11353
11527
|
else values.delete(o);
|
|
11354
11528
|
paint();
|
|
11355
|
-
|
|
11529
|
+
changed([...values], box.closest("tr"));
|
|
11356
11530
|
});
|
|
11357
11531
|
lab.appendChild(cb);
|
|
11358
11532
|
lab.appendChild(el("span", "", esc(o)));
|
|
@@ -11376,14 +11550,17 @@
|
|
|
11376
11550
|
wrap.appendChild(box);
|
|
11377
11551
|
} else if (control.type === "tags") {
|
|
11378
11552
|
const box = el("div", "tagbox");
|
|
11553
|
+
const values = () =>
|
|
11554
|
+
[...box.querySelectorAll(".tag")].map(tag => tag.dataset.value);
|
|
11379
11555
|
(control.values || []).forEach(v => {
|
|
11380
11556
|
const t = el("span", "tag", esc(v) + " ");
|
|
11557
|
+
t.dataset.value = v;
|
|
11381
11558
|
const x = el("button", "", "×");
|
|
11382
11559
|
x.type = "button";
|
|
11383
|
-
x.title = "Remove
|
|
11560
|
+
x.title = "Remove";
|
|
11384
11561
|
x.addEventListener("click", () => {
|
|
11385
11562
|
t.remove();
|
|
11386
|
-
|
|
11563
|
+
changed(values(), box.closest(".row"));
|
|
11387
11564
|
});
|
|
11388
11565
|
t.appendChild(x);
|
|
11389
11566
|
box.appendChild(t);
|
|
@@ -11391,18 +11568,19 @@
|
|
|
11391
11568
|
const add = el("button", "tag-add", "+ add");
|
|
11392
11569
|
add.type = "button";
|
|
11393
11570
|
add.addEventListener("click", () => {
|
|
11394
|
-
const v = prompt("Add value
|
|
11571
|
+
const v = prompt("Add value:");
|
|
11395
11572
|
if (!v) return;
|
|
11396
11573
|
const t = el("span", "tag", esc(v) + " ");
|
|
11574
|
+
t.dataset.value = v;
|
|
11397
11575
|
const x = el("button", "", "×");
|
|
11398
11576
|
x.type = "button";
|
|
11399
11577
|
x.addEventListener("click", () => {
|
|
11400
11578
|
t.remove();
|
|
11401
|
-
|
|
11579
|
+
changed(values(), box.closest(".row"));
|
|
11402
11580
|
});
|
|
11403
11581
|
t.appendChild(x);
|
|
11404
11582
|
box.insertBefore(t, add);
|
|
11405
|
-
|
|
11583
|
+
changed(values(), box.closest(".row"));
|
|
11406
11584
|
});
|
|
11407
11585
|
box.appendChild(add);
|
|
11408
11586
|
wrap.appendChild(box);
|
|
@@ -11415,7 +11593,11 @@
|
|
|
11415
11593
|
i.type = "text";
|
|
11416
11594
|
i.className = "ctl mono";
|
|
11417
11595
|
i.value = control[envName] || "";
|
|
11418
|
-
bind(
|
|
11596
|
+
bind(
|
|
11597
|
+
i,
|
|
11598
|
+
inp => inp.closest(".row"),
|
|
11599
|
+
configKey ? configKey + "." + envName : undefined
|
|
11600
|
+
);
|
|
11419
11601
|
cell.appendChild(i);
|
|
11420
11602
|
box.appendChild(cell);
|
|
11421
11603
|
});
|
|
@@ -11483,6 +11665,10 @@
|
|
|
11483
11665
|
|
|
11484
11666
|
function buildRow(row) {
|
|
11485
11667
|
const r = el("div", "row");
|
|
11668
|
+
if (row.key) {
|
|
11669
|
+
r.dataset.configKey = row.key;
|
|
11670
|
+
r.classList.toggle("modified", isDirtyRow(row.key));
|
|
11671
|
+
}
|
|
11486
11672
|
const left = el("div");
|
|
11487
11673
|
const label = el("div", "label");
|
|
11488
11674
|
label.appendChild(el("span", "", esc(row.label)));
|
|
@@ -13936,7 +14122,18 @@
|
|
|
13936
14122
|
|
|
13937
14123
|
/* --- boot (deferred so an injected live-config tag after this script is seen) --- */
|
|
13938
14124
|
function boot() {
|
|
14125
|
+
forEachConfigRow(row =>
|
|
14126
|
+
initialControls.set(row.key, { ...row.control })
|
|
14127
|
+
);
|
|
13939
14128
|
hydrateFromLiveConfig();
|
|
14129
|
+
if (lisaLiveMode) {
|
|
14130
|
+
document.getElementById("saveBtn").removeAttribute("title");
|
|
14131
|
+
document
|
|
14132
|
+
.getElementById("saveBtn")
|
|
14133
|
+
.removeAttribute("aria-describedby");
|
|
14134
|
+
document.getElementById("saveReadonlyReason").hidden = true;
|
|
14135
|
+
}
|
|
14136
|
+
updateSavebar();
|
|
13940
14137
|
renderAll();
|
|
13941
14138
|
showSection(location.hash ? location.hash.slice(1) : "overview");
|
|
13942
14139
|
if (!document.getElementById("section-" + activeSection))
|
|
@@ -13968,10 +14165,11 @@
|
|
|
13968
14165
|
});
|
|
13969
14166
|
|
|
13970
14167
|
document.getElementById("discardBtn").addEventListener("click", () => {
|
|
13971
|
-
|
|
13972
|
-
renderAll();
|
|
13973
|
-
showSection(activeSection);
|
|
14168
|
+
if (!saving) restoreConfigControls();
|
|
13974
14169
|
});
|
|
14170
|
+
document
|
|
14171
|
+
.getElementById("saveBtn")
|
|
14172
|
+
.addEventListener("click", () => void saveConfig());
|
|
13975
14173
|
|
|
13976
14174
|
document.getElementById("howtoClose").addEventListener("click", () => {
|
|
13977
14175
|
document.getElementById("howto").close();
|