Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose more tool information / navigability in UI. #17105

Merged
merged 7 commits into from
Dec 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
126 changes: 126 additions & 0 deletions client/src/components/Markdown/Elements/HistoryDatasetAsTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<script setup lang="ts">
import { computed } from "vue";

import { UrlDataProvider } from "@/components/providers/UrlDataProvider.js";

import LoadingSpan from "@/components/LoadingSpan.vue";

interface HistoryDatasetAsTableProps {
historyDatasetId: string;
compact: boolean;
showColumnHeaders: boolean;
title?: string;
footer?: string;
}

const props = withDefaults(defineProps<HistoryDatasetAsTableProps>(), {
compact: false,
showColumnHeaders: true,
title: undefined,
footer: undefined,
});

const itemUrl = computed(() => {
return `/api/datasets/${props.historyDatasetId}/get_content_as_text`;
});

const metaUrl = computed(() => {
return `/api/datasets/${props.historyDatasetId}`;
});

const expanded = false;

const contentClass = computed(() => {
if (expanded) {
return "embedded-dataset-expanded";
} else {
return "embedded-dataset";
}
});

function getFields(metaData: any) {
const fields = [];
const columnNames = metaData.metadata_column_names || [];
const columnCount = metaData.metadata_columns;
for (let i = 0; i < columnCount; i++) {
fields.push({
key: `${i}`,
label: columnNames[i] || i,
sortable: true,
});
}
return fields;
}

function getItems(textData: any, metaData: any) {
const tableData: object[] = [];
const delimiter: string = metaData.metadata_delimiter || "\t";
const comments: number = metaData.metadata_comment_lines || 0;
const lines = textData.split("\n");
lines.forEach((line: string, i: number) => {
if (i >= comments) {
const tabs = line.split(delimiter);
const rowData: string[] = [];
let hasData = false;
tabs.forEach((cellData: string, j: number) => {
const cellDataTrimmed = cellData.trim();
if (cellDataTrimmed) {
hasData = true;
}
rowData[j] = cellDataTrimmed;
});
if (hasData) {
tableData.push(rowData);
}
}
});
return tableData;
}
</script>

<template>
<b-card :no-body="props.compact">
<b-card-title v-if="title">
<b>{{ title }}</b>
</b-card-title>
<UrlDataProvider v-slot="{ result: itemContent, loading, error }" :url="itemUrl">
<LoadingSpan v-if="loading" message="Loading Dataset" />
<div v-else-if="error">{{ error }}</div>
<div v-else :class="contentClass">
<div v-if="itemContent.item_data">
<div>
<UrlDataProvider
v-slot="{ result: metaData, loading: metaLoading, error: metaError }"
:url="metaUrl">
<LoadingSpan v-if="metaLoading" message="Loading Metadata" />
<div v-else-if="metaError">{{ metaError }}</div>
<b-table
v-else
:thead-class="props.showColumnHeaders ? '' : 'd-none'"
striped
hover
:fields="getFields(metaData)"
:items="getItems(itemContent.item_data, metaData)" />
</UrlDataProvider>
</div>
</div>
<div v-else>No content found.</div>
<b-link v-if="itemContent.truncated" :href="itemContent.item_url"> Show More... </b-link>
</div>
</UrlDataProvider>
<b-card-footer v-if="footer">
{{ footer }}
</b-card-footer>
</b-card>
</template>

<style scoped>
.embedded-dataset {
max-height: 20rem;
overflow-y: auto;
}
.embedded-dataset-expanded {
max-height: 40rem;
overflow-y: auto;
}
</style>
63 changes: 46 additions & 17 deletions client/src/components/Markdown/Elements/JobMetrics.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,55 @@
<script setup lang="ts">
import { computed, watch } from "vue";

import { useJobStore } from "@/stores/jobStore";

import JobMetrics from "@/components/JobMetrics/JobMetrics.vue";
import ToolLinkPopover from "@/components/Tool/ToolLinkPopover.vue";

interface JobMetricsProps {
jobId: string;
title?: string;
footer?: string;
}

const props = withDefaults(defineProps<JobMetricsProps>(), {
title: undefined,
footer: undefined,
});

const jobStore = useJobStore();

const toolId = computed(() => {
return jobStore.getJob(props.jobId)?.tool_id;
});
const toolVersion = computed(() => {
return jobStore.getJob(props.jobId)?.tool_version;
});

watch(
props,
() => {
jobStore.fetchJob(props.jobId);
},
{ immediate: true }
);
</script>

<template>
<b-card nobody>
<b-card-title v-if="title">
<b>{{ title }}</b>
<icon ref="info" icon="info-circle" size="sm" />
<ToolLinkPopover :target="() => $refs.info" :tool-id="toolId" :tool-version="toolVersion" />
</b-card-title>
<JobMetrics
class="job-metrics"
:job-id="args.job_id"
:job-id="jobId"
:should-show-aws-estimate="false"
:should-show-carbon-emissions-estimates="false"
:include-title="false" />
<b-card-footer v-if="footer">
{{ footer }}
</b-card-footer>
</b-card>
</template>

<script>
import JobMetrics from "components/JobMetrics/JobMetrics";

export default {
components: {
JobMetrics,
},
props: {
args: {
type: Object,
default: null,
},
},
};
</script>
65 changes: 48 additions & 17 deletions client/src/components/Markdown/Elements/JobParameters.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,52 @@
<template>
<b-card nobody>
<JobParameters class="job-parameters" :job-id="args.job_id" :param="args.param" :include-title="false" />
</b-card>
</template>
<script setup lang="ts">
import { computed, watch } from "vue";

