Skip to content
Snippets Groups Projects
CreateFolderModal.vue 4.90 KiB
<script setup lang="ts">
import BootstrapModal from "@/components/modals/BootstrapModal.vue";
import { computed, onMounted, reactive } from "vue";

import { Modal, Toast } from "bootstrap";
import { useS3ObjectStore } from "@/stores/s3objects";

const objectRepository = useS3ObjectStore();

const props = defineProps<{
  modalID: string;
  bucketName: string;
  keyPrefix: string;
}>();

const randomIDSuffix = Math.random().toString(16).substring(2, 8);
let uploadModal: Modal | null = null;
let successToast: Toast | null = null;
let errorToast: Toast | null = null;

const currentFolders = computed<string[]>(() => props.keyPrefix.split("/"));

const formState = reactive<{
  folderName: string;
  uploading: boolean;
}>({
  folderName: "",
  uploading: false,
});

function uploadFolder() {
  const key =
    props.keyPrefix.length > 0
      ? props.keyPrefix + "/" + formState.folderName
      : formState.folderName;
  const reversedKey = key
    .replace(/(\/)\1+/g, "/")
    .split("")
    .reverse();
  const firstLetterIndex = reversedKey.findIndex((char) => char !== "/");
  if (firstLetterIndex < 0) {
    return;
  }
  const realKey = reversedKey.slice(firstLetterIndex).reverse().join("") + "/";
  formState.uploading = true;
  objectRepository
    .createFolder(props.bucketName, realKey)
    .then(() => {
      uploadModal?.hide();
      successToast?.show();
      formState.folderName = "";
    })
    .catch((e) => {
      console.error(e);
      errorToast?.show();
    })
    .finally(() => {
      formState.uploading = false;
    });
}

onMounted(() => {
  uploadModal = new Modal("#" + props.modalID);
  successToast = new Toast("#successToast-" + randomIDSuffix);
  errorToast = new Toast("#errorToast-" + randomIDSuffix);
});
</script>

<template>
  <div class="toast-container position-fixed top-toast 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="'successToast-' + randomIDSuffix"
    >
      <div class="d-flex">
        <div class="toast-body">Successfully created Folder</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="toast-container position-fixed top-toast end-0 p-3">
    <div
      role="alert"
      aria-live="assertive"
      aria-atomic="true"
      class="toast text-bg-danger align-items-center border-0"
      data-bs-autohide="true"
      :id="'errorToast-' + randomIDSuffix"
    >
      <div class="d-flex">
        <div class="toast-body">
          There has been some Error.<br />
          Try again later
        </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>
  <bootstrap-modal
    :modalID="modalID"
    :static-backdrop="true"
    modal-label="Create Folder Modal"
  >
    <template v-slot:header>
      <h4>Create folder in</h4>
      <ol class="breadcrumb">
        <li class="breadcrumb-item">{{ props.bucketName }}</li>
        <li
          class="breadcrumb-item"
          v-for="folder in currentFolders"
          :key="folder"
        >
          {{ folder }}
        </li>
      </ol>
    </template>
    <template v-slot:body>
      <div class="container-fluid">
        <div class="row">
          <form
            class="col-7"
            :id="'uploadFolderForm' + randomIDSuffix"
            @submit.prevent="uploadFolder"
          >
            <div class="mb-3">
              <label :for="'folderName' + randomIDSuffix" class="form-label"
                >Folder Name</label
              >
              <input
                type="text"
                class="form-control"
                :id="'folderName' + randomIDSuffix"
                required
                v-model="formState.folderName"
              />
            </div>
          </form>
          <div class="col-5">
            Note: Delimiters ('/') are allowed in the folder name to place the
            new folder into a folder that will be created when the folder is
            created (to any depth of folders).
          </div>
        </div>
      </div>
    </template>
    <template v-slot:footer>
      <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
        Close
      </button>
      <button
        :disabled="formState.uploading"
        type="submit"
        :form="'uploadFolderForm' + randomIDSuffix"
        class="btn btn-primary"
      >
        <span
          v-if="formState.uploading"
          class="spinner-border spinner-border-sm"
          role="status"
          aria-hidden="true"
        ></span>
        Create
      </button>
    </template>
  </bootstrap-modal>
</template>

<style scoped></style>