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>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, watch, onMounted, defineComponent } from 'vue';
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
import { useStorageStore } from '@/stores/storage';
|
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({
|
const StorageBox = defineComponent({
|
||||||
name: 'StorageBox',
|
name: 'StorageBox',
|
||||||
props: {
|
props: {
|
||||||
storage: Object,
|
storage: {
|
||||||
objects: Array,
|
type: Object as () => StorageSpace,
|
||||||
nestedStorages: Array
|
required: true
|
||||||
|
},
|
||||||
|
objects: {
|
||||||
|
type: Array as () => StorageObject[],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
nestedStorages: {
|
||||||
|
type: Array as () => StorageSpace[],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const objectsInCurrentStorage = computed(() => {
|
const objectsInCurrentStorage = computed(() => {
|
||||||
|
@ -72,87 +99,81 @@ const StorageBox = defineComponent({
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => (
|
return { objectsInCurrentStorage, childStorages };
|
||||||
<v-expansion-panel>
|
},
|
||||||
<v-expansion-panel-title>
|
template: `
|
||||||
<div class="d-flex align-center">
|
<v-expansion-panel>
|
||||||
<v-icon class="mr-2">mdi-package-variant-closed</v-icon>
|
<v-expansion-panel-title>
|
||||||
<span>{ props.storage.location || `Storage #${props.storage.id}` }</span>
|
<div class="d-flex align-center">
|
||||||
<v-chip class="ml-2" size="small" color="primary" variant="outlined">
|
<v-icon class="mr-2">mdi-package-variant-closed</v-icon>
|
||||||
{ objectsInCurrentStorage.value.length } objects
|
<span>{{ storage.location || \`Storage #\${storage.id}\` }}</span>
|
||||||
</v-chip>
|
<v-chip class="ml-2" size="small" color="primary" variant="outlined">
|
||||||
</div>
|
{{ objectsInCurrentStorage.length }} objects
|
||||||
</v-expansion-panel-title>
|
</v-chip>
|
||||||
<v-expansion-panel-text>
|
</div>
|
||||||
<div class="mb-4">
|
</v-expansion-panel-title>
|
||||||
<h3 class="text-subtitle-1 mb-2">Objects in this storage:</h3>
|
<v-expansion-panel-text>
|
||||||
{objectsInCurrentStorage.value.length > 0 ? (
|
<div class="mb-4">
|
||||||
<v-list lines="two">
|
<h3 class="text-subtitle-1 mb-2">Objects in this storage:</h3>
|
||||||
{objectsInCurrentStorage.value.map(obj => (
|
<v-list v-if="objectsInCurrentStorage.length > 0" lines="two">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
:key="obj.id"
|
v-for="obj in objectsInCurrentStorage"
|
||||||
:title="obj.name"
|
:key="obj.id"
|
||||||
:subtitle="obj.description || 'No description'"
|
:title="obj.name"
|
||||||
>
|
:subtitle="obj.description || 'No description'"
|
||||||
<template v-slot:prepend>
|
>
|
||||||
<v-icon>mdi-cube-outline</v-icon>
|
<template v-slot:prepend>
|
||||||
</template>
|
<v-icon>mdi-cube-outline</v-icon>
|
||||||
<template v-slot:append>
|
</template>
|
||||||
<v-chip size="small" color="grey" variant="flat">
|
<template v-slot:append>
|
||||||
SN: { obj.serialnumber || 'N/A' }
|
<v-chip size="small" color="grey" variant="flat">
|
||||||
</v-chip>
|
SN: {{ obj.serialnumber || 'N/A' }}
|
||||||
</template>
|
</v-chip>
|
||||||
</v-list-item>
|
</template>
|
||||||
))}
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
) : (
|
<v-alert v-else type="info" variant="tonal" density="compact">
|
||||||
<v-alert type="info" variant="tonal" density="compact">
|
No objects in this storage
|
||||||
No objects in this storage
|
</v-alert>
|
||||||
</v-alert>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
<div v-if="childStorages.length > 0" class="mt-4">
|
||||||
|
<h3 class="text-subtitle-1 mb-2">Nested storage spaces:</h3>
|
||||||
{childStorages.value.length > 0 && (
|
<v-expansion-panels>
|
||||||
<div class="mt-4">
|
<storage-box
|
||||||
<h3 class="text-subtitle-1 mb-2">Nested storage spaces:</h3>
|
v-for="childStorage in childStorages"
|
||||||
<v-expansion-panels>
|
:key="childStorage.id"
|
||||||
{childStorages.value.map(childStorage => (
|
:storage="childStorage"
|
||||||
<StorageBox
|
:objects="objects"
|
||||||
key={childStorage.id}
|
:nested-storages="nestedStorages"
|
||||||
storage={childStorage}
|
/>
|
||||||
objects={props.objects}
|
</v-expansion-panels>
|
||||||
nestedStorages={props.nestedStorages}
|
</div>
|
||||||
/>
|
</v-expansion-panel-text>
|
||||||
))}
|
</v-expansion-panel>
|
||||||
</v-expansion-panels>
|
`
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</v-expansion-panel-text>
|
|
||||||
</v-expansion-panel>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Main component logic
|
// Main component logic
|
||||||
const storageStore = useStorageStore();
|
const storageStore = useStorageStore();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const error = ref(null);
|
const error = ref<string | null>(null);
|
||||||
const selectedStorageId = ref(null);
|
const selectedStorageId = ref<number | null>(null);
|
||||||
|
|
||||||
const storageSpaces = computed(() => storageStore.storageSpaces);
|
const storageSpaces = computed<StorageSpace[]>(() => storageStore.storageSpaces);
|
||||||
const objects = computed(() => storageStore.objects);
|
const objects = computed<StorageObject[]>(() => storageStore.objects);
|
||||||
|
|
||||||
const selectedStorage = computed(() => {
|
const selectedStorage = computed<StorageSpace | null>(() => {
|
||||||
if (!selectedStorageId.value) return 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 [];
|
if (!selectedStorageId.value) return [];
|
||||||
return objects.value;
|
return objects.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const nestedStorages = computed(() => {
|
const nestedStorages = computed<StorageSpace[]>(() => {
|
||||||
return storageSpaces.value;
|
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;
|
loading.value = true;
|
||||||
error.value = null;
|
error.value = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await storageStore.fetchStorageHierarchy(storageId);
|
await storageStore.fetchStorageHierarchy(storageId);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
error.value = err.message || 'Failed to load storage data';
|
error.value = err.message || 'Failed to load storage data';
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -184,7 +205,7 @@ onMounted(async () => {
|
||||||
if (storageSpaces.value.length > 0) {
|
if (storageSpaces.value.length > 0) {
|
||||||
selectedStorageId.value = storageSpaces.value[0].id;
|
selectedStorageId.value = storageSpaces.value[0].id;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
error.value = err.message || 'Failed to load storage spaces';
|
error.value = err.message || 'Failed to load storage spaces';
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|
|
@ -1,31 +1,49 @@
|
||||||
import { defineStore } from 'pinia';
|
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', {
|
export const useStorageStore = defineStore('storage', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
storageSpaces: [] as any[],
|
storageSpaces: [] as StorageSpace[],
|
||||||
objects: [] as any[],
|
objects: [] as StorageObject[],
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null as string | null,
|
error: null as string | null,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
getStorageById: (state) => (id: number) => {
|
getStorageById: (state) => (id: number): StorageSpace | undefined => {
|
||||||
return state.storageSpaces.find(storage => storage.id === id);
|
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);
|
return state.objects.filter(obj => obj.storagespaceId === storageId);
|
||||||
},
|
},
|
||||||
|
|
||||||
getChildStorages: (state) => (parentId: number) => {
|
getChildStorages: (state) => (parentId: number): StorageSpace[] => {
|
||||||
return state.storageSpaces.filter(storage =>
|
return state.storageSpaces.filter(storage =>
|
||||||
storage.parent && storage.parent === parentId
|
storage.parent && storage.parent.valid && storage.parent.int64 === parentId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
async fetchStorageSpaces() {
|
async fetchStorageSpaces(): Promise<void> {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.error = null;
|
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.loading = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
|
@ -70,7 +88,7 @@ export const useStorageStore = defineStore('storage', {
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.objects = data;
|
this.objects = data as StorageObject[];
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.error = error.message;
|
this.error = error.message;
|
||||||
throw error;
|
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.loading = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
|
@ -101,7 +119,7 @@ export const useStorageStore = defineStore('storage', {
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.objects = data;
|
this.objects = data as StorageObject[];
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.error = error.message;
|
this.error = error.message;
|
||||||
throw error;
|
throw error;
|
||||||
|
|
Loading…
Add table
Reference in a new issue