<script setup lang="ts"> import { BucketService } from "@/client"; import type { BucketIn } from "@/client"; import { reactive, onMounted } from "vue"; import BootstrapModal from "@/components/BootstrapModal.vue"; import { useRouter } from "vue-router"; import { Modal } from "bootstrap"; const router = useRouter(); const emit = defineEmits(["bucketCreated"]); const bucket = reactive({ name: "", description: "" } as BucketIn); const formState = reactive({ validated: false, bucketNameTaken: false, loading: false, } as { validated: boolean; bucketNameTaken: boolean; loading: boolean; }); const props = defineProps<{ modalID: string; modalLabel: string; }>(); let createBucketModal: Modal | null = null; onMounted(() => { createBucketModal = new Modal("#" + props.modalID); console.log("Modal ID", props.modalID); }); function createBucket() { formState.validated = true; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const form = document.getElementById("bucketCreateForm")! as HTMLFormElement; formState.bucketNameTaken = false; if (form.checkValidity()) { formState.loading = true; BucketService.bucketCreateBucket(bucket) .then((createdBucket) => { emit("bucketCreated", createdBucket); createBucketModal?.hide(); bucket.name = ""; bucket.description = ""; formState.bucketNameTaken = false; formState.validated = false; router.push({ name: "bucket", params: { bucketName: createdBucket.name, subFolders: [] }, }); }) .catch((error) => { if ( error.status === 400 && error.body["detail"] === "Bucket name is already taken" ) { formState.bucketNameTaken = true; } }) .finally(() => { formState.loading = false; }); } } function modalClosed() { formState.validated = false; formState.bucketNameTaken = false; } </script> <template> <bootstrap-modal :modal-id="modalID" :static-backdrop="true" :modal-label="modalLabel" v-on="{ 'hidden.bs.modal': modalClosed }" > <template v-slot:header> Create new Bucket </template> <template v-slot:body> <form id="bucketCreateForm" :class="{ 'was-validated': formState.validated }" novalidate > <div class="mb-3"> <label for="bucketNameInput" class="form-label">Bucket Name</label> <div class="input-group"> <input type="text" class="form-control" id="bucketNameInput" required minlength="3" maxlength="63" pattern="(?!(^((2(5[0-5]|[0-4]\d)|[01]?\d{1,2})\.){3}(2(5[0-5]|[0-4]\d)|[01]?\d{1,2})$))^[a-z\d][a-z\d.-]{1,61}[a-z\d]$" v-model.trim="bucket.name" /> <div class="invalid-feedback"> Requirements <ul> <li>At least 3 Characters long</li> <li>Lowercase</li> <li>Only [a-z][0-9].-</li> <li>No IP address</li> </ul> </div> </div> </div> <div class="mb-3"> <label for="bucketDescriptionInput" class="form-label"> Description </label> <div class="input-group"> <textarea class="form-control" id="bucketDescriptionInput" required rows="5" minlength="126" maxlength="65536" v-model.trim="bucket.description" placeholder="Describe the purpose of the bucket" ></textarea> <div class="invalid-feedback"> Requirements <ul> <li>At least 126 Characters long</li> </ul> </div> </div> </div> </form> <div v-if="formState.bucketNameTaken" class="text-danger"> Bucket name already taken. </div> </template> <template v-slot:footer> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"> Close </button> <button type="submit" form="bucketCreateForm" class="btn btn-primary" :disabled="formState.loading" @click.prevent="createBucket" > <span v-if="formState.loading" class="spinner-border spinner-border-sm" role="status" aria-hidden="true" ></span> Save </button> </template> </bootstrap-modal> </template> <style scoped></style>