Merge pull request #14905 from ElectronicBlueberry/dnd-upload

Add global drag and drop upload
This commit is contained in:
Dannon
2022-12-19 12:55:13 -05:00
committed by GitHub
22 changed files with 428 additions and 228 deletions
-1
View File
@@ -20,7 +20,6 @@ export { SweepsterVisualization, SweepsterVisualizationView } from "viz/sweepste
export { createTabularDatasetChunkedView } from "mvc/dataset/data";
export { default as LegacyGridView } from "legacy/grid/grid-view";
export { create_chart, create_histogram } from "reports/run_stats";
export { openGlobalUploadModal } from "components/Upload";
export { runTour } from "components/Tour/runTour";
export { Toast } from "ui/toast"; // TODO: remove when external consumers are updated/gone (IES right now)
@@ -46,7 +46,7 @@ import { UrlTracker } from "./utilities";
import { Model } from "./model";
import { Services } from "./services";
import { getAppRoot } from "onload/loadConfig";
import { mountUploadModal } from "components/Upload";
import { useGlobalUploadModal } from "composables/globalUploadModal";
Vue.use(BootstrapVue);
@@ -78,6 +78,10 @@ export default {
default: true,
},
},
setup() {
const { openGlobalUploadModal } = useGlobalUploadModal();
return { openGlobalUploadModal };
},
data() {
return {
errorMessage: null,
@@ -133,7 +137,7 @@ export default {
modalShow: true,
selectable: true,
};
mountUploadModal(propsData);
this.openGlobalUploadModal(propsData);
this.modalShow = false;
},
/** Called when selection is complete, values are formatted and parsed to external callback **/
@@ -13,14 +13,17 @@
</template>
<script>
import { openGlobalUploadModal } from "components/Upload";
import { useGlobalUploadModal } from "composables/globalUploadModal";
export default {
props: {
message: { type: String, default: "This history is empty." },
},
setup() {
const { openGlobalUploadModal } = useGlobalUploadModal();
return { openGlobalUploadModal };
},
methods: {
openGlobalUploadModal,
clickDataLink() {
this.eventHub.$emit("openToolSection", "getext");
},
+7 -2
View File
@@ -70,7 +70,8 @@
<script>
import ToolSection from "./Common/ToolSection";
import ToolSearch from "./Common/ToolSearch";
import { UploadButton, openGlobalUploadModal } from "components/Upload";
import { UploadButton } from "components/Upload";
import { useGlobalUploadModal } from "composables/globalUploadModal";
import FavoritesButton from "./Buttons/FavoritesButton";
import PanelViewButton from "./Buttons/PanelViewButton";
import { filterToolSections, filterTools, hasResults } from "./utilities";
@@ -106,6 +107,10 @@ export default {
default: _l("Workflows"),
},
},
setup() {
const { openGlobalUploadModal } = useGlobalUploadModal();
return { openGlobalUploadModal };
},
data() {
return {
query: null,
@@ -171,7 +176,7 @@ export default {
onOpen(tool, evt) {
if (tool.id === "upload1") {
evt.preventDefault();
openGlobalUploadModal();
this.openGlobalUploadModal();
} else if (tool.form_style === "regular") {
evt.preventDefault();
// encode spaces in tool.id
@@ -28,7 +28,7 @@
<script>
import Vue from "vue";
import infiniteScroll from "vue-infinite-scroll";
import { openGlobalUploadModal } from "components/Upload";
import { useGlobalUploadModal } from "composables/globalUploadModal";
import { fetchData } from "./services";
import ToolsListItem from "./ToolsListItem";
@@ -44,6 +44,10 @@ export default {
default: null,
},
},
setup() {
const { openGlobalUploadModal } = useGlobalUploadModal();
return { openGlobalUploadModal };
},
data() {
return {
allLoaded: false,
@@ -62,7 +66,7 @@ export default {
methods: {
onOpen(tool) {
if (tool.id === "upload1") {
openGlobalUploadModal();
this.openGlobalUploadModal();
} else if (tool.form_style === "regular") {
// encode spaces in tool.id
const toolId = tool.id;
@@ -0,0 +1,71 @@
<script setup>
import { ref, computed } from "vue";
import { useFileDrop } from "composables/fileDrop";
import { useGlobalUploadModal } from "composables/globalUploadModal";
const modalContentElement = ref(null);
const { isFileOverDocument, isFileOverDropZone } = useFileDrop(modalContentElement, onDrop, true);
const modalClass = computed(() => {
if (isFileOverDropZone.value) {
return "ui-drag-and-drop-modal drag-over";
} else {
return "ui-drag-and-drop-modal";
}
});
const { openGlobalUploadModal } = useGlobalUploadModal();
function onDrop(event) {
console.debug(event.dataTransfer);
if (event.dataTransfer?.files?.length > 0) {
openGlobalUploadModal({
immediateUpload: true,
immediateFiles: event.dataTransfer.files,
});
}
}
</script>
<template>
<b-modal v-model="isFileOverDocument" :modal-class="modalClass" hide-header hide-footer centered>
<div ref="modalContentElement" class="inner-content h-xl">Drop Files here to Upload</div>
</b-modal>
</template>
<style lang="scss">
@import "theme/blue.scss";
.ui-drag-and-drop-modal {
.modal-content {
background-color: transparent;
border-radius: 16px;
border: 6px dashed;
border-color: $brand-secondary;
min-height: 40vh;
.modal-body {
display: flex;
}
.inner-content {
flex: 1 1 auto;
display: grid;
place-items: center;
color: $brand-secondary;
font-weight: bold;
}
}
&.drag-over {
.modal-content {
border-color: lighten($brand-info, 30%);
.inner-content {
color: lighten($brand-info, 30%);
}
}
}
}
</style>
@@ -289,6 +289,9 @@ export default {
_eventCreate: function () {
this.uploadbox.add([{ name: defaultNewFileName, size: 0, mode: "new" }]);
},
addFiles: function (files) {
this.uploadbox.add(files);
},
/** Pause upload process */
_eventStop: function () {
if (this.counterRunning > 0) {
@@ -28,7 +28,8 @@ import { VBTooltip } from "bootstrap-vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { library } from "@fortawesome/fontawesome-svg-core";
import { faUpload } from "@fortawesome/free-solid-svg-icons";
import { openGlobalUploadModal } from "./mount";
import { useGlobalUploadModal } from "composables/globalUploadModal";
library.add(faUpload);
export default {
@@ -39,6 +40,10 @@ export default {
props: {
title: { type: String, default: "Download from URL or upload files from disk" },
},
setup() {
const { openGlobalUploadModal } = useGlobalUploadModal();
return { openGlobalUploadModal };
},
data() {
return {
status: "",
@@ -58,7 +63,7 @@ export default {
},
methods: {
showUploadDialog() {
openGlobalUploadModal();
this.openGlobalUploadModal();
},
setStatus(val) {
this.status = val;
@@ -2,12 +2,12 @@ import MockAdapter from "axios-mock-adapter";
import axios from "axios";
import UploadModal from "./UploadModal";
import UploadModalContent from "./UploadModalContent";
import store from "../../store";
import { mount } from "@vue/test-utils";
import { getLocalVue } from "tests/jest/helpers";
import MockCurrentUser from "../providers/MockCurrentUser";
import MockCurrentHistory from "../providers/MockCurrentHistory";
import { getLocalVue, mockModule } from "tests/jest/helpers";
import { userStore } from "store/userStore";
import { historyStore } from "store/historyStore";
import { configStore } from "store/configStore";
import Vuex from "vuex";
jest.mock("app");
@@ -17,6 +17,16 @@ const propsData = {
fileSourcesConfigured: true,
};
const createStore = () => {
return new Vuex.Store({
modules: {
user: mockModule(userStore, { currentUser: { id: "fakeuser" } }),
history: mockModule(historyStore, { currentHistoryId: "fakehistory", histories: { fakehistory: {} } }),
config: mockModule(configStore, { config: {} }),
},
});
};
describe("UploadModal.vue", () => {
let wrapper;
let axiosMock;
@@ -47,17 +57,14 @@ describe("UploadModal.vue", () => {
axiosMock.onGet(`/api/datatypes?extension_only=False`).reply(200, datatypesResponse);
const localVue = getLocalVue();
const store = createStore();
wrapper = await mount(UploadModal, {
store,
provide: { store },
propsData,
localVue,
stubs: {
// Need to stub all this horrible-ness because of the last 2 tests
// which need to dig into the first layer of the mount tree, will remove
// all of this shortly with a PR that completely replaces Upload
CurrentUser: MockCurrentUser({ id: "fakeuser" }),
UserHistories: MockCurrentHistory({ id: "fakehistory" }),
BTabs: true,
BTab: true,
Collection: true,
@@ -66,6 +73,8 @@ describe("UploadModal.vue", () => {
RulesInput: true,
},
});
await wrapper.vm.open();
});
afterEach(() => {
@@ -74,8 +83,9 @@ describe("UploadModal.vue", () => {
});
it("should load with correct defaults", async () => {
expect(wrapper.vm.auto.id).toBe("auto");
expect(wrapper.vm.datatypesDisableAuto).toBe(false);
const contentWrapper = wrapper.findComponent(UploadModalContent);
expect(contentWrapper.vm.auto.id).toBe("auto");
expect(contentWrapper.vm.datatypesDisableAuto).toBe(false);
});
it("should fetch datatypes and parse them", async () => {
+114 -83
View File
@@ -1,87 +1,118 @@
<!--
Temporary modal wrapper until I replace the entire UploadModal which desperately needs a rewrite.
Provides user and current history to modal because it currently has initialization sequence issues
-->
<script setup>
import UploadModalContent from "./UploadModalContent";
import { ref, watch } from "vue";
import { getAppRoot } from "onload";
import { useCurrentUser } from "composables/user";
import { useUserHistories } from "composables/userHistories";
import { useConfig } from "composables/config";
const { currentUser } = useCurrentUser();
const { currentHistoryId } = useUserHistories(currentUser);
const { config, isLoaded } = useConfig();
function getDefaultOptions() {
const baseOptions = {
title: "Upload from Disk or Web",
modalStatic: true,
callback: null,
multiple: true,
selectable: false,
uploadPath: "",
immediateUpload: false,
immediateFiles: null,
};
const configOptions = isLoaded.value
? {
uploadPath: config.value.nginx_upload_path ?? `${getAppRoot()}api/tools`,
chunkUploadSize: config.value.chunk_upload_size,
fileSourcesConfigured: config.value.file_sources_configured,
ftpUploadSite: config.value.ftp_upload_site,
defaultDbKey: config.value.default_genome,
defaultExtension: config.value.default_extension,
}
: {};
return { ...baseOptions, ...configOptions };
}
const options = ref(getDefaultOptions());
const showModal = ref(false);
const content = ref(null);
function dismiss(result) {
if (result && options.value.callback) {
options.value.callback(result);
}
showModal.value = false;
}
function wait(milliseconds) {
return new Promise((resolve) => {
setTimeout(() => resolve(), milliseconds);
});
}
async function open(overrideOptions) {
const newOptions = overrideOptions ?? {};
options.value = { ...getDefaultOptions(), ...newOptions };
if (options.value.callback) {
options.value.hasCallback = true;
}
showModal.value = true;
await wait(100);
if (options.value.immediateUpload) {
content.value.immediateUpload(options.value.immediateFiles);
}
}
watch(
() => showModal.value,
(modalShown) => setIframeEvents(modalShown)
);
function setIframeEvents(disableEvents) {
const element = document.getElementById("galaxy_main");
if (element) {
element.style["pointer-events"] = disableEvents ? "none" : "auto";
}
}
defineExpose({
open,
});
</script>
<template>
<CurrentUser v-slot="{ user }">
<UserHistories v-if="user" v-slot="{ currentHistoryId }" :user="user">
<b-modal
v-model="modalShow"
:static="modalStatic"
header-class="no-separator"
modal-class="ui-modal"
dialog-class="upload-dialog"
body-class="upload-dialog-body"
no-enforce-focus
hide-footer>
<template v-slot:modal-header>
<h2 class="title h-sm" tabindex="0">{{ title | localize }}</h2>
</template>
<b-modal
v-model="showModal"
:static="options.modalStatic"
header-class="no-separator"
modal-class="ui-modal"
dialog-class="upload-dialog"
body-class="upload-dialog-body"
no-enforce-focus
hide-footer>
<template v-slot:modal-header>
<h2 class="title h-sm" tabindex="0">{{ options.title }}</h2>
</template>
<UploadModalContent
v-if="currentHistoryId"
:current-user-id="user.id"
:current-history-id="currentHistoryId"
v-bind="{ ...$props, ...$attrs }"
@dismiss="dismiss" />
</b-modal>
</UserHistories>
</CurrentUser>
<UploadModalContent
v-if="currentHistoryId"
ref="content"
:key="showModal"
:currentUserId="currentUser.id"
:currentHistoryId="currentHistoryId"
v-bind="options"
@dismiss="dismiss" />
</b-modal>
</template>
<script>
import CurrentUser from "../providers/CurrentUser";
import UserHistories from "components/providers/UserHistories";
import UploadModalContent from "./UploadModalContent";
import { commonProps } from "./helpers";
export default {
components: {
CurrentUser,
UserHistories,
UploadModalContent,
},
props: {
title: { type: String, default: "Download from web or upload from disk" },
modalStatic: { type: Boolean, default: true },
...commonProps,
},
data() {
return {
modalShow: false,
};
},
watch: {
modalShow() {
this.setIframeEvents(this.modalShow);
},
},
mounted() {
this.show();
// handles subsequent external requests to re-open a re-used modal
this.$root.$on("openUpload", this.show);
},
methods: {
show() {
this.modalShow = true;
},
hide() {
this.modalShow = false;
},
dismiss(result) {
if (undefined !== result) {
this.$root.$emit("uploadResult", result);
}
this.hide();
},
/** Disable mouse events in iframe to prevent interference with uploader drop box */
setIframeEvents(disableEvents) {
const element = document.getElementById("galaxy_main");
if (element) {
element.style["pointer-events"] = disableEvents ? "none" : "auto";
}
},
},
};
</script>
@@ -2,6 +2,7 @@
<b-tabs v-if="ready">
<b-tab v-if="showRegular" id="regular" title="Regular" button-id="tab-title-link-regular">
<default
ref="regular"
:app="this"
:lazy-load-max="50"
:multiple="multiple"
@@ -35,7 +36,6 @@ import RulesInput from "./RulesInput";
import LoadingSpan from "components/LoadingSpan";
import { uploadModelsToPayload } from "./helpers";
import { BTabs, BTab } from "bootstrap-vue";
import { commonProps } from "./helpers";
export default {
components: {
@@ -50,7 +50,29 @@ export default {
props: {
currentHistoryId: { type: String, required: true },
currentUserId: { type: String, default: "" },
...commonProps,
uploadPath: { type: String, required: true },
chunkUploadSize: { type: Number, default: 1024 },
fileSourcesConfigured: { type: Boolean, default: false },
ftpUploadSite: { type: String, default: "" },
defaultDbKey: { type: String, default: UploadUtils.DEFAULT_DBKEY },
defaultExtension: { type: String, default: UploadUtils.DEFAULT_EXTENSION },
datatypesDisableAuto: { type: Boolean, default: false },
formats: { type: Array, default: null },
multiple: {
// Restrict the forms to a single dataset upload if false
type: Boolean,
default: true,
},
hasCallback: {
// Return uploads when done if supplied.
type: Boolean,
default: false,
},
selectable: { type: Boolean, default: false },
auto: {
type: Object,
default: () => UploadUtils.AUTO_EXTENSION,
},
},
data: function () {
return {
@@ -180,6 +202,10 @@ export default {
toData: function (items, history_id, composite = false) {
return uploadModelsToPayload(items, history_id, composite);
},
immediateUpload: function (files) {
this.$refs.regular?.addFiles(files);
this.$refs.regular?._eventStart();
},
},
};
</script>
-18
View File
@@ -1,18 +0,0 @@
import { getGalaxyInstance } from "app";
import { getAppRoot } from "onload";
export function initializeUploadDefaults(propsData = {}) {
const Galaxy = getGalaxyInstance();
const appRoot = getAppRoot();
const defaults = {
multiple: true,
uploadPath: Galaxy.config.nginx_upload_path || `${appRoot}api/tools`,
chunkUploadSize: Galaxy.config.chunk_upload_size,
fileSourcesConfigured: Galaxy.config.file_sources_configured,
ftpUploadSite: Galaxy.config.ftp_upload_site,
defaultDbKey: Galaxy.config.default_genome,
defaultExtension: Galaxy.config.default_extension,
selectable: false,
};
return Object.assign({}, defaults, propsData);
}
-56
View File
@@ -1,4 +1,3 @@
import UploadUtils from "mvc/upload/upload-utils";
export const defaultNewFileName = "New File";
const URI_PREFIXES = ["http", "https", "ftp", "file", "gxfiles", "gximport", "gxuserimport", "gxftp"];
@@ -109,58 +108,3 @@ export function uploadModelsToPayload(items, history_id, composite = false) {
files: files,
};
}
export const commonProps = {
uploadPath: {
type: String,
required: true,
},
chunkUploadSize: {
type: Number,
default: 1024,
},
fileSourcesConfigured: {
type: Boolean,
default: false,
},
ftpUploadSite: {
type: String,
default: "",
},
defaultDbKey: {
type: String,
default: UploadUtils.DEFAULT_DBKEY,
},
defaultExtension: {
type: String,
default: UploadUtils.DEFAULT_EXTENSION,
},
datatypesDisableAuto: {
type: Boolean,
default: false,
},
formats: {
type: Array,
default: null,
},
multiple: {
// Restrict the forms to a single dataset upload if false
type: Boolean,
default: true,
},
hasCallback: {
// Return uploads when done if supplied.
type: Boolean,
default: false,
},
selectable: {
type: Boolean,
default: false,
},
auto: {
type: Object,
default: () => {
return UploadUtils.AUTO_EXTENSION;
},
},
};
-2
View File
@@ -2,6 +2,4 @@
* External entry point for Upload components (currently only the modal).
*/
export { default as UploadModal } from "./UploadModal";
export { initializeUploadDefaults } from "./config";
export { openGlobalUploadModal, mountUploadModal } from "./mount";
export { default as UploadButton } from "./UploadButton";
-37
View File
@@ -1,37 +0,0 @@
import UploadModal from "./UploadModal";
import { initializeUploadDefaults } from "./config";
import { mountVueComponent } from "utils/mountVueComponent";
export function mountUploadModal(options = {}) {
const props = initializeUploadDefaults(options);
// should use events insted of passing in functions
const { callback, ...propsData } = props;
if (callback) {
// internal display characteristic
propsData.hasCallback = true;
}
const mounter = mountVueComponent(UploadModal);
const container = document.createElement("div");
document.body.appendChild(container);
const uploadVm = mounter(propsData, container);
if (callback) {
uploadVm.$once("uploadResult", callback);
}
return uploadVm;
}
// Global upload dialog instance
let uploadVm = null;
export function openGlobalUploadModal(options) {
if (!uploadVm) {
uploadVm = mountUploadModal(options);
}
// re-open
uploadVm.$emit("openUpload", uploadVm);
return uploadVm;
}
+107
View File
@@ -0,0 +1,107 @@
import { ref, unref } from "vue";
import { useEventListener } from "@vueuse/core";
/**
* Custom File-Drop composable
* @param dropZone Element which files should be dropped on
* @param onDrop callback function called when drop occurs
* @param solo when true, only reacts if no modal is open
*/
export function useFileDrop(dropZone, onDrop, solo) {
const isFileOverDocument = ref(false);
const isFileOverDropZone = ref(false);
const dragBlocked = ref(false);
// Don't react to page-internal drag events
useEventListener(
document.body,
"dragstart",
() => {
dragBlocked.value = true;
},
true
);
useEventListener(
document.body,
"dragover",
(event) => {
if (!dragBlocked.value) {
// prevent the browser from opening the file
event.preventDefault();
}
},
true
);
useEventListener(
document.body,
"drop",
(event) => {
if (!dragBlocked.value) {
// prevent the browser from opening the file
event.preventDefault();
if (isFileOverDropZone.value && isFileOverDocument.value) {
unref(onDrop)(event);
}
}
isFileOverDocument.value = false;
dragBlocked.value = false;
},
true
);
useEventListener(
document.body,
"dragend",
() => {
// reset on drag end
isFileOverDocument.value = false;
isFileOverDropZone.value = false;
dragBlocked.value = false;
},
true
);
useEventListener(
document.body,
"dragenter",
(event) => {
// init values if drag is possible
if (!dragBlocked.value && !(unref(solo) && isAnyModalOpen())) {
isFileOverDocument.value = true;
isFileOverDropZone.value = false;
event.preventDefault();
}
},
true
);
/** returns if any bootstrap modal is open */
function isAnyModalOpen() {
return document.querySelectorAll(".modal.show").length > 0;
}
useEventListener(
dropZone,
"dragenter",
() => {
isFileOverDropZone.value = true;
},
true
);
useEventListener(
dropZone,
"dragleave",
() => {
isFileOverDropZone.value = false;
},
true
);
return { isFileOverDocument, isFileOverDropZone };
}
@@ -0,0 +1,16 @@
import { ref } from "vue";
let modal = ref(null);
export function setGlobalUploadModal(modalRef) {
// eslint-disable-next-line vue/no-ref-as-operand
modal = modalRef;
}
export function useGlobalUploadModal() {
const openGlobalUploadModal = (options) => {
modal.value?.open(options);
};
return { openGlobalUploadModal };
}
+19
View File
@@ -0,0 +1,19 @@
import { computed, watch, unref, inject } from "vue";
export function useUserHistories(user) {
const store = inject("store");
watch(
() => unref(user),
(newUser, oldUser) => {
if (newUser?.id !== oldUser?.id) {
store.dispatch("history/loadHistories");
}
},
{ immediate: true }
);
const currentHistoryId = computed(() => store.getters["history/currentHistoryId"]);
return { currentHistoryId };
}
+8 -2
View File
@@ -36,6 +36,7 @@
<div id="dd-helper" />
<Toast ref="toastRef" />
<ConfirmDialog ref="confirmDialogRef" />
<UploadModal ref="uploadModal" />
</div>
</template>
<script>
@@ -49,23 +50,28 @@ import { WindowManager } from "layout/window-manager";
import { safePath } from "utils/redirect";
import Toast from "components/Toast";
import ConfirmDialog from "components/ConfirmDialog";
import UploadModal from "components/Upload/UploadModal.vue";
import { ref } from "vue";
import { setToastComponentRef } from "composables/toast";
import { setConfirmDialogComponentRef } from "composables/confirmDialog";
import { ref } from "vue";
import { setGlobalUploadModal } from "composables/globalUploadModal";
export default {
components: {
Masthead,
Toast,
ConfirmDialog,
UploadModal,
},
setup() {
const toastRef = ref(null);
setToastComponentRef(toastRef);
const confirmDialogRef = ref(null);
setConfirmDialogComponentRef(confirmDialogRef);
const uploadModal = ref(null);
setGlobalUploadModal(uploadModal);
return { toastRef, confirmDialogRef };
return { toastRef, confirmDialogRef, uploadModal };
},
data() {
return {
@@ -14,6 +14,7 @@
</div>
</div>
<SidePanel v-if="showPanels" side="right" :current-panel="getHistoryIndex()" :current-panel-properties="{}" />
<DragAndDropModal />
</div>
</template>
<script>
@@ -22,11 +23,13 @@ import HistoryIndex from "components/History/Index";
import ToolBox from "components/Panels/ProviderAwareToolBox";
import SidePanel from "components/Panels/SidePanel";
import CenterFrame from "./CenterFrame";
import DragAndDropModal from "components/Upload/DragAndDropModal";
export default {
components: {
CenterFrame,
SidePanel,
DragAndDropModal,
},
data() {
return {
+3 -2
View File
@@ -4,12 +4,12 @@ import Vue from "vue";
import DataDialog from "components/DataDialog/DataDialog.vue";
import { FilesDialog } from "components/FilesDialog";
import DatasetCollectionDialog from "components/SelectionDialog/DatasetCollectionDialog.vue";
import { mountUploadModal } from "components/Upload";
import { uploadModelsToPayload } from "components/Upload/helpers";
import { getGalaxyInstance } from "app";
import { getAppRoot } from "onload/loadConfig";
import { submitUpload } from "utils/uploadbox";
import { rewatchHistory } from "store/historyStore/model/watchHistory";
import { useGlobalUploadModal } from "composables/globalUploadModal";
// This should be moved more centrally (though still hanging off Galaxy for
// external use?), and populated from the store; just using this as a temporary
@@ -44,7 +44,8 @@ export function dialog(callback, options = {}) {
history: history_id,
});
if (options.new) {
mountUploadModal(options);
const { openGlobalUploadModal } = useGlobalUploadModal();
openGlobalUploadModal(options);
} else {
_mountSelectionDialog(DataDialog, options);
}
+3 -3
View File
@@ -10486,9 +10486,9 @@ void-elements@^2.0.0:
integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==
vue-demi@*:
version "0.13.6"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.6.tgz#f9433cbd75e68a970dec066647f4ba6c08ced48f"
integrity sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==
version "0.13.11"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
vue-eslint-parser@^9.0.1:
version "9.0.3"