refactor: Convert StorageHierarchy component to TypeScript with proper typing
This commit is contained in:
parent
e3d8f9e8ee
commit
9213034093
2 changed files with 125 additions and 86 deletions
|
@ -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,24 +99,25 @@ const StorageBox = defineComponent({
|
|||
);
|
||||
});
|
||||
|
||||
return () => (
|
||||
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>{ props.storage.location || `Storage #${props.storage.id}` }</span>
|
||||
<span>{{ storage.location || \`Storage #\${storage.id}\` }}</span>
|
||||
<v-chip class="ml-2" size="small" color="primary" variant="outlined">
|
||||
{ objectsInCurrentStorage.value.length } objects
|
||||
{{ 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>
|
||||
{objectsInCurrentStorage.value.length > 0 ? (
|
||||
<v-list lines="two">
|
||||
{objectsInCurrentStorage.value.map(obj => (
|
||||
<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'"
|
||||
|
@ -99,60 +127,53 @@ const StorageBox = defineComponent({
|
|||
</template>
|
||||
<template v-slot:append>
|
||||
<v-chip size="small" color="grey" variant="flat">
|
||||
SN: { obj.serialnumber || 'N/A' }
|
||||
SN: {{ obj.serialnumber || 'N/A' }}
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-list-item>
|
||||
))}
|
||||
</v-list>
|
||||
) : (
|
||||
<v-alert type="info" variant="tonal" density="compact">
|
||||
<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">
|
||||
<div v-if="childStorages.length > 0" 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}
|
||||
<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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue