Skip to content

Commit

Permalink
Merge branch 'release_24.1' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
mvdbeek committed Aug 7, 2024
2 parents 203573a + dfea749 commit 5f635a3
Show file tree
Hide file tree
Showing 20 changed files with 232 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ function toggleActiveStep(stepId: number) {
<div v-if="!hideGraph" class="position-relative w-100">
<BCard no-body>
<WorkflowGraph
class="invocation-graph"
:steps="steps"
:datatypes-mapper="datatypesMapper"
:initial-position="initialPosition"
Expand Down Expand Up @@ -341,9 +342,15 @@ function toggleActiveStep(stepId: number) {
.graph-steps-aside {
overflow-y: scroll;
scroll-behavior: smooth;
&.steps-fixed-height {
max-height: 60vh;
}
}
.invocation-graph {
&:deep(.workflow-overview),
&:deep(.zoom-control) {
z-index: 100;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { library } from "@fortawesome/fontawesome-svg-core";
import { faChevronDown, faChevronUp, faSignInAlt } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { computed, ref, watch } from "vue";
import { computed, nextTick, ref, watch } from "vue";
import type { WorkflowInvocationElementView } from "@/api/invocations";
import { isWorkflowInput } from "@/components/Workflow/constants";
Expand Down Expand Up @@ -43,28 +43,28 @@ const props = withDefaults(defineProps<Props>(), {
});
const stepsDiv = ref<HTMLDivElement>();
const expandInvocationInputs = ref(false);
const workflowInputSteps = Object.values(props.workflow.steps).filter((step) => isWorkflowInput(step.type));
const hasSingularInput = computed(() => workflowInputSteps.length === 1);
const workflowRemainingSteps = hasSingularInput.value
? Object.values(props.workflow.steps)
: Object.values(props.workflow.steps).filter((step) => !isWorkflowInput(step.type));
const oneOrNoInput = computed(() => workflowInputSteps.length <= 1);
const expandInvocationInputs = ref(oneOrNoInput.value);
watch(
() => [props.activeNodeId, stepsDiv.value],
async ([nodeId, card]) => {
// if the active node id is an input step, expand the inputs section, else, collapse it
const isAnInput = workflowInputSteps.findIndex((step) => step.id === props.activeNodeId) !== -1;
expandInvocationInputs.value = isAnInput;
// if the active node id is an input step, expand the inputs section if not already expanded
if (!expandInvocationInputs.value) {
const isAnInput = workflowInputSteps.findIndex((step) => step.id === props.activeNodeId) !== -1;
expandInvocationInputs.value = isAnInput;
}
await nextTick();
// on full page view, scroll to the active step card in the steps section
if (props.isFullPage) {
if (nodeId !== undefined && card) {
// scroll to the active step card
const stepCard = stepsDiv.value?.querySelector(`[data-index="${props.activeNodeId}"]`);
const portletHeaderDiv = stepCard?.querySelector(".portlet-header");
stepsDiv.value?.scrollTo({ top: portletHeaderDiv?.getBoundingClientRect().top });
stepCard?.scrollIntoView({ block: "nearest", inline: "start" });
}
}
// clear any job being shown
Expand All @@ -81,7 +81,7 @@ function showJob(jobId: string | undefined) {
<template>
<div ref="stepsDiv" class="d-flex flex-column w-100">
<!-- Input Steps grouped in a separate portlet -->
<div v-if="workflowInputSteps.length > 1" class="ui-portlet-section w-100">
<div v-if="!oneOrNoInput" class="ui-portlet-section w-100">
<div
class="portlet-header portlet-operations"
role="button"
Expand All @@ -96,36 +96,21 @@ function showJob(jobId: string | undefined) {
</span>
<FontAwesomeIcon class="float-right" :icon="expandInvocationInputs ? faChevronUp : faChevronDown" />
</div>

<div v-if="expandInvocationInputs" class="portlet-content m-1">
<WorkflowInvocationStep
v-for="step in workflowInputSteps"
:key="step.id"
:data-index="step.id"
:invocation="props.invocation"
:workflow="props.workflow"
:workflow-step="step"
:in-graph-view="!props.hideGraph"
:graph-step="steps[step.id]"
:expanded="props.hideGraph ? undefined : props.activeNodeId === step.id"
:showing-job-id="props.showingJobId"
@show-job="showJob"
@update:expanded="emit('focus-on-step', step.id)" />
</div>
</div>
<!-- Non-Input (Tool/Subworkflow) Steps -->
<WorkflowInvocationStep
v-for="step in workflowRemainingSteps"
:key="step.id"
:data-index="step.id"
:invocation="props.invocation"
:workflow="props.workflow"
:workflow-step="step"
:in-graph-view="!props.hideGraph"
:graph-step="steps[step.id]"
:expanded="props.hideGraph ? undefined : props.activeNodeId === step.id"
:showing-job-id="props.showingJobId"
@show-job="showJob"
@update:expanded="emit('focus-on-step', step.id)" />
<div v-for="step in props.workflow.steps" :key="step.id">
<WorkflowInvocationStep
v-if="!isWorkflowInput(step.type) || (isWorkflowInput(step.type) && expandInvocationInputs)"
:class="{ 'mx-1': !oneOrNoInput && isWorkflowInput(step.type) }"
:data-index="step.id"
:invocation="props.invocation"
:workflow="props.workflow"
:workflow-step="step"
:in-graph-view="!props.hideGraph"
:graph-step="steps[step.id]"
:expanded="props.hideGraph ? undefined : props.activeNodeId === step.id"
:showing-job-id="props.showingJobId"
@show-job="showJob"
@update:expanded="emit('focus-on-step', step.id)" />
</div>
</div>
</template>
9 changes: 5 additions & 4 deletions config/plugins/visualizations/h5web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
],
"license": "AFL-3.0",
"dependencies": {
"@h5web/app": "^8.0.0",
"@h5web/app": "^12.0.1",
"buffer": "^6.0.3",
"normalize.css": "^8.0.1",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "18.3.1",
"react-dom": "18.3.1"
},
"scripts": {
"build": "parcel build src/script.js --dist-dir static"
},
"devDependencies": {
"parcel": "^2.12.0"
"parcel": "^2.12.0",
"process": "^0.11.10"
}
}
2 changes: 1 addition & 1 deletion doc/schema_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ $tag:tool|outputs|data|actions|action://complexType[@name='Action']
$tag:tool|outputs|data|actions|action|option://complexType[@name='ActionsOption']
$tag:tool|outputs|data|discover_datasets://complexType[@name='OutputDiscoverDatasets']
$tag:tool|outputs|collection://complexType[@name='OutputCollection']
$tag:tool|outputs|collection|data://complexType[@name='OutputCollectionDataElement']
$tag:tool|outputs|collection|data://complexType[@name='OutputCollectionData']
$tag:tool|outputs|collection|filter://complexType[@name='OutputFilter']
$tag:tool|outputs|collection|discover_datasets://complexType[@name='OutputCollectionDiscoverDatasets']
$tag:tool|tests://complexType[@name='Tests']
Expand Down
2 changes: 0 additions & 2 deletions lib/galaxy/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4382,8 +4382,6 @@ def full_delete(self):
# TODO: purge metadata files
self.deleted = True
self.purged = True
self.file_size = 0
self.total_size = 0

def get_access_roles(self, security_agent):
roles = []
Expand Down
15 changes: 15 additions & 0 deletions lib/galaxy/schema/invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ class FailureReason(str, Enum):
unexpected_failure = "unexpected_failure"


# The reasons below are attached to the invocation and user-actionable.
# Not included are `unexpected_failure` and `expression_evaluation_failed`.
# If expression evaluation fails we're not attaching the templated
# expression to the invocation, as it could contain secrets.
# If the failure reason is not in `FAILURE_REASONS_EXPECTED` we should
# log an exception so admins can debug and/or submit bug reports.
FAILURE_REASONS_EXPECTED = (
FailureReason.dataset_failed,
FailureReason.collection_failed,
FailureReason.job_failed,
FailureReason.output_not_found,
FailureReason.when_not_boolean,
)


class CancelReason(str, Enum):
"""Possible reasons for a cancelled workflow."""

Expand Down
99 changes: 34 additions & 65 deletions lib/galaxy/tool_util/xsd/galaxy.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -5827,15 +5827,24 @@ on Human (hg18)``.
<xs:attributeGroup ref="OutputDataAttributes"/>
</xs:complexType>

<!-- Allowed tags included in collection-data -->
<xs:group name="OutputCollectionDataElement">
<xs:choice>
<xs:element name="actions" type="Actions" />
<xs:element name="change_format" type="ChangeFormat" />
</xs:choice>
</xs:group>

<!-- Allowed tags included in collection -->
<xs:group name="OutputCollectionElement">
<xs:choice>
<xs:element name="data" type="OutputCollectionDataElement" />
<xs:element name="data" type="OutputCollectionData" />
<xs:element name="discover_datasets" type="OutputCollectionDiscoverDatasets" />
<xs:element name="filter" type="OutputFilter" />
</xs:choice>
</xs:group>

<xs:complexType name="OutputCollectionDataElement">
<xs:complexType name="OutputCollectionData">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Expand All @@ -5844,7 +5853,7 @@ define the elements of a collection statically. See also [Planemo's documentatio
]]></xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:group ref="OutputCollectionElement" minOccurs="0" maxOccurs="unbounded" />
<xs:group ref="OutputCollectionDataElement" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attributeGroup ref="OutputCommon" />
<xs:attributeGroup ref="OutputDataAttributes" />
Expand Down Expand Up @@ -6002,23 +6011,7 @@ Therefore a filter for such a variable looks like the following example.
</xs:simpleContent>
</xs:complexType>

<xs:complexType name="OutputDiscoverDatasets">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Describe datasets to dynamically collect after the job complete.
There are many simple tools with examples of this element distributed with
Galaxy, including:
* [multi_output.xml](https://github.com/galaxyproject/galaxy/blob/dev/test/functional/tools/multi_output.xml)
* [multi_output_assign_primary.xml](https://github.com/galaxyproject/galaxy/blob/dev/test/functional/tools/multi_output_assign_primary.xml)
* [multi_output_configured.xml](https://github.com/galaxyproject/galaxy/blob/dev/test/functional/tools/multi_output_configured.xml)
More information can be found on Planemo's documentation for
[multiple output files](https://planemo.readthedocs.io/en/latest/writing_advanced.html#multiple-output-files).
]]></xs:documentation>
</xs:annotation>
<xs:attributeGroup name="OutputDiscoverDatasetsCommon">
<xs:attribute name="from_provided_metadata" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Indicate that dataset filenames should simply be read from the provided metadata file (e.g. galaxy.json). If this is set - pattern and sort must not be set.</xs:documentation>
Expand Down Expand Up @@ -6069,6 +6062,26 @@ More information can be found on Planemo's documentation for
<xs:documentation xml:lang="en">Indication if this dataset is visible in output history. This defaults to ``false``, but probably shouldn't - be sure to set to ``true`` if that is your intention.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>

<xs:complexType name="OutputDiscoverDatasets">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Describe datasets to dynamically collect after the job complete.
There are many simple tools with examples of this element distributed with
Galaxy, including:
* [multi_output.xml](https://github.com/galaxyproject/galaxy/blob/dev/test/functional/tools/multi_output.xml)
* [multi_output_assign_primary.xml](https://github.com/galaxyproject/galaxy/blob/dev/test/functional/tools/multi_output_assign_primary.xml)
* [multi_output_configured.xml](https://github.com/galaxyproject/galaxy/blob/dev/test/functional/tools/multi_output_configured.xml)
More information can be found on Planemo's documentation for
[multiple output files](https://planemo.readthedocs.io/en/latest/writing_advanced.html#multiple-output-files).
]]></xs:documentation>
</xs:annotation>
<xs:attributeGroup ref="OutputDiscoverDatasetsCommon"/>
<xs:attribute name="assign_primary_output" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Replace the primary dataset described by the parameter ``data`` parameter with the first output discovered.</xs:documentation>
Expand All @@ -6092,51 +6105,7 @@ Galaxy, including:
]]></xs:documentation>
</xs:annotation>
<xs:attribute name="from_provided_metadata" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Indicate that dataset filenames should simply be read from the provided metadata file (e.g. galaxy.json). If this is set - pattern and sort_by must not be set.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="pattern" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Regular expression used to find filenames and parse dynamic properties.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="directory" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Directory (relative to working directory) to search for files.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="recurse" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Indicates that the specified directory should be searched recursively for matching files.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="match_relative_path" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Indicates that the entire path of the discovered dataset relative to the specified directory should be available for matching patterns.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="format" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Format (or datatype) of discovered datasets (an alias with ``ext``).</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ext" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Format (or datatype) of discovered datasets (an alias with ``format``).</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="sort_by" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">A string `[reverse_][SORT_COMP_]SORTBY` describing the desired sort order of the collection elements. `SORTBY` can be `filename`, `name`, `designation`, `dbkey` and the optional `SORT_COMP` can be either `lexical` or `numeric`. Default is lexical sorting by filename.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="visible" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">Indication if this dataset is visible in the history. This defaults to ``false``, but probably shouldn't - be sure to set to ``true`` if that is your intention.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attributeGroup ref="OutputDiscoverDatasetsCommon"/>
</xs:complexType>
<xs:complexType name="Actions">
<xs:annotation>
Expand Down
8 changes: 7 additions & 1 deletion lib/galaxy/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3867,8 +3867,14 @@ def add_copied_value_to_new_elements(new_label, dce_object):
if how_type == "tabular":
# We have a tabular file, where the first column is an existing element identifier,
# and the second column is the new element identifier.
new_labels_dict = {}
source_new_label = (line.strip().split("\t") for line in new_labels)
new_labels_dict = dict(source_new_label)
for i, label_pair in enumerate(source_new_label):
if not len(label_pair) == 2:
raise exceptions.MessageException(
f"Relabel mapping file line {i + 1} contains {len(label_pair)} columns, but 2 are required"
)
new_labels_dict[label_pair[0]] = label_pair[1]
for dce in hdca.collection.elements:
dce_object = dce.element_object
element_identifier = dce.element_identifier
Expand Down
7 changes: 5 additions & 2 deletions lib/galaxy/web/framework/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def __init__(self):
self.transaction_factory = DefaultWebTransaction
# Set if trace logging is enabled
self.trace_logger = None
self.session_factories = []

def add_ui_controller(self, controller_name, controller):
"""
Expand Down Expand Up @@ -170,10 +171,12 @@ def __call__(self, environ, start_response):
path_info = environ.get("PATH_INFO", "")

try:
self._model.set_request_id(request_id) # Start SQLAlchemy session scope
for session_factory in self.session_factories:
session_factory.set_request_id(request_id) # Start SQLAlchemy session scope
return self.handle_request(request_id, path_info, environ, start_response)
finally:
self._model.unset_request_id(request_id) # End SQLAlchemy session scope
for session_factory in self.session_factories:
session_factory.unset_request_id(request_id) # End SQLAlchemy session scope
self.trace(message="Handle request finished")
if self.trace_logger:
self.trace_logger.context_remove("request_id")
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/webapps/base/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def __init__(

# We need this to set the REQUEST_ID contextvar in model.base *BEFORE* a GalaxyWebTransaction is created.
# This will ensure a SQLAlchemy session is request-scoped for legacy (non-fastapi) endpoints.
self._model = galaxy_app.model
self.session_factories.append(galaxy_app.model)

def build_apispec(self):
"""
Expand Down
Loading

0 comments on commit 5f635a3

Please sign in to comment.