Skip to content

Commit

Permalink
Merge pull request #15260 from guerler/collapse_markdown
Browse files Browse the repository at this point in the history
Enable collapsing markdown elements
  • Loading branch information
dannon authored Jan 9, 2023
2 parents 5826b42 + 409276d commit 8f7c657
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 82 deletions.
4 changes: 2 additions & 2 deletions client/src/components/Markdown/Elements/HistoryLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
})
Expand Down
105 changes: 26 additions & 79 deletions client/src/components/Markdown/Markdown.vue
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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>
Expand All @@ -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>
Expand All @@ -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;
Expand All @@ -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: {
Expand Down Expand Up @@ -175,20 +122,20 @@ export default {
return {
markdownObjects: [],
markdownErrors: [],
historyDatasets: {},
datasets: {},
histories: {},
historyDatasetCollections: {},
collections: {},
workflows: {},
jobs: {},
invocations: {},
loading: true,
};
},
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);
Expand All @@ -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: {
Expand All @@ -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 || {};
Expand Down
106 changes: 106 additions & 0 deletions client/src/components/Markdown/MarkdownContainer.test.js
Original file line number Diff line number Diff line change
@@ -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!");
});
});
Loading

0 comments on commit 8f7c657

Please sign in to comment.