Skip to content

Commit 0cc187d

Browse files
committed
fix(ui): serialize state bootstrap
1 parent 17f8439 commit 0cc187d

2 files changed

Lines changed: 44 additions & 23 deletions

File tree

internal/ui/server_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ func TestRuneSettingsAreEnabledInStaticUI(t *testing.T) {
274274
}
275275
for _, want := range []string{
276276
"apply_runes: ids.applyRunes.checked",
277-
"ids.applyRunes.checked = settings.apply_runes",
277+
"ids.applyRunes.checked = Boolean(settings.apply_runes)",
278278
`ids.applyRunes.addEventListener("change", scheduleSave)`,
279279
} {
280280
if !strings.Contains(jsBody, want) {

internal/ui/static/assets/app.js

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ let updateChecking = false;
8181
let currentUpdateStatus = "idle";
8282

8383
let currentState = null;
84+
let stateRequestInFlight = null;
8485

8586
let currentMessage = { key: "message.no_sync_session" };
8687
let currentMessageIsError = false;
@@ -727,7 +728,7 @@ function ensureStateLog(items, logKey) {
727728
return appendLog(items, logKey);
728729
}
729730

730-
function renderLog(state, sync) {
731+
function renderLog(state = {}, sync) {
731732
if (state.last_error) {
732733
appendLog([{ key: state.last_error_code, fallback: state.last_error, tone: "error" }], `error:${state.last_error_code || state.last_error}`);
733734
return;
@@ -753,7 +754,7 @@ function renderLog(state, sync) {
753754
wrote = ensureStateLog([{ key: "log.sync_without_warnings" }], `sync:${state.last_sync_at || JSON.stringify(sync)}`) || wrote;
754755
}
755756

756-
if (!wrote && state.watcher.running) {
757+
if (!wrote && state.watcher && state.watcher.running) {
757758
ensureStateLog([{ key: "log.watcher_waiting" }], "watcher:running");
758759
}
759760

@@ -762,40 +763,42 @@ function renderLog(state, sync) {
762763
}
763764
}
764765

765-
function renderForms(state) {
766-
const settings = state.settings;
766+
function renderForms(state = {}) {
767+
const settings = state.settings || {};
767768
formsLoaded = true;
768-
ids.lcuEnabled.checked = settings.lcu_enabled;
769+
ids.lcuEnabled.checked = Boolean(settings.lcu_enabled);
769770
ids.patch.value = settings.patch || "";
770771
ids.patchRangeSlider.value = String(patchRangeIndexFromValue(patchRangeValueFromSettings(settings)));
771772
ids.leagueTierPresetSlider.value = String(leagueTierIndexFromPreset(settings.league_tier_preset || "emerald_plus"));
772-
ids.applyItems.checked = settings.apply_items;
773-
ids.applyRunes.checked = settings.apply_runes;
774-
ids.applySpells.checked = settings.apply_spells;
775-
ids.keepFlash.checked = settings.keep_flash;
776-
ids.dryRun.checked = settings.dry_run;
773+
ids.applyItems.checked = Boolean(settings.apply_items);
774+
ids.applyRunes.checked = Boolean(settings.apply_runes);
775+
ids.applySpells.checked = Boolean(settings.apply_spells);
776+
ids.keepFlash.checked = Boolean(settings.keep_flash);
777+
ids.dryRun.checked = Boolean(settings.dry_run);
777778
syncSpellsSuboptions();
778779
renderAdvancedSliderValues();
779780
renderModeStatus(settings);
780781
}
781782

782-
function renderState(state) {
783+
function renderState(state = {}) {
783784
currentState = state;
785+
const watcher = state.watcher || {};
786+
const lcu = state.lcu || {};
784787
renderUpdate(state);
785788
renderCoachlessAuth(state.coachless_auth || {});
786789

787-
watcherRunning = state.watcher.running;
790+
watcherRunning = Boolean(watcher.running);
788791
ids.watcherButton.textContent = watcherRunning ? t("action.stop_watcher") : t("action.start_watcher");
789792
ids.watcherButton.setAttribute("aria-pressed", String(watcherRunning));
790793
setValue(ids.watcherStatus, watcherRunning ? t("watcher.running") : t("watcher.stopped"), watcherRunning ? "good" : "");
791-
ids.watcherConfigWarning.hidden = !(state.watcher && state.watcher.config_stale);
794+
ids.watcherConfigWarning.hidden = !watcher.config_stale;
792795

793-
if (state.lcu.state === "connected") {
796+
if (lcu.state === "connected") {
794797
setValue(ids.lcuStatus, t("lcu.connected"), "good");
795-
} else if (state.lcu.state === "off") {
798+
} else if (lcu.state === "off") {
796799
setValue(ids.lcuStatus, t("lcu.disabled"), "warn");
797800
} else {
798-
setValue(ids.lcuStatus, textForDescriptor(state.lcu.message || "lcu.not_connected"), "bad");
801+
setValue(ids.lcuStatus, textForDescriptor(lcu.message || "lcu.not_connected"), "bad");
799802
}
800803

801804
const sync = state.last_sync;
@@ -813,7 +816,7 @@ function renderState(state) {
813816
setMessage({ key: "message.sync_with_warnings" });
814817
} else if (sync) {
815818
setMessage({ key: "message.sync_finished" });
816-
} else if (state.watcher.running) {
819+
} else if (watcher.running) {
817820
setMessage({ key: "message.watcher_waiting" });
818821
} else {
819822
setMessage({ key: "message.no_sync_session" });
@@ -822,16 +825,31 @@ function renderState(state) {
822825
renderLog(state, sync);
823826
}
824827

825-
async function loadForms() {
826-
const state = await api("/api/state");
828+
async function loadInitialState() {
829+
const state = await requestState();
827830
renderForms(state);
831+
renderState(state);
828832
}
829833

830834
async function loadState() {
831-
const state = await api("/api/state");
835+
const state = await requestState();
836+
if (!formsLoaded) {
837+
renderForms(state);
838+
}
832839
renderState(state);
833840
}
834841

842+
function requestState() {
843+
if (stateRequestInFlight) {
844+
return stateRequestInFlight;
845+
}
846+
847+
stateRequestInFlight = api("/api/state").finally(() => {
848+
stateRequestInFlight = null;
849+
});
850+
return stateRequestInFlight;
851+
}
852+
835853
async function checkUpdates(isManual) {
836854
updateChecking = true;
837855
renderUpdateButton();
@@ -986,8 +1004,11 @@ async function initialize() {
9861004
currentLocale = await ensureLocale(currentLocale);
9871005
applyStaticTranslations();
9881006
positionAdvancedSliderTicks();
989-
loadForms().catch(error => setMessage({ key: error.code, fallback: error.fallback || error.message }, true));
990-
loadState().catch(error => setMessage({ key: error.code, fallback: error.fallback || error.message }, true));
1007+
try {
1008+
await loadInitialState();
1009+
} catch (error) {
1010+
setMessage({ key: error.code, fallback: error.fallback || error.message }, true);
1011+
}
9911012
checkUpdates(false).catch(() => { });
9921013
setInterval(() => loadState().catch(() => { }), 3000);
9931014
}

0 commit comments

Comments
 (0)