Skip to content

Commit

Permalink
Tool markdown reports.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton committed Oct 24, 2024
1 parent e6d1b30 commit 91fa711
Show file tree
Hide file tree
Showing 26 changed files with 457 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ const { datasetPathDestination } = useDatasetPathDestination();
const props = defineProps<Props>();
const pathDestination = computed<PathDestination | null>(() =>
datasetPathDestination.value(props.historyDatasetId, props.path)
);
const pathDestination = computedAsync<PathDestination | null>(async () => {
return await datasetPathDestination.value(props.historyDatasetId, props.path);
}, null);
const imageUrl = computed(() => {
if (props.path === undefined || props.path === "undefined") {
return `${getAppRoot()}dataset/display?dataset_id=${props.historyDatasetId}`;
}
return pathDestination.value?.fileLink;
});
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Dataset/DatasetIndex/DatasetIndex.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { computedAsync } from "@vueuse/core";
import { computed } from "vue";
import type { DatasetExtraFiles } from "@/api/datasets";
Expand All @@ -13,7 +14,7 @@ const { datasetPathDestination } = useDatasetPathDestination();
const props = defineProps<Props>();
const pathDestination = computed<PathDestination | null>(() =>
const pathDestination = computedAsync<PathDestination | null>(() =>
datasetPathDestination.value(props.historyDatasetId, props.path)
);
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Dataset/DatasetLink/DatasetLink.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { computedAsync } from "@vueuse/core";
import { computed } from "vue";
import { hasDetails } from "@/api";
Expand All @@ -16,7 +17,7 @@ const { getDataset } = useDatasetStore();
const props = defineProps<Props>();
const pathDestination = computed<PathDestination | null>(() =>
const pathDestination = computedAsync<PathDestination | null>(() =>
datasetPathDestination.value(props.historyDatasetId, props.path)
);
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/History/Content/ContentItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,12 @@ const itemUrls = computed<ItemUrls>(() => {
: null,
};
}
let display = `/datasets/${id}/preview`;
if (props.item.extension == "tool_markdown") {
display = `/datasets/${id}/report`;
}
return {
display: `/datasets/${id}/preview`,
display: display,
edit: `/datasets/${id}/edit`,
showDetails: `/datasets/${id}/details`,
reportError: `/datasets/${id}/error`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,23 @@ interface HistoryDatasetAsTableProps {
showColumnHeaders: boolean;
title?: string;
footer?: string;
path?: string;
}
const props = withDefaults(defineProps<HistoryDatasetAsTableProps>(), {
compact: false,
showColumnHeaders: true,
title: undefined,
footer: undefined,
path: undefined,
});
const itemUrl = computed(() => {
return `/api/datasets/${props.historyDatasetId}/get_content_as_text`;
if (props.path) {
return `/api/datasets/${props.historyDatasetId}/get_content_as_text?filename=${props.path}`;
} else {
return `/api/datasets/${props.historyDatasetId}/get_content_as_text`;
}
});
const metaUrl = computed(() => {
Expand Down
17 changes: 12 additions & 5 deletions client/src/components/Markdown/Markdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@
Edit
<FontAwesomeIcon icon="edit" />
</b-button>
<h1 class="float-right align-middle mr-2 mt-1 h-md">Galaxy {{ markdownConfig.model_class }}</h1>
<h1 v-if="title" class="float-right align-middle mr-2 mt-1 h-md">
Galaxy {{ markdownConfig.model_class }}
</h1>
<span class="float-left font-weight-light">
<h1 class="text-break align-middle">
Title: {{ markdownConfig.title || markdownConfig.model_class }}
</h1>
<h1 v-if="title" class="text-break align-middle">Title: {{ title }}</h1>
<h2 v-if="workflowVersions" class="text-break align-middle">
Workflow Checkpoint: {{ workflowVersions.version }}
</h2>
</span>
</div>
<b-badge variant="info" class="w-100 rounded mb-3 white-space-normal">
<div class="float-left m-1 text-break">Generated with Galaxy {{ version }} on {{ time }}</div>
<div class="float-right m-1">Identifier: {{ markdownConfig.id }}</div>
<div v-if="showIdentifier" class="float-right m-1">Identifier: {{ markdownConfig.id }}</div>
</b-badge>
<div>
<b-alert v-if="markdownErrors.length > 0" variant="warning" show>
Expand Down Expand Up @@ -119,6 +119,10 @@ export default {
type: String,
default: null,
},
showIdentifier: {
type: Boolean,
default: true,
},
},
data() {
return {
Expand All @@ -137,6 +141,9 @@ export default {
effectiveExportLink() {
return this.enable_beta_markdown_export ? this.exportLink : null;
},
title() {
return this.markdownConfig.title || this.markdownConfig.model_class;
},
time() {
let generateTime = this.markdownConfig.generate_time;
if (generateTime) {
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Markdown/MarkdownContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ function argToBoolean(args, name, booleanDefault) {
:compact="argToBoolean(args, 'compact', false)"
:show-column-headers="argToBoolean(args, 'show_column_headers', true)"
:title="args.title"
:footer="args.footer" />
:footer="args.footer"
:path="args.path" />
<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" />
Expand Down
39 changes: 39 additions & 0 deletions client/src/components/Tool/ToolReport.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script setup lang="ts">
import { computed, ref } from "vue";
import { useConfig } from "@/composables/config";
import { urlData } from "@/utils/url";
import Markdown from "@/components/Markdown/Markdown.vue";
interface Props {
datasetId: string;
}
const props = defineProps<Props>();
const dataUrl = computed(() => {
return `/api/datasets/${props.datasetId}/report`;
});
const dataRef = ref<unknown>(null);
const { config, isConfigLoaded } = useConfig(true);
urlData({ url: dataUrl.value }).then((data) => {
dataRef.value = data;
});
</script>

<template>
<div>
<Markdown
v-if="isConfigLoaded && dataRef"
:markdown-config="dataRef"
:enable-beta-markdown-export="config.enable_beta_markdown_export"
download-endpoint="TODO"
:show-identifier="false"
:read-only="true" />
<div v-else>Loading....</div>
</div>
</template>
9 changes: 3 additions & 6 deletions client/src/composables/datasetPathDestination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ export function useDatasetPathDestination() {
const cache = ref<{ [key: string]: PathDestinationMap }>({});

const datasetPathDestination = computed(() => {
return (dataset_id: string, path?: string) => {
return async (dataset_id: string, path?: string) => {
const targetPath = path ?? "undefined";
const pathDestination = cache.value[dataset_id]?.[targetPath];
let pathDestination = cache.value[dataset_id]?.[targetPath];
if (!pathDestination) {
getPathDestination(dataset_id, path);
pathDestination = (await getPathDestination(dataset_id, path)) ?? undefined;
}
return pathDestination ?? null;
};
Expand All @@ -36,7 +36,6 @@ export function useDatasetPathDestination() {
await datasetExtraFilesStore.fetchDatasetExtFilesByDatasetId({ id: dataset_id });
datasetExtraFiles = datasetExtraFilesStore.getDatasetExtraFiles(dataset_id);
}

if (datasetExtraFiles === null) {
return null;
}
Expand Down Expand Up @@ -66,9 +65,7 @@ export function useDatasetPathDestination() {
}
pathDestination.fileLink = getCompositeDatasetLink(dataset_id, datasetEntry.path);
}

set(cache.value, dataset_id, { [path]: pathDestination });

return pathDestination;
}

Expand Down
6 changes: 6 additions & 0 deletions client/src/entry/analysis/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import ToolLanding from "components/Landing/ToolLanding";
import WorkflowLanding from "components/Landing/WorkflowLanding";
import PageDisplay from "components/PageDisplay/PageDisplay";
import PageEditor from "components/PageEditor/PageEditor";
import ToolReport from "components/Tool/ToolReport";
import ToolSuccess from "components/Tool/ToolSuccess";
import ToolsList from "components/ToolsList/ToolsList";
import ToolsJson from "components/ToolsView/ToolsSchemaJson/ToolsJson";
Expand Down Expand Up @@ -239,6 +240,11 @@ export function getRouter(Galaxy) {
src: `/datasets/${route.params.datasetId}/display/?preview=True`,
}),
},
{
path: "datasets/:datasetId/report",
component: ToolReport,
props: true,
},
{
// legacy route, potentially used by 3rd parties
path: "datasets/:datasetId/show_params",
Expand Down
1 change: 1 addition & 0 deletions lib/galaxy/config/sample/datatypes_conf.xml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@
<!-- End RGenetics Datatypes -->
<datatype extension="ipynb" type="galaxy.datatypes.text:Ipynb" display_in_upload="true"/>
<datatype extension="json" type="galaxy.datatypes.text:Json" display_in_upload="true"/>
<datatype extension="tool_markdown" type="galaxy.datatypes.text:Text" display_in_upload="true"/>
<datatype extension="expression.json" type="galaxy.datatypes.text:ExpressionJson" display_in_upload="true"/>
<!-- graph datatypes -->
<datatype extension="xgmml" type="galaxy.datatypes.graph:Xgmml" display_in_upload="true"/>
Expand Down
1 change: 1 addition & 0 deletions lib/galaxy/datatypes/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ def _serve_file_download(self, headers, data, trans, to_ext, file_size, **kwd):
composite_extensions = trans.app.datatypes_registry.get_composite_extensions()
composite_extensions.append("html") # for archiving composite datatypes
composite_extensions.append("data_manager_json") # for downloading bundles if bundled.
composite_extensions.append("tool_markdown")

if data.extension in composite_extensions:
return self._archive_composite_dataset(trans, data, headers, do_action=kwd.get("do_action", "zip"))
Expand Down
10 changes: 6 additions & 4 deletions lib/galaxy/managers/hdas.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,10 @@ def data_conversion_status(self, hda):

# .... data
# TODO: to data provider or Text datatype directly
def text_data(self, hda, preview=True):
def text_data(self, hda, preview=True, filename: Optional[str] = None):
"""
Get data from text file, truncating if necessary.
"""
# 1 MB
MAX_PEEK_SIZE = 1000000

truncated = False
hda_data = None
# For now, cannot get data from non-text datasets.
Expand All @@ -318,6 +315,11 @@ def text_data(self, hda, preview=True):
if not os.path.exists(file_path):
return truncated, hda_data

return self.text_data_truncated(file_path, preview=preview)

def text_data_truncated(self, file_path, preview=True):
# 1 MB
MAX_PEEK_SIZE = 1000000
truncated = preview and os.stat(file_path).st_size > MAX_PEEK_SIZE
with get_fileobj(file_path) as fh:
try:
Expand Down
66 changes: 65 additions & 1 deletion lib/galaxy/managers/markdown_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ def _remap(container, line):
)
if container == "history_link":
return (f"history_link(history_id={invocation.history.id})\n", False)
if container == "invocation_time":
elif container == "invocation_time":
return (f"invocation_time(invocation_id={invocation.id})\n", False)
ref_object_type = None
output_match = re.search(OUTPUT_LABEL_PATTERN, line)
Expand Down Expand Up @@ -953,6 +953,70 @@ def find_non_empty_group(match):
return galaxy_markdown


def resolve_job_markdown(trans, job, job_markdown):
"""Resolve job objects to convert tool markdown to 'internal' representation.
Replace references to abstract workflow parts with actual galaxy object IDs corresponding
to the actual executed workflow. For instance:
convert output=name -to- history_dataset_id=<id> | history_dataset_collection_id=<id>
convert input=name -to- history_dataset_id=<id> | history_dataset_collection_id=<id>
convert argument-less job directives to job
"""
io_dicts = job.io_dicts()

def _remap(container, line):
if container == "history_link":
return (f"history_link(history_id={job.history.id})\n", False)
elif container == "tool_stdout":
return (f"tool_stdout(job_id={job.id})\n", False)
elif container == "tool_stderr":
return (f"tool_stderr(job_id={job.id})\n", False)
elif container == "job_parameters":
return (f"job_parameters(job_id={job.id})\n", False)
elif container == "job_metrics":
return (f"job_metrics(job_id={job.id})\n", False)
ref_object_type = None
output_match = re.search(OUTPUT_LABEL_PATTERN, line)
input_match = re.search(INPUT_LABEL_PATTERN, line)

def find_non_empty_group(match):
for group in match.groups():
if group:
return group

target_match: Optional[Match]
ref_object: Optional[Any]
if output_match:
target_match = output_match
name = find_non_empty_group(target_match)
if name in io_dicts.out_data:
ref_object = io_dicts.out_data[name]
elif name in io_dicts.out_collections:
ref_object = io_dicts.out_collections[name]
else:
raise Exception("Unknown exception")
elif input_match:
target_match = input_match
name = find_non_empty_group(target_match)
ref_object = io_dicts.inp_data[name]
else:
target_match = None
ref_object = None
if ref_object:
assert target_match # tell type system, this is set when ref_object is set
if ref_object_type is None:
if ref_object.history_content_type == "dataset":
ref_object_type = "history_dataset"
else:
ref_object_type = "history_dataset_collection"
line = line.replace(target_match.group(), f"{ref_object_type}_id={ref_object.id}")
return (line, False)

galaxy_markdown = _remap_galaxy_markdown_calls(_remap, job_markdown)
return galaxy_markdown


def _remap_galaxy_markdown_containers(func, markdown):
new_markdown = markdown

Expand Down
7 changes: 7 additions & 0 deletions lib/galaxy/schema/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -3846,6 +3846,13 @@ class PageDetails(PageSummary):
model_config = ConfigDict(extra="allow")


class ToolReportForDataset(BaseModel):
content: Optional[str] = ContentField
generate_version: Optional[str] = GenerateVersionField
generate_time: Optional[str] = GenerateTimeField
model_config = ConfigDict(extra="allow")


class PageSummaryList(RootModel):
root: List[PageSummary] = Field(
default=[],
Expand Down
Loading

0 comments on commit 91fa711

Please sign in to comment.