Fix reactive nature of generic resource store
Some checks failed
/ golint (push) Failing after 10s

These changes are meant to make it possible for new events that come in
to immediately render in the components that depend on them.
This commit is contained in:
Eli Ribble 2026-05-21 23:09:11 +00:00
parent 74ef9a8b3a
commit cecb9ef0f0
No known key found for this signature in database
5 changed files with 92 additions and 59 deletions

View file

@ -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<dto, full extends uriHaver>(
api_base: string,
from_json: jsonConverter<dto, full>,
) {
const _resourceByURI = shallowRef<Map<string, full>>(new Map());
const byURI = shallowReactive<Map<string, full>>(new Map());
const _resourceFetchAll = ref<Promise<full[]> | null>(null);
const _resourceFetchByURI = shallowRef<Map<string, Promise<full> | null>>(
new Map(),
@ -33,32 +33,43 @@ function createResourceStore<dto, full extends uriHaver>(
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<full[]> {
const cur = _resourceFetchAll.value;
if (cur) {
return cur;
}
return fetchAll();
}
async function byID(id: string): Promise<full> {
const uri = uriFromID(id);
return byURI(uri);
return ensureURI(uri);
}
async function byURI(uri: string): Promise<full> {
let cur = _resourceFetchByURI.value.get(uri);
if (cur) {
return cur;
async function ensureURI(uri: string): Promise<full> {
// 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<full[]> {
/*
@ -71,9 +82,13 @@ function createResourceStore<dto, full extends uriHaver>(
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<string, full>();
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<full> {
@ -89,19 +104,16 @@ function createResourceStore<dto, full extends uriHaver>(
}
const body: dto = await response.json();
const report = from_json(body);
_resourceByURI.value.set(report.uri, report);
//let new_all = new Map<string, full>(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<dto, full extends uriHaver>(
return `${api_base}/${id}`;
}
return {
byAll,
byID,
byURI,
ensureURI,
fetchAll,
fetchByID,
fetchByURI,
getAll,
hasAll,
loadingAll,
loadingURI,