UNPKG

@nextcloud/upload

Version:
1 lines 39.1 kB
{"version":3,"file":"ConflictPicker-C2Kb2ELt.cjs","sources":["../../node_modules/vue-material-design-icons/ArrowRight.vue","../../node_modules/vue-material-design-icons/Close.vue","../../node_modules/vue-material-design-icons/File.vue","../../node_modules/vue-material-design-icons/Folder.vue","../../lib/components/NodesPicker.vue","../../lib/components/ConflictPicker.vue"],"sourcesContent":["<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon arrow-right-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"ArrowRightIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon close-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"CloseIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon file-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"FileIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<template>\n <span v-bind=\"$attrs\"\n :aria-hidden=\"title ? null : 'true'\"\n :aria-label=\"title\"\n class=\"material-design-icon folder-icon\"\n role=\"img\"\n @click=\"$emit('click', $event)\">\n <svg :fill=\"fillColor\"\n class=\"material-design-icon__svg\"\n :width=\"size\"\n :height=\"size\"\n viewBox=\"0 0 24 24\">\n <path d=\"M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z\">\n <title v-if=\"title\">{{ title }}</title>\n </path>\n </svg>\n </span>\n</template>\n\n<script>\nexport default {\n name: \"FolderIcon\",\n emits: ['click'],\n props: {\n title: {\n type: String,\n },\n fillColor: {\n type: String,\n default: \"currentColor\"\n },\n size: {\n type: Number,\n default: 24\n }\n }\n}\n</script>","<!--\n - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<fieldset class=\"node-picker__wrapper\" :data-cy-conflict-picker-fieldset=\"existing.basename\">\n\t\t<legend>{{ existing.basename }}</legend>\n\n\t\t<!-- Incoming file -->\n\t\t<NcCheckboxRadioSwitch :checked=\"isChecked(incoming, newSelected)\"\n\t\t\t:required=\"!isEnoughSelected\"\n\t\t\t:data-cy-conflict-picker-input-incoming=\"existing.basename\"\n\t\t\t@update:checked=\"onUpdateIncomingChecked\">\n\t\t\t<span class=\"node-picker node-picker--incoming\">\n\t\t\t\t<!-- Icon or preview -->\n\t\t\t\t<template v-if=\"!incomingPreview\">\n\t\t\t\t\t<FolderSvg v-if=\"isFolder(incoming)\" class=\"node-picker__icon\" :size=\"48\" />\n\t\t\t\t\t<FileSvg v-else class=\"node-picker__icon\" :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t\t<img v-else\n\t\t\t\t\tclass=\"node-picker__preview\"\n\t\t\t\t\t:src=\"incomingPreview\"\n\t\t\t\t\t:alt=\"t('Preview image')\"\n\t\t\t\t\tloading=\"lazy\">\n\n\t\t\t\t<!-- Description -->\n\t\t\t\t<span class=\"node-picker__desc\">\n\t\t\t\t\t<span class=\"node-picker__name\">{{ t('New version') }}</span>\n\t\t\t\t\t<NcDateTime v-if=\"incomingLastModified\"\n\t\t\t\t\t\t:timestamp=\"incomingLastModified\"\n\t\t\t\t\t\t:relative-time=\"false\"\n\t\t\t\t\t\t:format=\"{ timeStyle: 'short', dateStyle: 'medium' }\"\n\t\t\t\t\t\tclass=\"node-picker__mtime\" />\n\t\t\t\t\t<span v-else class=\"node-picker__mtime\">\n\t\t\t\t\t\t{{ t('Last modified date unknown') }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"node-picker__size\">{{ incomingSize }}</span>\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</NcCheckboxRadioSwitch>\n\n\t\t<!-- Existing file -->\n\t\t<NcCheckboxRadioSwitch :checked=\"isChecked(existing, oldSelected)\"\n\t\t\t:required=\"!isEnoughSelected\"\n\t\t\t:data-cy-conflict-picker-input-existing=\"existing.basename\"\n\t\t\t@update:checked=\"onUpdateExistingChecked\">\n\t\t\t<span class=\"node-picker node-picker--existing\">\n\t\t\t\t<!-- Icon or preview -->\n\t\t\t\t<template v-if=\"!existingPreview\">\n\t\t\t\t\t<FolderSvg v-if=\"isFolder(existing)\" class=\"node-picker__icon\" :size=\"48\" />\n\t\t\t\t\t<FileSvg v-else class=\"node-picker__icon\" :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t\t<img v-else\n\t\t\t\t\tclass=\"node-picker__preview\"\n\t\t\t\t\t:src=\"existingPreview\"\n\t\t\t\t\t:alt=\"t('Preview image')\"\n\t\t\t\t\tloading=\"lazy\">\n\n\t\t\t\t<!-- Description -->\n\t\t\t\t<span class=\"node-picker__desc\">\n\t\t\t\t\t<span class=\"node-picker__name\">{{ t('Existing version') }}</span>\n\t\t\t\t\t<NcDateTime v-if=\"existingLastModified\"\n\t\t\t\t\t\t:timestamp=\"existingLastModified\"\n\t\t\t\t\t\t:relative-time=\"false\"\n\t\t\t\t\t\t:format=\"{ timeStyle: 'short', dateStyle: 'medium' }\"\n\t\t\t\t\t\tclass=\"node-picker__mtime\" />\n\t\t\t\t\t<span v-else class=\"node-picker__mtime\">\n\t\t\t\t\t\t{{ t('Last modified date unknown') }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"node-picker__size\">{{ size(existing) }}</span>\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</NcCheckboxRadioSwitch>\n\t</fieldset>\n</template>\n\n<script lang=\"ts\">\nimport type { Node } from '@nextcloud/files'\nimport type { PropType } from 'vue'\n\nimport { defineComponent } from 'vue'\nimport { formatFileSize, FileType } from '@nextcloud/files'\nimport { generateUrl } from '@nextcloud/router'\n\nimport FileSvg from 'vue-material-design-icons/File.vue'\nimport FolderSvg from 'vue-material-design-icons/Folder.vue'\nimport NcDateTime from '@nextcloud/vue/dist/Components/NcDateTime.js'\nimport NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'\n\nimport { isFileSystemEntry, isFileSystemFileEntry } from '../utils/filesystem'\nimport { t } from '../utils/l10n.ts'\n\nconst PREVIEW_SIZE = 64\n\nexport default defineComponent({\n\tname: 'NodesPicker',\n\n\tcomponents: {\n\t\tFileSvg,\n\t\tFolderSvg,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcDateTime,\n\t},\n\n\tprops: {\n\t\tincoming: {\n\t\t\ttype: [File, Object] as PropType<File|FileSystemEntry|Node>,\n\t\t\trequired: true,\n\t\t},\n\t\texisting: {\n\t\t\ttype: Object as PropType<Node>,\n\t\t\trequired: true,\n\t\t},\n\t\tnewSelected: {\n\t\t\ttype: Array as PropType<(File|FileSystemEntry|Node)[]>,\n\t\t\trequired: true,\n\t\t},\n\t\toldSelected: {\n\t\t\ttype: Array as PropType<Node[]>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tasyncPreview: null as string | null,\n\t\t\tincomingFile: null as File | null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the incoming or existing file is selected.\n\t\t * This is used by the parent component to ensure\n\t\t * that the user has selected at least one of the two files.\n\t\t */\n\t\tisEnoughSelected(): boolean {\n\t\t\treturn this.isChecked(this.incoming, this.newSelected)\n\t\t\t\t|| this.isChecked(this.existing, this.oldSelected)\n\t\t},\n\n\t\tincomingPreview() {\n\t\t\tif (!this.incomingFile) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst preview = this.previewUrl(this.incomingFile)\n\t\t\treturn preview ?? this.asyncPreview\n\t\t},\n\n\t\tincomingLastModified(): Date | null {\n\t\t\tif (!this.incomingFile) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.lastModified(this.incomingFile)\n\t\t},\n\n\t\tincomingSize(): string {\n\t\t\tif (!this.incomingFile) {\n\t\t\t\treturn t('Unknown size')\n\t\t\t}\n\t\t\treturn this.size(this.incomingFile)\n\t\t},\n\n\t\texistingPreview() {\n\t\t\treturn this.previewUrl(this.existing)\n\t\t},\n\n\t\texistingLastModified() {\n\t\t\treturn this.lastModified(this.existing)\n\t\t},\n\t},\n\n\twatch: {\n\t\t/**\n\t\t * Watch \"incoming\" to update \"incomingFile\"\n\t\t */\n\t\tincoming: {\n\t\t\t// Run the watcher also on mount with initial \"incoming\" value\n\t\t\timmediate: true,\n\t\t\tasync handler() {\n\t\t\t\tif (this.incoming instanceof File) {\n\t\t\t\t\t// If \"incoming\" is a file then just use that\n\t\t\t\t\tthis.incomingFile = this.incoming\n\t\t\t\t} else if (isFileSystemFileEntry(this.incoming)) {\n\t\t\t\t\t// For FileSystemEntry we only support the file type\n\t\t\t\t\tthis.incomingFile = await new Promise<File>((resolve, reject) => (this.incoming as FileSystemFileEntry).file(resolve, reject))\n\t\t\t\t} else {\n\t\t\t\t\t// We do not support directories here\n\t\t\t\t\tthis.incomingFile = null\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\tlastModified(node: File|Node): Date | null {\n\t\t\tconst lastModified = node instanceof File\n\t\t\t\t? new Date(node.lastModified)\n\t\t\t\t: node.mtime\n\t\t\treturn lastModified ?? null\n\t\t},\n\t\tsize(node: File|Node): string {\n\t\t\tif (node.size) {\n\t\t\t\treturn formatFileSize(node.size, true)\n\t\t\t}\n\t\t\treturn t('Unknown size')\n\t\t},\n\t\tpreviewUrl(node: File|Node) {\n\t\t\tif (node instanceof File) {\n\t\t\t\tthis.previewImage(node).then((url: string | null) => {\n\t\t\t\t\tthis.asyncPreview = url\n\t\t\t\t})\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tif (node.type === FileType.Folder) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst previewUrl = node.attributes.previewUrl\n\t\t\t\t\t|| generateUrl('/core/preview?fileId={fileid}', {\n\t\t\t\t\t\tfileid: node.fileid,\n\t\t\t\t\t})\n\t\t\t\tconst url = new URL(window.location.origin + previewUrl)\n\n\t\t\t\t// Request tiny previews\n\t\t\t\turl.searchParams.set('x', PREVIEW_SIZE.toString())\n\t\t\t\turl.searchParams.set('y', PREVIEW_SIZE.toString())\n\t\t\t\turl.searchParams.set('mimeFallback', 'true')\n\n\t\t\t\t// Etag to force refresh preview on change\n\t\t\t\tconst etag = node.attributes?.etag || ''\n\t\t\t\turl.searchParams.set('v', etag.slice(0, 6))\n\n\t\t\t\treturn url.href\n\t\t\t} catch (e) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\tisFolder(node: File|FileSystemEntry|Node): boolean {\n\t\t\tif (isFileSystemEntry(node)) {\n\t\t\t\treturn node.isDirectory\n\t\t\t}\n\t\t\t// For typescript cast it as we are sure it is no FileSystemEntry here\n\t\t\tnode = node as File|Node\n\t\t\t// Guess based on node type\n\t\t\treturn node.type === FileType.Folder\n\t\t\t\t|| node.type === 'httpd/unix-directory'\n\t\t},\n\n\t\tisChecked(node: File|FileSystemEntry|Node, selected: (File|FileSystemEntry|Node)[]): boolean {\n\t\t\treturn selected.includes(node)\n\t\t},\n\n\t\tonUpdateIncomingChecked(checked: boolean) {\n\t\t\tif (checked) {\n\t\t\t\tthis.$emit('update:newSelected', [this.incoming, ...this.newSelected])\n\t\t\t} else {\n\t\t\t\tthis.$emit('update:newSelected', this.newSelected.filter((node) => node !== this.incoming))\n\t\t\t}\n\t\t},\n\t\tonUpdateExistingChecked(checked: boolean) {\n\t\t\tif (checked) {\n\t\t\t\tthis.$emit('update:oldSelected', [this.existing, ...this.oldSelected])\n\t\t\t} else {\n\t\t\t\tthis.$emit('update:oldSelected', this.oldSelected.filter((node) => node !== this.existing))\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Get the preview Image of a file\n\t\t * @param file the soon-to-be-uploaded File\n\t\t */\n\t\tasync previewImage(file: File): Promise<string|null> {\n\t\t\treturn new Promise((resolve) => {\n\t\t\t\tif (file instanceof File && file.type.startsWith('image/')) {\n\t\t\t\t\tconst reader = new FileReader()\n\t\t\t\t\treader.onload = async (e) => {\n\t\t\t\t\t\tconst result = e?.target?.result\n\t\t\t\t\t\tif (result instanceof ArrayBuffer) {\n\t\t\t\t\t\t\tconst blob = new Blob([result], { type: file.type })\n\t\t\t\t\t\t\tconst url = URL.createObjectURL(blob)\n\t\t\t\t\t\t\tresolve(url)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve(null)\n\t\t\t\t\t}\n\t\t\t\t\treader.readAsArrayBuffer(file)\n\t\t\t\t} else {\n\t\t\t\t\tresolve(null)\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\tt,\n\t},\n})\n</script>\n\n<style lang=\"scss\" scoped>\n$height: 64px;\n\n.node-picker__wrapper {\n\t// last fieldset does not have a border\n\t&:not(:last-of-type) {\n\t\tborder-bottom: 1px solid var(--color-border);\n\t}\n}\n\n.node-picker {\n\tdisplay: flex;\n\talign-items: center;\n\theight: $height;\n\n\t&__icon, &__preview {\n\t\theight: $height;\n\t\twidth: $height;\n\t\tmargin: 0 var(--secondary-margin);\n\t\tdisplay: block;\n\t\tflex: 0 0 $height;\n\t}\n\n\t&__icon {\n\t\tcolor: var(--color-text-maxcontrast);\n\n\t\t&.folder-icon {\n\t\t\tcolor: var(--color-primary-element);\n\t\t}\n\t}\n\n\t&__preview {\n\t\toverflow: hidden;\n\t\tborder-radius: calc(var(--border-radius) * 2);\n\t\tobject-fit: cover;\n\t}\n\n\t&__desc {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tspan {\n\t\t\twhite-space: nowrap;\n\t\t}\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<NcDialog can-close\n\t\tclass=\"conflict-picker\"\n\t\tdata-cy-conflict-picker\n\t\t:close-on-click-outside=\"false\"\n\t\t:show=\"opened\"\n\t\t:name=\"name\"\n\t\tsize=\"large\"\n\t\t@closing=\"onCancel\">\n\t\t<!-- Header -->\n\t\t<div class=\"conflict-picker__header\">\n\t\t\t<!-- Description -->\n\t\t\t<p id=\"conflict-picker-description\" class=\"conflict-picker__description\">\n\t\t\t\t{{ t('Which files do you want to keep?') }}<br>\n\t\t\t\t{{ t('If you select both versions, the incoming file will have a number added to its name.') }}<br>\n\t\t\t\t<template v-if=\"recursiveUpload\">\n\t\t\t\t\t{{ t('When an incoming folder is selected, the content is written into the existing folder and a recursive conflict resolution is performed.') }}\n\t\t\t\t</template>\n\t\t\t\t<template v-else>\n\t\t\t\t\t{{ t('When an incoming folder is selected, any conflicting files within it will also be overwritten.') }}\n\t\t\t\t</template>\n\t\t\t</p>\n\t\t</div>\n\n\t\t<!-- Main form and conflict picker -->\n\t\t<form ref=\"form\"\n\t\t\tclass=\"conflict-picker__form\"\n\t\t\taria-labelledby=\"conflict-picker-description\"\n\t\t\tdata-cy-conflict-picker-form\n\t\t\t@submit.prevent.stop=\"onSubmit\">\n\t\t\t<!-- Select all checkboxes -->\n\t\t\t<fieldset class=\"conflict-picker__all\" data-cy-conflict-picker-fieldset=\"all\">\n\t\t\t\t<legend class=\"hidden-visually\">\n\t\t\t\t\t{{ t('Select all checkboxes') }}\n\t\t\t\t</legend>\n\t\t\t\t<NcCheckboxRadioSwitch v-bind=\"selectAllNewBind\"\n\t\t\t\t\tdata-cy-conflict-picker-input-incoming=\"all\"\n\t\t\t\t\t@update:checked=\"onSelectAllNew\">\n\t\t\t\t\t{{ t('Select all new files') }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<NcCheckboxRadioSwitch v-bind=\"selectAllOldBind\"\n\t\t\t\t\tdata-cy-conflict-picker-input-existing=\"all\"\n\t\t\t\t\t@update:checked=\"onSelectAllOld\">\n\t\t\t\t\t{{ t('Select all existing files') }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</fieldset>\n\n\t\t\t<!-- Files loop -->\n\t\t\t<NodesPicker v-for=\"(node, index) in files\"\n\t\t\t\tref=\"nodesPicker\"\n\t\t\t\t:key=\"node.fileid\"\n\t\t\t\t:incoming=\"conflicts[index]\"\n\t\t\t\t:existing=\"files[index]\"\n\t\t\t\t:new-selected.sync=\"newSelected\"\n\t\t\t\t:old-selected.sync=\"oldSelected\" />\n\t\t</form>\n\n\t\t<!-- Controls -->\n\t\t<template #actions>\n\t\t\t<!-- Cancel the entire operation -->\n\t\t\t<NcButton :aria-label=\"t('Cancel')\"\n\t\t\t\t:title=\"t('Cancel the entire operation')\"\n\t\t\t\tdata-cy-conflict-picker-cancel\n\t\t\t\ttype=\"tertiary\"\n\t\t\t\t@click=\"onCancel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Close :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('Cancel') }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Align right -->\n\t\t\t<span class=\"dialog__actions-separator\" />\n\n\t\t\t<NcButton :aria-label=\"skipButtonLabel\"\n\t\t\t\tdata-cy-conflict-picker-skip\n\t\t\t\t@click=\"onSkip\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Close :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ skipButtonLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton :aria-label=\"t('Continue')\"\n\t\t\t\t:class=\"{ 'button-vue--disabled': !isEnoughSelected}\"\n\t\t\t\t:title=\"isEnoughSelected ? '' : blockedTitle\"\n\t\t\t\tdata-cy-conflict-picker-submit\n\t\t\t\tnative-type=\"submit\"\n\t\t\t\ttype=\"primary\"\n\t\t\t\t@click.stop.prevent=\"onSubmit\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ArrowRight :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('Continue') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</NcDialog>\n</template>\n\n<script lang=\"ts\">\nimport type { Node } from '@nextcloud/files'\nimport type { PropType } from 'vue'\nimport type { ConflictResolutionResult } from '../index.ts'\n\nimport { defineComponent } from 'vue'\nimport { showError } from '@nextcloud/dialogs'\nimport { getUniqueName } from '@nextcloud/files'\n\nimport ArrowRight from 'vue-material-design-icons/ArrowRight.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'\nimport NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'\nimport NcButton from '@nextcloud/vue/dist/Components/NcButton.js'\n\nimport { isFileSystemEntry } from '../utils/filesystem.ts'\nimport { n, t } from '../utils/l10n.ts'\nimport logger from '../utils/logger.ts'\nimport NodesPicker from './NodesPicker.vue'\n\nexport type NodesPickerRef = InstanceType<typeof NodesPicker>\n\nexport default defineComponent({\n\tname: 'ConflictPicker',\n\n\tcomponents: {\n\t\tArrowRight,\n\t\tClose,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcDialog,\n\t\tNodesPicker,\n\t},\n\n\tprops: {\n\t\t/** Directory/context file name */\n\t\tdirname: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** All the existing files in the current directory */\n\t\tcontent: {\n\t\t\ttype: Array as PropType<Node[]>,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** New files being moved/uploaded */\n\t\tconflicts: {\n\t\t\ttype: Array as PropType<(Node|File|FileSystemEntry)[]>,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * If set to true no hint about overwriting directory content will be shown\n\t\t */\n\t\trecursiveUpload: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['cancel', 'submit'],\n\n\tsetup() {\n\t\t// Non reactive props\n\t\treturn {\n\t\t\tblockedTitle: t('You need to select at least one version of each file to continue.'),\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t// computed list of conflicting files already present in the directory\n\t\t\tfiles: [] as Node[],\n\n\t\t\topened: true,\n\t\t\tnewSelected: [] as (Node|File|FileSystemEntry)[],\n\t\t\toldSelected: [] as Node[],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tname() {\n\t\t\tif (this?.dirname?.trim?.() !== '') {\n\t\t\t\treturn n('{count} file conflict in {dirname}', '{count} file conflicts in {dirname}', this.conflicts.length, {\n\t\t\t\t\tcount: this.conflicts.length,\n\t\t\t\t\tdirname: this.dirname,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn n('{count} file conflict', '{count} files conflict', this.conflicts.length, { count: this.conflicts.length })\n\t\t},\n\n\t\tskipButtonLabel() {\n\t\t\treturn n('Skip this file', 'Skip {count} files', this.conflicts.length, { count: this.conflicts.length })\n\t\t},\n\n\t\t// Select all incoming files\n\t\tselectAllNewBind() {\n\t\t\tconst label = this.isNoneNewSelected || this.isSomeNewSelected\n\t\t\t\t? this.t('Select all')\n\t\t\t\t: this.t('Unselect all')\n\t\t\treturn {\n\t\t\t\t'aria-label': label,\n\t\t\t\tchecked: this.isAllNewSelected,\n\t\t\t\tindeterminate: this.isSomeNewSelected,\n\t\t\t\ttitle: label,\n\t\t\t}\n\t\t},\n\n\t\tisAllNewSelected() {\n\t\t\treturn this.newSelected.length === this.conflicts.length\n\t\t},\n\t\tisNoneNewSelected() {\n\t\t\treturn this.newSelected.length === 0\n\t\t},\n\t\tisSomeNewSelected() {\n\t\t\treturn !this.isAllNewSelected && !this.isNoneNewSelected\n\t\t},\n\n\t\t// Select all existing files\n\t\tselectAllOldBind() {\n\t\t\tconst label = this.isNoneOldSelected || this.isSomeOldSelected\n\t\t\t\t? this.t('Select all')\n\t\t\t\t: this.t('Unselect all')\n\t\t\treturn {\n\t\t\t\t'aria-label': label,\n\t\t\t\tchecked: this.isAllOldSelected,\n\t\t\t\tindeterminate: this.isSomeOldSelected,\n\t\t\t\ttitle: label,\n\t\t\t}\n\t\t},\n\n\t\tisAllOldSelected() {\n\t\t\treturn this.oldSelected.length === this.files.length\n\t\t},\n\t\tisNoneOldSelected() {\n\t\t\treturn this.oldSelected.length === 0\n\t\t},\n\t\tisSomeOldSelected() {\n\t\t\treturn !this.isAllOldSelected && !this.isNoneOldSelected\n\t\t},\n\n\t\t// Global handlings\n\t\tisEnoughSelected() {\n\t\t\tif (this.isAllOldSelected || this.isAllNewSelected) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\t// If we're in an intermediate state, we need to check\n\t\t\t// if all files have at least one version selected.\n\t\t\treturn (this.$refs?.nodesPicker as NodesPickerRef[])?.every?.(picker => picker.isEnoughSelected)\n\t\t},\n\t},\n\n\tmounted() {\n\t\t// Using map keep the same order\n\t\tthis.files = this.conflicts.map((conflict: File|FileSystemEntry|Node) => {\n\t\t\tconst name = (conflict instanceof File || isFileSystemEntry(conflict)) ? conflict.name : conflict.basename\n\t\t\treturn this.content.find((node: Node) => node.basename === name)\n\t\t}).filter(Boolean) as Node[]\n\n\t\tif (this.conflicts.length === 0 || this.files.length === 0) {\n\t\t\tconst error = new Error('ConflictPicker: files and conflicts must not be empty')\n\t\t\tthis.onCancel(error)\n\t\t\tthrow error\n\t\t}\n\n\t\tif (this.conflicts.length !== this.files.length) {\n\t\t\tconst error = new Error('ConflictPicker: files and conflicts must have the same length. Make sure you filter out non conflicting files from the conflicts array.')\n\t\t\tthis.onCancel(error)\n\t\t\tthrow error\n\t\t}\n\n\t\t// Successful initialisation\n\t\tlogger.debug('ConflictPicker initialised', { files: this.files, conflicts: this.conflicts, content: this.content })\n\t},\n\n\tmethods: {\n\t\tonCancel(error?: Error) {\n\t\t\tthis.opened = false\n\t\t\tthis.$emit('cancel', error)\n\t\t},\n\n\t\tonSkip() {\n\t\t\tlogger.debug('Conflict skipped. Ignoring all conflicting files')\n\t\t\tthis.opened = false\n\t\t\tthis.$emit('submit', {\n\t\t\t\tselected: [],\n\t\t\t\trenamed: [],\n\t\t\t} as ConflictResolutionResult<File>)\n\t\t},\n\n\t\tonSubmit() {\n\t\t\t// Do not use a real button disabled state so\n\t\t\t// the user can still click and trigger the\n\t\t\t// form validation check.\n\t\t\tif (!this.isEnoughSelected) {\n\t\t\t\tthis.scrollValidityInputIntoView();\n\t\t\t\t(this.$refs.form as HTMLFormElement).reportValidity()\n\t\t\t\tshowError(this.blockedTitle)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst selectedOldNames = (this.oldSelected as Node[]).map((node: Node) => node.basename) as string[]\n\t\t\tconst directoryContent = this.content.map((node: Node) => node.basename) as string[]\n\n\t\t\t// Files that got selected twice (new and old) gets renamed\n\t\t\tconst renamed = [] as (File|FileSystemEntry|Node)[]\n\t\t\tconst toRename = (this.newSelected as (File|FileSystemEntry|Node)[]).filter((node) => {\n\t\t\t\tconst name = (node instanceof File || isFileSystemEntry(node)) ? node.name : node.basename\n\t\t\t\treturn selectedOldNames.includes(name)\n\t\t\t})\n\n\t\t\t// Rename files\n\t\t\tif (toRename.length > 0) {\n\t\t\t\ttoRename.forEach(file => {\n\t\t\t\t\tconst name = (file instanceof File || isFileSystemEntry(file)) ? file.name : file.basename\n\t\t\t\t\tconst newName = getUniqueName(name, directoryContent)\n\t\t\t\t\t// If File, create a new one with the new name\n\t\t\t\t\tif (file instanceof File || isFileSystemEntry(file)) {\n\t\t\t\t\t\t// Keep the original file object and force rename\n\t\t\t\t\t\tObject.defineProperty(file, 'name', { value: newName })\n\t\t\t\t\t\trenamed.push(file)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Rename the node\n\t\t\t\t\tfile.rename(newName)\n\t\t\t\t\trenamed.push(file)\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Remove files that got renamed from the new selection\n\t\t\tconst selected = (this.newSelected as (File|FileSystemEntry|Node)[]).filter((node) => {\n\t\t\t\tconst name = (node instanceof File || isFileSystemEntry(node)) ? node.name : node.basename\n\t\t\t\t// files that are not in the old selection\n\t\t\t\treturn !selectedOldNames.includes(name) && !toRename.includes(node)\n\t\t\t}) as (File|Node)[]\n\n\t\t\tlogger.debug('Conflict resolved', { selected, renamed })\n\t\t\tthis.opened = false\n\t\t\tthis.$emit('submit', {\n\t\t\t\tselected,\n\t\t\t\trenamed,\n\t\t\t} as ConflictResolutionResult<File|Node|FileSystemEntry>)\n\t\t},\n\n\t\t/**\n\t\t * Scroll the first invalid input into view.\n\t\t * This is needed because the browser uses behavior: \"nearest\" by default.\n\t\t */\n\t\tscrollValidityInputIntoView() {\n\t\t\tconst selector = '.checkbox-radio-switch input[type=\"checkbox\"]'\n\n\t\t\t// Reset the custom validity of all checkboxes\n\t\t\tconst checkboxes: HTMLInputElement[] = Array.from(this.$el.querySelectorAll(selector))\n\t\t\tcheckboxes.forEach(input => input?.setCustomValidity?.(''))\n\n\t\t\t// Scroll the first invalid input into view if any\n\t\t\tconst invalidInput = this.$el.querySelector(selector + ':invalid') as HTMLInputElement\n\t\t\tif (invalidInput) {\n\t\t\t\tinvalidInput.setCustomValidity(this.blockedTitle)\n\t\t\t\tinvalidInput.scrollIntoView({ behavior: 'instant', block: 'center' })\n\t\t\t}\n\t\t},\n\n\t\tonSelectAllNew(selected: boolean) {\n\t\t\tif (selected) {\n\t\t\t\tlogger.debug('Selected all new files')\n\t\t\t\tthis.newSelected = this.conflicts\n\t\t\t} else {\n\t\t\t\tlogger.debug('Cleared new selection')\n\t\t\t\tthis.newSelected = []\n\t\t\t}\n\t\t},\n\n\t\tonSelectAllOld(selected: boolean) {\n\t\t\tif (selected) {\n\t\t\t\tlogger.debug('Selected all existing files')\n\t\t\t\tthis.oldSelected = this.files\n\t\t\t} else {\n\t\t\t\tlogger.debug('Cleared old selection')\n\t\t\t\tthis.oldSelected = []\n\t\t\t}\n\t\t},\n\n\t\tt,\n\t},\n})\n</script>\n\n<style lang=\"scss\" scoped>\n:deep(.modal-container__content) {\n\t// Make the form scroll instead\n\tdisplay: flex;\n\toverflow: visible;\n\tflex-direction: column;\n}\n\n.conflict-picker {\n\t--margin: 36px;\n\t--secondary-margin: 18px;\n\n\t&__header {\n\t\tposition: sticky;\n\t\tz-index: 10;\n\t\ttop: 0;\n\t\tpadding: 0 var(--margin);\n\t\tpadding-bottom: var(--secondary-margin);\n\t\tbackground-color: var(--color-main-background);\n\t}\n\n\t&__form {\n\t\tposition: relative;\n\t\toverflow: auto;\n\t\tpadding: 0 var(--margin);\n\t\t// overlap header bottom padding\n\t\tmargin-top: calc(-1 * var(--secondary-margin));\n\t}\n\n\tfieldset {\n\t\tdisplay: grid;\n\t\twidth: 100%;\n\t\tmargin-top: calc(var(--secondary-margin) * 1.5);\n\t\tpadding-bottom: var(--secondary-margin);\n\t\tgrid-template-columns: 1fr 1fr;\n\n\t\t:deep(legend) {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\twidth: 100%;\n\t\t\tmargin-bottom: calc(var(--secondary-margin) / 2);\n\t\t}\n\n\t\t&.conflict-picker__all {\n\t\t\tposition: sticky;\n\t\t\ttop: 0;\n\t\t\tmargin: 0;\n\t\t\tpadding: var(--secondary-margin) 0;\n\t\t\tbackground-image: linear-gradient(to top, transparent, var(--color-main-background-blur) 10%, var(--color-main-background) 15%);\n\t\t\t// Proper select all checkboxes alignment\n\t\t\t& + fieldset {\n\t\t\t\tmargin-top: 0;\n\t\t\t}\n\n\t\t\t:deep(label) {\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Do not use a real disabled state so\n\t// the user can still click and trigger the\n\t// form validation check.\n\t.button-vue--disabled {\n\t\tcursor: default;\n\t\topacity: .5;\n\t\tfilter: saturate(.7);\n\t}\n\n\t:deep(.dialog__actions) {\n\t\twidth: auto;\n\t\tmargin-inline: 12px;\n\t\tspan.dialog__actions-separator {\n\t\t\tmargin-left: auto;\n\t\t}\n\t}\n}\n\n// Responsive layout\n@media screen and (max-width: 768px) {\n\t.conflict-picker {\n\t\t--margin: var(--secondary-margin) !important;\n\n\t\t&__description {\n\t\t\tdisplay: none !important;\n\t\t}\n\n\t\tfieldset {\n\t\t\tgrid-template-columns: 1fr !important;\n\t\t\t&.conflict-picker__all {\n\t\t\t\tposition: static;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Responsive layout\n@media screen and (max-width: 512px) {\n\t.conflict-picker {\n\t\t:deep(.dialog__actions) {\n\t\t\tflex-wrap: wrap;\n\t\t\tspan.dialog__actions-separator {\n\t\t\t\t// Make the second row wrap\n\t\t\t\twidth: 100%;\n\t\t\t}\n\t\t}\n\t}\n}\n</style>\n"],"names":["_sfc_main","defineComponent","NcCheckboxRadioSwitch","NcDateTime","t","isFileSystemFileEntry","formatFileSize","FileType","generateUrl","isFileSystemEntry","NcButton","NcDialog","n","logger","showError","getUniqueName"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}