@nextcloud/upload
Version:
Nextcloud file upload client
586 lines (585 loc) • 24.7 kB
JavaScript
import '../assets/ConflictPicker-C18pJD_w.css';
import { defineComponent } from "vue";
import { showError } from "@nextcloud/dialogs";
import { FileType, formatFileSize, getUniqueName } from "@nextcloud/files";
import { n as normalizeComponent, t, i as isFileSystemEntry, a as isFileSystemFileEntry, l as logger, b as n } from "./index-Dkr9ebK1.mjs";
import NcCheckboxRadioSwitch from "@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js";
import NcDialog from "@nextcloud/vue/dist/Components/NcDialog.js";
import NcButton from "@nextcloud/vue/dist/Components/NcButton.js";
import { generateUrl } from "@nextcloud/router";
import NcDateTime from "@nextcloud/vue/dist/Components/NcDateTime.js";
const _sfc_main$5 = {
name: "ArrowRightIcon",
emits: ["click"],
props: {
title: {
type: String
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
};
var _sfc_render$5 = function render() {
var _vm = this, _c = _vm._self._c;
return _c("span", _vm._b({ staticClass: "material-design-icon arrow-right-icon", attrs: { "aria-hidden": _vm.title ? null : "true", "aria-label": _vm.title, "role": "img" }, on: { "click": function($event) {
return _vm.$emit("click", $event);
} } }, "span", _vm.$attrs, false), [_c("svg", { staticClass: "material-design-icon__svg", attrs: { "fill": _vm.fillColor, "width": _vm.size, "height": _vm.size, "viewBox": "0 0 24 24" } }, [_c("path", { attrs: { "d": "M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" } }, [_vm.title ? _c("title", [_vm._v(_vm._s(_vm.title))]) : _vm._e()])])]);
};
var _sfc_staticRenderFns$5 = [];
var __component__$5 = /* @__PURE__ */ normalizeComponent(
_sfc_main$5,
_sfc_render$5,
_sfc_staticRenderFns$5,
false,
null,
null
);
const ArrowRight = __component__$5.exports;
const _sfc_main$4 = {
name: "CloseIcon",
emits: ["click"],
props: {
title: {
type: String
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
};
var _sfc_render$4 = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("span", _vm._b({ staticClass: "material-design-icon close-icon", attrs: { "aria-hidden": _vm.title ? null : "true", "aria-label": _vm.title, "role": "img" }, on: { "click": function($event) {
return _vm.$emit("click", $event);
} } }, "span", _vm.$attrs, false), [_c("svg", { staticClass: "material-design-icon__svg", attrs: { "fill": _vm.fillColor, "width": _vm.size, "height": _vm.size, "viewBox": "0 0 24 24" } }, [_c("path", { attrs: { "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" } }, [_vm.title ? _c("title", [_vm._v(_vm._s(_vm.title))]) : _vm._e()])])]);
};
var _sfc_staticRenderFns$4 = [];
var __component__$4 = /* @__PURE__ */ normalizeComponent(
_sfc_main$4,
_sfc_render$4,
_sfc_staticRenderFns$4,
false,
null,
null
);
const Close = __component__$4.exports;
const _sfc_main$3 = {
name: "FileIcon",
emits: ["click"],
props: {
title: {
type: String
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
};
var _sfc_render$3 = function render3() {
var _vm = this, _c = _vm._self._c;
return _c("span", _vm._b({ staticClass: "material-design-icon file-icon", attrs: { "aria-hidden": _vm.title ? null : "true", "aria-label": _vm.title, "role": "img" }, on: { "click": function($event) {
return _vm.$emit("click", $event);
} } }, "span", _vm.$attrs, false), [_c("svg", { staticClass: "material-design-icon__svg", attrs: { "fill": _vm.fillColor, "width": _vm.size, "height": _vm.size, "viewBox": "0 0 24 24" } }, [_c("path", { attrs: { "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" } }, [_vm.title ? _c("title", [_vm._v(_vm._s(_vm.title))]) : _vm._e()])])]);
};
var _sfc_staticRenderFns$3 = [];
var __component__$3 = /* @__PURE__ */ normalizeComponent(
_sfc_main$3,
_sfc_render$3,
_sfc_staticRenderFns$3,
false,
null,
null
);
const FileSvg = __component__$3.exports;
const _sfc_main$2 = {
name: "FolderIcon",
emits: ["click"],
props: {
title: {
type: String
},
fillColor: {
type: String,
default: "currentColor"
},
size: {
type: Number,
default: 24
}
}
};
var _sfc_render$2 = function render4() {
var _vm = this, _c = _vm._self._c;
return _c("span", _vm._b({ staticClass: "material-design-icon folder-icon", attrs: { "aria-hidden": _vm.title ? null : "true", "aria-label": _vm.title, "role": "img" }, on: { "click": function($event) {
return _vm.$emit("click", $event);
} } }, "span", _vm.$attrs, false), [_c("svg", { staticClass: "material-design-icon__svg", attrs: { "fill": _vm.fillColor, "width": _vm.size, "height": _vm.size, "viewBox": "0 0 24 24" } }, [_c("path", { attrs: { "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" } }, [_vm.title ? _c("title", [_vm._v(_vm._s(_vm.title))]) : _vm._e()])])]);
};
var _sfc_staticRenderFns$2 = [];
var __component__$2 = /* @__PURE__ */ normalizeComponent(
_sfc_main$2,
_sfc_render$2,
_sfc_staticRenderFns$2,
false,
null,
null
);
const FolderSvg = __component__$2.exports;
const PREVIEW_SIZE = 64;
const _sfc_main$1 = defineComponent({
name: "NodesPicker",
components: {
FileSvg,
FolderSvg,
NcCheckboxRadioSwitch,
NcDateTime
},
props: {
incoming: {
type: [File, Object],
required: true
},
existing: {
type: Object,
required: true
},
newSelected: {
type: Array,
required: true
},
oldSelected: {
type: Array,
required: true
}
},
data() {
return {
asyncPreview: null,
incomingFile: null
};
},
computed: {
/**
* Whether the incoming or existing file is selected.
* This is used by the parent component to ensure
* that the user has selected at least one of the two files.
*/
isEnoughSelected() {
return this.isChecked(this.incoming, this.newSelected) || this.isChecked(this.existing, this.oldSelected);
},
incomingPreview() {
if (!this.incomingFile) {
return null;
}
const preview = this.previewUrl(this.incomingFile);
return preview ?? this.asyncPreview;
},
incomingLastModified() {
if (!this.incomingFile) {
return null;
}
return this.lastModified(this.incomingFile);
},
incomingSize() {
if (!this.incomingFile) {
return t("Unknown size");
}
return this.size(this.incomingFile);
},
existingPreview() {
return this.previewUrl(this.existing);
},
existingLastModified() {
return this.lastModified(this.existing);
}
},
watch: {
/**
* Watch "incoming" to update "incomingFile"
*/
incoming: {
// Run the watcher also on mount with initial "incoming" value
immediate: true,
async handler() {
if (this.incoming instanceof File) {
this.incomingFile = this.incoming;
} else if (isFileSystemFileEntry(this.incoming)) {
this.incomingFile = await new Promise((resolve, reject) => this.incoming.file(resolve, reject));
} else {
this.incomingFile = null;
}
}
}
},
methods: {
lastModified(node) {
const lastModified = node instanceof File ? new Date(node.lastModified) : node.mtime;
return lastModified ?? null;
},
size(node) {
if (node.size) {
return formatFileSize(node.size, true);
}
return t("Unknown size");
},
previewUrl(node) {
if (node instanceof File) {
this.previewImage(node).then((url) => {
this.asyncPreview = url;
});
return null;
}
if (node.type === FileType.Folder) {
return null;
}
try {
const previewUrl = node.attributes.previewUrl || generateUrl("/core/preview?fileId={fileid}", {
fileid: node.fileid
});
const url = new URL(window.location.origin + previewUrl);
url.searchParams.set("x", PREVIEW_SIZE.toString());
url.searchParams.set("y", PREVIEW_SIZE.toString());
url.searchParams.set("mimeFallback", "true");
const etag = node.attributes?.etag || "";
url.searchParams.set("v", etag.slice(0, 6));
return url.href;
} catch (e) {
return null;
}
},
isFolder(node) {
if (isFileSystemEntry(node)) {
return node.isDirectory;
}
node = node;
return node.type === FileType.Folder || node.type === "httpd/unix-directory";
},
isChecked(node, selected) {
return selected.includes(node);
},
onUpdateIncomingChecked(checked) {
if (checked) {
this.$emit("update:newSelected", [this.incoming, ...this.newSelected]);
} else {
this.$emit("update:newSelected", this.newSelected.filter((node) => node !== this.incoming));
}
},
onUpdateExistingChecked(checked) {
if (checked) {
this.$emit("update:oldSelected", [this.existing, ...this.oldSelected]);
} else {
this.$emit("update:oldSelected", this.oldSelected.filter((node) => node !== this.existing));
}
},
/**
* Get the preview Image of a file
* @param file the soon-to-be-uploaded File
*/
async previewImage(file) {
return new Promise((resolve) => {
if (file instanceof File && file.type.startsWith("image/")) {
const reader = new FileReader();
reader.onload = async (e) => {
const result = e?.target?.result;
if (result instanceof ArrayBuffer) {
const blob = new Blob([result], { type: file.type });
const url = URL.createObjectURL(blob);
resolve(url);
return;
}
resolve(null);
};
reader.readAsArrayBuffer(file);
} else {
resolve(null);
}
});
},
t
}
});
var _sfc_render$1 = function render5() {
var _vm = this, _c = _vm._self._c;
_vm._self._setupProxy;
return _c("fieldset", { staticClass: "node-picker__wrapper", attrs: { "data-cy-conflict-picker-fieldset": _vm.existing.basename } }, [_c("legend", [_vm._v(_vm._s(_vm.existing.basename))]), _c("NcCheckboxRadioSwitch", { attrs: { "checked": _vm.isChecked(_vm.incoming, _vm.newSelected), "required": !_vm.isEnoughSelected, "data-cy-conflict-picker-input-incoming": _vm.existing.basename }, on: { "update:checked": _vm.onUpdateIncomingChecked } }, [_c("span", { staticClass: "node-picker node-picker--incoming" }, [!_vm.incomingPreview ? [_vm.isFolder(_vm.incoming) ? _c("FolderSvg", { staticClass: "node-picker__icon", attrs: { "size": 48 } }) : _c("FileSvg", { staticClass: "node-picker__icon", attrs: { "size": 48 } })] : _c("img", { staticClass: "node-picker__preview", attrs: { "src": _vm.incomingPreview, "alt": _vm.t("Preview image"), "loading": "lazy" } }), _c("span", { staticClass: "node-picker__desc" }, [_c("span", { staticClass: "node-picker__name" }, [_vm._v(_vm._s(_vm.t("New version")))]), _vm.incomingLastModified ? _c("NcDateTime", { staticClass: "node-picker__mtime", attrs: { "timestamp": _vm.incomingLastModified, "relative-time": false, "format": { timeStyle: "short", dateStyle: "medium" } } }) : _c("span", { staticClass: "node-picker__mtime" }, [_vm._v(" " + _vm._s(_vm.t("Last modified date unknown")) + " ")]), _c("span", { staticClass: "node-picker__size" }, [_vm._v(_vm._s(_vm.incomingSize))])], 1)], 2)]), _c("NcCheckboxRadioSwitch", { attrs: { "checked": _vm.isChecked(_vm.existing, _vm.oldSelected), "required": !_vm.isEnoughSelected, "data-cy-conflict-picker-input-existing": _vm.existing.basename }, on: { "update:checked": _vm.onUpdateExistingChecked } }, [_c("span", { staticClass: "node-picker node-picker--existing" }, [!_vm.existingPreview ? [_vm.isFolder(_vm.existing) ? _c("FolderSvg", { staticClass: "node-picker__icon", attrs: { "size": 48 } }) : _c("FileSvg", { staticClass: "node-picker__icon", attrs: { "size": 48 } })] : _c("img", { staticClass: "node-picker__preview", attrs: { "src": _vm.existingPreview, "alt": _vm.t("Preview image"), "loading": "lazy" } }), _c("span", { staticClass: "node-picker__desc" }, [_c("span", { staticClass: "node-picker__name" }, [_vm._v(_vm._s(_vm.t("Existing version")))]), _vm.existingLastModified ? _c("NcDateTime", { staticClass: "node-picker__mtime", attrs: { "timestamp": _vm.existingLastModified, "relative-time": false, "format": { timeStyle: "short", dateStyle: "medium" } } }) : _c("span", { staticClass: "node-picker__mtime" }, [_vm._v(" " + _vm._s(_vm.t("Last modified date unknown")) + " ")]), _c("span", { staticClass: "node-picker__size" }, [_vm._v(_vm._s(_vm.size(_vm.existing)))])], 1)], 2)])], 1);
};
var _sfc_staticRenderFns$1 = [];
var __component__$1 = /* @__PURE__ */ normalizeComponent(
_sfc_main$1,
_sfc_render$1,
_sfc_staticRenderFns$1,
false,
null,
"a1eb0469"
);
const NodesPicker = __component__$1.exports;
const _sfc_main = defineComponent({
name: "ConflictPicker",
components: {
ArrowRight,
Close,
NcButton,
NcCheckboxRadioSwitch,
NcDialog,
NodesPicker
},
props: {
/** Directory/context file name */
dirname: {
type: String,
default: ""
},
/** All the existing files in the current directory */
content: {
type: Array,
required: true
},
/** New files being moved/uploaded */
conflicts: {
type: Array,
required: true
},
/**
* If set to true no hint about overwriting directory content will be shown
*/
recursiveUpload: {
type: Boolean,
default: false
}
},
emits: ["cancel", "submit"],
setup() {
return {
blockedTitle: t("You need to select at least one version of each file to continue.")
};
},
data() {
return {
// computed list of conflicting files already present in the directory
files: [],
opened: true,
newSelected: [],
oldSelected: []
};
},
computed: {
name() {
if (this?.dirname?.trim?.() !== "") {
return n("{count} file conflict in {dirname}", "{count} file conflicts in {dirname}", this.conflicts.length, {
count: this.conflicts.length,
dirname: this.dirname
});
}
return n("{count} file conflict", "{count} files conflict", this.conflicts.length, { count: this.conflicts.length });
},
skipButtonLabel() {
return n("Skip this file", "Skip {count} files", this.conflicts.length, { count: this.conflicts.length });
},
// Select all incoming files
selectAllNewBind() {
const label = this.isNoneNewSelected || this.isSomeNewSelected ? this.t("Select all") : this.t("Unselect all");
return {
"aria-label": label,
checked: this.isAllNewSelected,
indeterminate: this.isSomeNewSelected,
title: label
};
},
isAllNewSelected() {
return this.newSelected.length === this.conflicts.length;
},
isNoneNewSelected() {
return this.newSelected.length === 0;
},
isSomeNewSelected() {
return !this.isAllNewSelected && !this.isNoneNewSelected;
},
// Select all existing files
selectAllOldBind() {
const label = this.isNoneOldSelected || this.isSomeOldSelected ? this.t("Select all") : this.t("Unselect all");
return {
"aria-label": label,
checked: this.isAllOldSelected,
indeterminate: this.isSomeOldSelected,
title: label
};
},
isAllOldSelected() {
return this.oldSelected.length === this.files.length;
},
isNoneOldSelected() {
return this.oldSelected.length === 0;
},
isSomeOldSelected() {
return !this.isAllOldSelected && !this.isNoneOldSelected;
},
// Global handlings
isEnoughSelected() {
if (this.isAllOldSelected || this.isAllNewSelected) {
return true;
}
return this.$refs?.nodesPicker?.every?.((picker) => picker.isEnoughSelected);
}
},
mounted() {
this.files = this.conflicts.map((conflict) => {
const name = conflict instanceof File || isFileSystemEntry(conflict) ? conflict.name : conflict.basename;
return this.content.find((node) => node.basename === name);
}).filter(Boolean);
if (this.conflicts.length === 0 || this.files.length === 0) {
const error = new Error("ConflictPicker: files and conflicts must not be empty");
this.onCancel(error);
throw error;
}
if (this.conflicts.length !== this.files.length) {
const error = new Error("ConflictPicker: files and conflicts must have the same length. Make sure you filter out non conflicting files from the conflicts array.");
this.onCancel(error);
throw error;
}
logger.debug("ConflictPicker initialised", { files: this.files, conflicts: this.conflicts, content: this.content });
},
methods: {
onCancel(error) {
this.opened = false;
this.$emit("cancel", error);
},
onSkip() {
logger.debug("Conflict skipped. Ignoring all conflicting files");
this.opened = false;
this.$emit("submit", {
selected: [],
renamed: []
});
},
onSubmit() {
if (!this.isEnoughSelected) {
this.scrollValidityInputIntoView();
this.$refs.form.reportValidity();
showError(this.blockedTitle);
return;
}
const selectedOldNames = this.oldSelected.map((node) => node.basename);
const directoryContent = this.content.map((node) => node.basename);
const renamed = [];
const toRename = this.newSelected.filter((node) => {
const name = node instanceof File || isFileSystemEntry(node) ? node.name : node.basename;
return selectedOldNames.includes(name);
});
if (toRename.length > 0) {
toRename.forEach((file) => {
const name = file instanceof File || isFileSystemEntry(file) ? file.name : file.basename;
const newName = getUniqueName(name, directoryContent);
if (file instanceof File || isFileSystemEntry(file)) {
Object.defineProperty(file, "name", { value: newName });
renamed.push(file);
return;
}
file.rename(newName);
renamed.push(file);
});
}
const selected = this.newSelected.filter((node) => {
const name = node instanceof File || isFileSystemEntry(node) ? node.name : node.basename;
return !selectedOldNames.includes(name) && !toRename.includes(node);
});
logger.debug("Conflict resolved", { selected, renamed });
this.opened = false;
this.$emit("submit", {
selected,
renamed
});
},
/**
* Scroll the first invalid input into view.
* This is needed because the browser uses behavior: "nearest" by default.
*/
scrollValidityInputIntoView() {
const selector = '.checkbox-radio-switch input[type="checkbox"]';
const checkboxes = Array.from(this.$el.querySelectorAll(selector));
checkboxes.forEach((input) => input?.setCustomValidity?.(""));
const invalidInput = this.$el.querySelector(selector + ":invalid");
if (invalidInput) {
invalidInput.setCustomValidity(this.blockedTitle);
invalidInput.scrollIntoView({ behavior: "instant", block: "center" });
}
},
onSelectAllNew(selected) {
if (selected) {
logger.debug("Selected all new files");
this.newSelected = this.conflicts;
} else {
logger.debug("Cleared new selection");
this.newSelected = [];
}
},
onSelectAllOld(selected) {
if (selected) {
logger.debug("Selected all existing files");
this.oldSelected = this.files;
} else {
logger.debug("Cleared old selection");
this.oldSelected = [];
}
},
t
}
});
var _sfc_render = function render6() {
var _vm = this, _c = _vm._self._c;
_vm._self._setupProxy;
return _c("NcDialog", { staticClass: "conflict-picker", attrs: { "can-close": "", "data-cy-conflict-picker": "", "close-on-click-outside": false, "show": _vm.opened, "name": _vm.name, "size": "large" }, on: { "closing": _vm.onCancel }, scopedSlots: _vm._u([{ key: "actions", fn: function() {
return [_c("NcButton", { attrs: { "aria-label": _vm.t("Cancel"), "title": _vm.t("Cancel the entire operation"), "data-cy-conflict-picker-cancel": "", "type": "tertiary" }, on: { "click": _vm.onCancel }, scopedSlots: _vm._u([{ key: "icon", fn: function() {
return [_c("Close", { attrs: { "size": 20 } })];
}, proxy: true }]) }, [_vm._v(" " + _vm._s(_vm.t("Cancel")) + " ")]), _c("span", { staticClass: "dialog__actions-separator" }), _c("NcButton", { attrs: { "aria-label": _vm.skipButtonLabel, "data-cy-conflict-picker-skip": "" }, on: { "click": _vm.onSkip }, scopedSlots: _vm._u([{ key: "icon", fn: function() {
return [_c("Close", { attrs: { "size": 20 } })];
}, proxy: true }]) }, [_vm._v(" " + _vm._s(_vm.skipButtonLabel) + " ")]), _c("NcButton", { class: { "button-vue--disabled": !_vm.isEnoughSelected }, attrs: { "aria-label": _vm.t("Continue"), "title": _vm.isEnoughSelected ? "" : _vm.blockedTitle, "data-cy-conflict-picker-submit": "", "native-type": "submit", "type": "primary" }, on: { "click": function($event) {
$event.stopPropagation();
$event.preventDefault();
return _vm.onSubmit.apply(null, arguments);
} }, scopedSlots: _vm._u([{ key: "icon", fn: function() {
return [_c("ArrowRight", { attrs: { "size": 20 } })];
}, proxy: true }]) }, [_vm._v(" " + _vm._s(_vm.t("Continue")) + " ")])];
}, proxy: true }]) }, [_c("div", { staticClass: "conflict-picker__header" }, [_c("p", { staticClass: "conflict-picker__description", attrs: { "id": "conflict-picker-description" } }, [_vm._v(" " + _vm._s(_vm.t("Which files do you want to keep?"))), _c("br"), _vm._v(" " + _vm._s(_vm.t("If you select both versions, the incoming file will have a number added to its name."))), _c("br"), _vm.recursiveUpload ? [_vm._v(" " + _vm._s(_vm.t("When an incoming folder is selected, the content is written into the existing folder and a recursive conflict resolution is performed.")) + " ")] : [_vm._v(" " + _vm._s(_vm.t("When an incoming folder is selected, any conflicting files within it will also be overwritten.")) + " ")]], 2)]), _c("form", { ref: "form", staticClass: "conflict-picker__form", attrs: { "aria-labelledby": "conflict-picker-description", "data-cy-conflict-picker-form": "" }, on: { "submit": function($event) {
$event.preventDefault();
$event.stopPropagation();
return _vm.onSubmit.apply(null, arguments);
} } }, [_c("fieldset", { staticClass: "conflict-picker__all", attrs: { "data-cy-conflict-picker-fieldset": "all" } }, [_c("legend", { staticClass: "hidden-visually" }, [_vm._v(" " + _vm._s(_vm.t("Select all checkboxes")) + " ")]), _c("NcCheckboxRadioSwitch", _vm._b({ attrs: { "data-cy-conflict-picker-input-incoming": "all" }, on: { "update:checked": _vm.onSelectAllNew } }, "NcCheckboxRadioSwitch", _vm.selectAllNewBind, false), [_vm._v(" " + _vm._s(_vm.t("Select all new files")) + " ")]), _c("NcCheckboxRadioSwitch", _vm._b({ attrs: { "data-cy-conflict-picker-input-existing": "all" }, on: { "update:checked": _vm.onSelectAllOld } }, "NcCheckboxRadioSwitch", _vm.selectAllOldBind, false), [_vm._v(" " + _vm._s(_vm.t("Select all existing files")) + " ")])], 1), _vm._l(_vm.files, function(node, index) {
return _c("NodesPicker", { key: node.fileid, ref: "nodesPicker", refInFor: true, attrs: { "incoming": _vm.conflicts[index], "existing": _vm.files[index], "new-selected": _vm.newSelected, "old-selected": _vm.oldSelected }, on: { "update:newSelected": function($event) {
_vm.newSelected = $event;
}, "update:new-selected": function($event) {
_vm.newSelected = $event;
}, "update:oldSelected": function($event) {
_vm.oldSelected = $event;
}, "update:old-selected": function($event) {
_vm.oldSelected = $event;
} } });
})], 2)]);
};
var _sfc_staticRenderFns = [];
var __component__ = /* @__PURE__ */ normalizeComponent(
_sfc_main,
_sfc_render,
_sfc_staticRenderFns,
false,
null,
"b34f1dac"
);
const ConflictPicker = __component__.exports;
export {
ConflictPicker as default
};