refactor: Convert StorageHierarchy component to TypeScript with proper typing

This commit is contained in:
garionion (aider) 2025-02-28 21:35:17 +01:00
parent e3d8f9e8ee
commit 9213034093
2 changed files with 125 additions and 86 deletions

View file

@ -50,16 +50,43 @@
</template>
<script lang="ts" setup>
import { ref, computed, watch, onMounted, defineComponent } from 'vue';
import { ref, computed, watch, onMounted } from 'vue';
import { useStorageStore } from '@/stores/storage';
// Component for recursive display of storage boxes
// Define types for our data
interface StorageSpace {
id: number;
parent: {
valid: boolean;
int64: number;
} | null;
location: string | null;
}
interface StorageObject {
id: number;
storagespaceId: number;
name: string;
description: string | null;
serialnumber: string | null;
}
// Create a separate component for storage boxes
const StorageBox = defineComponent({
name: 'StorageBox',
props: {
storage: Object,
objects: Array,
nestedStorages: Array
storage: {
type: Object as () => StorageSpace,
required: true
},
objects: {
type: Array as () => StorageObject[],
required: true
},
nestedStorages: {
type: Array as () => StorageSpace[],
required: true
}
},
setup(props) {
const objectsInCurrentStorage = computed(() => {
@ -72,87 +99,81 @@ const StorageBox = defineComponent({
);
});
return () => (
<v-expansion-panel>
<v-expansion-panel-title>
<div class="d-flex align-center">
<v-icon class="mr-2">mdi-package-variant-closed</v-icon>
<span>{ props.storage.location || `Storage #${props.storage.id}` }</span>
<v-chip class="ml-2" size="small" color="primary" variant="outlined">
{ objectsInCurrentStorage.value.length } objects
</v-chip>
</div>
</v-expansion-panel-title>
<v-expansion-panel-text>
<div class="mb-4">
<h3 class="text-subtitle-1 mb-2">Objects in this storage:</h3>
{objectsInCurrentStorage.value.length > 0 ? (
<v-list lines="two">
{objectsInCurrentStorage.value.map(obj => (
<v-list-item
:key="obj.id"
:title="obj.name"
:subtitle="obj.description || 'No description'"
>
<template v-slot:prepend>
<v-icon>mdi-cube-outline</v-icon>
</template>
<template v-slot:append>
<v-chip size="small" color="grey" variant="flat">
SN: { obj.serialnumber || 'N/A' }
</v-chip>
</template>
</v-list-item>
))}
</v-list>
) : (
<v-alert type="info" variant="tonal" density="compact">
No objects in this storage
</v-alert>
)}
</div>
return { objectsInCurrentStorage, childStorages };
},
template: `
<v-expansion-panel>
<v-expansion-panel-title>
<div class="d-flex align-center">
<v-icon class="mr-2">mdi-package-variant-closed</v-icon>
<span>{{ storage.location || \`Storage #\${storage.id}\` }}</span>
<v-chip class="ml-2" size="small" color="primary" variant="outlined">
{{ objectsInCurrentStorage.length }} objects
</v-chip>
</div>
</v-expansion-panel-title>
<v-expansion-panel-text>
<div class="mb-4">
<h3 class="text-subtitle-1 mb-2">Objects in this storage:</h3>
<v-list v-if="objectsInCurrentStorage.length > 0" lines="two">
<v-list-item
v-for="obj in objectsInCurrentStorage"
:key="obj.id"
:title="obj.name"
:subtitle="obj.description || 'No description'"
>
<template v-slot:prepend>
<v-icon>mdi-cube-outline</v-icon>
</template>
<template v-slot:append>
<v-chip size="small" color="grey" variant="flat">
SN: {{ obj.serialnumber || 'N/A' }}
</v-chip>
</template>
</v-list-item>
</v-list>
<v-alert v-else type="info" variant="tonal" density="compact">
No objects in this storage
</v-alert>
</div>
{childStorages.value.length > 0 && (
<div class="mt-4">
<h3 class="text-subtitle-1 mb-2">Nested storage spaces:</h3>
<v-expansion-panels>
{childStorages.value.map(childStorage => (
<StorageBox
key={childStorage.id}
storage={childStorage}
objects={props.objects}
nestedStorages={props.nestedStorages}
/>
))}
</v-expansion-panels>
</div>
)}
</v-expansion-panel-text>
</v-expansion-panel>
);
}
<div v-if="childStorages.length > 0" class="mt-4">
<h3 class="text-subtitle-1 mb-2">Nested storage spaces:</h3>
<v-expansion-panels>
<storage-box
v-for="childStorage in childStorages"
:key="childStorage.id"
:storage="childStorage"
:objects="objects"
:nested-storages="nestedStorages"
/>
</v-expansion-panels>
</div>
</v-expansion-panel-text>
</v-expansion-panel>
`
});
// Main component logic
const storageStore = useStorageStore();
const loading = ref(false);
const error = ref(null);
const selectedStorageId = ref(null);
const error = ref<string | null>(null);
const selectedStorageId = ref<number | null>(null);
const storageSpaces = computed(() => storageStore.storageSpaces);
const objects = computed(() => storageStore.objects);
const storageSpaces = computed<StorageSpace[]>(() => storageStore.storageSpaces);
const objects = computed<StorageObject[]>(() => storageStore.objects);
const selectedStorage = computed(() => {
const selectedStorage = computed<StorageSpace | null>(() => {
if (!selectedStorageId.value) return null;
return storageSpaces.value.find(s => s.id === selectedStorageId.value);
return storageSpaces.value.find(s => s.id === selectedStorageId.value) || null;
});
const objectsInStorage = computed(() => {
const objectsInStorage = computed<StorageObject[]>(() => {
if (!selectedStorageId.value) return [];
return objects.value;
});
const nestedStorages = computed(() => {
const nestedStorages = computed<StorageSpace[]>(() => {
return storageSpaces.value;
});
@ -162,13 +183,13 @@ watch(selectedStorageId, async (newId) => {
}
});
async function fetchStorageData(storageId) {
async function fetchStorageData(storageId: number): Promise<void> {
loading.value = true;
error.value = null;
try {
await storageStore.fetchStorageHierarchy(storageId);
} catch (err) {
} catch (err: any) {
error.value = err.message || 'Failed to load storage data';
} finally {
loading.value = false;
@ -184,7 +205,7 @@ onMounted(async () => {
if (storageSpaces.value.length > 0) {
selectedStorageId.value = storageSpaces.value[0].id;
}
} catch (err) {
} catch (err: any) {
error.value = err.message || 'Failed to load storage spaces';
} finally {
loading.value = false;

View file

@ -1,31 +1,49 @@
import { defineStore } from 'pinia';
// Define types for our data
interface StorageSpace {
id: number;
parent: {
valid: boolean;
int64: number;
} | null;
location: string | null;
}
interface StorageObject {
id: number;
storagespaceId: number;
name: string;
description: string | null;
serialnumber: string | null;
}
export const useStorageStore = defineStore('storage', {
state: () => ({
storageSpaces: [] as any[],
objects: [] as any[],
storageSpaces: [] as StorageSpace[],
objects: [] as StorageObject[],
loading: false,
error: null as string | null,
}),
getters: {
getStorageById: (state) => (id: number) => {
getStorageById: (state) => (id: number): StorageSpace | undefined => {
return state.storageSpaces.find(storage => storage.id === id);
},
getObjectsInStorage: (state) => (storageId: number) => {
getObjectsInStorage: (state) => (storageId: number): StorageObject[] => {
return state.objects.filter(obj => obj.storagespaceId === storageId);
},
getChildStorages: (state) => (parentId: number) => {
getChildStorages: (state) => (parentId: number): StorageSpace[] => {
return state.storageSpaces.filter(storage =>
storage.parent && storage.parent === parentId
storage.parent && storage.parent.valid && storage.parent.int64 === parentId
);
}
},
actions: {
async fetchStorageSpaces() {
async fetchStorageSpaces(): Promise<void> {
this.loading = true;
this.error = null;
@ -54,7 +72,7 @@ export const useStorageStore = defineStore('storage', {
}
},
async fetchObjectsInStorage(storageId: number) {
async fetchObjectsInStorage(storageId: number): Promise<void> {
this.loading = true;
this.error = null;
@ -70,7 +88,7 @@ export const useStorageStore = defineStore('storage', {
}
const data = await response.json();
this.objects = data;
this.objects = data as StorageObject[];
} catch (error: any) {
this.error = error.message;
throw error;
@ -79,7 +97,7 @@ export const useStorageStore = defineStore('storage', {
}
},
async fetchStorageHierarchy(rootStorageId: number) {
async fetchStorageHierarchy(rootStorageId: number): Promise<void> {
this.loading = true;
this.error = null;
@ -101,7 +119,7 @@ export const useStorageStore = defineStore('storage', {
}
const data = await response.json();
this.objects = data;
this.objects = data as StorageObject[];
} catch (error: any) {
this.error = error.message;
throw error;