From bd39d403a5f41e4799c5e682cb5cb3923d4ba1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20G=C3=B6bel?= <dgoebel@techfak.uni-bielefeld.de> Date: Mon, 8 Aug 2022 17:42:16 +0200 Subject: [PATCH] Refactor the Bucket view to decouple it from the route parameters #17 --- src/components/BucketView.vue | 145 +++++++++++++++++----------------- src/router/index.ts | 1 + 2 files changed, 72 insertions(+), 74 deletions(-) diff --git a/src/components/BucketView.vue b/src/components/BucketView.vue index d45d20f..ba9ad1c 100644 --- a/src/components/BucketView.vue +++ b/src/components/BucketView.vue @@ -1,5 +1,4 @@ <script setup lang="ts"> -import { useRoute } from "vue-router"; import { onMounted, reactive, watch, computed } from "vue"; import type { ComputedRef } from "vue"; import type { S3ObjectMetaInformation } from "@/client"; @@ -10,7 +9,23 @@ import dayjs from "dayjs"; // Constants // ----------------------------------------------------------------------------- -const route = useRoute(); + +const props = defineProps<{ + bucketName: string; + subFolders: string[] | string; +}>(); + +const currentSubFolders: ComputedRef<string[]> = computed(() => { + /** + * Transform a single sub folder from a string to an array containing the string and + * replace an empty string with an empty list + */ + return props.subFolders instanceof Array + ? props.subFolders + : props.subFolders.length > 0 + ? [props.subFolders] + : []; +}); // Typescript types // ----------------------------------------------------------------------------- @@ -36,13 +51,11 @@ type FolderTree = { // ----------------------------------------------------------------------------- const objectState = reactive({ objects: [], - visibleObjects: [], loading: true, bucketNotFoundError: false, bucketPermissionError: false, } as { objects: S3ObjectMetaInformation[]; - visibleObjects: (S3ObjectWithFolder | S3PseudoFolder)[]; loading: boolean; bucketNotFoundError: boolean; bucketPermissionError: boolean; @@ -51,33 +64,15 @@ const objectState = reactive({ // Watcher // ----------------------------------------------------------------------------- watch( - () => route.params, - (newRouteParams, oldRouteParams) => { - if ( - newRouteParams.bucketName && - oldRouteParams.bucketName !== newRouteParams.bucketName - ) { + () => props.bucketName, + (newBucketName, oldBucketName) => { + if (oldBucketName !== newBucketName) { // If bucket is changed, update the objects - updateObjects(newRouteParams.bucketName as string); - } else if ( - newRouteParams.subFolders && - oldRouteParams.subFolders !== newRouteParams.subFolders - ) { - // If sub folder is changed, update the visible objects - updateVisibleObjects(newRouteParams.subFolders as string[]); + updateObjects(newBucketName); } } ); -watch( - () => objectState.objects, - () => { - updateVisibleObjects( - subFolderInUrl.value ? (route.params.subFolders as string[]) : [] - ); - } -); - // Computed Properties // ----------------------------------------------------------------------------- const folderStructure: ComputedRef<FolderTree> = computed(() => { @@ -141,7 +136,7 @@ const objectsWithFolders: ComputedRef<S3ObjectWithFolder[]> = computed(() => { }); const subFolderInUrl: ComputedRef<boolean> = computed( - () => route.params.subFolders != null && route.params.subFolders.length > 0 + () => currentSubFolders.value.length > 0 ); const errorLoadingObjects: ComputedRef<boolean> = computed( () => objectState.bucketPermissionError || objectState.bucketNotFoundError @@ -150,7 +145,7 @@ const errorLoadingObjects: ComputedRef<boolean> = computed( // Lifecycle Hooks // ----------------------------------------------------------------------------- onMounted(() => { - updateObjects(route.params.bucketName as string); + updateObjects(props.bucketName); }); // Functions @@ -217,41 +212,43 @@ function updateObjects(bucketName: string) { }); } -/** - * Update the visible objects based on the current sub folder - * @param subFolders sub folders as ordered array - */ -function updateVisibleObjects(subFolders: string[]) { - objectState.visibleObjects = []; - let currentFolder = folderStructure.value; - for (const subFolder of subFolders) { - if (currentFolder.subFolders[subFolder] == null) { - return; - } else { - currentFolder = currentFolder.subFolders[subFolder]; +const visibleObjects: ComputedRef<(S3ObjectWithFolder | S3PseudoFolder)[]> = + computed(() => { + /** + * Compute the visible objects based on the current sub folder + */ + let currentFolder = folderStructure.value; + // Navigate into right sub folder + for (const subFolder of currentSubFolders.value) { + if (currentFolder.subFolders[subFolder] == null) { + // If sub folder doesn't exist, no object is visible + return []; + } else { + currentFolder = currentFolder.subFolders[subFolder]; + } } - } - const arr = []; - arr.push(...currentFolder.files); - arr.push( - ...Object.keys(currentFolder.subFolders).map((subFolderName) => { - const folderSize = calculateFolderSize( - currentFolder.subFolders[subFolderName] - ); - const folderLastModified = dayjs( - calculateFolderLastModified(currentFolder.subFolders[subFolderName]) - ).toISOString(); - return { - name: subFolderName, - size: folderSize, - key: subFolderName, - parentFolder: subFolders, - last_modified: folderLastModified, - } as S3PseudoFolder; - }) - ); - objectState.visibleObjects = arr; -} + // Add all objects and sub folders from the current sub folder as visible object + const arr = []; + arr.push(...currentFolder.files); + arr.push( + ...Object.keys(currentFolder.subFolders).map((subFolderName) => { + const folderSize = calculateFolderSize( + currentFolder.subFolders[subFolderName] + ); + const folderLastModified = dayjs( + calculateFolderLastModified(currentFolder.subFolders[subFolderName]) + ).toISOString(); + return { + name: subFolderName, + size: folderSize, + key: subFolderName, + parentFolder: currentSubFolders.value, + last_modified: folderLastModified, + } as S3PseudoFolder; + }) + ); + return arr; + }); function isS3Object( obj: S3PseudoFolder | S3ObjectWithFolder @@ -269,25 +266,25 @@ function isS3Object( v-if="subFolderInUrl" :to="{ name: 'bucket', - params: { bucketName: route.params.bucketName, subFolders: [] }, + params: { bucketName: props.bucketName, subFolders: [] }, }" - >{{ route.params.bucketName }} + >{{ props.bucketName }} </router-link> - <span v-else>{{ route.params.bucketName }}</span> + <span v-else>{{ props.bucketName }}</span> </li> <li class="breadcrumb-item" - v-for="(folder, index) in route.params.subFolders" + v-for="(folder, index) in currentSubFolders" :key="folder" - :class="{ active: index === route.params.subFolders.length }" + :class="{ active: index === currentSubFolders.length }" > <router-link - v-if="index !== route.params.subFolders.length - 1" + v-if="index !== currentSubFolders.length - 1" :to="{ name: 'bucket', params: { - bucketName: route.params.bucketName, - subFolders: route.params.subFolders.slice(0, index + 1), + bucketName: props.bucketName, + subFolders: currentSubFolders.slice(0, index + 1), }, }" >{{ folder }} @@ -363,7 +360,7 @@ function isS3Object( <caption> Displaying {{ - objectState.loading ? 0 : objectState.visibleObjects.length + objectState.loading ? 0 : visibleObjects.length }} Objects </caption> @@ -387,7 +384,7 @@ function isS3Object( </tr> </tbody> <!-- Table body when no objects are in the bcuket --> - <tbody v-else-if="objectState.visibleObjects.length === 0"> + <tbody v-else-if="visibleObjects.length === 0"> <tr> <td colspan="4" class="text-center fst-italic fw-light"> No objects to display @@ -396,7 +393,7 @@ function isS3Object( </tbody> <!-- Table body when showing objects --> <tbody v-else> - <tr v-for="obj in objectState.visibleObjects" :key="obj.key"> + <tr v-for="obj in visibleObjects" :key="obj.key"> <th scope="row" class="text-truncate"> <!-- Show file name if row is an object --> <div v-if="isS3Object(obj)">{{ obj.pseudoFileName }}</div> @@ -407,7 +404,7 @@ function isS3Object( :to="{ name: 'bucket', params: { - bucketName: route.params.bucketName, + bucketName: props.bucketName, subFolders: obj.parentFolder.concat(obj.name), }, }" diff --git a/src/router/index.ts b/src/router/index.ts index 1c4428c..15fec02 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -19,6 +19,7 @@ const router = createRouter({ path: ":bucketName/:subFolders*", name: "bucket", component: () => import("../components/BucketView.vue"), + props: true, }, ], }, -- GitLab