<script>
import JobParameters from "components/JobParameters/JobParameters";
import { useJobStore } from "@/stores/jobStore";

export default {
components: {
JobParameters,
},
props: {
args: {
type: Object,
default: null,
},
import JobParameters from "@/components/JobParameters/JobParameters.vue";
import ToolLinkPopover from "@/components/Tool/ToolLinkPopover.vue";

interface JobParametersProps {
jobId: string;
param?: string;
title?: string;
footer?: string;
}

const props = withDefaults(defineProps<JobParametersProps>(), {
param: undefined,
title: undefined,
footer: undefined,
});

const jobStore = useJobStore();

const toolId = computed(() => {
return jobStore.getJob(props.jobId)?.tool_id;
});
const toolVersion = computed(() => {
return jobStore.getJob(props.jobId)?.tool_version;
});

watch(
props,
() => {
jobStore.fetchJob(props.jobId);
},
};
{ immediate: true }
);
</script>

<template>
<b-card nobody>
<b-card-title v-if="title">
<b>{{ title }}</b>
<icon ref="info" icon="info-circle" size="sm" />
<ToolLinkPopover :target="() => $refs.info" :tool-id="toolId" :tool-version="toolVersion" />
</b-card-title>
<JobParameters class="job-parameters" :job-id="jobId" :param="param" :include-title="false" />
<b-card-footer v-if="footer">
{{ footer }}
</b-card-footer>
</b-card>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { isEmpty } from "@/utils/utils";

import WorkflowTree from "./WorkflowTree.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
import ToolLinkPopover from "@/components/Tool/ToolLinkPopover.vue";
import WorkflowStepIcon from "@/components/WorkflowInvocationState/WorkflowStepIcon.vue";
import WorkflowStepTitle from "@/components/WorkflowInvocationState/WorkflowStepTitle.vue";

interface WorkflowDisplayProps {
workflowId: string;
Expand Down Expand Up @@ -102,7 +105,20 @@ onMounted(async () => {
</b-alert>
<div v-if="itemContent !== null">
<div v-for="step in itemContent?.steps" :key="step.order_index" class="mb-2">
<div>Step {{ step.order_index + 1 }}: {{ step.label }}</div>
<span :id="`step-icon-${step.order_index}`">
<WorkflowStepIcon v-if="step.type" :step-type="step.type" />
</span>
<ToolLinkPopover
v-if="step.type == 'tool'"
:target="`step-icon-${step.order_index}`"
:tool-id="step.tool_id"
:tool-version="step.tool_version" />
<WorkflowStepTitle
:step-tool-id="step.tool_id"
:step-subworkflow-id="step.subworkflow_id"
:step-label="step.label"
:step-type="step.type"
:step-index="step.order_index" />
<WorkflowTree :input="step" :skip-head="true" />
</div>
</div>
Expand Down
32 changes: 30 additions & 2 deletions client/src/components/Markdown/MarkdownContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { computed, ref } from "vue";
import { useConfig } from "@/composables/config";

import HistoryDatasetAsImage from "./Elements/HistoryDatasetAsImage.vue";
import HistoryDatasetAsTable from "./Elements/HistoryDatasetAsTable.vue";
import HistoryDatasetCollectionDisplay from "./Elements/HistoryDatasetCollection/CollectionDisplay.vue";
import HistoryDatasetDetails from "./Elements/HistoryDatasetDetails.vue";
import HistoryDatasetDisplay from "./Elements/HistoryDatasetDisplay.vue";
Expand Down Expand Up @@ -68,6 +69,17 @@ const props = defineProps({

const isCollapsible = computed(() => props.args.collapse !== undefined);
const isVisible = computed(() => !isCollapsible.value || toggle.value);

function argToBoolean(args, name, booleanDefault) {
const valueAsString = args[name];
if (valueAsString == "true") {
return true;
} else if (valueAsString == "false") {
return false;
} else {
return booleanDefault;
}
}
</script>

<template>
Expand Down Expand Up @@ -126,11 +138,27 @@ const isVisible = computed(() => !isCollapsible.value || toggle.value);
</InstanceUrl>
<HistoryLink v-else-if="name == 'history_link'" :args="args" :histories="histories" />
<HistoryDatasetAsImage v-else-if="name == 'history_dataset_as_image'" :args="args" />
<HistoryDatasetAsTable
v-else-if="name == 'history_dataset_as_table'"
:history-dataset-id="args.history_dataset_id"
:compact="argToBoolean(args, 'compact', false)"
:show-column-headers="argToBoolean(args, 'show_column_headers', true)"
:title="args.title"
:footer="args.footer" />
<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" />
<JobMetrics
v-else-if="name == 'job_metrics'"
:job-id="args.job_id"
:title="args.title"
:footer="args.footer" />
<JobParameters
v-else-if="name == 'job_parameters'"
:job-id="args.job_id"
:param="args.param || undefined"
:title="args.title"
:footer="args.footer" />
<WorkflowDisplay
v-else-if="name == 'workflow_display'"
:workflow-id="args.workflow_id"
Expand Down
5 changes: 5 additions & 0 deletions client/src/components/Markdown/MarkdownToolBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ const historySharedElements = [
name: "Embedded Dataset",
emitter: "onHistoryDatasetId",
},
{
id: "history_dataset_as_table",
name: "Embedded Dataset (as table)",
emitter: "onHistoryDatasetId",
},
{
id: "history_dataset_type",
name: "Dataset Type",
Expand Down
Loading
Loading