Skip to content

Commit c443d08

Browse files
committed
Merge branch 'release_25.0' into release_25.1
2 parents ba446cb + 2fc9903 commit c443d08

File tree

7 files changed

+70
-5
lines changed

7 files changed

+70
-5
lines changed

client/src/components/Dataset/DatasetView.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { usePersistentToggle } from "@/composables/persistentToggle";
88
import { useDatasetStore } from "@/stores/datasetStore";
99
import { useDatatypesMapperStore } from "@/stores/datatypesMapperStore";
1010
import { useDatatypeStore } from "@/stores/datatypeStore";
11+
import { withPrefix } from "@/utils/redirect";
1112
import { bytesToString } from "@/utils/utils";
1213
1314
import DatasetError from "../DatasetInformation/DatasetError.vue";
@@ -56,6 +57,7 @@ const showError = computed(
5657
const isAutoDownloadType = computed(
5758
() => dataset.value && datatypeStore.isDatatypeAutoDownload(dataset.value.file_ext),
5859
);
60+
const downloadUrl = computed(() => withPrefix(`/datasets/${props.datasetId}/display`));
5961
const preferredVisualization = computed(
6062
() => dataset.value && datatypeStore.getPreferredVisualization(dataset.value.file_ext),
6163
);
@@ -195,7 +197,7 @@ watch(
195197
<h4>Download Required</h4>
196198
<p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p>
197199
<p>File size: <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p>
198-
<a :href="`/datasets/${datasetId}/display`" class="btn btn-primary mt-2" download>
200+
<a :href="downloadUrl" class="btn btn-primary mt-2" download>
199201
<FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> Download File
200202
</a>
201203
</div>
@@ -222,7 +224,7 @@ watch(
222224
<h4>Download Required</h4>
223225
<p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p>
224226
<p>File size: <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p>
225-
<a :href="`/datasets/${datasetId}/display`" class="btn btn-primary mt-2" download>
227+
<a :href="downloadUrl" class="btn btn-primary mt-2" download>
226228
<FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> Download File
227229
</a>
228230
</div>

lib/galaxy/config/sample/datatypes_conf.xml.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@
599599
<datatype extension="odgi" type="galaxy.datatypes.binary:Binary" subclass="true" description="Genomic variation graphs self index used by odgi." display_in_upload="true"/>
600600
<datatype extension="vg" type="galaxy.datatypes.binary:CompressedArchive" subclass="true" description="Genomic variation graphs." display_in_upload="true"/>
601601
<datatype extension="xg" type="galaxy.datatypes.binary:Binary" subclass="true" description="Genomic variation graphs with vg index." display_in_upload="true"/>
602+
<datatype extension="gam" type="galaxy.datatypes.binary:Binary" subclass="true" description="Binary file storing sequencing read alignments to genome variation graphs, used by the VG toolkit." display_in_upload="true" description_url="https://github.com/vgteam/vg/wiki/File-Formats#gam-graph-alignment--map-vgs-bam"/>
602603
<datatype extension="protobuf2" type="galaxy.datatypes.binary:Binary" subclass="true" description="Protocol Buffers (Protobuf) is data format for serializing structured data." display_in_upload="true"/>
603604
<datatype extension="protobuf3" type="galaxy.datatypes.binary:Binary" subclass="true" description="Protocol Buffers (Protobuf) is data format for serializing structured data." display_in_upload="true"/>
604605
<datatype extension="onnx" type="galaxy.datatypes.binary:Binary" subclass="true" description="ONNX (Open neural network exchange) is data format for storing and sharing machine learning and deep learning models." display_in_upload="true">

lib/galaxy/managers/landing.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
)
55
from uuid import uuid4
66

7-
from pydantic import UUID4
7+
from pydantic import (
8+
UUID4,
9+
ValidationError,
10+
)
811
from sqlalchemy import select
912

1013
from galaxy.exceptions import (
@@ -38,6 +41,7 @@
3841
LandingRequestInternalToolState,
3942
LandingRequestToolState,
4043
)
44+
from galaxy.tool_util_models.parameters import DataOrCollectionRequestAdapter
4145
from galaxy.util import safe_str_cmp
4246
from .context import ProvidesUserContext
4347
from .tools import (
@@ -107,11 +111,25 @@ def create_workflow_landing_request(self, payload: CreateWorkflowLandingRequestP
107111
model.workflow_source = payload.workflow_id
108112
model.uuid = uuid4()
109113
model.client_secret = payload.client_secret
110-
model.request_state = payload.request_state
114+
model.request_state = self.validate_workflow_request_state(payload.request_state)
111115
model.public = payload.public
112116
self._save(model)
113117
return self._workflow_response(model)
114118

119+
def validate_workflow_request_state(self, request_state: Optional[dict]) -> Optional[dict]:
120+
# This would ideally be run in the context of a workflow input definition
121+
if isinstance(request_state, dict):
122+
for key, value in request_state.items():
123+
if isinstance(value, dict):
124+
try:
125+
# persist values after model validators and aliases have been applied
126+
request_state[key] = DataOrCollectionRequestAdapter.validate_python(value).model_dump(
127+
by_alias=True, exclude_unset=True, mode="json"
128+
)
129+
except ValidationError:
130+
pass
131+
return request_state
132+
115133
def claim_tool_landing_request(
116134
self, trans: ProvidesUserContext, uuid: UUID4, claim: Optional[ClaimLandingPayload]
117135
) -> ToolLandingRequest:

lib/galaxy/tool_util/parser/yaml.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,10 @@ def parse_input_type(self):
403403
return "param"
404404

405405
def parse_extensions(self):
406-
return [ext.strip().lower() for ext in self.input_dict.get("extensions", ["data"])]
406+
extensions = self.input_dict.get("extensions")
407+
if not extensions:
408+
extensions = self.get("format", "data").split(",")
409+
return [ext.strip().lower() for ext in extensions]
407410

408411
def parse_nested_inputs_source(self):
409412
assert self.parse_input_type() == "repeat"

lib/galaxy_test/api/test_landing.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,14 @@ def test_create_private_workflow_landing_anonymous_user(self):
232232
_cannot_claim_request(self.dataset_populator, response)
233233
_cannot_use_request(self.dataset_populator, response)
234234

235+
@skip_without_tool("cat1")
236+
def test_workflow_landing_uniform_response(self):
237+
request = _get_simple_landing_payload(self.workflow_populator, public=True)
238+
response = self.dataset_populator.create_workflow_landing(request)
239+
landing_request = self.dataset_populator.use_workflow_landing_raw(response.uuid)
240+
# Make sure url is turned into location
241+
assert landing_request["request_state"]["WorkflowInput1"]["location"]
242+
235243
def test_landing_claim_preserves_source_metadata(self):
236244
request = CreateWorkflowLandingRequestPayload(
237245
workflow_id="https://dockstore.org/api/ga4gh/trs/v2/tools/#workflow/github.com/iwc-workflows/chipseq-pe/main/versions/v0.12",

lib/galaxy_test/api/test_workflows.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,33 @@ def test_workflow_download_instance(self):
831831
assert initial_instance_download["workflow_id"] == first_instance_id
832832
assert initial_instance_download["name"] == original_name
833833

834+
def test_workflow_run_input_extension_restriction_applied(self):
835+
workflow_id = self.workflow_populator.upload_yaml_workflow(
836+
"""
837+
class: GalaxyWorkflow
838+
inputs:
839+
tabular_input:
840+
type: data
841+
format:
842+
- tabular
843+
steps:
844+
first_cat:
845+
tool_id: cat1
846+
in:
847+
input1: tabular_input
848+
"""
849+
)
850+
with self.dataset_populator.test_history() as history_id:
851+
# Upload a txt file that should NOT be available for the tabular input
852+
self.dataset_populator.new_dataset(history_id, content="hello world", file_type="txt", wait=True)
853+
854+
# Download workflow in run style to get the form with available datasets
855+
run_workflow = self._download_workflow(workflow_id, style="run", history_id=history_id)
856+
tabular_input_step = run_workflow["steps"][0]
857+
input_options = tabular_input_step["inputs"][0]
858+
assert input_options["extensions"] == ["tabular"]
859+
assert not input_options["options"]["hda"]
860+
834861
def test_update(self):
835862
original_workflow = self.workflow_populator.load_workflow(name="test_import")
836863
uuids = {}

lib/galaxy_test/base/populators.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,12 @@ def use_tool_landing(self, uuid: UUID4) -> ToolLandingRequest:
952952
api_asserts.assert_status_code_is(landing_reponse, 200)
953953
return ToolLandingRequest.model_validate(landing_reponse.json())
954954

955+
def use_workflow_landing_raw(self, uuid: UUID4):
956+
url = f"workflow_landings/{uuid}"
957+
landing_reponse = self._get(url, {"client_secret": "foobar"})
958+
api_asserts.assert_status_code_is(landing_reponse, 200)
959+
return landing_reponse.json()
960+
955961
def create_tool_from_path(self, tool_path: str) -> dict[str, Any]:
956962
tool_directory = os.path.dirname(os.path.abspath(tool_path))
957963
payload = dict(

0 commit comments

Comments
 (0)