@nextcloud/vue
Version:
Nextcloud vue components
270 lines (269 loc) • 12.2 kB
JavaScript
import '../assets/NcUploadPicker.css';
import { defineComponent, useTemplateRef, onBeforeMount, onUnmounted, watch, ref, computed, openBlock, createBlock, unref, withCtx, withDirectives, createElementVNode, normalizeClass, createVNode, createElementBlock, toDisplayString, createTextVNode, createCommentVNode, vShow } from "vue";
import { b as mdiClose, C as mdiPlus } from "./mdi.mjs";
import { openConflictPicker } from "@nextcloud/dialogs";
import { getUniqueName } from "@nextcloud/files";
import { getUploader, UploaderStatus, UploadStatus } from "@nextcloud/files/upload";
import { N as NcButton } from "./NcButton.mjs";
import { N as NcFilePicker } from "./NcFilePicker.mjs";
import { N as NcIconSvgWrapper } from "./NcIconSvgWrapper.mjs";
import { N as NcProgressBar } from "./NcProgressBar.mjs";
import { useFormatRelativeTime } from "../composables/useFormatDateTime/index.mjs";
import "../composables/useHotKey/index.mjs";
import "../composables/useIsDarkTheme/index.mjs";
import "../composables/useIsFullscreen/index.mjs";
import "../composables/useIsMobile/index.mjs";
import { r as register, E as t10, a as t } from "./_l10n.mjs";
import { c as createElementId } from "./createElementId.mjs";
import { l as logger } from "./logger.mjs";
import { _ as _export_sfc } from "./_plugin-vue_export-helper.mjs";
function basename(path, extname2) {
path = path.replace(/\\/g, "/").replace(/\/+$/g, "").replace(/.*\//, "");
return path;
}
register(t10);
const _hoisted_1 = ["id"];
const _hoisted_2 = { key: 0 };
const _hoisted_3 = { key: 1 };
const _hoisted_4 = ["title"];
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "NcUploadPicker",
props: {
actions: { default: () => [] },
destination: {},
content: {},
accept: { default: () => [] },
disabled: { type: Boolean },
label: { default: () => t("New") },
multiple: { type: Boolean },
iconOnly: { type: Boolean },
variant: { default: "secondary" },
directory: { type: Boolean }
},
emits: ["upload:started", "upload:finished", "paused", "resumed", "finished"],
setup(__props, { expose: __expose, emit: __emit }) {
const props = __props;
const emit = __emit;
__expose({
reset
});
const filePickerElement = useTemplateRef("filePicker");
const progressTimeId = createElementId();
const uploadManager = getUploader();
onBeforeMount(() => {
window.addEventListener("beforeunload", onBeforePageUnload);
uploadManager.addEventListener("uploadFinished", onUploadFinished);
uploadManager.addEventListener("uploadStarted", onUploadStarted);
uploadManager.addEventListener("uploadProgress", updateEta);
uploadManager.addEventListener("finished", onUploaderFinished);
uploadManager.addEventListener("paused", onUploaderPaused);
uploadManager.addEventListener("reset", updateUploadStatus);
uploadManager.addEventListener("resumed", onUploaderResumed);
updateUploadStatus();
});
onUnmounted(() => {
window.removeEventListener("beforeunload", onBeforePageUnload);
uploadManager.removeEventListener("uploadFinished", onUploadFinished);
uploadManager.removeEventListener("uploadStarted", onUploadStarted);
uploadManager.removeEventListener("uploadProgress", updateEta);
uploadManager.removeEventListener("finished", onUploaderFinished);
uploadManager.removeEventListener("paused", onUploaderPaused);
uploadManager.removeEventListener("reset", updateUploadStatus);
uploadManager.removeEventListener("resumed", onUploaderResumed);
});
watch(() => props.destination, () => setDestination(props.destination), { immediate: true });
const isPaused = ref(uploadManager.status === UploaderStatus.PAUSED);
function onUploaderPaused() {
updateUploadStatus();
emit("paused", [...uploadManager.queue]);
}
function onUploaderResumed() {
updateUploadStatus();
emit("resumed", [...uploadManager.queue]);
}
const hasFailure = ref(false);
const isUploading = ref(false);
const isAssembling = ref(false);
const isOnlyAssembling = ref(false);
function updateUploadStatus() {
isPaused.value = uploadManager.status === UploaderStatus.PAUSED;
isUploading.value = uploadManager.status === UploaderStatus.UPLOADING || isPaused.value && uploadManager.queue.length > 0;
hasFailure.value = uploadManager.queue.some((upload) => upload.status === UploadStatus.FAILED);
isAssembling.value = uploadManager.queue.some((upload) => upload.status === UploadStatus.ASSEMBLING);
isOnlyAssembling.value = isAssembling.value && uploadManager.queue.every((upload) => upload.status >= UploadStatus.ASSEMBLING);
}
function reset() {
filePickerElement.value?.reset();
}
function setDestination(destination) {
if (!destination) {
logger.debug("Invalid destination");
return;
}
uploadManager.destination = destination;
}
const etaProgress = ref(0);
const etaSpeed = ref("");
const etaRaw = ref(Infinity);
const etaTimeRaw = computed(() => etaRaw.value === Infinity ? Infinity : new Date(Date.now() + etaRaw.value));
const etaTimeFormatted = useFormatRelativeTime(etaTimeRaw, { ignoreSeconds: true });
const etaTime = computed(() => etaTimeRaw.value === Infinity ? t("Estimating …") : etaTimeFormatted.value);
function updateEta() {
etaRaw.value = uploadManager.statistics.eta === Infinity ? Infinity : uploadManager.statistics.eta * 1e3;
etaSpeed.value = uploadManager.statistics.speedReadable;
etaProgress.value = uploadManager.statistics.progress;
}
function onUploaderFinished() {
updateUploadStatus();
emit("finished");
}
function onUploadFinished(event) {
updateUploadStatus();
emit("upload:finished", event.detail);
}
function onUploadStarted(event) {
updateUploadStatus();
emit("upload:started", event.detail);
}
async function onPick(files) {
try {
await uploadManager.batchUpload("", files, { callback: handleConflicts });
} catch (error) {
logger.debug("Error while uploading", { error });
} finally {
reset();
}
}
async function handleConflicts(nodes, currentPath) {
try {
const content = await props.content(currentPath);
const conflicts = content.filter((node) => nodes.includes(node.displayname) || nodes.includes(node.basename));
const uploadMapping = Object.fromEntries(nodes.map((name) => [name, name]));
if (conflicts.length === 0) {
return uploadMapping;
}
const existingNodes = content.filter((node) => nodes.includes(node.displayname) || nodes.includes(node.basename));
const result = await openConflictPicker(basename(currentPath), conflicts, existingNodes, { recursive: props.directory });
if (result) {
const usedNames = content.map((node) => node.basename);
for (const node of conflicts) {
if (result.skipped.some((skipped) => skipped.basename === node.basename)) {
delete uploadMapping[node.basename];
} else if (result.renamed.some((renamed) => renamed.basename === node.basename)) {
const newName = getUniqueName(basename(node.basename), usedNames);
uploadMapping[node.basename] = newName;
usedNames.push(newName);
}
}
return uploadMapping;
}
} catch (error) {
logger.error("Error during conflict resolution - skipping upload", { error });
}
return false;
}
function onCancel() {
uploadManager.reset();
reset();
}
function onBeforePageUnload(event) {
if (uploadManager.queue.length > 0) {
event.preventDefault();
event.returnValue = "";
}
}
return (_ctx, _cache) => {
return openBlock(), createBlock(NcFilePicker, {
ref: "filePicker",
accept: __props.accept,
actionCaption: __props.actions.length > 0 || __props.directory ? unref(t)("Upload from device") : void 0,
actions: __props.actions,
directory: __props.directory,
disabled: __props.disabled,
iconOnly: __props.iconOnly,
label: __props.label,
multiple: __props.multiple,
variant: __props.variant,
onPick
}, {
icon: withCtx(() => [
createVNode(NcIconSvgWrapper, { path: unref(mdiPlus) }, null, 8, ["path"])
]),
default: withCtx(() => [
withDirectives(createElementVNode("div", {
class: normalizeClass([_ctx.$style.uploadPicker_progress, {
[_ctx.$style.uploadPicker_progress__uploading]: isUploading.value,
[_ctx.$style.uploadPicker_progress__paused]: isPaused.value
}])
}, [
createVNode(NcProgressBar, {
ariaLabel: unref(t)("Upload progress"),
ariaDescribedby: unref(progressTimeId),
error: hasFailure.value,
value: etaProgress.value,
size: "medium"
}, null, 8, ["ariaLabel", "ariaDescribedby", "error", "value"]),
createElementVNode("p", {
id: unref(progressTimeId),
class: normalizeClass(_ctx.$style.uploadPicker_progressLabel)
}, [
isPaused.value ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(
unref(t)("paused")
/* TRANSLATORS: State of the current upload - it is paused */
), 1)) : isOnlyAssembling.value ? (openBlock(), createElementBlock("span", _hoisted_3, toDisplayString(
unref(t)("assembling")
/* TRANSLATORS: State of the current upload - chunks of the uploaded files are being assembled into the final file */
), 1)) : (openBlock(), createElementBlock("span", {
key: 2,
title: `${etaTime.value} (${etaSpeed.value})`
}, [
createTextVNode(toDisplayString(etaTime.value) + " ", 1),
etaSpeed.value && etaRaw.value > 31e3 ? (openBlock(), createElementBlock("span", {
key: 0,
class: normalizeClass(_ctx.$style.uploadPicker_progressLabelSpeed)
}, " (" + toDisplayString(etaSpeed.value) + ") ", 3)) : createCommentVNode("", true)
], 8, _hoisted_4))
], 10, _hoisted_1)
], 2), [
[vShow, isUploading.value]
]),
isUploading.value && !isOnlyAssembling.value ? (openBlock(), createBlock(NcButton, {
key: 0,
class: normalizeClass(_ctx.$style.uploadPicker_cancelButton),
"aria-label": unref(t)("Cancel uploads"),
variant: "tertiary",
onClick: onCancel
}, {
icon: withCtx(() => [
createVNode(NcIconSvgWrapper, { path: unref(mdiClose) }, null, 8, ["path"])
]),
_: 1
}, 8, ["class", "aria-label"])) : createCommentVNode("", true)
]),
_: 1
}, 8, ["accept", "actionCaption", "actions", "directory", "disabled", "iconOnly", "label", "multiple", "variant"]);
};
}
});
const uploadPicker_progress = "_uploadPicker_progress_LchrN";
const uploadPicker_progress__uploading = "_uploadPicker_progress__uploading_RBQWf";
const uploadPicker_progress__paused = "_uploadPicker_progress__paused_t4TGj";
const breathing = "_breathing_B9q41";
const uploadPicker_progressLabel = "_uploadPicker_progressLabel_iEywW";
const uploadPicker_progressLabelSpeed = "_uploadPicker_progressLabelSpeed_dIEb3";
const style0 = {
uploadPicker_progress,
uploadPicker_progress__uploading,
uploadPicker_progress__paused,
breathing,
uploadPicker_progressLabel,
uploadPicker_progressLabelSpeed
};
const cssModules = {
"$style": style0
};
const NcUploadPicker = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]);
export {
NcUploadPicker as N
};
//# sourceMappingURL=NcUploadPicker.mjs.map