perf: fix N+1 query pattern across all modules + rack numbering
CRITICAL PERF BUG: Every hook did storage.list() (1 HTTP call fetching ALL items with values, discarding values, returning only keys) then storage.get() for EACH key (N individual HTTP calls re-fetching values one by one). With 6 entries + contacts + tags, Registratura page fired ~40 sequential HTTP requests on load, where 3 would suffice. Fix: Replace list()+N*get() with single exportAll() call in ALL hooks: - registratura/registry-service.ts (added exportAll to RegistryStorage interface) - address-book/use-contacts.ts - it-inventory/use-inventory.ts - password-vault/use-vault.ts - word-templates/use-templates.ts - prompt-generator/use-prompt-generator.ts - hot-desk/use-reservations.ts - email-signature/use-saved-signatures.ts - digital-signatures/use-signatures.ts - ai-chat/use-chat.ts - core/tagging/tag-service.ts (uses storage.export()) Additional fixes: - registratura/use-registry.ts: addEntry uses optimistic local state update instead of double-refresh; closeEntry batches saves with Promise.all + single refresh - server-rack.tsx: reversed slot rendering so U1 is at bottom (standard rack numbering, per user's physical rack) Performance impact: ~90% reduction in HTTP requests on page load for all modules
This commit is contained in:
@@ -59,7 +59,8 @@ export function useRegistry() {
|
||||
async (
|
||||
data: Omit<RegistryEntry, "id" | "number" | "createdAt" | "updatedAt">,
|
||||
) => {
|
||||
// Fetch fresh entries to prevent duplicate numbers from stale state
|
||||
// Fetch fresh entries to prevent duplicate numbers from stale state.
|
||||
// This single call replaces what was previously list() + N×get().
|
||||
const freshEntries = await getAllEntries(storage);
|
||||
const now = new Date().toISOString();
|
||||
const number = generateRegistryNumber(
|
||||
@@ -76,10 +77,11 @@ export function useRegistry() {
|
||||
updatedAt: now,
|
||||
};
|
||||
await saveEntry(storage, entry);
|
||||
await refresh();
|
||||
// Update local state directly to avoid a second full fetch
|
||||
setEntries((prev) => [entry, ...prev]);
|
||||
return entry;
|
||||
},
|
||||
[storage, refresh],
|
||||
[storage],
|
||||
);
|
||||
|
||||
const updateEntry = useCallback(
|
||||
@@ -108,29 +110,36 @@ export function useRegistry() {
|
||||
[storage, refresh],
|
||||
);
|
||||
|
||||
/** Close an entry and optionally its linked entries */
|
||||
/** Close an entry and optionally its linked entries.
|
||||
* Batches all saves, then does a single refresh at the end.
|
||||
*/
|
||||
const closeEntry = useCallback(
|
||||
async (id: string, closeLinked: boolean) => {
|
||||
const entry = entries.find((e) => e.id === id);
|
||||
if (!entry) return;
|
||||
await updateEntry(id, { status: "inchis" });
|
||||
// Save main entry as closed
|
||||
const now = new Date().toISOString();
|
||||
const closedMain: RegistryEntry = {
|
||||
...entry,
|
||||
status: "inchis",
|
||||
updatedAt: now,
|
||||
};
|
||||
await saveEntry(storage, closedMain);
|
||||
// Close linked entries in parallel
|
||||
const linked = entry.linkedEntryIds ?? [];
|
||||
if (closeLinked && linked.length > 0) {
|
||||
for (const linkedId of linked) {
|
||||
const linked = entries.find((e) => e.id === linkedId);
|
||||
if (linked && linked.status !== "inchis") {
|
||||
const updatedLinked: RegistryEntry = {
|
||||
...linked,
|
||||
status: "inchis",
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
await saveEntry(storage, updatedLinked);
|
||||
}
|
||||
}
|
||||
await refresh();
|
||||
const saves = linked
|
||||
.map((linkedId) => entries.find((e) => e.id === linkedId))
|
||||
.filter((e): e is RegistryEntry => !!e && e.status !== "inchis")
|
||||
.map((e) =>
|
||||
saveEntry(storage, { ...e, status: "inchis", updatedAt: now }),
|
||||
);
|
||||
await Promise.all(saves);
|
||||
}
|
||||
// Single refresh at the end
|
||||
await refresh();
|
||||
},
|
||||
[entries, updateEntry, storage, refresh],
|
||||
[entries, storage, refresh],
|
||||
);
|
||||
|
||||
const updateFilter = useCallback(
|
||||
|
||||
Reference in New Issue
Block a user