Skip to content
Snippets Groups Projects
CopyObjectModal.vue 6.19 KiB
Newer Older
  • Learn to ignore specific revisions
  • <script setup lang="ts">
    import type { S3Client } from "@aws-sdk/client-s3";
    import { CopyObjectCommand } from "@aws-sdk/client-s3";
    
    import BootstrapModal from "@/components/modals/BootstrapModal.vue";
    
    import { Modal, Toast } from "bootstrap";
    import { onMounted, reactive, watch } from "vue";
    
    import type { S3ObjectMetaInformation } from "@/client/s3proxy";
    
    import dayjs from "dayjs";
    
    import { useBucketStore } from "@/stores/buckets";
    
    
    const props = defineProps<{
      modalID: string;
      sourceObject: S3ObjectMetaInformation;
      s3Client: S3Client;
    }>();
    
    const formState = reactive({
      destKey: "",
      destBucket: "",
      uploading: false,
    } as {
      destKey: string;
      destBucket: string;
      uploading: boolean;
    });
    
    const bucketRepository = useBucketStore();
    
    
    const emit = defineEmits<{
      (e: "object-copied", object: S3ObjectMetaInformation): void;
    }>();
    
    const randomIDSuffix = Math.random().toString(16).substr(2, 8);
    let copyModal: Modal | null = null;
    let successToast: Toast | null = null;
    let errorToast: Toast | null = null;
    
    function getFileName(key: string): string {
      const splittedKey = key.split("/");
      return splittedKey[splittedKey.length - 1];
    }
    
    function copyObject() {
      const command = new CopyObjectCommand({
        Bucket: formState.destBucket,
        CopySource: encodeURI(
          `/${props.sourceObject.bucket}/${props.sourceObject.key}`
        ),
        Key: formState.destKey,
      });
      formState.uploading = true;
      props.s3Client
        .send(command)
        .then(() => {
          emit("object-copied", {
            key: formState.destKey,
            bucket: formState.destBucket,
            size: props.sourceObject.size,
            last_modified: dayjs().toISOString(),
    
            content_type: props.sourceObject.content_type,
    
          });
          copyModal?.hide();
          successToast?.show();
          formState.destBucket = "";
        })
        .catch((e) => {
          console.error(e);
          errorToast?.show();
        })
        .finally(() => {
          formState.uploading = false;
        });
    }
    
    function modalClosed() {
      formState.destBucket = "";
    }
    
    watch(
      () => props.sourceObject.key,
      (newKey) => {
        formState.destKey = newKey;
      }
    );
    
    onMounted(() => {
      copyModal = 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 copied file</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="Copy Object Modal"
    
        v-on="{ 'hidden.bs.modal': modalClosed }"
      >
        <template v-slot:header>
          <h4>Copy file {{ getFileName(props.sourceObject.key) }}</h4>
        </template>
        <template v-slot:body>
          <div class="container-fluid">
            <div class="row">
              <form
                class="col-7"
                :id="'copyObjectForm' + randomIDSuffix"
                @submit.prevent="copyObject"
              >
                <div class="mb-3">
                  <label
                    :for="'destinationBucket' + randomIDSuffix"
                    class="form-label"
                  >
                    Destination Bucket *
                  </label>
                  <select
                    class="form-select text-lowercase"
                    :id="'destinationBucket' + randomIDSuffix"
                    required
                    v-model="formState.destBucket"
                  >
                    <option disabled selected>Select one...</option>
                    <option
    
                      v-for="bucket in bucketRepository.writableBuckets"
    
                      :key="bucket.name"
                      :value="bucket.name"
                    >
                      {{ bucket.name }}
                    </option>
                  </select>
                </div>
                <div class="mb-3">
                  <label :for="'objectKey' + randomIDSuffix" class="form-label"
                    >Destination Filename *</label
                  >
                  <input
                    type="text"
                    class="form-control"
                    :id="'objectKey' + randomIDSuffix"
                    required
                    v-model="formState.destKey"
                  />
                </div>
              </form>
              <div class="col-5">
                You can copy objects. You have to create destination container prior
                to copy.<br />
                You can specify folder by using '/' at destination object field. For
                example, if you want to copy object under the folder named
                'folder1', you need to specify destination object like
                'folder1/[your object name]'.
              </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="'copyObjectForm' + randomIDSuffix"
            class="btn btn-primary"
          >
            <span
              v-if="formState.uploading"
              class="spinner-border spinner-border-sm"
              role="status"
              aria-hidden="true"
            ></span>
            Copy
          </button>
        </template>
      </bootstrap-modal>
    </template>
    
    <style scoped></style>