diff --git a/client/src/components/Collections/common/CollectionEditView.vue b/client/src/components/Collections/common/CollectionEditView.vue index 8e4dbe08f62..6a50660bad4 100644 --- a/client/src/components/Collections/common/CollectionEditView.vue +++ b/client/src/components/Collections/common/CollectionEditView.vue @@ -2,15 +2,15 @@

{{ l("Edit Collection Attributes") }}

- {{ l(newCollectionInfoMessage) }} + {{ l(infoMessage) }}
- {{ errorMessage }} + {{ l(errorMessage) }}
- +
@@ -24,13 +24,13 @@
- + - + @@ -94,6 +94,10 @@ export default { jobError: null, noQuotaIncrease: true, loadingString: "Loading Datatypes", + infoMessage: "This will create a new collection in your History. Your quota will not increase.", //initialmessage on first/database tab + newCollectionMessage: "This will create a new collection in your History.", + noQuotaIncreaseMessage: "Your quota will not increase.", + expectWaitTimeMessage: "This operation might take a short while, depending on the size of your collection.", }; }, computed: { @@ -103,13 +107,6 @@ export default { datatypeFromElements: function () { return this.attributesData.extension; }, - newCollectionInfoMessage: function () { - let newCollectionMessage = "This will create a new collection in your History."; - if (this.noQuotaIncrease) { - newCollectionMessage += " Your quota usage will not increase."; - } - return newCollectionMessage; - }, historyId: function () { return this.$store.getters["history/currentHistoryId"]; }, @@ -118,6 +115,9 @@ export default { this.getCollectionDataAndAttributes(); }, methods: { + updateInfoMessage: function (strMessage) { + this.infoMessage = strMessage; + }, getCollectionDataAndAttributes: async function () { let attributesGet = this.$store.getters.getCollectionAttributes(this.collection_id); if (attributesGet == null) { diff --git a/client/src/components/Grid/GridHistory.vue b/client/src/components/Grid/GridHistory.vue index c00cf5641ae..a7cabb8b37d 100644 --- a/client/src/components/Grid/GridHistory.vue +++ b/client/src/components/Grid/GridHistory.vue @@ -5,8 +5,16 @@ diff --git a/client/src/components/Grid/history-list.js b/client/src/components/Grid/history-list.js index 42b8c21ff2c..6e283988061 100644 --- a/client/src/components/Grid/history-list.js +++ b/client/src/components/Grid/history-list.js @@ -65,7 +65,7 @@ var View = Backbone.View.extend({ this.active_tab = "user"; this.model = new Backbone.Model(); Utils.get({ - url: `${getAppRoot()}history/list?${$.param(Galaxy.params)}`, + url: `${getAppRoot()}history/${options.action_id}?${$.param(Galaxy.params)}`, success: (response) => { this.model.set(response); this.render(); diff --git a/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js b/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js index 0fb9f79c592..22885e82301 100644 --- a/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js +++ b/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js @@ -38,6 +38,8 @@ describe("HistoryFilters", () => { "[placeholder='any extension']": "ext-filter", "[placeholder='any tag']": "tag filter", "[placeholder='any state']": "state-filter", + "[placeholder='any database']": "db-filter", + "[placeholder='index equals']": "hid-related", "[placeholder='index greater']": "hid-greater", "[placeholder='index lower']": "hid-lower", "[placeholder='created after']": "January 1, 2022", @@ -79,7 +81,7 @@ describe("HistoryFilters", () => { await expectCorrectEmits( wrapper, false, - "create_time>'January 1, 2022' create_time<'January 1, 2023' extension:ext-filter hid>hid-greater hid'January 1, 2022' create_time<'January 1, 2023' extension:ext-filter genome_build:db-filter related:hid-related hid>hid-greater hidFilter by state: + Filter by database: + Filter by related to item index: Filter by item index: diff --git a/client/src/components/History/HistoryFilters.js b/client/src/components/History/HistoryFilters.js index e8d9dd9bb8e..4f9c48a639c 100644 --- a/client/src/components/History/HistoryFilters.js +++ b/client/src/components/History/HistoryFilters.js @@ -5,6 +5,7 @@ export const validFilters = { state: equals("state"), name: contains("name"), extension: equals("extension"), + genome_build: contains("genome_build"), hid_ge: compare("hid", "ge"), hid_gt: compare("hid", "gt"), hid_le: compare("hid", "le"), diff --git a/client/src/entry/analysis/router.js b/client/src/entry/analysis/router.js index 2506529252a..35f23445242 100644 --- a/client/src/entry/analysis/router.js +++ b/client/src/entry/analysis/router.js @@ -237,7 +237,7 @@ export function getRouter(Galaxy) { props: true, }, { - path: "histories/list", + path: "histories/:actionId", component: GridHistory, props: true, redirect: redirectAnon(), diff --git a/client/src/utils/navigation/navigation.yml b/client/src/utils/navigation/navigation.yml index 4157da48d60..6c2ecc38481 100644 --- a/client/src/utils/navigation/navigation.yml +++ b/client/src/utils/navigation/navigation.yml @@ -309,6 +309,7 @@ edit_dataset_attributes: edit_collection_attributes: selectors: + alert_info: 'div.alert-info' database_genome_tab: type: xpath selector: '//a[contains(text(), "Database/Build")]' diff --git a/client/src/utils/webhooks.js b/client/src/utils/webhooks.js index 1fb9452853a..c2ecd90bb3e 100644 --- a/client/src/utils/webhooks.js +++ b/client/src/utils/webhooks.js @@ -29,11 +29,9 @@ const WebhookView = Backbone.View.extend({ this.$el.attr("tool_version", toolVersion); getWebHookData().then((data) => { - if (options.type) { - data.reset(filterType(data, options.type)); - } - if (data.length > 0) { - this.render(weightedRandomPick(data)); + const filteredData = filterData(data, options); + if (filteredData.length > 0) { + this.render(weightedRandomPick(filteredData)); } }); }, @@ -46,13 +44,17 @@ const WebhookView = Backbone.View.extend({ }, }); +function filterData(data, options) { + let filteredData = data; + if (options.type) { + filteredData = filterType(data, options.type); + } + return filteredData; +} + const load = (options) => { getWebHookData().then((data) => { - let filteredData = data; - if (options.type) { - filteredData = filterType(data, options.type); - } - options.callback(filteredData); + options.callback(filterData(data, options)); }); }; diff --git a/doc/schema_template.md b/doc/schema_template.md index 9a6461d3f16..6bb23179654 100644 --- a/doc/schema_template.md +++ b/doc/schema_template.md @@ -74,6 +74,7 @@ $tag:tool|outputs|data|actions://complexType[@name='Actions'] $tag:tool|outputs|data|actions|conditional://complexType[@name='ActionsConditional'] $tag:tool|outputs|data|actions|conditional|when://complexType[@name='ActionsConditionalWhen'] $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|filter://complexType[@name='OutputFilter'] diff --git a/lib/galaxy/managers/genomes.py b/lib/galaxy/managers/genomes.py index 4601824b3ea..f6af2d73d9a 100644 --- a/lib/galaxy/managers/genomes.py +++ b/lib/galaxy/managers/genomes.py @@ -1,8 +1,11 @@ from typing import ( Any, List, + TYPE_CHECKING, ) +from sqlalchemy import func + from galaxy import model as m from galaxy.exceptions import ( ReferenceDataError, @@ -10,6 +13,10 @@ from galaxy.exceptions import ( ) from galaxy.managers.context import ProvidesUserContext from galaxy.structured_app import StructuredApp +from .base import raise_filter_err + +if TYPE_CHECKING: + from galaxy.managers.base import OrmFilterParsersType class GenomesManager: @@ -64,3 +71,30 @@ class GenomesManager: raise ReferenceDataError(f"Data tables not found for {index_type} for {id}") else: return f"{file_name}{ext}" + + +class GenomeFilterMixin: + orm_filter_parsers: "OrmFilterParsersType" + valid_ops = ("eq", "contains", "has") + + def create_genome_filter(self, attr, op, val): + def _create_genome_filter(model_class=None): + if op not in GenomeFilterMixin.valid_ops: + raise_filter_err(attr, op, val, "bad op in filter") + if model_class is None: + return True + # Doesn't filter genome_build for collections + if model_class.__name__ == "HistoryDatasetCollectionAssociation": + return False + column = func.json_extract(model_class.table.c._metadata, "$.dbkey") + lower_val = val.lower() # Ignore case + if op == "eq": + cond = func.lower(column) == lower_val + else: + cond = func.lower(column).contains(lower_val, autoescape=True) + return cond + + return _create_genome_filter + + def _add_parsers(self): + self.orm_filter_parsers.update({"genome_build": self.create_genome_filter}) diff --git a/lib/galaxy/managers/hdas.py b/lib/galaxy/managers/hdas.py index 819eba9e447..7abbee7f3b7 100644 --- a/lib/galaxy/managers/hdas.py +++ b/lib/galaxy/managers/hdas.py @@ -337,6 +337,7 @@ class HDASerializer( # datasets._UnflattenedMetadataDatasetAssociationSerialize "hid", "history_content_type", "dataset_id", + "genome_build", "state", "extension", "deleted", diff --git a/lib/galaxy/managers/history_contents.py b/lib/galaxy/managers/history_contents.py index 8b3a87768d0..22adbfa74a2 100644 --- a/lib/galaxy/managers/history_contents.py +++ b/lib/galaxy/managers/history_contents.py @@ -37,6 +37,7 @@ from galaxy.managers import ( annotatable, base, deletable, + genomes, hdas, hdcas, taggable, @@ -521,6 +522,7 @@ class HistoryContentsFilters( base.ModelFilterParser, annotatable.AnnotatableFilterMixin, deletable.PurgableFiltersMixin, + genomes.GenomeFilterMixin, taggable.TaggableFilterMixin, tools.ToolFilterMixin, ): @@ -563,8 +565,10 @@ class HistoryContentsFilters( return sql.column("history_content_type") == val raise_filter_err(attr, op, val, "bad op in filter") - if attr == "related" and op == "eq": - return sql.column("hid").in_(json.loads(val)) + if attr == "related": + if op == "eq": + return sql.column("hid").in_(json.loads(val)) + raise_filter_err(attr, op, val, "bad op in filter") if attr == "type_id": if op == "eq": @@ -617,12 +621,14 @@ class HistoryContentsFilters( def _add_parsers(self): super()._add_parsers() annotatable.AnnotatableFilterMixin._add_parsers(self) + genomes.GenomeFilterMixin._add_parsers(self) deletable.PurgableFiltersMixin._add_parsers(self) taggable.TaggableFilterMixin._add_parsers(self) tools.ToolFilterMixin._add_parsers(self) self.orm_filter_parsers.update( { "history_content_type": {"op": ("eq")}, + # maybe remove related from here, as there's no corresponding field? "related": {"op": ("eq")}, "type_id": {"op": ("eq", "in"), "val": self.parse_type_id_list}, "hid": {"op": ("eq", "ge", "le", "gt", "lt"), "val": int}, diff --git a/lib/galaxy/model/store/discover.py b/lib/galaxy/model/store/discover.py index 3fa64e59e17..2f169ea3d67 100644 --- a/lib/galaxy/model/store/discover.py +++ b/lib/galaxy/model/store/discover.py @@ -104,7 +104,6 @@ class ModelPersistenceContext(metaclass=abc.ABCMeta): if primary_data is not None: primary_data.extension = ext - primary_data.visible = visible primary_data.dbkey = dbkey else: if not library_folder: @@ -811,12 +810,13 @@ def persist_hdas(elements, model_persistence_context, final_job_state="ok"): hashes = fields_match.hashes created_from_basename = fields_match.created_from_basename extra_files = fields_match.extra_files + visible = fields_match.visible info, state = discovered_file.discovered_state(element, final_job_state) dataset = model_persistence_context.create_dataset( ext=ext, designation=designation, - visible=True, + visible=visible, dbkey=dbkey, name=name, filename=discovered_file.path, diff --git a/lib/galaxy/tool_util/xsd/galaxy.xsd b/lib/galaxy/tool_util/xsd/galaxy.xsd index 142e1c00cd2..12e7efbcf41 100644 --- a/lib/galaxy/tool_util/xsd/galaxy.xsd +++ b/lib/galaxy/tool_util/xsd/galaxy.xsd @@ -5752,22 +5752,30 @@ Source of the tabular data ``from_data_table``, ``from_param``, or ``from_file`` - + - + - + - + @@ -5806,7 +5814,7 @@ of this directive. ]]> - + @@ -5931,6 +5939,13 @@ Applies to ``param_value``, ``boolean`` ]]> + + + + ]]> + + @@ -5943,9 +5958,9 @@ Applies to ``param_value`` Applies to ``multiple_splitter`` - + - Applies to ``column_strip`` + Applies to ``column_strip``. The given string is removed from the start or end of the column. diff --git a/lib/galaxy/webapps/galaxy/api/history_contents.py b/lib/galaxy/webapps/galaxy/api/history_contents.py index 02f75a82ac8..add89f3c198 100644 --- a/lib/galaxy/webapps/galaxy/api/history_contents.py +++ b/lib/galaxy/webapps/galaxy/api/history_contents.py @@ -382,7 +382,7 @@ class FastAPIHistoryContents: @router.get( "/api/histories/{history_id}/contents/{id}", name="history_content", - summary="Return detailed information about an HDA within a history.", + summary="Return detailed information about an HDA within a history. ``/api/histories/{history_id}/contents/{type}s/{id}`` should be used instead.", deprecated=True, ) def show( @@ -635,7 +635,7 @@ class FastAPIHistoryContents: ) @router.put( "/api/histories/{history_id}/contents/{id}", - summary="Updates the values for the history content item with the given ``ID``.", + summary="Updates the values for the history content item with the given ``ID``. ``/api/histories/{history_id}/contents/{type}s/{id}`` should be used instead.", deprecated=True, ) def update( diff --git a/lib/galaxy_test/api/test_history_contents.py b/lib/galaxy_test/api/test_history_contents.py index de9267a9a10..427f6178053 100644 --- a/lib/galaxy_test/api/test_history_contents.py +++ b/lib/galaxy_test/api/test_history_contents.py @@ -1263,7 +1263,7 @@ class TestHistoryContentsApiBulkOperation(ApiTestCase): with self.dataset_populator.test_history() as history_id: self._create_test_history_contents(history_id) - invalid_filter_keys_with_stats = ["genome_build", "data_type", "annotation"] + invalid_filter_keys_with_stats = ["data_type", "annotation"] for filter_key in invalid_filter_keys_with_stats: response = self._get_contents_with_stats( diff --git a/lib/galaxy_test/api/test_tools.py b/lib/galaxy_test/api/test_tools.py index ca6c812a9eb..b36df9743dc 100644 --- a/lib/galaxy_test/api/test_tools.py +++ b/lib/galaxy_test/api/test_tools.py @@ -819,6 +819,23 @@ class TestToolsApi(ApiTestCase, TestsTools): def test_apply_rules_6(self): self._apply_rules_and_check(rules_test_data.EXAMPLE_6) + @skip_without_tool("galaxy_json_sleep") + def test_dataset_hidden_after_job_finish(self): + with self.dataset_populator.test_history() as history_id: + inputs = { + "sleep_time": 5, + } + response = self._run("galaxy_json_sleep", history_id, inputs, assert_ok=True) + output = response["outputs"][0] + response = self._put( + f"histories/{history_id}/contents/datasets/{output['id']}", data={"visible": False}, json=True + ) + response.raise_for_status() + output_details = self.dataset_populator.get_history_dataset_details(history_id, dataset=output, wait=False) + assert not output_details["visible"] + output_details = self.dataset_populator.get_history_dataset_details(history_id, dataset=output, wait=True) + assert not output_details["visible"] + @skip_without_tool("multi_select") def test_multi_select_as_list(self): with self.dataset_populator.test_history(require_new=False) as history_id: diff --git a/lib/galaxy_test/selenium/test_collection_edit.py b/lib/galaxy_test/selenium/test_collection_edit.py index 72bb3142293..af584a38977 100644 --- a/lib/galaxy_test/selenium/test_collection_edit.py +++ b/lib/galaxy_test/selenium/test_collection_edit.py @@ -14,6 +14,8 @@ class TestCollectionEdit(SeleniumTestCase): self.create_simple_list_collection() self.open_collection_edit_view() self.navigate_to_database_tab() + alert_element = self.components.edit_collection_attributes.alert_info.wait_for_visible() + assert "This will create a new collection in your History. Your quota will not increase." in alert_element.text dataValue = "unspecified" self.check_current_data_value(dataValue) dataNew = "hg17" @@ -29,6 +31,11 @@ class TestCollectionEdit(SeleniumTestCase): self.create_simple_list_collection_txt() self.open_collection_edit_view() self.navigate_to_datatype_tab() + alert_element = self.components.edit_collection_attributes.alert_info.wait_for_visible() + + assert ( + "This operation might take a short while, depending on the size of your collection." in alert_element.text + ) dataValue = "txt" self.check_current_data_value(dataValue) dataNew = "tabular" diff --git a/static/welcome.html.sample b/static/welcome.html.sample index b35df44203c..b82ca6a713a 100644 --- a/static/welcome.html.sample +++ b/static/welcome.html.sample @@ -2,7 +2,7 @@ - +
diff --git a/templates/webapps/galaxy/visualization/phyloviz.mako b/templates/webapps/galaxy/visualization/phyloviz.mako index af744a3339c..064412e469f 100644 --- a/templates/webapps/galaxy/visualization/phyloviz.mako +++ b/templates/webapps/galaxy/visualization/phyloviz.mako @@ -1,5 +1,7 @@ <%inherit file="/base/base_panels.mako"/> ## +<%def name="title()">${ config.get('title', 'Phyloviz') + ' | Galaxy' } + <%def name="init()"> <% self.has_left_panel=False diff --git a/test/functional/tools/galaxy_json_discover_and_sleep.xml b/test/functional/tools/galaxy_json_discover_and_sleep.xml new file mode 100644 index 00000000000..8b598bb72fa --- /dev/null +++ b/test/functional/tools/galaxy_json_discover_and_sleep.xml @@ -0,0 +1,28 @@ + + + + {"output_tool_supplied_metadata": { + "name": "my dynamic name", + "ext": "txt", + "info": "my dynamic info" + }} + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/functional/tools/sample_tool_conf.xml b/test/functional/tools/sample_tool_conf.xml index 8c83979591a..f215f1f2bdf 100644 --- a/test/functional/tools/sample_tool_conf.xml +++ b/test/functional/tools/sample_tool_conf.xml @@ -1,15 +1,15 @@ - - + +
- - + + @@ -19,10 +19,10 @@ - - - - + + + + @@ -30,6 +30,7 @@ +