Newer
Older
<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 { 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>
<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"
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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"
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
: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>