From 2eaa6b5de193607a44928ce3e73b93b12fd5419c Mon Sep 17 00:00:00 2001 From: Exelo Date: Thu, 11 Jun 2026 16:11:47 +0900 Subject: [PATCH 1/2] feat: add packages deletion --- .../client/ecs/component/component-handle.ts | 2 +- .../client/ecs/component/component-manager.ts | 11 ++++-- src/lib/client/ecs/system/system-handle.ts | 2 +- src/lib/client/ecs/system/system-manager.ts | 11 ++++-- src/lib/client/sync-file-system/sfs-file.ts | 10 ++++++ .../ecs-tree/packages/package-row.svelte | 34 ++++++++++++++----- src/routes/fs/project/+server.ts | 17 ++++++++++ 7 files changed, 73 insertions(+), 14 deletions(-) diff --git a/src/lib/client/ecs/component/component-handle.ts b/src/lib/client/ecs/component/component-handle.ts index 4ec19d3..5a3ad19 100644 --- a/src/lib/client/ecs/component/component-handle.ts +++ b/src/lib/client/ecs/component/component-handle.ts @@ -35,6 +35,6 @@ export class ComponentHandle { } delete() { - this._manager.delete(this.id); + return this._manager.delete(this.id); } } diff --git a/src/lib/client/ecs/component/component-manager.ts b/src/lib/client/ecs/component/component-manager.ts index ec84b2a..f993853 100644 --- a/src/lib/client/ecs/component/component-manager.ts +++ b/src/lib/client/ecs/component/component-manager.ts @@ -62,9 +62,16 @@ export class ComponentManager { return handle; } - delete(id: string) { + async delete(id: string) { const components = get(_storage); - _storage.set(components.filter((component) => component.id !== id)); + const component = components.find((c) => c.id === id); + + if (!component) throw new Error(`System not found: ${id}`); + + _storage.set(components.filter((c) => c.id !== id)); + const { fs } = useProject(); + const file = await fs.getFile(component.path); + await file.delete(); const subscriptions = get(_subscriptions); if (subscriptions[id]) { diff --git a/src/lib/client/ecs/system/system-handle.ts b/src/lib/client/ecs/system/system-handle.ts index d963691..2a84c7c 100644 --- a/src/lib/client/ecs/system/system-handle.ts +++ b/src/lib/client/ecs/system/system-handle.ts @@ -35,6 +35,6 @@ export class SystemHandle { } delete() { - this._manager.delete(this.id); + return this._manager.delete(this.id); } } diff --git a/src/lib/client/ecs/system/system-manager.ts b/src/lib/client/ecs/system/system-manager.ts index c2cb561..c5819c3 100644 --- a/src/lib/client/ecs/system/system-manager.ts +++ b/src/lib/client/ecs/system/system-manager.ts @@ -61,9 +61,16 @@ export class SystemManager { return handle; } - delete(id: string) { + async delete(id: string) { const systems = get(_storage); - _storage.set(systems.filter((system) => system.id !== id)); + const system = systems.find((s) => s.id === id); + + if (!system) throw new Error(`System not found: ${id}`); + + _storage.set(systems.filter((s) => s.id !== id)); + const { fs } = useProject(); + const file = await fs.getFile(system.path); + await file.delete(); const subscriptions = get(_subscriptions); if (subscriptions[id]) { diff --git a/src/lib/client/sync-file-system/sfs-file.ts b/src/lib/client/sync-file-system/sfs-file.ts index 1699728..86cf35b 100644 --- a/src/lib/client/sync-file-system/sfs-file.ts +++ b/src/lib/client/sync-file-system/sfs-file.ts @@ -73,6 +73,16 @@ export class SfsFile { if (!res.ok) throw new Error(`Failed to sync file: ${await res.text()}`); } + async delete(): Promise { + const res = await fetch(this._route, { + method: 'DELETE', + headers: { + [SESSION_PROJECT_HEADER]: this._handler.project.id, + }, + }); + if (!res.ok) throw new Error(`Failed to delete file: ${await res.text()}`); + } + async getFile(): Promise { await this._preRead(); return this._cache!; diff --git a/src/lib/components/Widget/ecs-tree/packages/package-row.svelte b/src/lib/components/Widget/ecs-tree/packages/package-row.svelte index 40d9f90..2677db4 100644 --- a/src/lib/components/Widget/ecs-tree/packages/package-row.svelte +++ b/src/lib/components/Widget/ecs-tree/packages/package-row.svelte @@ -20,6 +20,7 @@ import { get, type Writable } from 'svelte/store'; import { tabsStore } from '$lib/components/Tabs/store'; import { getType } from '@utils/file'; + import { Spinner } from '$lib/components/ui/spinner'; type Props = | { @@ -48,7 +49,9 @@ const selectedEntity = $derived($activeScene.entities.selected); const selectedEntityData = $derived($selectedEntity?.store); - const disabled = $derived.by<'added' | 'selected' | null>(() => { + let deleteLoading = $state(false); + + const disabled = $derived.by<'added' | 'selected' | 'delete' | null>(() => { const isNotSelected = type === 'component' ? !$selectedEntity : !$activeScene; if (isNotSelected) return 'selected'; @@ -58,6 +61,8 @@ : $activeSceneData.systems.includes(handle.id); if (isAlreadyAdded) return 'added'; + if (deleteLoading) return 'delete'; + return null; }); const items: PackageItems = $derived(ITEMS[type]); @@ -93,9 +98,10 @@ }); }; - const handleDelete = () => { - // @todo delete package - handle.delete(); + const handleDelete = async () => { + deleteLoading = true; + await handle.delete(); + deleteLoading = false; }; const onDelete = (e: MouseEvent) => { @@ -133,13 +139,17 @@ {/if} @@ -157,8 +167,16 @@ {/if} - - + + {#if deleteLoading} + + {:else} + + {/if} Delete diff --git a/src/routes/fs/project/+server.ts b/src/routes/fs/project/+server.ts index 5238e51..1ddb881 100644 --- a/src/routes/fs/project/+server.ts +++ b/src/routes/fs/project/+server.ts @@ -40,3 +40,20 @@ export const POST = useRequestHandler(async ({ event, project }) => { return Response.json({ success: true }); }); + +/** + * To delete a project file, use the following URL: + * /fs/project?path=path/to/file + * The path must be relative to /client + * Only the client is handled for now + */ +export const DELETE = useRequestHandler(async ({ event, project }) => { + const path = event.url.searchParams.get('path'); + if (!path) throw new Exception('Bad Request', 'Missing path query param', 400); + + const file = project.client.fs.getFile(decodeURIComponent(path).replace(/\?url$/, '')); + + file.delete(); + + return Response.json({ success: true }); +}); From c565cdff08b8031c0e515b4d06f17f94c098e843 Mon Sep 17 00:00:00 2001 From: Exelo Date: Thu, 11 Jun 2026 16:12:13 +0900 Subject: [PATCH 2/2] fix: key on folder when they have the same name as an entity --- .../Widget/ecs-tree/scenes/entities/entity-tree.svelte | 2 +- .../Widget/ecs-tree/scenes/entities/folder-tree-node.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/Widget/ecs-tree/scenes/entities/entity-tree.svelte b/src/lib/components/Widget/ecs-tree/scenes/entities/entity-tree.svelte index 434285e..7193162 100644 --- a/src/lib/components/Widget/ecs-tree/scenes/entities/entity-tree.svelte +++ b/src/lib/components/Widget/ecs-tree/scenes/entities/entity-tree.svelte @@ -314,7 +314,7 @@ {/if}
- {#each tree as node (node.kind === 'entity' ? node.id : node.path)} + {#each tree as node (node.kind === 'entity' ? node.id : `${node.path}-folder`)} {#if node.kind === 'entity'} {:else} diff --git a/src/lib/components/Widget/ecs-tree/scenes/entities/folder-tree-node.svelte b/src/lib/components/Widget/ecs-tree/scenes/entities/folder-tree-node.svelte index 11d0547..37aa193 100644 --- a/src/lib/components/Widget/ecs-tree/scenes/entities/folder-tree-node.svelte +++ b/src/lib/components/Widget/ecs-tree/scenes/entities/folder-tree-node.svelte @@ -176,7 +176,7 @@ {#if expandedFolders.has(node.path)} - {#each node.children as child (child.kind === 'entity' ? child.id : child.path)} + {#each node.children as child (child.kind === 'entity' ? child.id : `${child.path}-folder`)} {#if child.kind === 'entity'}