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

Annotation and Title detail #18762

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open
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
10 changes: 6 additions & 4 deletions client/src/components/Workflow/List/WorkflowCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ interface Props {
workflow: any;
gridView?: boolean;
publishedView?: boolean;
showActions?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
gridView: false,
publishedView: false,
showActions: true,
});

const emit = defineEmits<{
Expand Down Expand Up @@ -132,6 +134,7 @@ async function onTagClick(tag: string) {
<WorkflowInvocationsCount v-if="!isAnonymous && !shared" class="mx-1" :workflow="workflow" />

<WorkflowActions
v-if="showActions"
:workflow="workflow"
:published="publishedView"
@refreshList="emit('refreshList', true)"
Expand All @@ -155,7 +158,7 @@ async function onTagClick(tag: string) {
size="sm"
title="Rename"
@click="showRename = !showRename">
<FontAwesomeIcon :icon="faPen" fixed-width />
<FontAwesomeIcon v-if="showActions" :icon="faPen" fixed-width />
</BButton>
</span>

Expand All @@ -169,15 +172,14 @@ async function onTagClick(tag: string) {
<div class="workflow-card-footer">
<div class="workflow-card-tags">
<StatelessTags
clickable
:value="workflow.tags"
:disabled="isAnonymous || workflow.deleted || shared"
:disabled="!showActions || isAnonymous || workflow.deleted || shared"
:max-visible-tags="gridView ? 2 : 8"
@input="onTagsUpdate($event)"
@tag-click="onTagClick($event)" />
</div>

<div class="workflow-card-actions">
<div v-if="showActions" class="workflow-card-actions">
<WorkflowActionsExtend
:workflow="workflow"
:published="publishedView"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const userOwned = computed(() => {

<template>
<aside class="workflow-information">
<hgroup>
<hgroup v-if="props.embedded">
<Heading h2 size="xl" class="mb-0">About This Workflow</Heading>
<span class="ml-2">
<span data-description="workflow name"> {{ workflowInfo.name }} </span> - Version
Expand Down
105 changes: 61 additions & 44 deletions client/src/components/Workflow/Run/WorkflowRunFormSimple.vue
Original file line number Diff line number Diff line change
@@ -1,56 +1,71 @@
<template>
<div>
<div v-if="isConfigLoaded" class="h4 clearfix mb-3">
<div v-if="isConfigLoaded">
<BAlert v-if="!canRunOnHistory" variant="warning" show>
<span v-localize>
The workflow cannot run because the current history is immutable. Please select a different history
or send the results to a new one using the run settings ⚙️
</span>
</BAlert>
<b>Workflow: {{ model.name }}</b> <i>(version: {{ model.runData.version + 1 }})</i>
<ButtonSpinner
id="run-workflow"
:wait="waitingForRequest"
:disabled="hasValidationErrors || !canRunOnHistory"
class="float-right"
title="Run Workflow"
@onClick="onExecute" />
<b-dropdown
v-if="showRuntimeSettings(currentUser)"
id="dropdown-form"
ref="dropdown"
class="workflow-run-settings float-right"
style="margin-right: 10px"
title="Workflow Run Settings"
no-caret>
<template v-slot:button-content>
<span class="fa fa-cog" />
</template>
<b-dropdown-form>
<b-form-checkbox v-model="sendToNewHistory" class="workflow-run-settings-target">
Send results to a new history
</b-form-checkbox>
<b-form-checkbox
v-if="reuseAllowed(currentUser)"
v-model="useCachedJobs"
title="This may skip executing jobs that you have already run.">
Attempt to re-use jobs with identical parameters?
</b-form-checkbox>
<b-form-checkbox
v-if="isConfigLoaded && config.object_store_allows_id_selection"
v-model="splitObjectStore">
Send outputs and intermediate to different storage locations?
</b-form-checkbox>
<WorkflowStorageConfiguration
v-if="isConfigLoaded && config.object_store_allows_id_selection"
:split-object-store="splitObjectStore"
:invocation-preferred-object-store-id="preferredObjectStoreId"
:invocation-intermediate-preferred-object-store-id="preferredIntermediateObjectStoreId"
@updated="onStorageUpdate">
</WorkflowStorageConfiguration>
</b-dropdown-form>
</b-dropdown>
<div class="ui-portlet-section">
<div class="d-flex portlet-header">
<div class="flex-grow-1">
<div class="px-1">
<span class="fa fa-sitemap" />
<b class="mx-1">Workflow: {{ model.name }}</b>
<i>(version: {{ model.runData.version + 1 }})</i>
</div>
</div>
<div class="d-flex align-items-end flex-nowrap">
<b-dropdown
v-if="showRuntimeSettings(currentUser)"
id="dropdown-form"
ref="dropdown"
class="workflow-run-settings"
style="margin-right: 10px"
title="Workflow Run Settings"
variant="link"
no-caret>
<template v-slot:button-content>
<span class="fa fa-cog" />
</template>
<b-dropdown-form>
<b-form-checkbox v-model="sendToNewHistory" class="workflow-run-settings-target">
Send results to a new history
</b-form-checkbox>
<b-form-checkbox
v-if="reuseAllowed(currentUser)"
v-model="useCachedJobs"
title="This may skip executing jobs that you have already run.">
Attempt to re-use jobs with identical parameters?
</b-form-checkbox>
<b-form-checkbox
v-if="isConfigLoaded && config.object_store_allows_id_selection"
v-model="splitObjectStore">
Send outputs and intermediate to different storage locations?
</b-form-checkbox>
<WorkflowStorageConfiguration
v-if="isConfigLoaded && config.object_store_allows_id_selection"
:split-object-store="splitObjectStore"
:invocation-preferred-object-store-id="preferredObjectStoreId"
:invocation-intermediate-preferred-object-store-id="
preferredIntermediateObjectStoreId
"
@updated="onStorageUpdate">
</WorkflowStorageConfiguration>
</b-dropdown-form>
</b-dropdown>
<ButtonSpinner
id="run-workflow"
:wait="waitingForRequest"
:disabled="hasValidationErrors || !canRunOnHistory"
title="Run Workflow"
@onClick="onExecute" />
</div>
</div>
</div>
</div>
<WorkflowRunName v-if="isConfigLoaded" :model="this.model" :embedded="false" />
<FormDisplay
:inputs="formInputs"
:allow-empty-value-on-required-input="true"
Expand All @@ -74,13 +89,15 @@ import { useConfig } from "@/composables/config";
import { useUserStore } from "@/stores/userStore";

import { invokeWorkflow } from "./services";
import WorkflowRunName from "./WorkflowRunName";
import WorkflowStorageConfiguration from "./WorkflowStorageConfiguration";

export default {
components: {
ButtonSpinner,
FormDisplay,
WorkflowStorageConfiguration,
WorkflowRunName,
},
props: {
model: {
Expand Down
56 changes: 56 additions & 0 deletions client/src/components/Workflow/Run/WorkflowRunName.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<script setup lang="ts">
import { library } from "@fortawesome/fontawesome-svg-core";
import { faChevronDown, faChevronUp } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { computed, ref } from "vue";

import WorkflowCard from "@/components/Workflow/List/WorkflowCard.vue";

library.add(faChevronDown, faChevronUp);

const props = defineProps({
model: {
type: Object,
required: true,
},
});

const expandAnnotations = ref(true);

const workflow = computed(() => {
return {
id: props.model.runData.id,
name: props.model.runData.name,
owner: props.model.runData.owner,
tags: props.model.runData.annotation.tags.map((t: { user_tname: string }) => t.user_tname),
annotations: [props.model.runData.annotation.annotation],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@itisAliRH for this line annotations: [props.model.runData.annotation.annotation], is ok to only use the first annotation record (ie. annotation[0])? Or are other annotation records need to be included/consolidated somehow?

update_time: props.model.runData.annotation.update_time,
};
});
</script>

<template>
<div class="ui-portlet-section w-100">
<div
class="portlet-header cursor-pointer"
role="button"
:tabindex="0"
@keyup.enter="expandAnnotations = !expandAnnotations"
@click="expandAnnotations = !expandAnnotations">
<b class="portlet-operations portlet-title-text">
<span v-localize class="font-weight-bold">About This Workflow</span>
</b>
<span v-b-tooltip.hover.bottom title="Collapse/Expand" variant="link" size="sm" class="float-right">
<FontAwesomeIcon :icon="expandAnnotations ? faChevronUp : faChevronDown" fixed-width />
</span>
</div>
<div class="portlet-content" :style="expandAnnotations ? 'display: none;' : ''">
<WorkflowCard
:workflow="workflow"
:published-view="true"
:grid-view="true"
:show-actions="false"
:class="'grid-view'" />
</div>
</div>
</template>
26 changes: 26 additions & 0 deletions lib/galaxy/managers/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,26 @@ def _workflow_from_raw_description(

return workflow, missing_tool_tups

def convert_to_dict_from_many(self, obj, depth=0, max_depth=5):
if depth > max_depth:
return "<max depth reached>"

if isinstance(obj, list):
return [self.convert_to_dict_from_many(item, depth=depth + 1, max_depth=max_depth) for item in obj]
elif isinstance(obj, dict) or hasattr(obj, "__dict__"):
if isinstance(obj, dict):
items = obj.items() # Dictionary case
else:
items = obj.__dict__.items() # Custom object case

return {
key: self.convert_to_dict_from_many(value, depth=depth + 1, max_depth=max_depth)
for key, value in items
if not key.startswith("_")
}
else:
return obj

def workflow_to_dict(self, trans, stored, style="export", version=None, history=None):
"""Export the workflow contents to a dictionary ready for JSON-ification and to be
sent out via API for instance. There are three styles of export allowed 'export', 'instance', and
Expand Down Expand Up @@ -1070,13 +1090,19 @@ def _workflow_to_dict_run(self, trans, stored, workflow, history=None):
}
for oc in step.output_connections
]
annotations_dict = {
"annotation": self.get_item_annotation_str(trans.sa_session, trans.user, stored),
"update_time": (stored.update_time).isoformat(),
"tags": self.convert_to_dict_from_many(stored.tags),
}
if step.annotations:
step_model["annotation"] = step.annotations[0].annotation
if step.upgrade_messages:
step_model["messages"] = step.upgrade_messages
step_models.append(step_model)
return {
"id": trans.app.security.encode_id(stored.id),
"annotation": annotations_dict,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvdbeek Please let me know if it would be even better to serialize these SQLAlchemy objects in stored.annotations in some other way, happy to replace.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're including properties here that are not part of the annotation model.
This is a good attempt that goes in the right direction, I'll try to find some time to rework this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - any insights & examples are appreciated too.

"history_id": trans.app.security.encode_id(history.id) if history else None,
"name": stored.name,
"owner": stored.user.username,
Expand Down
Loading