Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
125cc48
Add Galaxy Visualization and Vega Markdown Wrappers
guerler Mar 18, 2025
5a60196
Add customized json stringify utility which alphabetically sorts keys
guerler Mar 18, 2025
ac6eb22
Add configuration wrapper for visualizations
guerler Mar 18, 2025
64b198a
Update data attachment condition to cover galaxy and visualization cells
guerler Mar 18, 2025
1ff4d15
Add visualization to add item dropdown
guerler Mar 18, 2025
b902d0c
Add property to determine maximum number of lines in code editor
guerler Mar 18, 2025
f447e93
Populate, encode and decode invocation ids contained in markdown json…
guerler Mar 18, 2025
2c533f3
Add re-usable wrapper for Galaxy visualizations
guerler Mar 18, 2025
4cdaffa
Add vega and vitessce templates
guerler Mar 19, 2025
9c810a7
Avoid using window location in tiffviewer
guerler Mar 19, 2025
d72edc2
Update visualizations
guerler Mar 19, 2025
c291d9b
Parse root with window.location.origin when building visualizations
guerler Mar 19, 2025
10dfe69
Switch to editor without page reload
guerler Mar 19, 2025
ef7d90c
Switch default to cell-based markdown editor
guerler Mar 19, 2025
efa0c48
Fix formatting
guerler Mar 19, 2025
50dbb95
Remove unused import
guerler Mar 19, 2025
b4cb43b
Cast invocation type before calling parser
guerler Mar 19, 2025
24abb9a
Switch default to text editor
guerler Mar 19, 2025
3dec0e3
Add test cases and enable cell based markdown editor in workflow reports
guerler Mar 20, 2025
8c40e3f
Add another test case for invocation id replacement
guerler Mar 20, 2025
34a7fb8
Fix fits graph viewer and add to embeddables
guerler Mar 21, 2025
c27bdee
Fix linting
guerler Mar 21, 2025
ce916dc
Limit invocation id replacment to visualization blocks
guerler Mar 21, 2025
750915f
Adjust unit tests
guerler Mar 21, 2025
d3eb5a6
Fix linting
guerler Mar 21, 2025
38e82bd
Update heatmap version
guerler Mar 21, 2025
86d3dbd
Remove comment
guerler Mar 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/components/Markdown/Editor/CellAction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<small class="my-1 mx-3 text-info">{{ title }}</small>
</span>
<CellOption
v-if="name !== 'markdown'"
v-if="['galaxy', 'visualization'].includes(name)"
title="Attach Data"
description="Select data for this cell"
:icon="faPaperclip"
Expand Down
9 changes: 8 additions & 1 deletion client/src/components/Markdown/Editor/CellAdd.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
<script setup lang="ts">
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { BAlert } from "bootstrap-vue";
import { computed, ref } from "vue";
import { computed, onMounted, type Ref, ref } from "vue";

import { getVisualizations } from "./services";
import cellTemplates from "./templates.yml";
import type { CellType, TemplateEntry } from "./types";

Expand All @@ -46,9 +47,11 @@ defineEmits<{

const buttonRef = ref();
const query = ref("");
const visualizations: Ref<Array<TemplateEntry>> = ref([]);

const allTemplates = computed(() => {
const result = { ...(cellTemplates as Record<string, Array<TemplateEntry>>) };
result["Visualization"] = visualizations.value;
return result;
});

Expand All @@ -67,6 +70,10 @@ const filteredTemplates = computed(() => {
});
return filteredCategories;
});

onMounted(async () => {
visualizations.value = await getVisualizations();
});
</script>

