Merge pull request #17495 from itisAliRH/workflow-import-refactor

Refactor Workflow Import components
This commit is contained in:
John Chilton
2024-02-29 17:15:58 -05:00
committed by GitHub
9 changed files with 185 additions and 132 deletions
@@ -1,14 +1,14 @@
import { getLocalVue } from "@tests/jest/helpers";
import { mount } from "@vue/test-utils";
import { getLocalVue } from "tests/jest/helpers";
import FromFileOrUrl from "./FromFileOrUrl.vue";
let lastPostRequest;
let lastPostRequest: Map<string, string>;
jest.mock("axios", () => ({
post: (_url, request) => {
post: jest.fn((_url, request) => {
lastPostRequest = request;
},
}),
}));
const localVue = getLocalVue(true);
@@ -1,12 +1,12 @@
<script setup lang="ts">
import axios from "axios";
import { BAlert, BButton, BForm, BFormGroup, BFormInput } from "bootstrap-vue";
import { computed, type Ref, ref } from "vue";
import { useRouter } from "vue-router/composables";
import { getRedirectOnImportPath } from "@/components/Workflow/redirectPath";
import { withPrefix } from "@/utils/redirect";
import { getRedirectOnImportPath } from "../redirectPath";
import LoadingSpan from "@/components/LoadingSpan.vue";
const loading = ref(false);
@@ -78,31 +78,38 @@ async function submit(ev: SubmitEvent) {
</script>
<template>
<b-form class="mt-4 workflow-import-file" @submit="submit">
<BForm class="mt-4 workflow-import-file" @submit="submit">
<h2 class="h-sm">Import from a Galaxy workflow export URL or a workflow file</h2>
<b-form-group label="Archived Workflow URL">
<b-form-input
<BFormGroup label="Archived Workflow URL">
<BFormInput
id="workflow-import-url-input"
v-model="sourceURL"
aria-label="Workflow Import URL"
type="url" />
If the workflow is accessible via a URL, enter the URL above and click Import.
</b-form-group>
<b-form-group label="Archived Workflow File">
</BFormGroup>
<BFormGroup label="Archived Workflow File">
<b-form-file v-model="sourceFile" :accept="acceptedWorkflowFormats" />
If the workflow is in a file on your computer, choose it and then click Import.
</b-form-group>
<b-alert :show="hasErrorMessage" variant="danger">{{ errorMessage }}</b-alert>
<b-alert v-if="loading" show variant="info">
</BFormGroup>
<BAlert :show="hasErrorMessage" variant="danger">
{{ errorMessage }}
</BAlert>
<BAlert v-if="loading" show variant="info">
<LoadingSpan message="Loading your workflow, this may take a while - please be patient." />
</b-alert>
<b-button
</BAlert>
<BButton
id="workflow-import-button"
type="submit"
:disabled="isImportDisabled"
:title="importTooltip"
variant="primary">
Import workflow
</b-button>
</b-form>
</BButton>
</BForm>
</template>
@@ -1,42 +1,30 @@
<script setup lang="ts">
import { BAlert, BCard, BFormGroup, BFormInput } from "bootstrap-vue";
import { storeToRefs } from "pinia";
import { computed, type Ref, ref, watch } from "vue";
import { useRouter } from "vue-router/composables";
import { getRedirectOnImportPath } from "@/components/Workflow/redirectPath";
import { Services } from "@/components/Workflow/services";
import { Toast } from "@/composables/toast";
import { useUserStore } from "@/stores/userStore";
import { getRedirectOnImportPath } from "../redirectPath";
import { Services } from "../services";
import type { TrsSelection, TrsTool as TrsToolInterface } from "./types";
import TrsServerSelection from "./TrsServerSelection.vue";
import TrsTool from "./TrsTool.vue";
import TrsUrlImport from "./TrsUrlImport.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
import TrsServerSelection from "@/components/Workflow/Import/TrsServerSelection.vue";
import TrsTool from "@/components/Workflow/Import/TrsTool.vue";
import TrsUrlImport from "@/components/Workflow/Import/TrsUrlImport.vue";
const props = defineProps({
queryTrsServer: {
type: String,
default: null,
},
queryTrsId: {
type: String,
default: null,
},
queryTrsVersionId: {
type: String,
default: null,
},
queryTrsUrl: {
type: String,
default: null,
},
isRun: {
type: Boolean,
default: false,
},
});
interface Props {
isRun?: boolean;
queryTrsId?: string;
queryTrsUrl?: string;
queryTrsServer?: string;
queryTrsVersionId?: string;
}
const props = defineProps<Props>();
const trsTool: Ref<TrsToolInterface | null> = ref(null);
const loading = ref(false);
@@ -158,47 +146,56 @@ async function importVersionFromUrl(url: string, isRunFormRedirect = false) {
<template>
<div class="workflow-import-trs-id">
<b-card v-if="!isAnonymous" title="GA4GH Tool Registry Server (TRS) Workflow Import">
<BCard v-if="!isAnonymous" title="GA4GH Tool Registry Server (TRS) Workflow Import">
<div>
<b>TRS Server:</b>
<TrsServerSelection
:trs-selection="trsSelection"
:query-trs-server="props.queryTrsServer"
@onError="onTrsSelectionError"
@onTrsSelection="onTrsSelection" />
</div>
<b-alert v-if="isAutoImport && !hasErrorMessage" show variant="info">
<BAlert v-if="isAutoImport && !hasErrorMessage" show variant="info">
<LoadingSpan message="Loading your Workflow" />
</b-alert>
</BAlert>
<div v-else>
<div class="my-3">
<b-form-group label="TRS ID:" label-for="trs-id-input" label-class="font-weight-bold">
<b-form-input id="trs-id-input" v-model="toolId" debounce="500" />
</b-form-group>
<BFormGroup label="TRS ID:" label-for="trs-id-input" label-class="font-weight-bold">
<BFormInput id="trs-id-input" v-model="toolId" debounce="500" />
</BFormGroup>
</div>
<div>
<b-alert v-if="loading" show variant="info">
<BAlert v-if="loading" show variant="info">
<LoadingSpan :message="`Loading ${toolIdTrimmed}, this may take a while - please be patient`" />
</b-alert>
<b-alert :show="hasErrorMessage" variant="danger">{{ errorMessage }}</b-alert>
<b-alert v-if="importing" show variant="info">
</BAlert>
<BAlert :show="hasErrorMessage" variant="danger">
{{ errorMessage }}
</BAlert>
<BAlert v-if="importing" show variant="info">
<LoadingSpan message="Importing workflow" />
</b-alert>
</BAlert>
</div>
<TrsTool
v-if="trsTool"
:trs-tool="trsTool"
@onImport="(versionId) => importVersion(trsSelection?.id, trsTool?.id, versionId)" />
</div>
<hr />
<div>
<TrsUrlImport
:query-trs-url="props.queryTrsUrl"
@onImport="(url) => importVersionFromUrl(url, isRun)" />
</div>
</b-card>
<b-alert v-else class="text-center my-2" show variant="danger">
</BCard>
<BAlert v-else class="text-center my-2" show variant="danger">
Anonymous user cannot import workflows, please register or log in
</b-alert>
</BAlert>
</div>
</template>
@@ -1,18 +1,23 @@
<script setup lang="ts">
import { library } from "@fortawesome/fontawesome-svg-core";
import { faQuestion, faTimes } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import axios from "axios";
import { BCard } from "bootstrap-vue";
import { BAlert, BButton, BCard, BFormInput, BInputGroup, BInputGroupAppend, BTable } from "bootstrap-vue";
import { computed, type Ref, ref, watch } from "vue";
import { useRouter } from "vue-router/composables";
import { getRedirectOnImportPath } from "@/components/Workflow/redirectPath";
import { Services } from "@/components/Workflow/services";
import { withPrefix } from "@/utils/redirect";
import { getRedirectOnImportPath } from "../redirectPath";
import { Services } from "../services";
import type { TrsSelection } from "./types";
import TrsServerSelection from "./TrsServerSelection.vue";
import TrsTool from "./TrsTool.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
import TrsServerSelection from "@/components/Workflow/Import/TrsServerSelection.vue";
import TrsTool from "@/components/Workflow/Import/TrsTool.vue";
library.add(faQuestion, faTimes);
type TrsSearchData = {
id: string;
@@ -122,10 +127,13 @@ async function importVersion(trsId?: string, toolIdToImport?: string, version?:
<template>
<BCard class="workflow-import-trs-search" title="GA4GH Tool Registry Server (TRS) Workflow Search">
<b-alert :show="hasErrorMessage" variant="danger">{{ errorMessage }}</b-alert>
<BAlert :show="hasErrorMessage" variant="danger">
{{ errorMessage }}
</BAlert>
<div class="mb-3">
<b>TRS Server:</b>
<TrsServerSelection
:trs-selection="trsSelection"
@onTrsSelection="onTrsSelection"
@@ -133,38 +141,41 @@ async function importVersion(trsId?: string, toolIdToImport?: string, version?:
</div>
<div>
<b-input-group class="mb-3">
<b-form-input
<BInputGroup class="mb-3">
<BFormInput
id="trs-search-query"
v-model="query"
debounce="500"
placeholder="search query"
data-description="filter text input"
@keyup.esc="query = ''" />
<b-input-group-append>
<b-button
<BInputGroupAppend>
<BButton
v-b-tooltip
placement="bottom"
size="sm"
data-description="show help toggle"
:title="searchHelp">
<icon icon="question" />
</b-button>
<b-button size="sm" title="clear search" @click="query = ''">
<icon icon="times" />
</b-button>
</b-input-group-append>
</b-input-group>
<FontAwesomeIcon :icon="faQuestion" />
</BButton>
<BButton size="sm" title="clear search" @click="query = ''">
<FontAwesomeIcon :icon="faTimes" />
</BButton>
</BInputGroupAppend>
</BInputGroup>
</div>
<div>
<b-alert v-if="loading" variant="info" show>
<BAlert v-if="loading" variant="info" show>
<LoadingSpan :message="`Searching for ${query}, this may take a while - please be patient`" />
</b-alert>
<b-alert v-else-if="!query" variant="info" show> Enter search query to begin search. </b-alert>
<b-alert v-else-if="results.length == 0" variant="info" show>
</BAlert>
<BAlert v-else-if="!query" variant="info" show> Enter search query to begin search. </BAlert>
<BAlert v-else-if="results.length == 0" variant="info" show>
No search results found, refine your search.
</b-alert>
<b-table
</BAlert>
<BTable
v-else
:fields="fields"
:items="itemsComputed"
@@ -175,15 +186,16 @@ async function importVersion(trsId?: string, toolIdToImport?: string, version?:
@row-clicked="showRowDetails">
<template v-slot:row-details="row">
<BCard>
<b-alert v-if="importing" variant="info" show>
<BAlert v-if="importing" variant="info" show>
<LoadingSpan message="Importing workflow" />
</b-alert>
</BAlert>
<TrsTool
:trs-tool="row.item.data"
@onImport="(versionId) => importVersion(trsSelection?.id, row.item.data.id, versionId)" />
</BCard>
</template>
</b-table>
</BTable>
</div>
</BCard>
</template>
@@ -1,13 +1,22 @@
<script setup lang="ts">
import { library } from "@fortawesome/fontawesome-svg-core";
import { faCaretDown } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BLink } from "bootstrap-vue";
import { computed, type Ref, ref, watch } from "vue";
import { Services } from "../services";
import { Services } from "@/components/Workflow/services";
import type { TrsSelection } from "./types";
const props = defineProps<{
library.add(faCaretDown);
interface Props {
queryTrsServer?: string;
trsSelection?: TrsSelection | null;
}>();
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: "onError", errorMessage: string): void;
@@ -88,15 +97,16 @@ function possibleServeUrlsMatch(a: string, b: string) {
<template>
<span v-if="!loading" class="m-1 text-muted">
<span v-if="showDropdown" class="dropdown">
<b-link
<BLink
id="dropdownTrsServer"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
class="font-weight-bold">
{{ selection?.label }}
<span class="fa fa-caret-down" />
</b-link>
<FontAwesomeIcon :icon="faCaretDown" />
</BLink>
<div class="dropdown-menu" aria-labelledby="dropdownTrsServer">
<a
v-for="serverSelection in trsServers"
@@ -104,15 +114,15 @@ function possibleServeUrlsMatch(a: string, b: string) {
class="dropdown-item"
href="javascript:void(0)"
role="button"
@click.prevent="onTrsSelection(serverSelection)"
>{{ serverSelection.label }}</a
>
@click.prevent="onTrsSelection(serverSelection)">
{{ serverSelection.label }}
</a>
</div>
</span>
<span v-else>
<b-link :href="selection?.link_url" target="_blank" class="font-weight-bold" :title="selection?.doc">
<BLink :href="selection?.link_url" target="_blank" class="font-weight-bold" :title="selection?.doc">
{{ selection?.label }}
</b-link>
</BLink>
</span>
</span>
</template>
@@ -1,7 +1,18 @@
<script setup lang="ts">
import { library } from "@fortawesome/fontawesome-svg-core";
import { faUpload } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BButton } from "bootstrap-vue";
import type { TrsTool, TrsToolVersion } from "./types";
const props = defineProps<{ trsTool: TrsTool }>();
library.add(faUpload);
interface Props {
trsTool: TrsTool;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: "onImport", versionId: string): void;
@@ -17,27 +28,32 @@ function importVersion(version: TrsToolVersion) {
<div>
<div>
<b>Name:</b>
<span>{{ props.trsTool.name }}</span>
</div>
<div>
<b>Description:</b>
<span>{{ props.trsTool.description }}</span>
</div>
<div>
<b>Organization</b>
<span>{{ props.trsTool.organization }}</span>
</div>
<div>
<b>Versions</b>
<ul>
<li v-for="version in props.trsTool.versions" :key="version.id">
<b-button
<BButton
class="m-1 workflow-import"
:data-version-name="version.name"
@click="importVersion(version)">
{{ version.name }}
<icon icon="upload" />
</b-button>
<FontAwesomeIcon :icon="faUpload" />
</BButton>
</li>
</ul>
</div>
@@ -1,12 +1,16 @@
<script setup lang="ts">
import { BButton, BForm, BFormGroup, BFormInput } from "bootstrap-vue";
import { computed, ref } from "vue";
const props = defineProps({
queryTrsUrl: {
type: String,
default: null,
},
});
interface Props {
queryTrsUrl?: string;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: "onImport", url: string): void;
}>();
const trsUrl = ref(props.queryTrsUrl);
@@ -18,13 +22,12 @@ const importTooltip = computed(() => {
return isImportDisabled.value ? "You must provide a TRS URL." : "Import workflow from TRS URL";
});
const emit = defineEmits<{
(e: "onImport", url: string): void;
}>();
function submit(ev: SubmitEvent) {
ev.preventDefault();
emit("onImport", trsUrl.value);
if (trsUrl.value) {
emit("onImport", trsUrl.value);
}
}
// Automatically trigger the import if the TRS URL was provided as a query param
@@ -34,19 +37,21 @@ if (trsUrl.value) {
</script>
<template>
<b-form class="mt-4" @submit="submit">
<BForm class="mt-4" @submit="submit">
<h2 class="h-sm">alternatively, provide a TRS URL directly</h2>
<b-form-group label="TRS URL:" label-class="font-weight-bold">
<b-form-input id="trs-import-url-input" v-model="trsUrl" aria-label="TRS URL" type="url" />
<BFormGroup label="TRS URL:" label-class="font-weight-bold">
<BFormInput id="trs-import-url-input" v-model="trsUrl" aria-label="TRS URL" type="url" />
If the workflow is accessible via a TRS URL, enter the URL above and click Import.
</b-form-group>
<b-button
</BFormGroup>
<BButton
id="trs-url-import-button"
type="submit"
:disabled="isImportDisabled"
:title="importTooltip"
variant="primary">
Import workflow
</b-button>
</b-form>
</BButton>
</BForm>
</template>
@@ -1,28 +1,34 @@
<script setup>
import FromFileOrUrl from "./Import/FromFileOrUrl";
import TrsImport from "./Import/TrsImport";
import TrsSearch from "./Import/TrsSearch";
<script setup lang="ts">
import { BTab, BTabs } from "bootstrap-vue";
import FromFileOrUrl from "@/components/Workflow/Import/FromFileOrUrl.vue";
import TrsImport from "@/components/Workflow/Import/TrsImport.vue";
import TrsSearch from "@/components/Workflow/Import/TrsSearch.vue";
</script>
<template>
<section>
<h1 class="h-lg">Import workflow</h1>
<b-tabs fill>
<b-tab title-link-class="workflow-import-file-link" title="Archived file or url" active>
<BTabs fill>
<BTab title-link-class="workflow-import-file-link" title="Archived file or url" active>
<FromFileOrUrl />
</b-tab>
<b-tab title-link-class="workflow-import-trs-search-link" title="GA4GH servers">
</BTab>
<BTab title-link-class="workflow-import-trs-search-link" title="GA4GH servers">
<div class="mt-4">
<h2 class="h-sm">Import a Workflow from Configured GA4GH Tool Registry Servers (e.g. Dockstore)</h2>
<TrsSearch />
</div>
</b-tab>
<b-tab title-link-class="workflow-import-trs-id-link" title="TRS ID">
</BTab>
<BTab title-link-class="workflow-import-trs-id-link" title="TRS ID">
<div class="mt-4">
<h2 class="h-sm">Import from a TRS ID</h2>
<TrsImport />
</div>
</b-tab>
</b-tabs>
</BTab>
</BTabs>
</section>
</template>
+2 -2
View File
@@ -649,7 +649,7 @@ trs_search:
import_version: '[data-version-name*="${version}"]'
select_server:
type: xpath
selector: "//a[contains(@class, 'dropdown-item') and text() = '${server}']"
selector: "//a[contains(@class, 'dropdown-item') and normalize-space(text()) = '${server}']"
trs_import:
selectors:
@@ -661,7 +661,7 @@ trs_import:
select_server_button: "#dropdownTrsServer"
select_server:
type: xpath
selector: "//a[contains(@class, 'dropdown-item') and text() = '${server}']"
selector: "//a[contains(@class, 'dropdown-item') and normalize-space(text()) = '${server}']"
url_input: "#trs-import-url-input"
url_import_button: "#trs-url-import-button"