refactor(storage): standardize size limits to use GB units

This commit is contained in:
2026-05-01 02:14:05 +03:00
parent d0aa86205f
commit 1cf38d126d
17 changed files with 255 additions and 114 deletions

View File

@@ -398,6 +398,12 @@
gap: 4px;
}
.setting-input-row {
display: flex;
align-items: center;
gap: 6px;
}
.setting-hint {
color: #444444;
font-size: 11px;

View File

@@ -82,7 +82,10 @@
const value = currentValue(row);
let valid = true;
if (row.type === "int" || row.type === "int64") {
if (row.type === "size_gb") {
if (!/^\d+(?:\.\d+)?$/.test(value)) valid = false;
else if (Number(value) < row.minimum) valid = false;
} else if (row.type === "int" || row.type === "int64") {
if (!/^\d+$/.test(value)) valid = false;
else if (Number(value) < row.minimum) valid = false;
} else if (row.type === "bool") {
@@ -179,7 +182,7 @@
function draftValues() {
const values = {};
rows.forEach((row) => {
if (!row.locked) values[row.key] = currentValue(row);
if (!row.locked && isDirty(row)) values[row.key] = currentValue(row);
});
return values;
}
@@ -205,6 +208,8 @@
if (row.hint) {
row.hint.textContent = payload.locked
? "Locked by environment or hard runtime implication."
: payload.type === "size_gb"
? "Use GB values. Decimals allowed, for example `0.5`."
: (payload.default_value ? `Default: ${payload.default_value}` : "");
}
if (row.badge) {
@@ -241,8 +246,13 @@
}
async function saveChanges() {
const values = draftValues();
if (Object.keys(values).length === 0) {
showToast("No changed settings to save", "info");
return;
}
try {
const payload = await postJSON("/admin/settings/save", { values: draftValues() });
const payload = await postJSON("/admin/settings/save", { values });
hydrateRows(payload.rows);
showToast(payload.message || "Settings saved", payload.warnings?.length ? "warning" : "success");
} catch (error) {
@@ -261,6 +271,25 @@
}
}
async function resetSingleSetting(row) {
if (row.locked || !row.input) return;
if (isDirty(row)) {
row.input.value = row.element.dataset.original || "";
updateView();
showToast(`${row.label} draft cleared`);
return;
}
try {
const payload = await postJSON("/admin/settings/reset", { keys: [row.key] });
hydrateRows(payload.rows);
showToast(`${row.label} reset`, "success");
} catch (error) {
showToast(error.message, "error", 3200);
}
}
async function exportSettings() {
try {
const response = await fetch("/admin/settings/export");
@@ -321,8 +350,8 @@
window.WarpBoxUI?.openPopup?.(
"Reset Behavior",
`
<p>Reset defaults writes built-in WarpBox defaults as admin overrides for editable settings.</p>
<p>Environment-only settings stay locked and unchanged.</p>
<p>Reset clears saved admin overrides.</p>
<p>After reset, environment values win again. If no environment value exists, built-in defaults apply.</p>
`
);
}
@@ -390,11 +419,7 @@
rows.forEach((row) => {
row.input?.addEventListener(row.input.tagName === "SELECT" ? "change" : "input", updateView);
row.element.querySelector(".row-reset")?.addEventListener("click", () => {
if (row.locked || !row.input) return;
row.input.value = row.element.dataset.default || row.element.dataset.original || "";
updateView();
});
row.element.querySelector(".row-reset")?.addEventListener("click", () => resetSingleSetting(row));
row.element.querySelector(".row-info")?.addEventListener("click", () => showRowInfo(row));
});