-
Daniel Göbel authoredDaniel Göbel authored
CopyObjectModal.vue 6.19 KiB
<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: string;
destBucket: string;
uploading: boolean;
}>({
destKey: "",
destBucket: "",
uploading: false,
});
const bucketRepository = useBucketStore();
const emit = defineEmits<{
(e: "object-copied", object: S3ObjectMetaInformation): void;
}>();
const randomIDSuffix = Math.random().toString(16).substring(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>
<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>
<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 buckets 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>