Award refs are now computed once and stored on the QSO as a JSON column
(award_refs, e.g. {"DDFM":"74","WAJA":"12"}) instead of recomputing the whole
award engine on every grid page load. Written on log/edit/UDP-import and
bulk-recomputed when an award definition or reference list changes; a one-time
per-logbook backfill materializes pre-existing QSOs. The grid reads the column
directly like any other field, so it's fast and available everywhere (including
the shared MySQL logbook).
Also fix per-profile grid column layout: the DB copy was already per-profile,
but the localStorage cache used one global namespace and shadowed it, so a
profile switch kept the previous profile's columns/widths. gridPrefs now scopes
the cache by active profile id and the grids remount on profile:changed.
66 lines
2.8 KiB
TypeScript
66 lines
2.8 KiB
TypeScript
// Portable grid-column preferences (visibility / order / width / sort).
|
|
//
|
|
// Stored in the DB settings table (so they travel with the logbook and
|
|
// survive a reinstall) AND mirrored to the WebView localStorage as a fast,
|
|
// flicker-free cache. On a fresh machine localStorage is empty, so we fall
|
|
// back to the DB copy and re-seed the cache.
|
|
import { GetUIPref, SetUIPref } from '../../wailsjs/go/main/App';
|
|
|
|
// The DB copy is ALREADY per-profile (the backend prefixes every ui.* key with
|
|
// the active profile id). The localStorage cache, however, is one namespace for
|
|
// the whole WebView, so without scoping it too a profile switch would keep
|
|
// serving the previous profile's cached layout and the correct per-profile DB
|
|
// value would never win. lsScope makes the cache per-profile as well; it's set
|
|
// once the active profile is known and updated on every profile switch.
|
|
let lsScope = '';
|
|
|
|
// setGridPrefsProfile scopes the localStorage cache to a profile. Call it before
|
|
// the grids read their state (at startup) and again whenever the active profile
|
|
// changes so each profile keeps its own column layout / widths.
|
|
export function setGridPrefsProfile(id: number | string | null | undefined): void {
|
|
lsScope = id == null || id === '' ? '' : `p${id}.`;
|
|
}
|
|
|
|
// lsKey scopes ONLY the localStorage cache key. The DB key passed to
|
|
// GetUIPref/SetUIPref is left untouched — the backend already scopes it.
|
|
function lsKey(key: string): string {
|
|
return lsScope + key;
|
|
}
|
|
|
|
// loadLocal reads the cached column state synchronously (used in onGridReady
|
|
// to apply instantly, before the async DB round-trip).
|
|
export function loadLocal(key: string): any[] | null {
|
|
try {
|
|
const raw = localStorage.getItem(lsKey(key));
|
|
const v = raw ? JSON.parse(raw) : null;
|
|
return Array.isArray(v) ? v : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// loadRemote pulls the portable copy from the DB (null if none / unset).
|
|
export async function loadRemote(key: string): Promise<any[] | null> {
|
|
try {
|
|
const v = await GetUIPref(key);
|
|
const parsed = v ? JSON.parse(v) : null;
|
|
return Array.isArray(parsed) ? parsed : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// saveState write-throughs to both the cache and the DB (fire-and-forget). Only
|
|
// the cache key is profile-scoped; the DB key is scoped by the backend.
|
|
export function saveState(key: string, state: any[]) {
|
|
const json = JSON.stringify(state);
|
|
try { localStorage.setItem(lsKey(key), json); } catch { /* quota / private mode */ }
|
|
SetUIPref(key, json).catch(() => { /* DB unavailable — cache still holds it */ });
|
|
}
|
|
|
|
// seedLocal writes a value into the cache without touching the DB (used after
|
|
// hydrating the cache from the DB on a fresh machine).
|
|
export function seedLocal(key: string, state: any[]) {
|
|
try { localStorage.setItem(lsKey(key), JSON.stringify(state)); } catch { /* ignore */ }
|
|
}
|