From 005b04e380b0090cbc1240dfb870c1062cf337ed Mon Sep 17 00:00:00 2001 From: "garionion (aider)" Date: Thu, 27 Feb 2025 18:16:18 +0100 Subject: [PATCH] feat: add storage hierarchy component to display nested objects --- web/src/components/StorageHierarchy.vue | 193 ++++++++++++++++++++++++ web/src/pages/index.vue | 18 ++- web/src/stores/storage.ts | 109 +++++++++++++ 3 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 web/src/components/StorageHierarchy.vue create mode 100644 web/src/stores/storage.ts diff --git a/web/src/components/StorageHierarchy.vue b/web/src/components/StorageHierarchy.vue new file mode 100644 index 0000000..df5ddb9 --- /dev/null +++ b/web/src/components/StorageHierarchy.vue @@ -0,0 +1,193 @@ + + + diff --git a/web/src/pages/index.vue b/web/src/pages/index.vue index dac59c7..bd6a890 100644 --- a/web/src/pages/index.vue +++ b/web/src/pages/index.vue @@ -1,7 +1,21 @@ diff --git a/web/src/stores/storage.ts b/web/src/stores/storage.ts new file mode 100644 index 0000000..c064e02 --- /dev/null +++ b/web/src/stores/storage.ts @@ -0,0 +1,109 @@ +import { defineStore } from 'pinia'; + +export const useStorageStore = defineStore('storage', { + state: () => ({ + storageSpaces: [] as any[], + objects: [] as any[], + loading: false, + error: null as string | null, + }), + + getters: { + getStorageById: (state) => (id: number) => { + return state.storageSpaces.find(storage => storage.id === id); + }, + + getObjectsInStorage: (state) => (storageId: number) => { + return state.objects.filter(obj => obj.storagespaceId === storageId); + }, + + getChildStorages: (state) => (parentId: number) => { + return state.storageSpaces.filter(storage => + storage.parent && storage.parent === parentId + ); + } + }, + + actions: { + async fetchStorageSpaces() { + this.loading = true; + this.error = null; + + try { + const response = await fetch('/api/v1/storageSpaces', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('auth_token')}`, + }, + }); + + if (!response.ok) { + throw new Error('Failed to fetch storage spaces'); + } + + const data = await response.json(); + this.storageSpaces = data; + } catch (error: any) { + this.error = error.message; + throw error; + } finally { + this.loading = false; + } + }, + + async fetchObjectsInStorage(storageId: number) { + this.loading = true; + this.error = null; + + try { + const response = await fetch(`/api/v1/storageSpaces/${storageId}/objects`, { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('auth_token')}`, + }, + }); + + if (!response.ok) { + throw new Error('Failed to fetch objects'); + } + + const data = await response.json(); + this.objects = data; + } catch (error: any) { + this.error = error.message; + throw error; + } finally { + this.loading = false; + } + }, + + async fetchStorageHierarchy(rootStorageId: number) { + this.loading = true; + this.error = null; + + try { + // First, ensure we have all storage spaces + if (this.storageSpaces.length === 0) { + await this.fetchStorageSpaces(); + } + + // Then fetch all objects in the hierarchy + const response = await fetch(`/api/v1/storageSpaces/${rootStorageId}/hierarchy/objects`, { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('auth_token')}`, + }, + }); + + if (!response.ok) { + throw new Error('Failed to fetch storage hierarchy'); + } + + const data = await response.json(); + this.objects = data; + } catch (error: any) { + this.error = error.message; + throw error; + } finally { + this.loading = false; + } + } + } +});