<style>
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/Markdown/Editor/CellCode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const props = defineProps({
type: String,
default: "github_light_default",
},
maxLines: {
type: Number,
default: 99999,
},
mode: {
type: String,
default: "json",
Expand Down Expand Up @@ -44,7 +48,7 @@ async function buildEditor() {
aceEditor = ace.edit(editor.value, {
highlightActiveLine: false,
highlightGutterLine: false,
maxLines: 30,
maxLines: props.maxLines,
minLines: 1,
mode: modePath,
showPrintMargin: false,
Expand Down
8 changes: 8 additions & 0 deletions client/src/components/Markdown/Editor/CellWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
:labels="labels"
@cancel="$emit('configure')"
@change="handleConfigure($event)" />
<ConfigureVisualization
v-else-if="name === 'visualization' && configure"
:name="name"
:content="content"
:labels="labels"
@cancel="$emit('configure')"
@change="handleConfigure($event)" />
<CellCode
:key="name"
class="mt-1"
Expand All @@ -60,6 +67,7 @@ import type { WorkflowLabel } from "./types";
import CellAction from "./CellAction.vue";
import CellButton from "./CellButton.vue";
import ConfigureGalaxy from "./Configurations/ConfigureGalaxy.vue";
import ConfigureVisualization from "./Configurations/ConfigureVisualization.vue";
import SectionWrapper from "@/components/Markdown/Sections/SectionWrapper.vue";

const CellCode = () => import("./CellCode.vue");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<template>
<b-alert v-if="errorMessage" variant="warning" show>{{ errorMessage }}</b-alert>
<MarkdownSelector v-else-if="labels !== undefined" argument-name="Dataset" :labels="labels" @onOk="onLabel" />
<DataDialog
v-else-if="currentHistoryId !== null"
:history="currentHistoryId"
format="id"
@onOk="onData"
@onCancel="$emit('cancel')" />
<b-alert v-else v-localize variant="info" show> No history available to choose from. </b-alert>
</template>

<script setup lang="ts">
import { storeToRefs } from "pinia";
import { type Ref, ref, watch } from "vue";

import type { DatasetLabel, WorkflowLabel } from "@/components/Markdown/Editor/types";
import { stringify } from "@/components/Markdown/Utilities/stringify";
import { useHistoryStore } from "@/stores/historyStore";

import DataDialog from "@/components/DataDialog/DataDialog.vue";
import MarkdownSelector from "@/components/Markdown/MarkdownSelector.vue";

const { currentHistoryId } = storeToRefs(useHistoryStore());

const props = defineProps<{
content: string;
labels?: Array<WorkflowLabel>;
}>();

const emit = defineEmits<{
(e: "cancel"): void;
(e: "change", content: string): void;
}>();

interface contentType {
dataset_id?: string;
dataset_label?: DatasetLabel;
dataset_url?: string;
}

const contentObject: Ref<contentType | undefined> = ref();
const errorMessage = ref("");

function onData(datasetId: any) {
if (contentObject.value) {
contentObject.value.dataset_id = datasetId;
contentObject.value.dataset_label = undefined;
contentObject.value.dataset_url = undefined;
emit("change", stringify(contentObject.value));
}
}

function onLabel(selectedLabel: any) {
if (selectedLabel !== undefined) {
const labelType = selectedLabel.type;
const label = selectedLabel.label;
if (contentObject.value && label && labelType) {
contentObject.value.dataset_label = {
invocation_id: "",
[labelType]: label,
};
contentObject.value.dataset_id = undefined;
contentObject.value.dataset_url = undefined;
emit("change", stringify(contentObject.value));
}
}
}

function parseContent() {
try {
contentObject.value = JSON.parse(props.content);
errorMessage.value = "";
} catch (e) {
errorMessage.value = `Failed to parse: ${e}`;
}
}

watch(
() => props.content,
() => parseContent(),
{ immediate: true }
);
</script>
31 changes: 31 additions & 0 deletions client/src/components/Markdown/Editor/services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import axios from "axios";

import { getAppRoot } from "@/onload";
import { rethrowSimple } from "@/utils/simple-error";

import type { TemplateEntry } from "./types";

export interface VisualizationType {
description: string;
html: string;
logo?: string;
name: string;
}

export async function getVisualizations(): Promise<Array<TemplateEntry>> {
try {
const { data } = await axios.get(`${getAppRoot()}api/plugins?embeddable=True`);
return data.map((v: VisualizationType) => ({
title: v.html,
description: v.description || "",
logo: v.logo ? `${getAppRoot()}${v.logo}` : undefined,
cell: {
name: "visualization",
configure: true,
content: `{ "visualization_name": "${v.name}", "visualization_title": "${v.html}" }`,
},
}));
} catch (e) {
rethrowSimple("Failed to load Visualizations.");
}
}
65 changes: 65 additions & 0 deletions client/src/components/Markdown/Editor/templates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,68 @@ Galaxy:
cell:
name: "galaxy"
content: "generate_galaxy_version()"

Vega:
- title: "Bar Diagram"
description: "Basic bar diagram"
cell:
name: "vega"
content: |
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A simple bar chart with embedded data.",
"data": {"values": [
{ "a": "A", "b": 1 },
{ "a": "B", "b": 2 },
{ "a": "C", "b": 3 }
]},
"mark": "bar",
"encoding": {
"x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
"y": {"field": "b", "type": "quantitative"}
}
}
- title: "Line Chart"
description: "Basic line chart"
cell:
name: "vega"
content: |
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A simple line chart with embedded data.",
"data": {"values": [
{ "a": "A", "b": 1 },
{ "a": "B", "b": 2 },
{ "a": "C", "b": 3 }
]},
"mark": "line",
"encoding": {
"x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
"y": {"field": "b", "type": "quantitative"}
}
}

Vitessce:
- title: "Hello World"
description: "A simple vitessce example"
cell:
name: "vitessce"
content: |
{
"version": "1.0.16",
"name": "Example configuration",
"description": "",
"datasets": [],
"initStrategy": "auto",
"coordinationSpace": {},
"layout": [{
"component": "description",
"props": {
"description": "Hello, world!"
},
"x": 0,
"y": 0,
"w": 6,
"h": 6
}]
}
1 change: 0 additions & 1 deletion client/src/components/Markdown/MarkdownEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
</div>
<div>
<b-form-radio-group
v-if="!labels || labels.length === 0"
v-model="editor"
v-b-tooltip.hover.bottom
button-variant="outline-primary"
Expand Down
42 changes: 42 additions & 0 deletions client/src/components/Markdown/Sections/MarkdownVega.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import { ref, watch } from "vue";

const VegaWrapper = () => import("@/components/Common/VegaWrapper.vue");

const props = defineProps<{
content: string;
}>();

const errorMessage = ref("");
const spec = ref({});

function render() {
try {
errorMessage.value = "";
spec.value = {
...JSON.parse(props.content),
width: "container",
};
} catch (e: any) {
errorMessage.value = String(e);
spec.value = {};
}
}

watch(
() => props.content,
() => {
render();
},
{ immediate: true }
);
</script>

<template>
<div>
<b-alert v-if="errorMessage" class="p-2" variant="danger" show>
{{ errorMessage }}
</b-alert>
<VegaWrapper :spec="spec" />
</div>
</template>
Loading
Loading