diff --git a/src/components/S3KeyView.vue b/src/components/S3KeyView.vue index 71c865308c06a0bd2b731658fca1023429b3a91c..0ba2f825236449fea35edcc8af05c32581aa4f06 100644 --- a/src/components/S3KeyView.vue +++ b/src/components/S3KeyView.vue @@ -3,9 +3,15 @@ import type { S3Key } from "@/client"; import type { Ref } from "vue"; import { ref, watch } from "vue"; import BootstrapIcon from "@/components/BootstrapIcon.vue"; +import DeleteModal from "@/components/Modals/DeleteModal.vue"; const props = defineProps<{ s3key: S3Key; + deletable: boolean; +}>(); + +const emit = defineEmits<{ + (e: "delete-key", accessKey: string): void; }>(); watch( @@ -16,9 +22,22 @@ watch( ); const visibleSecret: Ref<boolean> = ref(false); + +function deleteKeyTrigger() { + if (props.deletable) { + emit("delete-key", props.s3key.access_key); + } +} </script> <template> + <DeleteModal + modalID="delete-key-modal" + modal-label="Delete S3 Key" + :object-name-delete="props.s3key.access_key" + :back-modal-id="undefined" + @confirm-delete="deleteKeyTrigger" + /> <h3>Access Key:</h3> <input class="form-control-plaintext text-white fs-4" @@ -52,7 +71,15 @@ const visibleSecret: Ref<boolean> = ref(false); aria-describedby="s3-secret-key" readonly /> - <button type="button" class="btn btn-danger fs-5" disabled>Delete</button> + <button + type="button" + class="btn btn-danger fs-5" + :disabled="!props.deletable" + data-bs-toggle="modal" + data-bs-target="#delete-key-modal" + > + Delete + </button> </template> <style scoped></style> diff --git a/src/views/object-storage/S3KeysView.vue b/src/views/object-storage/S3KeysView.vue index 8995f7d4a074ee2769ae519bab8bf4fca75f364a..6f6d0f386a579a198ae02e3b6effd9e1a0fbf6df 100644 --- a/src/views/object-storage/S3KeysView.vue +++ b/src/views/object-storage/S3KeysView.vue @@ -1,9 +1,11 @@ <script setup lang="ts"> import S3KeyView from "@/components/S3KeyView.vue"; -import { reactive, onMounted } from "vue"; +import { reactive, onMounted, computed } from "vue"; +import type { ComputedRef } from "vue"; import type { S3Key } from "@/client"; import { KeyService } from "@/client"; import { useAuthStore } from "@/stores/auth"; +import { Toast } from "bootstrap"; const authStore = useAuthStore(); @@ -13,26 +15,51 @@ authStore.$onAction(({ name, args }) => { } }); +let successToast: Toast | null = null; + const keyState = reactive({ keys: [], activeKey: 0, - loading: true, + initialLoading: true, + deletedKey: "", } as { keys: S3Key[]; activeKey: number; - loading: boolean; + initialLoading: boolean; + deletedKey: string; }); +const allowKeyDeletion: ComputedRef<boolean> = computed( + () => keyState.keys.length > 1 +); + function refreshKeys(uid: string) { KeyService.keyGetUserKeys(uid) .then((keys) => { keyState.keys = keys; }) .catch((err) => console.error(err)) - .finally(() => (keyState.loading = false)); + .finally(() => (keyState.initialLoading = false)); +} + +function deleteKey(accessKey: string) { + if (allowKeyDeletion.value && authStore.user != null) { + KeyService.keyDeleteUserKey(accessKey, authStore.user.uid) + .then(() => { + keyState.deletedKey = accessKey; + keyState.activeKey = 0; + keyState.keys = keyState.keys.filter( + (s3key) => s3key.access_key !== accessKey + ); + authStore.setS3Key(keyState.keys[0]); + successToast?.show(); + }) + .catch((err) => console.error(err)); + } } onMounted(() => { + successToast = new Toast("#successKeyToast"); if (authStore.user != null) { refreshKeys(authStore.user.uid); } @@ -40,6 +67,28 @@ onMounted(() => { </script> <template> + <div class="toast-container position-fixed top-0 end-0 p-3"> + <div + role="alert" + aria-live="assertive" + aria-atomic="true" + class="toast text-bg-success align-items-center border-0" + data-bs-autohide="true" + :id="'successKeyToast'" + > + <div class="d-flex"> + <div class="toast-body"> + Successfully deleted S3 Key {{ keyState.deletedKey }} + </div> + <button + type="button" + class="btn-close btn-close-white me-2 m-auto" + data-bs-dismiss="toast" + aria-label="Close" + ></button> + </div> + </div> + </div> <div class="row m-2 border-bottom border-light mt-4"> <div class="col-12"></div> <h1 class="mb-2 text-light">S3 Keys</h1> @@ -63,6 +112,8 @@ onMounted(() => { <s3-key-view v-if="keyState.keys.length > 0" :s3key="keyState.keys[keyState.activeKey]" + :deletable="allowKeyDeletion" + @delete-key="deleteKey" /> <div v-else> No keys here. <br />