Skip to content
Snippets Groups Projects
CreateFolderModal.vue 5.46 KiB
Newer Older
  • Learn to ignore specific revisions
  • <script setup lang="ts">
    import type { S3Client } from "@aws-sdk/client-s3";
    import { PutObjectCommand } from "@aws-sdk/client-s3";
    
    import BootstrapModal from "@/components/modals/BootstrapModal.vue";
    
    import { computed, onMounted, reactive } from "vue";
    
    import type { S3ObjectMetaInformation } from "@/client/s3proxy";
    
    import dayjs from "dayjs";
    import { Modal, Toast } from "bootstrap";
    
    const props = defineProps<{
      modalID: string;
      bucketName: string;
      keyPrefix: string;
      s3Client: S3Client;
    }>();
    
    const randomIDSuffix = Math.random().toString(16).substr(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 emit = defineEmits<{
      (e: "folder-created", object: S3ObjectMetaInformation): void;
    }>();
    
    
    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();
      console.log(reversedKey);
      const firstLetterIndex = reversedKey.findIndex((char) => char !== "/");
      if (firstLetterIndex < 0) {
        return;
      }
      const realKey = reversedKey.slice(firstLetterIndex).reverse().join("") + "/";
      console.log(realKey);
    
      const command = new PutObjectCommand({
        Bucket: props.bucketName,
        Body: "",
        ContentType: "text/plain",
    
      });
      formState.uploading = true;
      props.s3Client
        .send(command)
        .then(() => {
          uploadModal?.hide();
          successToast?.show();
          emit("folder-created", {
    
            key: realKey,
    
            bucket: props.bucketName,
            size: 0,
            last_modified: dayjs().toISOString(),
    
            content_type: "text/plain",
    
          });
          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>
    
    Daniel Göbel's avatar
    Daniel Göbel committed
      <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>
    
    Daniel Göbel's avatar
    Daniel Göbel committed
      <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>