From bc0f126c6a2ba194e37390f8c590e9cc48ade99f Mon Sep 17 00:00:00 2001 From: Polle Pas Date: Tue, 1 Jul 2025 16:25:15 +0200 Subject: [PATCH] Fix subresources not updated when resource is deleted #1087 --- browser/CHANGELOG.md | 3 +- .../src/handlers/sideBarHandler.ts | 47 ++++++++++++------- browser/lib/src/search.ts | 2 +- browser/lib/src/store.ts | 13 +++-- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/browser/CHANGELOG.md b/browser/CHANGELOG.md index b3a505082..6ae5c270f 100644 --- a/browser/CHANGELOG.md +++ b/browser/CHANGELOG.md @@ -24,10 +24,11 @@ This changelog covers all five packages, as they are (for now) updated as a whol - `resource.props` is now writeable: `resource.props.name = 'New Name'`. - Added `store.preloadResourceTree()` method, see docs for more info. - Fix generated ontologies not working in a Next.js server context. -- SEMI BREAKING CHANGE: When using generated types by cli, @tomic/lib now requires them to be generated by @tomic/cli v0.41.0 or above. - Fix types masquerading as esm module in cjs build. - `store.search()` now handles multiple values for the same property correctly. - [#1077](https://github.com/atomicdata-dev/atomic-server/issues/1077) Fix bug where resource.new would not be set back to true when saving fails. +- SEMI BREAKING CHANGE: When using generated types by cli, @tomic/lib now requires them to be generated by @tomic/cli v0.41.0 or above. +- BREAKING CHANGE: The `StoreEvents.ResourceRemoved` event callback now only receives the subject of the resource instead of the resource itself. ### @tomic/react diff --git a/browser/data-browser/src/handlers/sideBarHandler.ts b/browser/data-browser/src/handlers/sideBarHandler.ts index 9a2f4a7d2..fe99bf88f 100644 --- a/browser/data-browser/src/handlers/sideBarHandler.ts +++ b/browser/data-browser/src/handlers/sideBarHandler.ts @@ -1,4 +1,11 @@ -import { Resource, Store, isString, dataBrowser, core } from '@tomic/react'; +import { + Resource, + Store, + isString, + dataBrowser, + core, + CollectionBuilder, +} from '@tomic/react'; export function buildSideBarNewResourceHandler(store: Store) { // When a resource is saved add it to the parents subResources list if it's not already there. @@ -26,25 +33,33 @@ export function buildSideBarNewResourceHandler(store: Store) { export function buildSideBarRemoveResourceHandler(store: Store) { // When a resource is deleted remove it from the parents subResources list. - return async (resource: Resource) => { - const parentSubject = resource.get(core.properties.parent); + return async (subject: string) => { + const collection = new CollectionBuilder(store) + .setProperty(dataBrowser.properties.subResources) + .setValue(subject) + .build(); - if (!isString(parentSubject)) { - throw new Error(`Resource doesn't have a parent: ${resource.subject} `); - } + for await (const member of collection) { + try { + const resource = await store.getResource(member); - const parent = await store.getResource(parentSubject); - const subResources = parent.getSubjects( - dataBrowser.properties.subResources, - ); + if (!(await resource.canWrite(store.getAgent()?.subject))) { + continue; + } + + const subResources = resource.getArray( + dataBrowser.properties.subResources, + ) as string[]; - if (subResources.length > 0) { - await parent.set( - dataBrowser.properties.subResources, - subResources.filter(r => r !== resource.subject), - ); + await resource.set( + dataBrowser.properties.subResources, + subResources.filter(r => r !== subject), + ); - await parent.save(); + await resource.save(); + } catch (e) { + console.error('Error removing resource from parent', e); + } } }; } diff --git a/browser/lib/src/search.ts b/browser/lib/src/search.ts index 52c5f0ad1..3e9ac922f 100644 --- a/browser/lib/src/search.ts +++ b/browser/lib/src/search.ts @@ -115,6 +115,6 @@ export function removeCachedSearchResults(store: Store) { ); for (const resource of searchResources) { - store.removeResource(resource.subject); + store.removeResource(resource.subject, false); } } diff --git a/browser/lib/src/store.ts b/browser/lib/src/store.ts index cd763b274..26753fe1f 100644 --- a/browser/lib/src/store.ts +++ b/browser/lib/src/store.ts @@ -27,6 +27,7 @@ import { initOntologies } from './ontologies/index.js'; type ResourceCallback = ( resource: Resource, ) => void; +type SubjectCallback = (subject: string) => void; /** Callback called when the stores agent changes */ type AgentCallback = (agent: Agent | undefined) => void; type ErrorCallback = (e: Error) => void; @@ -92,7 +93,7 @@ export interface ImportJsonADOptions { */ type StoreEventHandlers = { [StoreEvents.ResourceSaved]: ResourceCallback; - [StoreEvents.ResourceRemoved]: ResourceCallback; + [StoreEvents.ResourceRemoved]: SubjectCallback; [StoreEvents.ResourceManuallyCreated]: ResourceCallback; [StoreEvents.AgentChanged]: AgentCallback; [StoreEvents.ServerURLChanged]: ServerURLCallback; @@ -662,13 +663,16 @@ export class Store { }); } - /** Removes (destroys / deletes) resource from this store */ - public removeResource(subject: string): void { + /** Removes resource from this store, does not delete it from the server, use `resource.destroy()` to delete it from the server. */ + public removeResource(subject: string, shouldNotify = true): void { const resource = this.resources.get(subject); if (resource) { this.resources.delete(subject); - this.eventManager.emit(StoreEvents.ResourceRemoved, resource); + + if (shouldNotify) { + this.eventManager.emit(StoreEvents.ResourceRemoved, subject); + } } } @@ -1048,7 +1052,6 @@ export class Store { } /** Lets subscribers know that a resource has been changed. Time to update your views. - * Make sure the resource is a new reference, otherwise React will not rerender. */ private async notify(resource: Resource): Promise { const subject = resource.subject;