From cecb9ef0f040b759c335d1b27db8a7c727b81623 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Thu, 21 May 2026 23:09:11 +0000 Subject: [PATCH] Fix reactive nature of generic resource store These changes are meant to make it possible for new events that come in to immediately render in the components that depend on them. --- ts/components/CardPublicReport.vue | 11 +++- ts/components/CommunicationColumnList.vue | 12 +++- ts/store/resource.ts | 67 +++++++++++++---------- ts/view/Communication.vue | 59 +++++++++++--------- ts/view/review/Contact.vue | 2 +- 5 files changed, 92 insertions(+), 59 deletions(-) diff --git a/ts/components/CardPublicReport.vue b/ts/components/CardPublicReport.vue index 000926c3..ef2e1668 100644 --- a/ts/components/CardPublicReport.vue +++ b/ts/components/CardPublicReport.vue @@ -144,6 +144,7 @@ diff --git a/ts/components/CommunicationColumnList.vue b/ts/components/CommunicationColumnList.vue index 95a31d21..3e9853e2 100644 --- a/ts/components/CommunicationColumnList.vue +++ b/ts/components/CommunicationColumnList.vue @@ -203,6 +203,7 @@ diff --git a/ts/store/resource.ts b/ts/store/resource.ts index f6ef8021..403459bd 100644 --- a/ts/store/resource.ts +++ b/ts/store/resource.ts @@ -1,8 +1,8 @@ import { defineStore } from "pinia"; -import { ref, shallowRef } from "vue"; +import { ref, shallowRef, shallowReactive } from "vue"; +import { log } from "@/log"; import { SSEManager, SSEMessageResource } from "@/SSEManager"; -import { useSessionStore } from "@/store/session"; import { apiClient } from "@/client"; import { @@ -23,7 +23,7 @@ function createResourceStore( api_base: string, from_json: jsonConverter, ) { - const _resourceByURI = shallowRef>(new Map()); + const byURI = shallowReactive>(new Map()); const _resourceFetchAll = ref | null>(null); const _resourceFetchByURI = shallowRef | null>>( new Map(), @@ -33,32 +33,43 @@ function createResourceStore( SSEManager.subscribe((msg: SSEMessageResource) => { if (msg.resource.startsWith(resource_name)) { if (msg.type == "created") { + console.log("New resource", resource_name, msg.resource, msg.uri); fetchByURI(msg.uri); } else if (msg.type == "updated") { + console.log("Updated resource", resource_name, msg.resource, msg.uri); fetchByURI(msg.uri); } } }); - async function byAll(): Promise { - const cur = _resourceFetchAll.value; - if (cur) { - return cur; - } - return fetchAll(); - } async function byID(id: string): Promise { const uri = uriFromID(id); - return byURI(uri); + return ensureURI(uri); } - async function byURI(uri: string): Promise { - let cur = _resourceFetchByURI.value.get(uri); - if (cur) { - return cur; + async function ensureURI(uri: string): Promise { + // Check if we already have the data + const existing = byURI.get(uri); + if (existing) { + return existing; + } + + // Check if we're already fetching it + let fetchPromise = _resourceFetchByURI.value.get(uri); + if (fetchPromise) { + return fetchPromise; + } + + // Start fetching + fetchPromise = fetchByURI(uri); + _resourceFetchByURI.value.set(uri, fetchPromise); + + try { + const result = await fetchPromise; + return result; + } finally { + // Clean up the promise after it resolves + _resourceFetchByURI.value.delete(uri); } - cur = fetchByURI(uri); - _resourceFetchByURI.value.set(uri, cur); - return cur; } async function fetchAll(): Promise { /* @@ -71,9 +82,13 @@ function createResourceStore( const url = `/api${api_base}`; const dtos = (await apiClient.JSONGet(url)) as dto[]; const resources = dtos.map((m: dto) => from_json(m)); + //let new_all = new Map(); resources.forEach((r: full) => { - _resourceByURI.value.set(r.uri, r); + byURI.set(r.uri, r); + //new_all.set(r.uri, r); + log.info("Set", resource_name, r); }); + //byURI.value = new_all; return resources; } async function fetchByID(id: string): Promise { @@ -89,19 +104,16 @@ function createResourceStore( } const body: dto = await response.json(); const report = from_json(body); - _resourceByURI.value.set(report.uri, report); + //let new_all = new Map(byURI.value); + //new_all.set(report.uri, report); + byURI.set(report.uri, report); + //byURI.value = new_all; return report; } catch (err) { console.error("Error loading users:", err); throw err; } } - function getAll(): full[] | null { - if (_resourceFetchAll) { - return Array.from(_resourceByURI.value.values()); - } - return null; - } function hasAll(): boolean { return !!_resourceFetchAll.value; } @@ -118,13 +130,12 @@ function createResourceStore( return `${api_base}/${id}`; } return { - byAll, byID, byURI, + ensureURI, fetchAll, fetchByID, fetchByURI, - getAll, hasAll, loadingAll, loadingURI, diff --git a/ts/view/Communication.vue b/ts/view/Communication.vue index f3760834..83b74514 100644 --- a/ts/view/Communication.vue +++ b/ts/view/Communication.vue @@ -23,10 +23,7 @@