mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #15260 from guerler/collapse_markdown
Enable collapsing markdown elements
This commit is contained in:
@@ -15,11 +15,11 @@
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import Vue from "vue";
|
||||
import BootstrapVue from "bootstrap-vue";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { errorMessageAsString } from "utils/simple-error";
|
||||
import { safePath } from "utils/redirect";
|
||||
|
||||
Vue.use(BootstrapVue);
|
||||
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
methods: {
|
||||
onClick() {
|
||||
axios
|
||||
.post(`${getAppRoot()}api/histories`, { history_id: this.args.history_id })
|
||||
.post(safePath("/api/histories"), { history_id: this.args.history_id })
|
||||
.then(() => {
|
||||
this.imported = true;
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="markdown-wrapper">
|
||||
<LoadingSpan v-if="loading" />
|
||||
<loading-span v-if="loading" />
|
||||
<div v-else>
|
||||
<div>
|
||||
<sts-download-button
|
||||
@@ -28,7 +28,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<b-badge variant="info" class="w-100 rounded mb-3">
|
||||
<div class="float-left m-1">Published with Galaxy {{ getVersion }} on {{ getTime }}</div>
|
||||
<div class="float-left m-1">Published with Galaxy {{ version }} on {{ time }}</div>
|
||||
<div class="float-right m-1">Identifier {{ markdownConfig.id }}</div>
|
||||
</b-badge>
|
||||
<div>
|
||||
@@ -41,47 +41,18 @@
|
||||
</div>
|
||||
<div v-for="(obj, index) in markdownObjects" :key="index" class="markdown-components">
|
||||
<p v-if="obj.name == 'default'" class="text-justify m-2" v-html="obj.content" />
|
||||
<div v-else-if="obj.name == 'generate_galaxy_version'" class="galaxy-version">
|
||||
<pre><code>{{ getVersion }}</code></pre>
|
||||
</div>
|
||||
<div v-else-if="obj.name == 'generate_time'" class="galaxy-time">
|
||||
<pre><code>{{ getTime }}</code></pre>
|
||||
</div>
|
||||
<HistoryLink v-else-if="obj.name == 'history_link'" :args="obj.args" :histories="histories" />
|
||||
<HistoryDatasetAsImage v-else-if="obj.name == 'history_dataset_as_image'" :args="obj.args" />
|
||||
<HistoryDatasetLink v-else-if="obj.name == 'history_dataset_link'" :args="obj.args" />
|
||||
<HistoryDatasetIndex v-else-if="obj.name == 'history_dataset_index'" :args="obj.args" />
|
||||
<InvocationTime v-else-if="obj.name == 'invocation_time'" :args="obj.args" :invocations="invocations" />
|
||||
<JobMetrics v-else-if="obj.name == 'job_metrics'" :args="obj.args" />
|
||||
<JobParameters v-else-if="obj.name == 'job_parameters'" :args="obj.args" />
|
||||
<WorkflowDisplay v-else-if="obj.name == 'workflow_display'" :args="obj.args" :workflows="workflows" />
|
||||
<Visualization v-else-if="obj.name == 'visualization'" :args="obj.args" />
|
||||
<HistoryDatasetCollectionDisplay
|
||||
v-else-if="obj.name == 'history_dataset_collection_display'"
|
||||
:args="obj.args"
|
||||
:collections="historyDatasetCollections" />
|
||||
<ToolStd
|
||||
v-else-if="['tool_stdout', 'tool_stderr'].includes(obj.name)"
|
||||
:args="obj.args"
|
||||
:name="obj.name"
|
||||
:jobs="jobs" />
|
||||
<HistoryDatasetDisplay
|
||||
v-else-if="['history_dataset_embedded', 'history_dataset_display'].includes(obj.name)"
|
||||
:args="obj.args"
|
||||
:datasets="historyDatasets"
|
||||
:embedded="obj.name == 'history_dataset_embedded'" />
|
||||
<HistoryDatasetDetails
|
||||
v-else-if="
|
||||
[
|
||||
'history_dataset_name',
|
||||
'history_dataset_info',
|
||||
'history_dataset_peek',
|
||||
'history_dataset_type',
|
||||
].includes(obj.name)
|
||||
"
|
||||
<markdown-container
|
||||
v-else
|
||||
:name="obj.name"
|
||||
:args="obj.args"
|
||||
:datasets="historyDatasets" />
|
||||
:datasets="datasets"
|
||||
:collections="collections"
|
||||
:histories="histories"
|
||||
:invocations="invocations"
|
||||
:jobs="jobs"
|
||||
:time="time"
|
||||
:version="version"
|
||||
:workflows="workflows" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -97,21 +68,9 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||
import { faDownload, faEdit } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import LoadingSpan from "components/LoadingSpan";
|
||||
import HistoryDatasetAsImage from "./Elements/HistoryDatasetAsImage";
|
||||
import HistoryDatasetDisplay from "./Elements/HistoryDatasetDisplay";
|
||||
import HistoryDatasetLink from "./Elements/HistoryDatasetLink";
|
||||
import HistoryDatasetIndex from "./Elements/HistoryDatasetIndex";
|
||||
import HistoryDatasetCollectionDisplay from "./Elements/HistoryDatasetCollection/CollectionDisplay";
|
||||
import HistoryDatasetDetails from "./Elements/HistoryDatasetDetails";
|
||||
import HistoryLink from "./Elements/HistoryLink";
|
||||
import InvocationTime from "./Elements/InvocationTime";
|
||||
import JobMetrics from "./Elements/JobMetrics";
|
||||
import JobParameters from "./Elements/JobParameters";
|
||||
import ToolStd from "./Elements/ToolStd";
|
||||
import WorkflowDisplay from "./Elements/Workflow/WorkflowDisplay";
|
||||
import Visualization from "./Elements/Visualization";
|
||||
import StsDownloadButton from "components/StsDownloadButton";
|
||||
import LoadingSpan from "components/LoadingSpan.vue";
|
||||
import StsDownloadButton from "components/StsDownloadButton.vue";
|
||||
import MarkdownContainer from "./MarkdownContainer.vue";
|
||||
|
||||
const FUNCTION_VALUE_REGEX = `\\s*(?:[\\w_\\-]+|\\"[^\\"]+\\"|\\'[^\\']+\\')\\s*`;
|
||||
const FUNCTION_CALL = `\\s*[\\w\\|]+\\s*=` + FUNCTION_VALUE_REGEX;
|
||||
@@ -132,21 +91,9 @@ library.add(faDownload, faEdit);
|
||||
export default {
|
||||
store: store,
|
||||
components: {
|
||||
HistoryDatasetDetails,
|
||||
HistoryDatasetAsImage,
|
||||
HistoryDatasetCollectionDisplay,
|
||||
HistoryDatasetDisplay,
|
||||
HistoryDatasetIndex,
|
||||
HistoryDatasetLink,
|
||||
HistoryLink,
|
||||
JobMetrics,
|
||||
JobParameters,
|
||||
LoadingSpan,
|
||||
ToolStd,
|
||||
WorkflowDisplay,
|
||||
Visualization,
|
||||
InvocationTime,
|
||||
MarkdownContainer,
|
||||
FontAwesomeIcon,
|
||||
LoadingSpan,
|
||||
StsDownloadButton,
|
||||
},
|
||||
props: {
|
||||
@@ -175,9 +122,9 @@ export default {
|
||||
return {
|
||||
markdownObjects: [],
|
||||
markdownErrors: [],
|
||||
historyDatasets: {},
|
||||
datasets: {},
|
||||
histories: {},
|
||||
historyDatasetCollections: {},
|
||||
collections: {},
|
||||
workflows: {},
|
||||
jobs: {},
|
||||
invocations: {},
|
||||
@@ -185,10 +132,10 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
getVersion() {
|
||||
return this.markdownConfig.generate_version || "Unknown Galaxy Version";
|
||||
effectiveExportLink() {
|
||||
return this.enable_beta_markdown_export ? this.exportLink : null;
|
||||
},
|
||||
getTime() {
|
||||
time() {
|
||||
const generateTime = this.markdownConfig.generate_time;
|
||||
if (generateTime) {
|
||||
const date = new Date(generateTime);
|
||||
@@ -202,8 +149,8 @@ export default {
|
||||
}
|
||||
return "unavailable";
|
||||
},
|
||||
effectiveExportLink() {
|
||||
return this.enable_beta_markdown_export ? this.exportLink : null;
|
||||
version() {
|
||||
return this.markdownConfig.generate_version || "Unknown Galaxy Version";
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
@@ -221,9 +168,9 @@ export default {
|
||||
const markdown = config.content || config.markdown;
|
||||
this.markdownErrors = config.errors || [];
|
||||
this.markdownObjects = this.splitMarkdown(markdown);
|
||||
this.historyDatasets = config.history_datasets || {};
|
||||
this.datasets = config.history_datasets || {};
|
||||
this.histories = config.histories || {};
|
||||
this.historyDatasetCollections = config.history_dataset_collections || {};
|
||||
this.collections = config.history_dataset_collections || {};
|
||||
this.workflows = config.workflows || {};
|
||||
this.jobs = config.jobs || {};
|
||||
this.invocations = config.invocations || {};
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import axios from "axios";
|
||||
import flushPromises from "flush-promises";
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { getLocalVue } from "tests/jest/helpers";
|
||||
import MockAdapter from "axios-mock-adapter";
|
||||
import { safePath } from "utils/redirect";
|
||||
import MountTarget from "./MarkdownContainer.vue";
|
||||
|
||||
// mock routes
|
||||
jest.mock("utils/redirect");
|
||||
safePath.mockImplementation((url) => url);
|
||||
|
||||
const localVue = getLocalVue();
|
||||
const axiosMock = new MockAdapter(axios);
|
||||
|
||||
async function mountComponent(propsData, apiMap = {}) {
|
||||
axiosMock.reset();
|
||||
for (const [method, apiDetails] of Object.entries(apiMap)) {
|
||||
for (const [path, response] of Object.entries(apiDetails)) {
|
||||
axiosMock[method](path).reply(200, response);
|
||||
}
|
||||
}
|
||||
return mount(MountTarget, {
|
||||
localVue,
|
||||
propsData,
|
||||
stubs: {
|
||||
FontAwesomeIcon: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function testCollapse(wrapper) {
|
||||
const nolink = wrapper.find("a");
|
||||
expect(nolink.exists()).toBe(false);
|
||||
const collapse = "Click here to expand/collapse";
|
||||
await wrapper.setProps({ args: { collapse } });
|
||||
const link = wrapper.find("a");
|
||||
expect(link.text()).toBe(collapse);
|
||||
const container = wrapper.find(".collapse");
|
||||
expect(container.attributes("style")).toBe("display: none;");
|
||||
await link.trigger("click");
|
||||
expect(container.attributes("style")).toBe("");
|
||||
}
|
||||
|
||||
describe("MarkdownContainer", () => {
|
||||
it("Renders version", async () => {
|
||||
const version = "test_version";
|
||||
const wrapper = await mountComponent({
|
||||
name: "generate_galaxy_version",
|
||||
args: {},
|
||||
version,
|
||||
});
|
||||
const versionEl = wrapper.find(".galaxy-version");
|
||||
expect(versionEl.exists()).toBe(true);
|
||||
expect(versionEl.find("code").text()).toBe(version);
|
||||
testCollapse(wrapper);
|
||||
});
|
||||
|
||||
it("Renders time stamp", async () => {
|
||||
const time = "test_time";
|
||||
const wrapper = await mountComponent({
|
||||
name: "generate_time",
|
||||
args: {},
|
||||
time,
|
||||
});
|
||||
const version = wrapper.find(".galaxy-time");
|
||||
expect(version.exists()).toBe(true);
|
||||
expect(version.find("code").text()).toBe(time);
|
||||
testCollapse(wrapper);
|
||||
});
|
||||
|
||||
it("Renders history link", async () => {
|
||||
const wrapper = await mountComponent(
|
||||
{
|
||||
name: "history_link",
|
||||
args: { history_id: "test_history_id" },
|
||||
histories: { test_history_id: { name: "history_name" } },
|
||||
},
|
||||
{
|
||||
onPost: { "/api/histories": {} },
|
||||
}
|
||||
);
|
||||
const link = wrapper.find("a");
|
||||
expect(link.text()).toBe("Click to Import History: history_name.");
|
||||
await link.trigger("click");
|
||||
const postedData = JSON.parse(axiosMock.history.post[0].data);
|
||||
expect(postedData.history_id).toBe("test_history_id");
|
||||
await flushPromises();
|
||||
const error = wrapper.find(".text-success");
|
||||
const message = error.find("span");
|
||||
expect(message.text()).toBe("Successfully Imported History: history_name!");
|
||||
});
|
||||
|
||||
it("Renders history link (with failing import error message)", async () => {
|
||||
const wrapper = await mountComponent({
|
||||
name: "history_link",
|
||||
args: { history_id: "test_history_id" },
|
||||
histories: { test_history_id: { name: "history_name" } },
|
||||
});
|
||||
await wrapper.find("a").trigger("click");
|
||||
await flushPromises();
|
||||
const error = wrapper.find(".text-danger");
|
||||
const message = error.find("span");
|
||||
expect(message.text()).toBe("Failed to Import History: history_name!");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,110 @@
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import HistoryDatasetAsImage from "./Elements/HistoryDatasetAsImage.vue";
|
||||
import HistoryDatasetDisplay from "./Elements/HistoryDatasetDisplay.vue";
|
||||
import HistoryDatasetLink from "./Elements/HistoryDatasetLink.vue";
|
||||
import HistoryDatasetIndex from "./Elements/HistoryDatasetIndex.vue";
|
||||
import HistoryDatasetCollectionDisplay from "./Elements/HistoryDatasetCollection/CollectionDisplay.vue";
|
||||
import HistoryDatasetDetails from "./Elements/HistoryDatasetDetails.vue";
|
||||
import HistoryLink from "./Elements/HistoryLink.vue";
|
||||
import InvocationTime from "./Elements/InvocationTime.vue";
|
||||
import JobMetrics from "./Elements/JobMetrics.vue";
|
||||
import JobParameters from "./Elements/JobParameters.vue";
|
||||
import ToolStd from "./Elements/ToolStd.vue";
|
||||
import WorkflowDisplay from "./Elements/Workflow/WorkflowDisplay.vue";
|
||||
import Visualization from "./Elements/Visualization.vue";
|
||||
|
||||
const toggle = ref(false);
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
args: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
datasets: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
collections: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
histories: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
invocations: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
jobs: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
time: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
version: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
workflows: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const isCollapsible = computed(() => props.args.collapse !== undefined);
|
||||
const isVisible = computed(() => !isCollapsible.value || toggle.value);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<b-link v-if="isCollapsible" class="font-weight-bold" @click="toggle = !toggle">
|
||||
{{ args.collapse }}
|
||||
</b-link>
|
||||
<b-collapse :visible="isVisible">
|
||||
<div v-if="name == 'generate_galaxy_version'" class="galaxy-version">
|
||||
<pre><code>{{ version }}</code></pre>
|
||||
</div>
|
||||
<div v-else-if="name == 'generate_time'" class="galaxy-time">
|
||||
<pre><code>{{ time }}</code></pre>
|
||||
</div>
|
||||
<HistoryLink v-else-if="name == 'history_link'" :args="args" :histories="histories" />
|
||||
<HistoryDatasetAsImage v-else-if="name == 'history_dataset_as_image'" :args="args" />
|
||||
<HistoryDatasetLink v-else-if="name == 'history_dataset_link'" :args="args" />
|
||||
<HistoryDatasetIndex v-else-if="name == 'history_dataset_index'" :args="args" />
|
||||
<InvocationTime v-else-if="name == 'invocation_time'" :args="args" :invocations="invocations" />
|
||||
<JobMetrics v-else-if="name == 'job_metrics'" :args="args" />
|
||||
<JobParameters v-else-if="name == 'job_parameters'" :args="args" />
|
||||
<WorkflowDisplay v-else-if="name == 'workflow_display'" :args="args" :workflows="workflows" />
|
||||
<Visualization v-else-if="name == 'visualization'" :args="args" />
|
||||
<HistoryDatasetCollectionDisplay
|
||||
v-else-if="name == 'history_dataset_collection_display'"
|
||||
:args="args"
|
||||
:collections="collections" />
|
||||
<ToolStd v-else-if="['tool_stdout', 'tool_stderr'].includes(name)" :args="args" :name="name" :jobs="jobs" />
|
||||
<HistoryDatasetDisplay
|
||||
v-else-if="['history_dataset_embedded', 'history_dataset_display'].includes(name)"
|
||||
:args="args"
|
||||
:datasets="datasets"
|
||||
:embedded="name == 'history_dataset_embedded'" />
|
||||
<HistoryDatasetDetails
|
||||
v-else-if="
|
||||
[
|
||||
'history_dataset_name',
|
||||
'history_dataset_info',
|
||||
'history_dataset_peek',
|
||||
'history_dataset_type',
|
||||
].includes(name)
|
||||
"
|
||||
:name="name"
|
||||
:args="args"
|
||||
:datasets="datasets" />
|
||||
</b-collapse>
|
||||
</div>
|
||||
</template>
|
||||
@@ -24,6 +24,7 @@ class DynamicArguments:
|
||||
|
||||
|
||||
DYNAMIC_ARGUMENTS = DynamicArguments()
|
||||
SHARED_ARGUMENTS: List[str] = ["collapse"]
|
||||
VALID_ARGUMENTS: Dict[str, Union[List[str], DynamicArguments]] = {
|
||||
"history_link": ["history_id"],
|
||||
"history_dataset_display": ["input", "output", "history_dataset_id"],
|
||||
@@ -73,7 +74,7 @@ def validate_galaxy_markdown(galaxy_markdown, internal=True):
|
||||
def _validate_arg(arg_str, valid_args, line_no):
|
||||
if arg_str is not None:
|
||||
arg_name = arg_str.split("=", 1)[0].strip()
|
||||
if arg_name not in valid_args:
|
||||
if arg_name not in valid_args and arg_name not in SHARED_ARGUMENTS:
|
||||
invalid_line("Invalid argument to Galaxy directive [{argument}]", line_no, argument=arg_name)
|
||||
|
||||
expecting_container_close_for = None
|
||||
|
||||
Reference in New Issue
Block a user