From 3e0c13671816b4f1f18798d6e181bb89c3db1d52 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 11 Sep 2025 14:52:57 -0400 Subject: [PATCH 001/893] Attempt to fix transient API test failures. I don't really think this will fix the problem - this seems like a deep bug in Galaxy to me but it might be worth attempting. The two things I did here is wait on the testing initial condition (the job search can find the job before we delete the dataset) in case there is a race condition of some sort and then use the more percise dataset deletion route in case there is a clash between collections and datasets. I think we defer to the dataset so this second thing probably won't help but I think the more percise endpoint simplifies the test and ensures this isn't the problem. --- lib/galaxy_test/api/test_jobs.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/galaxy_test/api/test_jobs.py b/lib/galaxy_test/api/test_jobs.py index e23ab2540808..9115159e7797 100644 --- a/lib/galaxy_test/api/test_jobs.py +++ b/lib/galaxy_test/api/test_jobs.py @@ -860,17 +860,22 @@ def test_search_delete_hdca_output(self, history_id): } ) tool_response = self._job_search(tool_id="collection_creates_list", history_id=history_id, inputs=inputs) - output_id = tool_response.json()["outputs"][0]["id"] + output_dict = tool_response.json()["outputs"][0] + assert output_dict["history_content_type"] == "dataset" + output_id = output_dict["id"] + # Wait for job search to register the job, make sure initial conditions set. + search_payload = self._search_payload(history_id=history_id, tool_id="collection_creates_list", inputs=inputs) + self._search(search_payload, expected_search_count=1) # We delete a single tool output, no job should be returned - delete_respone = self._delete(f"histories/{history_id}/contents/{output_id}") + delete_response = self._delete(f"histories/{history_id}/contents/datasets/{output_id}") self._assert_status_code_is_ok(delete_respone) search_payload = self._search_payload(history_id=history_id, tool_id="collection_creates_list", inputs=inputs) self._search(search_payload, expected_search_count=0) tool_response = self._job_search(tool_id="collection_creates_list", history_id=history_id, inputs=inputs) output_collection_id = tool_response.json()["output_collections"][0]["id"] # We delete a collection output, no job should be returned - delete_respone = self._delete(f"histories/{history_id}/contents/dataset_collections/{output_collection_id}") - self._assert_status_code_is_ok(delete_respone) + delete_response = self._delete(f"histories/{history_id}/contents/dataset_collections/{output_collection_id}") + self._assert_status_code_is_ok(delete_response) search_payload = self._search_payload(history_id=history_id, tool_id="collection_creates_list", inputs=inputs) self._search(search_payload, expected_search_count=0) From 72f707cfd52e5e9c9e784d381e5fad3562644335 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Wed, 1 Oct 2025 15:23:46 +0200 Subject: [PATCH 002/893] Fix delete_respone typo --- lib/galaxy_test/api/test_jobs.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/galaxy_test/api/test_jobs.py b/lib/galaxy_test/api/test_jobs.py index 9115159e7797..52fb8a42f717 100644 --- a/lib/galaxy_test/api/test_jobs.py +++ b/lib/galaxy_test/api/test_jobs.py @@ -772,12 +772,12 @@ def test_search(self, history_id): search_payload = self._search_payload(history_id=history_id, tool_id="cat1", inputs=copied_inputs) self._search(search_payload, expected_search_count=1) # Now we delete the original input HDA that was used -- we should still be able to find the job - delete_respone = self._delete(f"histories/{history_id}/contents/{dataset_id}") - self._assert_status_code_is_ok(delete_respone) + delete_response = self._delete(f"histories/{history_id}/contents/{dataset_id}") + self._assert_status_code_is_ok(delete_response) self._search(search_payload, expected_search_count=1) # Now we also delete the copy -- we shouldn't find a job - delete_respone = self._delete(f"histories/{new_history_id}/contents/{new_dataset_id}") - self._assert_status_code_is_ok(delete_respone) + delete_response = self._delete(f"histories/{new_history_id}/contents/{new_dataset_id}") + self._assert_status_code_is_ok(delete_response) self._search(search_payload, expected_search_count=0) @pytest.mark.require_new_history @@ -802,8 +802,8 @@ def test_search_delete_outputs(self, history_id): inputs = json.dumps({"input1": {"src": "hda", "id": dataset_id}}) tool_response = self._job_search(tool_id="cat1", history_id=history_id, inputs=inputs) output_id = tool_response.json()["outputs"][0]["id"] - delete_respone = self._delete(f"histories/{history_id}/contents/{output_id}") - self._assert_status_code_is_ok(delete_respone) + delete_response = self._delete(f"histories/{history_id}/contents/{output_id}") + self._assert_status_code_is_ok(delete_response) search_payload = self._search_payload(history_id=history_id, tool_id="cat1", inputs=inputs) self._search(search_payload, expected_search_count=0) @@ -846,8 +846,8 @@ def test_search_with_hdca_list_input(self, history_id): # We delete the ouput (this is a HDA, as multi_data_param reduces collections) # and use the correct input job definition, the job should not be found output_id = tool_response.json()["outputs"][0]["id"] - delete_respone = self._delete(f"histories/{history_id}/contents/{output_id}") - self._assert_status_code_is_ok(delete_respone) + delete_response = self._delete(f"histories/{history_id}/contents/{output_id}") + self._assert_status_code_is_ok(delete_response) search_payload = self._search_payload(history_id=history_id, tool_id="multi_data_param", inputs=inputs) self._search(search_payload, expected_search_count=0) @@ -868,7 +868,7 @@ def test_search_delete_hdca_output(self, history_id): self._search(search_payload, expected_search_count=1) # We delete a single tool output, no job should be returned delete_response = self._delete(f"histories/{history_id}/contents/datasets/{output_id}") - self._assert_status_code_is_ok(delete_respone) + self._assert_status_code_is_ok(delete_response) search_payload = self._search_payload(history_id=history_id, tool_id="collection_creates_list", inputs=inputs) self._search(search_payload, expected_search_count=0) tool_response = self._job_search(tool_id="collection_creates_list", history_id=history_id, inputs=inputs) @@ -906,12 +906,12 @@ def test_search_with_hdca_pair_input(self, history_id): ) self._search(search_payload, expected_search_count=1) # Now we delete the original input HDCA that was used -- we should still be able to find the job - delete_respone = self._delete(f"histories/{history_id}/contents/dataset_collections/{list_id_a}") - self._assert_status_code_is_ok(delete_respone) + delete_response = self._delete(f"histories/{history_id}/contents/dataset_collections/{list_id_a}") + self._assert_status_code_is_ok(delete_response) self._search(search_payload, expected_search_count=1) # Now we also delete the copy -- we shouldn't find a job - delete_respone = self._delete(f"histories/{history_id}/contents/dataset_collections/{new_list_a}") - self._assert_status_code_is_ok(delete_respone) + delete_response = self._delete(f"histories/{history_id}/contents/dataset_collections/{new_list_a}") + self._assert_status_code_is_ok(delete_response) self._search(search_payload, expected_search_count=0) @pytest.mark.require_new_history From a381133f2cb20b4a5602e2e339bcdc65ba25025e Mon Sep 17 00:00:00 2001 From: guerler Date: Mon, 29 Sep 2025 18:42:37 +0300 Subject: [PATCH 003/893] Remove Trackster client code --- client/src/bundleEntries.js | 8 +- client/src/viz/bbi-data-manager.js | 67 - client/src/viz/config.js | 413 --- client/src/viz/icon-button.js | 179 - client/src/viz/tools.js | 335 -- client/src/viz/trackster.js | 557 --- client/src/viz/trackster/filters.js | 665 ---- client/src/viz/trackster/painters.js | 1761 ---------- client/src/viz/trackster/slotting.js | 205 -- client/src/viz/trackster/tracks.js | 4859 -------------------------- client/src/viz/trackster/util.js | 145 - client/src/viz/visualization.js | 1105 ------ client/src/viz/viz_views.js | 111 - 13 files changed, 1 insertion(+), 10409 deletions(-) delete mode 100644 client/src/viz/bbi-data-manager.js delete mode 100644 client/src/viz/config.js delete mode 100644 client/src/viz/icon-button.js delete mode 100644 client/src/viz/tools.js delete mode 100644 client/src/viz/trackster.js delete mode 100644 client/src/viz/trackster/filters.js delete mode 100644 client/src/viz/trackster/painters.js delete mode 100644 client/src/viz/trackster/slotting.js delete mode 100644 client/src/viz/trackster/tracks.js delete mode 100644 client/src/viz/trackster/util.js delete mode 100644 client/src/viz/visualization.js delete mode 100644 client/src/viz/viz_views.js diff --git a/client/src/bundleEntries.js b/client/src/bundleEntries.js index 38239b840224..e06edc17fe2b 100644 --- a/client/src/bundleEntries.js +++ b/client/src/bundleEntries.js @@ -1,5 +1,5 @@ /** - * The big list of horrible globals we expose on window.bundleEntries. + * The list of horrible globals we expose on window.bundleEntries. * * Everything that is exposed on this global variable is something that the python templates * require for their hardcoded initializations. These objects are going to have to continue @@ -10,18 +10,12 @@ /* jquery and _ are exposed via expose-loader while several external plugins rely on these */ import $ from "jquery"; // eslint-disable-line no-unused-vars import _ from "underscore"; // eslint-disable-line no-unused-vars -import { TracksterUIView } from "viz/trackster"; export { getGalaxyInstance, setGalaxyInstance } from "app"; export { default as LegacyGridView } from "legacy/grid/grid-view"; export { createTabularDatasetChunkedView } from "mvc/dataset/data"; export { create_chart, create_histogram } from "reports/run_stats"; export { Toast } from "ui/toast"; // TODO: remove when external consumers are updated/gone (IES right now) -export { TracksterUI } from "viz/trackster"; - -export function trackster(options) { - new TracksterUIView(options); -} // Previously wandering around as window.thing = thing in the onload script export { hide_modal, Modal, show_in_overlay, show_message, show_modal } from "layout/modal"; diff --git a/client/src/viz/bbi-data-manager.js b/client/src/viz/bbi-data-manager.js deleted file mode 100644 index 9cf8231323f6..000000000000 --- a/client/src/viz/bbi-data-manager.js +++ /dev/null @@ -1,67 +0,0 @@ -import $ from "jquery"; -import * as bigwig from "libs/bbi/bigwig"; -import { getAppRoot } from "onload/loadConfig"; -import visualization from "viz/visualization"; - -/** - * Data manager for BBI datasets/files, including BigWig and BigBed. - */ -var BBIDataManager = visualization.GenomeDataManager.extend({ - /** - * Load data from server and manage data entries. Adds a Deferred to manager - * for region; when data becomes available, replaces Deferred with data. - * Returns the Deferred that resolves when data is available. - */ - load_data: function (region, mode, resolution, extra_params) { - var deferred = $.Deferred(); - this.set_data(region, deferred); - - var url = `${getAppRoot()}datasets/${this.get("dataset").id}/display`; - - var self = this; - $.when(bigwig.makeBwg(url)).then((bb, err) => { - $.when(bb.readWigData(region.get("chrom"), region.get("start"), region.get("end"))).then((data) => { - // Transform data into "bigwig" format for LinePainter. "bigwig" format is an array of 2-element arrays - // where each element is [position, score]; unlike real bigwig format, no gaps are allowed. - var result = []; - - var prev = { max: Number.MIN_VALUE }; - data.forEach((d) => { - // If there is a gap between prev and d, fill it with an interval with score 0. - // This is necessary for LinePainter to draw correctly. - if (prev.max !== d.min - 1) { - // +1 to start after previous region. - result.push([prev.max + 1, 0]); - // -2 = -1 for converting from 1-based to 0-based coordinates, - // -1 for ending before current region. - result.push([d.min - 2, 0]); - } - - // Add data point for entry start. -1 to convert from wiggle - // 1-based coordinates to 0-based browser coordinates. - result.push([d.min - 1, d.score]); - - // Add data point for entry end: - result.push([d.max, d.score]); - - prev = d; - }); - - var entry = { - data: result, - region: region, - dataset_type: "bigwig", - }; - - self.set_data(region, entry); - deferred.resolve(entry); - }); - }); - - return deferred; - }, -}); - -export default { - BBIDataManager: BBIDataManager, -}; diff --git a/client/src/viz/config.js b/client/src/viz/config.js deleted file mode 100644 index c1c55162cc14..000000000000 --- a/client/src/viz/config.js +++ /dev/null @@ -1,413 +0,0 @@ -import { getGalaxyInstance } from "app"; -import Backbone from "backbone"; -import $ from "jquery"; -import _ from "underscore"; -import util_mod from "viz/trackster/util"; - -/** - * A configuration setting. Currently key is used as id. - */ -var ConfigSetting = Backbone.Model.extend({ - initialize: function (options) { - // Use key as id for now. - var key = this.get("key"); - this.set("id", key); - - // Set defaults based on key. - var defaults = _.find( - [ - { - key: "name", - label: "Name", - type: "text", - default_value: "", - }, - { - key: "color", - label: "Color", - type: "color", - default_value: null, - }, - { - key: "min_value", - label: "Min Value", - type: "float", - default_value: null, - }, - { - key: "max_value", - label: "Max Value", - type: "float", - default_value: null, - }, - { - key: "mode", - type: "string", - default_value: this.mode, - hidden: true, - }, - { - key: "height", - type: "int", - default_value: 32, - hidden: true, - }, - { - key: "pos_color", - label: "Positive Color", - type: "color", - default_value: "#FF8C00", - }, - { - key: "neg_color", - label: "Negative Color", - type: "color", - default_value: "#4169E1", - }, - { - key: "block_color", - label: "Block color", - type: "color", - default_value: null, - }, - { - key: "label_color", - label: "Label color", - type: "color", - default_value: "black", - }, - { - key: "show_insertions", - label: "Show insertions", - type: "bool", - default_value: false, - }, - { - key: "show_counts", - label: "Show summary counts", - type: "bool", - default_value: true, - }, - { - key: "reverse_strand_color", - label: "Antisense strand color", - type: "color", - default_value: null, - }, - { - key: "show_differences", - label: "Show differences only", - type: "bool", - default_value: true, - }, - ], - (s) => s.key === key, - ); - if (defaults) { - this.set(_.extend({}, defaults, options)); - } - - if (this.get("value") === undefined && this.get("default_value") !== undefined) { - // Use default to set value (if present). - this.set_value(this.get("default_value")); - - // If no default value for color config, set random color. - if (!this.get("value") && this.get("type") === "color") { - // For color setting, set random color. - this.set("value", util_mod.get_random_color()); - } - } - }, - - /** - * Cast and set value. This should be instead of - * setting.set('value', new_value) - */ - set_value: function (value, options) { - var type = this.get("type"); - - if (type === "float") { - value = parseFloat(value); - } else if (type === "int") { - value = parseInt(value, 10); - } - // TODO: handle casting from string to bool? - - this.set({ value: value }, options); - }, -}); - -/** - * Collection of config settings. - */ -var ConfigSettingCollection = Backbone.Collection.extend( - { - model: ConfigSetting, - - /** - * Save settings as a dictionary of key-value pairs. - * This function is needed for backwards compatibility. - */ - to_key_value_dict: function () { - var rval = {}; - this.each((setting) => { - rval[setting.get("key")] = setting.get("value"); - }); - - return rval; - }, - - /** - * Returns value for a given key. Returns undefined if there is no setting with the specified key. - */ - get_value: function (key) { - var s = this.get(key); - if (s) { - return s.get("value"); - } - - return undefined; - }, - - /** - * Set value for a setting. - */ - set_value: function (key, value, options) { - var s = this.get(key); - if (s) { - return s.set_value(value, options); - } - - return undefined; - }, - - /** - * Set default value for a setting. - */ - set_default_value: function (key, default_value) { - var s = this.get(key); - if (s) { - return s.set("default_value", default_value); - } - - return undefined; - }, - }, - { - /** - * Utility function that creates a ConfigSettingsCollection from a set of models - * and a saved_values dictionary. - */ - from_models_and_saved_values: function (models, saved_values) { - // If there are saved values, copy models and update with saved values. - if (saved_values) { - models = _.map(models, (m) => _.extend({}, m, { value: saved_values[m.key] })); - } - - return new ConfigSettingCollection(models); - }, - }, -); - -/** - * Viewer for config settings collection. - */ -var ConfigSettingCollectionView = Backbone.View.extend({ - className: "config-settings-view", - - /** - * Renders form for editing configuration settings. - */ - render: function () { - var container = this.$el; - - this.collection.each((param, index) => { - // Hidden params have no representation in the form - if (param.get("hidden")) { - return; - } - - // Build row for param. - var id = `param_${index}`; - - var type = param.get("type"); - var value = param.get("value"); - var row = $("
").appendTo(container); - row.append( - $("