Skip to content

Commit

Permalink
Merge branch 'release_24.2' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
nsoranzo committed Jan 7, 2025
2 parents 356ed82 + fe1bf1e commit cd999d2
Show file tree
Hide file tree
Showing 17 changed files with 184 additions and 81 deletions.
17 changes: 4 additions & 13 deletions client/src/components/ActivityBar/ActivitySettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ function executeActivity(activity: Activity) {
</script>

<template>
<div class="activity-settings rounded no-highlight">
<div v-if="foundActivities" class="activity-settings-content">
<div>
<div v-if="foundActivities">
<button
v-for="activity in filteredActivities"
:key="activity.id"
Expand Down Expand Up @@ -122,7 +122,7 @@ function executeActivity(activity: Activity) {
</div>
</button>
</div>
<div v-else class="activity-settings-content">
<div v-else>
<b-alert v-localize class="py-1 px-2" show> No matching activities found. </b-alert>
</div>
</div>
Expand All @@ -131,23 +131,14 @@ function executeActivity(activity: Activity) {
<style lang="scss">
@import "theme/blue.scss";
.activity-settings {
overflow-y: hidden;
display: flex;
flex-direction: column;
}
.activity-settings-content {
overflow-y: auto;
}
.activity-settings-item {
background: none;
border: none;
text-align: left;
transition: none;
width: 100%;
}
.activity-settings-item:hover {
background: $gray-200;
}
Expand Down
18 changes: 16 additions & 2 deletions client/src/components/Panels/VisualizationPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,11 @@ onMounted(() => {
<h3>Create Visualization</h3>
<DelayedInput :delay="100" placeholder="Search visualizations" @change="query = $event" />
</template>
<div class="overflow-y mt-2">
<div>
<LoadingSpan v-if="isLoading" message="Loading visualizations" />
<div v-else-if="filteredPlugins.length > 0">
<div v-for="plugin in filteredPlugins" :key="plugin.name">
<button :data-plugin-name="plugin.name" @click="selectVisualization(plugin)">
<button class="plugin-item" :data-plugin-name="plugin.name" @click="selectVisualization(plugin)">
<div class="d-flex">
<div class="plugin-thumbnail mr-2">
<img v-if="plugin.logo" alt="visualization" :src="absPath(plugin.logo)" />
Expand Down Expand Up @@ -143,6 +143,20 @@ onMounted(() => {
</template>

<style lang="scss">
@import "theme/blue.scss";
.plugin-item {
background: none;
border: none;
text-align: left;
transition: none;
width: 100%;
}
.plugin-item:hover {
background: $gray-200;
}
.plugin-thumbnail {
img {
width: 2rem;
Expand Down
11 changes: 6 additions & 5 deletions lib/galaxy/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8103,7 +8103,7 @@ class WorkflowStep(Base, RepresentById, UsesCreateAndUpdateTime):
tool_errors: Mapped[Optional[bytes]] = mapped_column(JSONType)
position: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
config: Mapped[Optional[bytes]] = mapped_column(JSONType)
order_index: Mapped[Optional[int]]
order_index: Mapped[int]
when_expression: Mapped[Optional[bytes]] = mapped_column(JSONType)
uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType)
label: Mapped[Optional[str]] = mapped_column(Unicode(255))
Expand Down Expand Up @@ -8201,17 +8201,18 @@ def setup_inputs_by_name(self):
# Ensure input_connections has already been set.

# Make connection information available on each step by input name.
inputs_by_name = {}
inputs_by_name: Dict[str, Any] = {}
for step_input in self.inputs:
input_name = step_input.name
assert input_name not in inputs_by_name
inputs_by_name[input_name] = step_input
self._inputs_by_name = inputs_by_name
return inputs_by_name

@property
def inputs_by_name(self):
if self._inputs_by_name is None:
self.setup_inputs_by_name()
return self.setup_inputs_by_name()
return self._inputs_by_name

def get_input(self, input_name):
Expand Down Expand Up @@ -8690,7 +8691,7 @@ class WorkflowInvocation(Base, UsesCreateAndUpdateTime, Dictifiable, Serializabl
state: Mapped[Optional[str]] = mapped_column(TrimmedString(64), index=True)
scheduler: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
handler: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType())
uuid: Mapped[Optional[Union[UUID]]] = mapped_column(UUIDType())
history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)

history = relationship("History", back_populates="workflow_invocations")
Expand Down Expand Up @@ -9415,7 +9416,7 @@ class WorkflowInvocationStep(Base, Dictifiable, Serializable):
)
action: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)

workflow_step = relationship("WorkflowStep")
workflow_step: Mapped[WorkflowStep] = relationship("WorkflowStep")
job: Mapped[Optional["Job"]] = relationship(back_populates="workflow_invocation_step", uselist=False)
implicit_collection_jobs = relationship("ImplicitCollectionJobs", uselist=False)
output_dataset_collections = relationship(
Expand Down
2 changes: 2 additions & 0 deletions lib/galaxy/model/store/ro_crate_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ def _add_step_parameter_pv(self, step: WorkflowInvocationStep, crate: ROCrate):

def _add_step_parameter_fp(self, step: WorkflowInvocationStep, crate: ROCrate):
param_id = step.workflow_step.label
assert step.workflow_step.tool_inputs
param_type = step.workflow_step.tool_inputs["parameter_type"]
return crate.add(
ContextEntity(
Expand All @@ -375,6 +376,7 @@ def _add_step_parameter_fp(self, step: WorkflowInvocationStep, crate: ROCrate):

def _add_step_tool_pv(self, step: WorkflowInvocationStep, tool_input: str, crate: ROCrate):
param_id = tool_input
assert step.workflow_step.tool_inputs
return crate.add(
ContextEntity(
crate,
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/tool_util/deps/conda_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
VERSIONED_ENV_DIR_NAME = re.compile(r"__(.*)@(.*)")
UNVERSIONED_ENV_DIR_NAME = re.compile(r"__(.*)@_uv_")
USE_PATH_EXEC_DEFAULT = False
CONDA_PACKAGE_SPECS = ("conda>=23.7.0", "conda-libmamba-solver", "'pyopenssl>=22.1.0'")
CONDA_PACKAGE_SPECS = ("conda>=23.7.0", "conda-libmamba-solver", "pyopenssl>=22.1.0")
CONDA_BUILD_SPECS = ("conda-build>=3.22.0",)
USE_LOCAL_DEFAULT = False

Expand Down
27 changes: 25 additions & 2 deletions lib/galaxy/tools/parameters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
)
from .workflow_utils import (
is_runtime_value,
NO_REPLACEMENT,
runtime_to_json,
)
from .wrapped import flat_to_nested_state
Expand Down Expand Up @@ -174,14 +175,36 @@ def callback_helper(input, input_values, name_prefix, label_prefix, parent_prefi
if input.name not in input_values:
args["error"] = f"No value found for '{args.get('prefixed_label')}'."
new_value = callback(**args)

# is this good enough ? feels very ugh
if new_value == [no_replacement_value]:
# Single unspecified value in multiple="true" input with a single null input, pretend it's a singular value
new_value = no_replacement_value
if isinstance(new_value, list):
# Maybe mixed input, I guess tool defaults don't really make sense here ?
# Would e.g. be default dataset in multiple="true" input, you wouldn't expect the default to be inserted
# if other inputs are connected and provided.
new_value = [item if not item == no_replacement_value else None for item in new_value]

if no_replacement_value is REPLACE_ON_TRUTHY:
replace = bool(new_value)
else:
replace = new_value != no_replacement_value
if replace:
input_values[input.name] = new_value
elif replace_optional_connections and is_runtime_value(value) and hasattr(input, "value"):
input_values[input.name] = input.value
elif replace_optional_connections:
# Only used in workflow context
has_default = hasattr(input, "value")
if new_value is value is NO_REPLACEMENT or is_runtime_value(value):
# NO_REPLACEMENT means value was connected but left unspecified
if has_default:
# Use default if we have one
input_values[input.name] = input.value
else:
# Should fail if input is not optional and does not have default value
# Effectively however depends on parameter implementation.
# We might want to raise an exception here, instead of depending on a tool parameter value error.
input_values[input.name] = None

def get_current_case(input, input_values):
test_parameter = input.test_param
Expand Down
14 changes: 11 additions & 3 deletions lib/galaxy/tools/parameters/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
ParameterParseException,
text_input_is_optional,
)
from galaxy.tools.parameters.workflow_utils import workflow_building_modes
from galaxy.tools.parameters.workflow_utils import (
NO_REPLACEMENT,
workflow_building_modes,
)
from galaxy.util import (
sanitize_param,
string_as_bool,
Expand Down Expand Up @@ -247,6 +250,8 @@ def to_python(self, value, app):
def value_to_basic(self, value, app, use_security=False):
if is_runtime_value(value):
return runtime_to_json(value)
elif value == NO_REPLACEMENT:
return {"__class__": "NoReplacement"}
return self.to_json(value, app, use_security)

def value_from_basic(self, value, app, ignore_errors=False):
Expand All @@ -255,8 +260,11 @@ def value_from_basic(self, value, app, ignore_errors=False):
if isinstance(self, HiddenToolParameter):
raise ParameterValueError(message_suffix="Runtime Parameter not valid", parameter_name=self.name)
return runtime_to_object(value)
elif isinstance(value, MutableMapping) and value.get("__class__") == "UnvalidatedValue":
return value["value"]
elif isinstance(value, MutableMapping):
if value.get("__class__") == "UnvalidatedValue":
return value["value"]
elif value.get("__class__") == "NoReplacement":
return NO_REPLACEMENT
# Delegate to the 'to_python' method
try:
return self.to_python(value, app)
Expand Down
9 changes: 9 additions & 0 deletions lib/galaxy/tools/parameters/workflow_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from collections.abc import MutableMapping


class NoReplacement:

def __str__(self):
return "NO_REPLACEMENT singleton"


NO_REPLACEMENT = NoReplacement()


class workflow_building_modes:
DISABLED = False
ENABLED = True
Expand Down
Loading

0 comments on commit cd999d2

Please sign in to comment.