feat: central frontend store (RDFA-483)#128
Conversation
b01166d to
092ef5a
Compare
092ef5a to
acf3557
Compare
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Signed-off-by: Finn Tarnowsky <finn.tarnowsky@soptim.de>
Commit the spec as a contract and generate the client offline from it
8c9e468 to
9105d54
Compare
9105d54 to
fdf5b8e
Compare
fdf5b8e to
b1e92a9
Compare
…cross builds Signed-off-by: Jan-Hendrik Spahn <jan-hendrik.spahn@soptim.de>
# Conflicts: # backend/src/main/java/org/rdfarchitect/api/controller/datasets/diagrams/CrossProfileDiagramIDRESTController.java # backend/src/main/java/org/rdfarchitect/api/controller/datasets/graphs/diagrams/CustomDiagramClassRESTController.java # backend/src/main/java/org/rdfarchitect/services/diagrams/CustomCustomDiagramService.java # backend/src/main/java/org/rdfarchitect/services/update/classes/UpdateClassService.java # backend/src/test/java/org/rdfarchitect/services/diagrams/CustomDiagramsServiceTest.java # frontend/package-lock.json # frontend/src/lib/api/apiDatasetUtils.js # frontend/src/lib/api/backend.js # frontend/src/lib/rendering/svelteflow/components/SvelteFlowPaneContextMenu.svelte # frontend/src/lib/rendering/svelteflow/svelteFlowWrapper.svelte # frontend/src/routes/GraphDeleteDialog.svelte # frontend/src/routes/ImportDialog.svelte # frontend/src/routes/NewClassDialog.svelte # frontend/src/routes/NewGraphDialog.svelte # frontend/src/routes/delete-relations-dialog/DeleteDependenciesDialog.svelte # frontend/src/routes/layout/menu-bar/Edit.svelte # frontend/src/routes/mainpage/classEditor/classEditor.svelte # frontend/src/routes/mainpage/classEditor/components/associations/save-association-to-backend.js # frontend/src/routes/mainpage/classEditor/components/enum-entries/save-enum-entry-to-backend.js # frontend/src/routes/mainpage/classEditor/fetch-class-editor-context.js # frontend/src/routes/mainpage/packageNavigation/DatasetSection.svelte # frontend/src/routes/mainpage/packageNavigation/PackageDeleteDialog.svelte # frontend/src/routes/mainpage/packageNavigation/build-nav-object.js # frontend/src/routes/mainpage/packageNavigation/custom-diagram-dialogs/CustomDiagramDeleteDialog.svelte # frontend/src/routes/mainpage/packageNavigation/custom-diagram-dialogs/RemoveFromDiagramDialog.svelte # frontend/src/routes/mainpage/packageNavigation/save-copy-class-to-backend.js
# Conflicts: # frontend/src/lib/api/backend.js # frontend/src/routes/NewClassDialog.svelte
spah-soptim
left a comment
There was a problem hiding this comment.
Re-review done.
Architecture is half-wired: the stores notify subscribers, but the UI still refreshes via forceReloadTrigger and versionControlStore.undo/redo hardcodes which stores to invalidate (misses datatypesStore/diagramStore resulting into stale caches after undo). Not worth fixing in this PR, but worth a follow up.
| function pasteClass(copyAsAbstract, copyAttributes, copyAssociations) { | ||
| saveCopyClass( | ||
| classStore.saveCopyClass( | ||
| editorState.selectedDataset.getValue(), | ||
| editorState.selectedGraph.getValue(), | ||
| selectedPackageDetails, |
There was a problem hiding this comment.
The menu-bar/shortcut paste is broken.
pasteClass calls classStore.saveCopyClass(dataset, graph, selectedPackageDetails, copyAsAbstract, ...) with 6 args, but the actual store method is pasteCopiedClasses(datasetName, graphURI, request).
It should call the wrapper in save-copy-class-to-backend.js (which has exactly this 6-arg signature) instead. The svelteflow context-menu paste path is fine.
| const { error, data } = await crossProfileStore.fetchRenderingData( | ||
| editorState.selectedDataset.getValue(), | ||
| ); | ||
|
|
||
| const responseText = await res.text(); | ||
| if (!responseText) { | ||
| displayDiagram = false; | ||
| } else { | ||
| response = JSON.parse(responseText); | ||
| renderingFormat = response.format; | ||
| displayDiagram = true; | ||
| } | ||
| } catch (error) { | ||
| console.error("Error fetching cross profile diagram data:", error); | ||
| if (error || !data) { | ||
| displayDiagram = false; | ||
| response = null; | ||
| renderingFormat = null; | ||
| } finally { | ||
| isLoading = false; | ||
| } else { | ||
| renderingFormat = response.format; | ||
| displayDiagram = true; | ||
| } |
There was a problem hiding this comment.
fetchCrossProfileRenderingData destructures { error, data } but never assigns response = data (all the three other fetchers do).
| associationUUIDs.fromUUID, | ||
| associationUUIDs.toUUID, |
There was a problem hiding this comment.
save-association-to-backend.js:44 / AssociationEditorDialog.svelte:102
new associations get undefined UUIDs.
classStore.addAssociationPair returns an AssociationPairDto ({from: {...}, to: {...}}), but the dialog reads result.associationUUIDs.fromUUID/.toUUID. Only the replace path returns {fromUUID, toUUID}.
| const res = await bec.getOntology( | ||
| datasetNavEntry.label, | ||
| await ontologyStore.loadOntology(datasetNavEntry.id, graphNavEntry.id); | ||
| const { data } = await ontologyStore.getOntologyForGraph( |
There was a problem hiding this comment.
ontology is always undefined.
const { data } = await ontologyStore.getOntologyForGraph(...), but the store returns OntologyDto | null directly, not {data} (OntologyStore.ts:198-204). The {#if ontology} profile-header UI never renders.
| const { error } = versionControlStore.undo( | ||
| datasetNavEntry.id, | ||
| graphNavEntry.id, | ||
| ); | ||
|
|
||
| if (!error) { | ||
| forceReloadTrigger.trigger(); | ||
| } | ||
| } | ||
|
|
||
| async function getOntology() { | ||
| const res = await bec.getOntology( | ||
| datasetNavEntry.label, | ||
| function redo() { | ||
| const { error } = versionControlStore.redo( |
There was a problem hiding this comment.
GraphSection.svelte:136,147
missing await on versionControlStore.undo/redo.
{ error } is destructured from a Promise, so error is always undefined and the reload fires unconditionally before the undo round-trip completes.
| * Generic loader for a slot in a graph's vocabulary. Caches data per | ||
| * (dataset, graph) and per slot, coalesces concurrent fetches. | ||
| */ | ||
| async function loadSlot<K extends keyof GraphVocabulary>( |
There was a problem hiding this comment.
Store scaffolding is copy-pasted six times: the {data, fetchedAt, pending, error} slot type, makeKey with the :: separator, prefix-based invalidation, and the describeError→log→toast→return boilerplate.
DatatypesStore.loadSlot already is the generic helper - extracting it (plus a shared AsyncSlot) would remove the duplicated lines per store and make the :: key convention a single point of truth.
| function invalidateAll() { | ||
| update(() => ({ graphs: new Map() })); | ||
| } |
There was a problem hiding this comment.
The invalidateAll() and invalidateDataset() functions in all six stores have zero callers (except the graphStore.invalidateDataset). Worth a follow-up.
| } | ||
|
|
||
| // ---------- invalidation ---------- | ||
| function invalidateDataset(datasetName: string) { |
There was a problem hiding this comment.
The DiagramStore.invalidateDataset also evicts all graph-diagram lists on dataset-diagram-only mutations. Could be fixed in a follow up. Nothing blocking.
| await loadXsdPrimitives(); | ||
| await datatypesStore.loadForGraph(datasetName, graphUri); | ||
| const xsd = await getXSDPrimitives(); |
There was a problem hiding this comment.
It awaits two independent fetches sequentially and redundantly re-reads getXSDPrimitives(). Could be worth a follow-up. Non blocking.
| @@ -144,7 +118,7 @@ | |||
| $effect(async () => { | |||
There was a problem hiding this comment.
duplicate readonly-recompute effect.
Description
Test Checklist
General Behavior
Global MenuBar
Welcome Page
Editor - MenuBar
Editor - Navigation
Editor - Package View
Editor - Class Editor
Prefixes Page
Changelog Page
Compare Page