From 56ac322ed111ada3fcd4cfef0ab017628c9cf803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20G=C3=B6bel?= <dgoebel@techfak.uni-bielefeld.de> Date: Wed, 17 Aug 2022 11:42:06 +0200 Subject: [PATCH] Add ability to delete a permission in the permission modal #19 --- src/components/BucketListItem.vue | 9 ++- src/components/BucketView.vue | 1 + src/components/PermissionModal.vue | 86 +++++++++++++++++++++--- src/views/object-storage/BucketsView.vue | 17 +++-- 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/src/components/BucketListItem.vue b/src/components/BucketListItem.vue index dd79c9a..69b1069 100644 --- a/src/components/BucketListItem.vue +++ b/src/components/BucketListItem.vue @@ -17,7 +17,8 @@ const props = defineProps<{ const tooltipID = Math.random().toString(16).substr(2, 8); const emit = defineEmits<{ - (e: "delete-bucket", bucket_name: string): void; + (e: "delete-bucket", bucketName: string): void; + (e: "permission-deleted", bucketName: string): void; }>(); onMounted(() => { @@ -37,6 +38,8 @@ onMounted(() => { :edit-user-permission="props.permission" :readonly="true" :editable="false" + :deletable="true" + @permission-deleted="(bucketName) => emit('permission-deleted', bucketName)" /> <div class="mt-2 mb-2"> <div @@ -72,9 +75,9 @@ onMounted(() => { </router-link> <div :hidden="!props.active" - class="ps-2 rounded-bottom bg-light text-bg-light" + class="ps-2 pe-2 rounded-bottom bg-light text-bg-light border border-3 border-top-0 border-primary" > - <table class="table table-sm table-borderless"> + <table class="table table-sm table-borderless mb-0"> <tbody> <tr> <th scope="row" class="fw-bold">Created:</th> diff --git a/src/components/BucketView.vue b/src/components/BucketView.vue index 21fe2c3..acec756 100644 --- a/src/components/BucketView.vue +++ b/src/components/BucketView.vue @@ -364,6 +364,7 @@ watch( :edit-user-permission="undefined" :editable="false" :readonly="false" + :deletable="false" /> <!-- Add folder button --> <button diff --git a/src/components/PermissionModal.vue b/src/components/PermissionModal.vue index 9adb360..b850422 100644 --- a/src/components/PermissionModal.vue +++ b/src/components/PermissionModal.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import { onMounted, reactive, watch, computed } from "vue"; +import { onMounted, reactive, watch, ref, computed, defineEmits } from "vue"; import BootstrapModal from "@/components/BootstrapModal.vue"; import { Modal } from "bootstrap"; import dayjs from "dayjs"; @@ -8,7 +8,7 @@ import type { S3ObjectMetaInformation, BucketPermissionParameters, } from "@/client"; -import type { ComputedRef } from "vue"; +import type { ComputedRef, Ref } from "vue"; import { PermissionEnum, BucketPermissionsService } from "@/client"; import { Toast } from "bootstrap"; import BootstrapIcon from "@/components/BootstrapIcon.vue"; @@ -35,12 +35,13 @@ const props = defineProps<{ editUserPermission: BucketPermission | undefined; readonly: boolean; editable: boolean; + deletable: boolean; }>(); // Variables // ----------------------------------------------------------------------------- const toastID = Math.random().toString(16).substr(2, 8); -let createPermissionModal: Modal | null = null; +let permissionModal: Modal | null = null; let successToast: Toast | null = null; // Reactive State @@ -64,6 +65,8 @@ const permission = reactive({ bucket_name: props.bucketName, } as BucketPermission); +const permissionDeleted: Ref<boolean> = ref(false); + // Computes Properties // ----------------------------------------------------------------------------- const editPermission: ComputedRef<boolean> = computed( @@ -93,6 +96,12 @@ watch( () => updatePermission() ); +// Events +// ----------------------------------------------------------------------------- +const emit = defineEmits<{ + (e: "permission-deleted", bucket_name: string): void; +}>(); + // Functions // ----------------------------------------------------------------------------- /** @@ -107,7 +116,14 @@ function modalClosed() { } /** - * Check if a input should be visible based on its state + * Callback when the toast is hidden again. + */ +function toastHidden() { + permissionDeleted.value = false; +} + +/** + * Check if an input should be visible based on its state * @param input Input which visibility should be determined. */ function inputVisible(input: string | undefined): boolean { @@ -204,12 +220,39 @@ function formSubmit() { ); serverAnswerPromise .then(() => { - createPermissionModal?.hide(); + permissionModal?.hide(); + successToast?.show(); + updatePermission(); + }) + .catch(() => { + formState.error = true; + }) + .finally(() => { + formState.loading = false; + }); + } +} + +/** + * Delete a permission for a bucket user combination + * @param bucketName Bucket to delete + * @param uid ID of grantee of the permission + */ +function deletePermission(bucketName: string, uid: string) { + if (!formState.loading) { + formState.loading = true; + BucketPermissionsService.bucketPermissionsDeletePermissionForBucket( + bucketName, + uid + ) + .then(() => { + permissionDeleted.value = true; + permissionModal?.hide(); successToast?.show(); + emit("permission-deleted", bucketName); }) - .catch((err) => { + .catch(() => { formState.error = true; - console.error(err); }) .finally(() => { formState.loading = false; @@ -220,7 +263,7 @@ function formSubmit() { // Lifecycle Hooks // ----------------------------------------------------------------------------- onMounted(() => { - createPermissionModal = new Modal("#" + props.modalID); + permissionModal = new Modal("#" + props.modalID); successToast = new Toast("#" + "toast-" + toastID, { autohide: true }); updatePermission(); }); @@ -235,12 +278,14 @@ onMounted(() => { class="toast text-bg-success align-items-center border-0" data-bs-autohide="false" :id="'toast-' + toastID" + v-on="{ 'hidden.bs.toast': toastHidden }" > <div class="d-flex"> <div class="toast-body"> Successfully - <span v-if="editPermission">created</span> - <span v-else>edited</span> + <span v-if="permissionDeleted">deleted</span> + <span v-else-if="editPermission">edited</span> + <span v-else>created</span> Permission </div> <button @@ -265,8 +310,19 @@ onMounted(() => { >Edit Permission </template> <template v-slot:header v-else> Create new Permission </template> - <template v-slot:extra-button v-if="formState.readonly && props.editable"> + <template v-slot:extra-button> + <bootstrap-icon + v-if="props.deletable" + icon="trash-fill" + :height="15" + :width="15" + fill="currentColor" + class="me-2" + :class="{ 'delete-icon': !formState.loading }" + @click="deletePermission(permission.bucket_name, permission.uid)" + /> <bootstrap-icon + v-if="formState.readonly && props.editable" icon="pencil-fill" :height="15" :width="15" @@ -438,4 +494,12 @@ onMounted(() => { .pseudo-link:hover { color: var(--bs-primary); } + +.delete-icon { + color: var(--bs-secondary); + cursor: pointer; +} +.delete-icon:hover { + color: var(--bs-danger); +} </style> diff --git a/src/views/object-storage/BucketsView.vue b/src/views/object-storage/BucketsView.vue index ba6c70b..0fab4f5 100644 --- a/src/views/object-storage/BucketsView.vue +++ b/src/views/object-storage/BucketsView.vue @@ -56,13 +56,19 @@ function addBucket(bucket: BucketOut) { function deleteBucket(bucketName: string) { BucketService.bucketDeleteBucket(bucketName).then(() => { - router.push({ name: "buckets" }); - bucketsState.buckets = bucketsState.buckets.filter( - (bucket) => bucket.name !== bucketName - ); + bucketDeleted(bucketName); }); } +function bucketDeleted(bucketName: string) { + if (bucketsState.buckets.map((bucket) => bucket.name).includes(bucketName)) { + router.push({ name: "buckets" }); + } + bucketsState.buckets = bucketsState.buckets.filter( + (bucket) => bucket.name !== bucketName + ); +} + onMounted(() => { fetchBuckets(); }); @@ -113,7 +119,7 @@ onMounted(() => { /> </div> - <div class="list-group overflow-scroll mt-3"> + <div class="list-group mt-3"> <div v-if="!bucketsState.loading"> <bucket-list-item v-for="bucket in bucketsState.buckets" @@ -126,6 +132,7 @@ onMounted(() => { :loading="false" :permission="bucketsState.permissions[bucket.name]" @delete-bucket="deleteBucket" + @permission-deleted="(bucketName) => bucketDeleted(bucketName)" /> </div> <div v-else> -- GitLab