Skip to content
Snippets Groups Projects

Resolve "Refactor buckets into pinia store"

Merged Daniel Göbel requested to merge feature/29-refactor-buckets-into-pinia-store into development
3 files
+ 48
4
Compare changes
  • Side-by-side
  • Inline
Files
3
<script setup lang="ts">
import { onMounted, reactive, watch, computed } from "vue";
import type { ComputedRef } from "vue";
import type { S3ObjectMetaInformation, BucketPermissionOut } from "@/client";
import type {
S3ObjectMetaInformation,
BucketPermissionOut,
BucketOut,
} from "@/client";
FolderTree,
S3PseudoFolder,
S3ObjectWithFolder,
} from "@/types/PseudoFolder";
import { ObjectService } from "@/client";
import BootstrapIcon from "@/components/BootstrapIcon.vue";
import { filesize } from "filesize";
@@ -27,8 +28,10 @@ import {
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { awsAuthMiddlewareOptions } from "@aws-sdk/middleware-signing";
import { useAuthStore } from "@/stores/auth";
import { useBucketStore } from "@/stores/buckets";
const authStore = useAuthStore();
const bucketRepository = useBucketStore();
const middleware = [
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -51,7 +54,6 @@ let client = new S3Client({
accessKeyId: authStore.s3key?.access_key ?? "",
secretAccessKey: authStore.s3key?.secret_key ?? "",
},
tls: import.meta.env.VITE_S3_URL.startsWith("https"),
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
@@ -71,7 +73,6 @@ authStore.$onAction(({ name, args }) => {
accessKeyId: args[0].access_key,
secretAccessKey: args[0].secret_key,
},
tls: import.meta.env.VITE_S3_URL.startsWith("https"),
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
@@ -87,31 +88,10 @@ const props = defineProps<{
bucketName: string;
subFolders: string[] | string;
permission: BucketPermissionOut | undefined;
writableBuckets: BucketOut[];
}>();
const randomIDSuffix = Math.random().toString(16).substr(2, 8);
let successToast: Toast | null = null;
// Typescript types
// -----------------------------------------------------------------------------
interface S3ObjectWithFolder extends S3ObjectMetaInformation {
folder: string[];
pseudoFileName: string;
}
type S3PseudoFolder = {
size: number;
parentFolder: string[];
last_modified: string;
name: string;
key: string;
};
type FolderTree = {
subFolders: Record<string, FolderTree>;
files: S3ObjectWithFolder[];
};
// Reactive State
// -----------------------------------------------------------------------------
@@ -167,6 +147,7 @@ watch(
if (oldBucketName !== newBucketName) {
// If bucket is changed, update the objects
updateObjects(newBucketName);
objectState.filterString = "";
}
}
);
@@ -298,10 +279,8 @@ const subFolderInUrl: ComputedRef<boolean> = computed(
const errorLoadingObjects: ComputedRef<boolean> = computed(
() => objectState.bucketPermissionError || objectState.bucketNotFoundError
);
const writeS3Permission: ComputedRef<boolean> = computed(
() =>
props.permission == undefined || props.permission.permission == "READWRITE"
const writableBucket: ComputedRef<boolean> = computed(() =>
bucketRepository.writableBucket(props.bucketName)
);
// Lifecycle Hooks
@@ -391,9 +370,10 @@ function isS3Object(
* @param newObject Uploaded object
*/
function objectUploaded(newObject: S3ObjectMetaInformation) {
const index = objectState.objects
.map((obj) => obj.key)
.indexOf(newObject.key);
bucketRepository.fetchBucket(newObject.bucket);
const index = objectState.objects.findIndex(
(obj) => obj.key === newObject.key
);
if (index > -1) {
objectState.objects[index] = newObject;
} else {
@@ -406,6 +386,7 @@ function objectUploaded(newObject: S3ObjectMetaInformation) {
* @param copiedObject Uploaded object
*/
function objectCopied(copiedObject: S3ObjectMetaInformation) {
bucketRepository.fetchBucket(copiedObject.bucket);
if (copiedObject.bucket === props.bucketName) {
objectState.objects.push(copiedObject);
}
@@ -428,6 +409,7 @@ function confirmedDeleteObject(key: string) {
client
.send(command)
.then(() => {
bucketRepository.fetchBucket(props.bucketName);
const splittedKey = key.split("/");
deleteObjectsState.deletedItem = splittedKey[splittedKey.length - 1];
successToast?.show();
@@ -483,6 +465,7 @@ function confirmedDeleteFolder(folderPath: string) {
client
.send(command)
.then(() => {
bucketRepository.fetchBucket(props.bucketName);
const splittedPath = folderPath.split("/");
deleteObjectsState.deletedItem = splittedPath[splittedPath.length - 2];
successToast?.show();
@@ -598,6 +581,7 @@ watch(
placeholder="Search Objects"
aria-label="Search Objects"
aria-describedby="objects-search-wrapping"
:disabled="errorLoadingObjects"
v-model.trim="objectState.filterString"
/>
</div>
@@ -607,7 +591,7 @@ watch(
<button
type="button"
class="btn btn-secondary me-2 tooltip-container"
:disabled="errorLoadingObjects || !writeS3Permission"
:disabled="errorLoadingObjects || !writableBucket"
data-bs-toggle="modal"
data-bs-title="Upload Object"
data-bs-target="#upload-object-modal"
@@ -627,7 +611,7 @@ watch(
<button
type="button"
class="btn btn-secondary m-2 tooltip-container"
:disabled="errorLoadingObjects || !writeS3Permission"
:disabled="errorLoadingObjects || !writableBucket"
data-bs-toggle="modal"
data-bs-title="Create Folder"
data-bs-target="#create-folder-modal"
@@ -645,7 +629,7 @@ watch(
/>
<!-- Add bucket permission button -->
<button
:hidden="props.permission != null"
:hidden="bucketRepository.getBucketPermission(props.bucketName) != null"
type="button"
class="btn btn-secondary m-2 tooltip-container"
:disabled="errorLoadingObjects"
@@ -675,7 +659,7 @@ watch(
"
/>
<button
:hidden="props.permission != null"
:hidden="bucketRepository.getBucketPermission(props.bucketName) != null"
type="button"
class="btn btn-secondary m-2 tooltip-container"
:disabled="errorLoadingObjects"
@@ -692,7 +676,7 @@ watch(
<span class="visually-hidden">View Bucket Permissions</span>
</button>
<permission-list-modal
v-if="props.permission == null"
v-if="bucketRepository.getBucketPermission(props.bucketName) == null"
:bucket-name="props.bucketName"
:sub-folders="folderStructure"
modalID="permission-list-modal"
@@ -703,12 +687,33 @@ watch(
<!-- Body -->
<div class="pt-3">
<!-- If bucket not found -->
<div v-if="objectState.bucketNotFoundError">
<p>Bucket not found</p>
<div v-if="objectState.bucketNotFoundError" class="text-center fs-2 mt-5">
<bootstrap-icon
icon="search"
class="mb-3"
:width="64"
:height="64"
style="color: var(--bs-secondary)"
fill="currentColor"
/>
<p>
Bucket <i>{{ props.bucketName }}</i> not found
</p>
</div>
<!-- If no permission for bucket -->
<div v-else-if="objectState.bucketPermissionError">
<p>No permission for this bucket</p>
<div
v-else-if="objectState.bucketPermissionError"
class="text-center fs-2 mt-5"
>
<bootstrap-icon
icon="folder-x"
class="mb-3"
:width="64"
:height="64"
style="color: var(--bs-secondary)"
fill="currentColor"
/>
<p>You don't have permission for this bucket</p>
</div>
<!-- Show content of bucket -->
<div v-else>
@@ -719,7 +724,7 @@ watch(
<caption>
Displaying
{{
objectState.loading ? 0 : visibleObjects.length
objectState.loading ? 0 : filteredObjects.length
}}
Objects
</caption>
@@ -821,7 +826,7 @@ watch(
<button
class="dropdown-item"
type="button"
:disabled="!writeS3Permission"
:disabled="!writableBucket"
data-bs-toggle="modal"
data-bs-target="#edit-object-modal"
@click="objectState.editObjectKey = obj.key"
@@ -833,7 +838,7 @@ watch(
<button
class="dropdown-item"
type="button"
:disabled="!writeS3Permission"
:disabled="!writableBucket"
data-bs-toggle="modal"
data-bs-target="#copy-object-modal"
@click="objectState.copyObject = obj"
@@ -848,7 +853,7 @@ watch(
@click="deleteObject(obj.key)"
data-bs-toggle="modal"
data-bs-target="#delete-object-modal"
:disabled="!writeS3Permission"
:disabled="!writableBucket"
>
<bootstrap-icon
icon="trash-fill"
@@ -867,7 +872,7 @@ watch(
<button
type="button"
class="btn btn-danger btn-sm align-middle"
:disabled="!writeS3Permission"
:disabled="!writableBucket"
data-bs-toggle="modal"
data-bs-target="#delete-object-modal"
@click="
@@ -902,7 +907,6 @@ watch(
:source-object="objectState.copyObject"
:s3-client="client"
modalID="copy-object-modal"
:available-buckets="props.writableBuckets"
@object-copied="objectCopied"
/>
<object-detail-modal
Loading