Skip to content
Snippets Groups Projects
Commit 83a06cc3 authored by Daniel Göbel's avatar Daniel Göbel
Browse files

Filter Buckets and objects by their name

parent 35aae1b8
No related branches found
No related tags found
2 merge requests!22Version 1.0.0,!14Filter Buckets and objects by their name
......@@ -17,7 +17,7 @@ import CopyObjectModal from "@/components/Modals/CopyObjectModal.vue";
import PermissionModal from "@/components/Modals/PermissionModal.vue";
import ObjectDetailModal from "@/components/Modals/ObjectDetailModal.vue";
import CreateFolderModal from "@/components/Modals/CreateFolderModal.vue";
import DeleteModal from "@/components/Modals/DeleteModal.vue"
import DeleteModal from "@/components/Modals/DeleteModal.vue";
import {
S3Client,
DeleteObjectCommand,
......@@ -114,16 +114,25 @@ type FolderTree = {
// Reactive State
// -----------------------------------------------------------------------------
const deleteObjectsState = reactive({
deletedItem: "",
potentialObjectToDelete: "",
deleteFolder: true,
} as {
deletedItem: string;
potentialObjectToDelete: string;
deleteFolder: boolean;
});
const objectState = reactive({
objects: [],
loading: true,
filterString: "",
bucketNotFoundError: false,
bucketPermissionError: false,
createdPermission: undefined,
deletedItem: "",
editObjectKey: "",
potentialObjectToDelete: "",
deleteFolder: true,
copyObject: {
key: "",
size: 0,
......@@ -139,13 +148,11 @@ const objectState = reactive({
} as {
objects: S3ObjectMetaInformation[];
loading: boolean;
filterString: string;
bucketNotFoundError: boolean;
bucketPermissionError: boolean;
createdPermission: undefined | BucketPermission;
deletedItem: string;
editObjectKey: string;
potentialObjectToDelete: string;
deleteFolder: boolean;
copyObject: S3ObjectMetaInformation;
viewDetailObject: S3ObjectMetaInformation;
});
......@@ -164,6 +171,15 @@ watch(
// Computed Properties
// -----------------------------------------------------------------------------
const filteredObjects: ComputedRef<(S3ObjectWithFolder | S3PseudoFolder)[]> =
computed(() => {
return objectState.filterString.length > 0
? visibleObjects.value.filter((obj) =>
obj.key.includes(objectState.filterString)
)
: visibleObjects.value;
});
const folderStructure: ComputedRef<FolderTree> = computed(() => {
/**
* Store the entire folder structure in a bucket in a tree-like data structure
......@@ -394,8 +410,8 @@ function objectCopied(copiedObject: S3ObjectMetaInformation) {
}
function deleteObject(key: string) {
objectState.potentialObjectToDelete = key;
objectState.deleteFolder = false;
deleteObjectsState.potentialObjectToDelete = key;
deleteObjectsState.deleteFolder = false;
}
/**
......@@ -411,7 +427,7 @@ function confirmedDeleteObject(key: string) {
.send(command)
.then(() => {
const splittedKey = key.split("/");
objectState.deletedItem = splittedKey[splittedKey.length - 1];
deleteObjectsState.deletedItem = splittedKey[splittedKey.length - 1];
successToast?.show();
objectState.objects = objectState.objects.filter(
(obj) => obj.key !== key
......@@ -443,8 +459,8 @@ async function downloadObject(key: string, bucket: string) {
}
function deleteFolder(folderPath: string) {
objectState.potentialObjectToDelete = folderPath;
objectState.deleteFolder = true;
deleteObjectsState.potentialObjectToDelete = folderPath;
deleteObjectsState.deleteFolder = true;
}
/**
......@@ -466,7 +482,7 @@ function confirmedDeleteFolder(folderPath: string) {
.send(command)
.then(() => {
const splittedPath = folderPath.split("/");
objectState.deletedItem = splittedPath[splittedPath.length - 2];
deleteObjectsState.deletedItem = splittedPath[splittedPath.length - 2];
successToast?.show();
objectState.objects = objectState.objects.filter(
(obj) => !obj.key.startsWith(folderPath)
......@@ -510,7 +526,7 @@ watch(
>
<div class="d-flex">
<div class="toast-body">
Successfully deleted {{ objectState.deletedItem }}
Successfully deleted {{ deleteObjectsState.deletedItem }}
</div>
<button
type="button"
......@@ -524,9 +540,13 @@ watch(
<DeleteModal
modalID="delete-object-modal"
modal-label="some-label"
:object-name-delete="objectState.potentialObjectToDelete"
:object-name-delete="deleteObjectsState.potentialObjectToDelete"
:back-modal-id="undefined"
@confirm-delete="objectState.deleteFolder ? confirmedDeleteFolder(objectState.potentialObjectToDelete) : confirmedDeleteObject(objectState.potentialObjectToDelete)"
@confirm-delete="
deleteObjectsState.deleteFolder
? confirmedDeleteFolder(deleteObjectsState.potentialObjectToDelete)
: confirmedDeleteObject(deleteObjectsState.potentialObjectToDelete)
"
/>
<!-- Navbar Breadcrumb -->
<nav aria-label="breadcrumb" class="fs-2">
......@@ -577,7 +597,7 @@ watch(
placeholder="Search Objects"
aria-label="Search Objects"
aria-describedby="objects-search-wrapping"
disabled
v-model.trim="objectState.filterString"
/>
</div>
</div>
......@@ -723,8 +743,8 @@ watch(
<td></td>
</tr>
</tbody>
<!-- Table body when no objects are in the bcuket -->
<tbody v-else-if="visibleObjects.length === 0">
<!-- Table body when no objects are in the bucket -->
<tbody v-else-if="filteredObjects.length === 0">
<tr>
<td colspan="4" class="text-center fst-italic fw-light">
No objects to display
......@@ -733,7 +753,7 @@ watch(
</tbody>
<!-- Table body when showing objects -->
<tbody v-else>
<tr v-for="obj in visibleObjects" :key="obj.key">
<tr v-for="obj in filteredObjects" :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>
......
......@@ -18,11 +18,13 @@ const authStore = useAuthStore();
const bucketsState = reactive({
buckets: [],
permissions: {},
filterString: "",
potentialDeleteBucketName: "",
loading: true,
} as {
buckets: BucketOut[];
loading: boolean;
filterString: string;
permissions: Record<string, BucketPermission>;
potentialDeleteBucketName: string;
});
......@@ -63,6 +65,14 @@ const currentPermission: ComputedRef<BucketPermission | undefined> = computed(
}
);
const filteredBuckets: ComputedRef<BucketOut[]> = computed(() => {
return bucketsState.filterString.length > 0
? bucketsState.buckets.filter((bucket) =>
bucket.name.includes(bucketsState.filterString)
)
: bucketsState.buckets;
});
function addBucket(bucket: BucketOut) {
bucketsState.buckets.push(bucket);
}
......@@ -143,25 +153,38 @@ onMounted(() => {
placeholder="Search Buckets"
aria-label="Search Buckets"
aria-describedby="buckets-search-wrapping"
disabled
v-model.trim="bucketsState.filterString"
/>
</div>
<div class="list-group mt-3">
<div v-if="!bucketsState.loading">
<bucket-list-item
v-for="bucket in bucketsState.buckets"
:key="bucket.name"
:active="
route.params.bucketName != null &&
route.params.bucketName === bucket.name
"
:bucket="bucket"
:loading="false"
:permission="bucketsState.permissions[bucket.name]"
@delete-bucket="deleteBucket"
@permission-deleted="(bucketName) => bucketDeleted(bucketName)"
/>
<div v-if="filteredBuckets.length > 0">
<bucket-list-item
v-for="bucket in filteredBuckets"
:key="bucket.name"
:active="
route.params.bucketName != null &&
route.params.bucketName === bucket.name
"
:bucket="bucket"
:loading="false"
:permission="bucketsState.permissions[bucket.name]"
@delete-bucket="deleteBucket"
@permission-deleted="(bucketName) => bucketDeleted(bucketName)"
/>
</div>
<div v-else class="text-center fs-2 mt-5">
<bootstrap-icon
icon="search"
class="mb-2"
:width="56"
:height="56"
style="color: var(--bs-secondary)"
fill="currentColor"
/><br />
Could not find any Buckets
</div>
</div>
<div v-else>
<bucket-list-item
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment