mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge branch 'release_24.1' into dev
This commit is contained in:
@@ -14,9 +14,10 @@ import {
|
||||
LazyChangeDataAction,
|
||||
LazyChangePositionAction,
|
||||
LazyChangeSizeAction,
|
||||
RemoveAllFreehandCommentsAction,
|
||||
ToggleCommentSelectedAction,
|
||||
} from "./commentActions";
|
||||
import { mockComment, mockToolStep, mockWorkflow } from "./mockData";
|
||||
import { mockComment, mockFreehandComment, mockToolStep, mockWorkflow } from "./mockData";
|
||||
import {
|
||||
CopyStepAction,
|
||||
InsertStepAction,
|
||||
@@ -90,6 +91,12 @@ describe("Workflow Undo Redo Actions", () => {
|
||||
return comment;
|
||||
}
|
||||
|
||||
function addFreehandComment() {
|
||||
const comment = mockFreehandComment(commentStore.highestCommentId + 1);
|
||||
commentStore.addComments([comment]);
|
||||
return comment;
|
||||
}
|
||||
|
||||
function addStep() {
|
||||
const step = mockToolStep(stepStore.getStepIndex + 1);
|
||||
stepStore.addStep(step);
|
||||
@@ -141,6 +148,15 @@ describe("Workflow Undo Redo Actions", () => {
|
||||
const action = new ToggleCommentSelectedAction(commentStore, comment);
|
||||
testUndoRedo(action);
|
||||
});
|
||||
|
||||
it("RemoveAllFreehandCommentsAction", () => {
|
||||
addFreehandComment();
|
||||
addFreehandComment();
|
||||
addFreehandComment();
|
||||
|
||||
const action = new RemoveAllFreehandCommentsAction(commentStore);
|
||||
testUndoRedo(action);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Workflow Actions", () => {
|
||||
|
||||
@@ -177,3 +177,28 @@ export class ToggleCommentSelectedAction extends UndoRedoAction {
|
||||
this.store.setCommentMultiSelected(this.commentId, !this.toggleTo);
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveAllFreehandCommentsAction extends UndoRedoAction {
|
||||
store;
|
||||
comments;
|
||||
|
||||
constructor(store: WorkflowCommentStore) {
|
||||
super();
|
||||
|
||||
this.store = store;
|
||||
const freehandComments = store.comments.filter((comment) => comment.type === "freehand");
|
||||
this.comments = structuredClone(freehandComments);
|
||||
}
|
||||
|
||||
get name() {
|
||||
return "remove all freehand comments";
|
||||
}
|
||||
|
||||
run() {
|
||||
this.store.deleteFreehandComments();
|
||||
}
|
||||
|
||||
undo() {
|
||||
this.store.addComments(structuredClone(this.comments));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkflowComment } from "@/stores/workflowEditorCommentStore";
|
||||
import { FreehandWorkflowComment, WorkflowComment } from "@/stores/workflowEditorCommentStore";
|
||||
import type { Step } from "@/stores/workflowStepStore";
|
||||
|
||||
import type { Workflow } from "../modules/model";
|
||||
@@ -227,3 +227,21 @@ export function mockComment(id: number): WorkflowComment {
|
||||
data: { size: 2, text: "Enter Text" },
|
||||
};
|
||||
}
|
||||
|
||||
export function mockFreehandComment(id: number): FreehandWorkflowComment {
|
||||
return {
|
||||
id,
|
||||
position: [0, 0],
|
||||
size: [100, 200],
|
||||
type: "freehand",
|
||||
color: "none",
|
||||
data: {
|
||||
thickness: 1,
|
||||
line: [
|
||||
[0, 0],
|
||||
[10, 20],
|
||||
[100, 200],
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { BoxSelect } from "lucide-vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed, toRefs, watch } from "vue";
|
||||
|
||||
import { RemoveAllFreehandCommentsAction } from "@/components/Workflow/Editor/Actions/commentActions";
|
||||
import { useUid } from "@/composables/utils/uid";
|
||||
import { useWorkflowStores } from "@/composables/workflowStores";
|
||||
import { type CommentTool } from "@/stores/workflowEditorToolbarStore";
|
||||
@@ -45,7 +46,7 @@ library.add(
|
||||
faTrash
|
||||
);
|
||||
|
||||
const { toolbarStore, commentStore } = useWorkflowStores();
|
||||
const { toolbarStore, undoRedoStore, commentStore } = useWorkflowStores();
|
||||
const { snapActive, currentTool } = toRefs(toolbarStore);
|
||||
|
||||
const { commentOptions } = toolbarStore;
|
||||
@@ -122,7 +123,7 @@ const thicknessId = useUid("thickness-");
|
||||
const smoothingId = useUid("smoothing-");
|
||||
|
||||
function onRemoveAllFreehand() {
|
||||
commentStore.deleteFreehandComments();
|
||||
undoRedoStore.applyAction(new RemoveAllFreehandCommentsAction(commentStore));
|
||||
}
|
||||
|
||||
useToolLogic();
|
||||
|
||||
@@ -489,12 +489,16 @@ class DatasetAssociationManager(
|
||||
|
||||
def ensure_dataset_on_disk(self, trans, dataset):
|
||||
# Not a guarantee data is really present, but excludes a lot of expected cases
|
||||
if not dataset.dataset:
|
||||
raise exceptions.InternalServerError("Item has no associated dataset.")
|
||||
if dataset.purged or dataset.dataset.purged:
|
||||
raise exceptions.ItemDeletionException("The dataset you are attempting to view has been purged.")
|
||||
elif dataset.deleted and not (trans.user_is_admin or self.is_owner(dataset, trans.get_user())):
|
||||
raise exceptions.ItemDeletionException("The dataset you are attempting to view has been deleted.")
|
||||
elif dataset.state == Dataset.states.UPLOAD:
|
||||
raise exceptions.Conflict("Please wait until this dataset finishes uploading before attempting to view it.")
|
||||
elif dataset.state == Dataset.states.NEW:
|
||||
raise exceptions.Conflict("The dataset you are attempting to view is new and has no data.")
|
||||
elif dataset.state == Dataset.states.DISCARDED:
|
||||
raise exceptions.ItemDeletionException("The dataset you are attempting to view has been discarded.")
|
||||
elif dataset.state == Dataset.states.DEFERRED:
|
||||
|
||||
@@ -61,6 +61,7 @@ class GalaxyDataTestConfig(Bunch):
|
||||
self.object_store = "disk"
|
||||
self.object_store_check_old_style = False
|
||||
self.object_store_cache_path = "/tmp/cache"
|
||||
self.object_store_cache_size = -1
|
||||
self.object_store_store_by = "uuid"
|
||||
|
||||
self.umask = os.umask(0o77)
|
||||
|
||||
@@ -1726,6 +1726,7 @@ def config_to_dict(config):
|
||||
"jobs_directory": config.jobs_directory,
|
||||
"new_file_path": config.new_file_path,
|
||||
"object_store_cache_path": config.object_store_cache_path,
|
||||
"object_store_cache_size": config.object_store_cache_size,
|
||||
"gid": config.gid,
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
List,
|
||||
Sequence,
|
||||
Union,
|
||||
)
|
||||
|
||||
from galaxy.tools.parameters.basic import (
|
||||
@@ -187,6 +189,26 @@ def process_key(incoming_key: str, incoming_value: Any, d: Dict[str, Any]):
|
||||
process_key("|".join(key_parts[1:]), incoming_value=incoming_value, d=subdict)
|
||||
|
||||
|
||||
def nested_key_to_path(key: str) -> Sequence[Union[str, int]]:
|
||||
"""
|
||||
Convert a tool state key that is separated with '|' and '_n' into path iterable.
|
||||
E.g. "cond|repeat_0|paramA" -> ["cond", "repeat", 0, "paramA"].
|
||||
Return value can be used with `boltons.iterutils.get_path`.
|
||||
"""
|
||||
path: List[Union[str, int]] = []
|
||||
key_parts = key.split("|")
|
||||
if len(key_parts) == 1:
|
||||
return key_parts
|
||||
for key_part in key_parts:
|
||||
if "_" in key_part:
|
||||
input_name, _index = key_part.rsplit("_", 1)
|
||||
if _index.isdigit():
|
||||
path.extend((input_name, int(_index)))
|
||||
continue
|
||||
path.append(key_part)
|
||||
return path
|
||||
|
||||
|
||||
def flat_to_nested_state(incoming: Dict[str, Any]):
|
||||
nested_state: Dict[str, Any] = {}
|
||||
for key, value in incoming.items():
|
||||
@@ -194,4 +216,11 @@ def flat_to_nested_state(incoming: Dict[str, Any]):
|
||||
return nested_state
|
||||
|
||||
|
||||
__all__ = ("LegacyUnprefixedDict", "WrappedParameters", "make_dict_copy", "process_key", "flat_to_nested_state")
|
||||
__all__ = (
|
||||
"LegacyUnprefixedDict",
|
||||
"WrappedParameters",
|
||||
"make_dict_copy",
|
||||
"process_key",
|
||||
"flat_to_nested_state",
|
||||
"nested_key_to_path",
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@ from typing import (
|
||||
Union,
|
||||
)
|
||||
|
||||
from boltons.iterutils import get_path
|
||||
from typing_extensions import Protocol
|
||||
|
||||
from galaxy import model
|
||||
@@ -35,6 +36,7 @@ from galaxy.schema.invocation import (
|
||||
WarningReason,
|
||||
)
|
||||
from galaxy.tools.parameters.basic import raw_to_galaxy
|
||||
from galaxy.tools.parameters.wrapped import nested_key_to_path
|
||||
from galaxy.util import ExecutionTimer
|
||||
from galaxy.workflow import modules
|
||||
from galaxy.workflow.run_request import (
|
||||
@@ -444,6 +446,10 @@ class WorkflowProgress:
|
||||
replacement = temp
|
||||
else:
|
||||
replacement = self.replacement_for_connection(connection[0], is_data=is_data)
|
||||
elif step.state and (state_input := get_path(step.state.inputs, nested_key_to_path(prefixed_name), None)):
|
||||
# workflow submitted with step parameters populates state directly
|
||||
# via populate_module_and_state
|
||||
replacement = state_input
|
||||
else:
|
||||
for step_input in step.inputs:
|
||||
if step_input.name == prefixed_name and step_input.default_value_set:
|
||||
|
||||
@@ -6982,6 +6982,35 @@ steps:
|
||||
# Take a valid stat and make it invalid, assert workflow won't run.
|
||||
self._assert_status_code_is(invocation_response, 400)
|
||||
|
||||
@skip_without_tool("collection_paired_test")
|
||||
def test_run_map_over_with_step_parameter_dict(self):
|
||||
# Tests what the legacy run form submits
|
||||
with self.dataset_populator.test_history() as history_id:
|
||||
hdca = self.dataset_collection_populator.create_list_of_pairs_in_history(history_id).json()["outputs"][0]
|
||||
workflow_id = self._upload_yaml_workflow(
|
||||
"""
|
||||
class: GalaxyWorkflow
|
||||
steps:
|
||||
"0":
|
||||
tool_id: collection_paired_conditional_structured_like
|
||||
state:
|
||||
cond:
|
||||
input1:
|
||||
__class__: RuntimeValue
|
||||
"""
|
||||
)
|
||||
workflow_request = {
|
||||
"history": f"hist_id={history_id}",
|
||||
"parameters": dumps({"0": {"cond|input1": {"values": [{"id": hdca["id"], "src": "hdca"}]}}}),
|
||||
"parameters_normalized": True,
|
||||
}
|
||||
url = f"workflows/{workflow_id}/invocations"
|
||||
invocation_response = self._post(url, data=workflow_request, json=True)
|
||||
invocation_response.raise_for_status()
|
||||
self.workflow_populator.wait_for_invocation_and_jobs(
|
||||
history_id=history_id, workflow_id=workflow_id, invocation_id=invocation_response.json()["id"]
|
||||
)
|
||||
|
||||
@skip_without_tool("validation_default")
|
||||
def test_parameter_substitution_validation_value_errors_1(self):
|
||||
substitions = dict(select_param='" ; echo "moo')
|
||||
|
||||
@@ -3,10 +3,28 @@ from typing import (
|
||||
Dict,
|
||||
)
|
||||
|
||||
from galaxy.tools.parameters.wrapped import process_key
|
||||
from galaxy.tools.parameters.wrapped import (
|
||||
nested_key_to_path,
|
||||
process_key,
|
||||
)
|
||||
from .util import BaseParameterTestCase
|
||||
|
||||
|
||||
def test_nested_key_to_path():
|
||||
assert nested_key_to_path("param") == ["param"]
|
||||
assert nested_key_to_path("param_x") == ["param_x"]
|
||||
assert nested_key_to_path("cond|param_x") == ["cond", "param_x"]
|
||||
assert nested_key_to_path("param_") == ["param_"]
|
||||
assert nested_key_to_path("cond|param_") == ["cond", "param_"]
|
||||
assert nested_key_to_path("repeat_1|inner_repeat_1|data_table_column_value") == [
|
||||
"repeat",
|
||||
1,
|
||||
"inner_repeat",
|
||||
1,
|
||||
"data_table_column_value",
|
||||
]
|
||||
|
||||
|
||||
class TestProcessKey:
|
||||
def test_process_key(self):
|
||||
nested_dict: Dict[str, Any] = {}
|
||||
|
||||
Reference in New Issue
Block a user