Merge pull request #11711 from mvdbeek/dev

Merge 20.09 into dev
This commit is contained in:
Marius van den Beek
2021-03-25 16:37:05 +01:00
committed by GitHub
25 changed files with 235 additions and 116 deletions
@@ -9,7 +9,8 @@ import LIST_CREATOR from "components/Collections/ListCollectionCreator";
import LIST_CREATOR_MODAL from "components/Collections/ListCollectionCreatorModal";
import PAIR_CREATOR from "components/Collections/PairCollectionCreator";
import PAIR_CREATOR_MODAL from "components/Collections/PairCollectionCreatorModal";
import PAIRED_CREATOR from "components/Collections/PairedListCollectionCreatorModal";
import PAIRED_CREATOR from "components/Collections/PairedListCollectionCreator";
import PAIRED_CREATOR_MODAL from "components/Collections/PairedListCollectionCreatorModal";
import RULE_CREATOR_MODAL from "components/Collections/RuleBasedCollectionCreatorModal";
import HDCA_MODEL from "mvc/history/hdca-model";
@@ -33,8 +34,10 @@ var ImportCollectionModal = Backbone.View.extend({
this.histories = new mod_library_model.GalaxyHistories();
return this.histories.fetch();
},
createNewHistory: function (new_history_name) {
return axios.post(`${getAppRoot()}api/histories`, { name: new_history_name });
async createNewHistory(new_history_name) {
const { data } = await axios.post(`${getAppRoot()}api/histories`, { name: new_history_name });
getGalaxyInstance().currHistoryPanel.switchToHistory(data.id);
return data;
},
showCollectionSelect: function (e) {
const Galaxy = getGalaxyInstance();
@@ -144,16 +147,32 @@ var ImportCollectionModal = Backbone.View.extend({
creator_class
);
} else if (this.collectionType === "list:paired") {
const elements = collection_elements.map((element) => ({
id: element.id,
name: element.name,
src: "ldda",
}));
PAIRED_CREATOR.pairedListCollectionCreatorModal(elements, {
historyId: history_id,
title: modal_title,
defaultHideSourceItems: true,
});
creator_class = PAIRED_CREATOR;
creationFn = (elements, name, hideSourceItems) => {
elements = elements.map((pair) => ({
collection_type: "paired",
src: "new_collection",
name: pair.name,
element_identifiers: [
{
name: "forward",
id: pair.forward.id,
src: "ldda",
},
{
name: "reverse",
id: pair.reverse.id,
src: "ldda",
},
],
}));
return this.createHDCA(elements, "list:paired", name, hideSourceItems, history_id);
};
PAIRED_CREATOR_MODAL.pairedListCollectionCreatorModal(
collection_elements,
{ creationFn: creationFn, title: modal_title, defaultHideSourceItems: true },
creator_class
);
} else if (this.collectionType === "rules") {
const creationFn = (elements, collectionType, name, hideSourceItems) => {
return this.createHDCA(elements, collectionType, name, hideSourceItems, history_id);
@@ -35,7 +35,9 @@
@show="open(tab, $event)"
>
<template v-for="(item, idx) in tab.menu">
<div v-if="item.divider" class="dropdown-divider" :key="`divider-${idx}`" />
<b-dropdown-item
v-else-if="item.hidden !== true"
:href="formatUrl(item.url)"
:key="`item-${idx}`"
:target="item.target || '_parent'"
@@ -45,7 +47,6 @@
>
{{ item.title }}
</b-dropdown-item>
<div v-if="item.divider" class="dropdown-divider" :key="`divider-${idx}`" />
</template>
</b-nav-item-dropdown>
</template>
+41 -35
View File
@@ -32,41 +32,43 @@
</div>
</div>
</b-row>
<b-row class="ml-3 mb-1">
<i class="pref-icon pt-1 fa fa-lg fa-radiation" />
<div class="pref-content pr-1">
<a href="javascript:void(0)"><b v-b-modal.modal-prevent-closing>Delete Account</b></a>
<div class="form-text text-muted">Delete your account on this Galaxy server.</div>
<b-modal
id="modal-prevent-closing"
centered
ref="modal"
title="Account Deletion"
title-tag="h2"
@show="resetModal"
@hidden="resetModal"
@ok="handleOk"
>
<p>
<b-alert variant="danger" :show="showDeleteError">{{ deleteError }}</b-alert>
<b>
This action cannot be undone. Your account will be permanently deleted, along with the data
contained in it.
</b>
</p>
<b-form ref="form" @submit.prevent="handleSubmit">
<b-form-group
:state="nameState"
label="Enter your user email for this account as confirmation."
label-for="Email"
invalid-feedback="Incorrect email"
>
<b-form-input id="name-input" v-model="name" :state="nameState" required></b-form-input>
</b-form-group>
</b-form>
</b-modal>
</div>
</b-row>
<ConfigProvider v-slot="{ config }">
<b-row v-if="config && !config.single_user" class="ml-3 mb-1">
<i class="pref-icon pt-1 fa fa-lg fa-radiation" />
<div class="pref-content pr-1">
<a href="javascript:void(0)"><b v-b-modal.modal-prevent-closing>Delete Account</b></a>
<div class="form-text text-muted">Delete your account on this Galaxy server.</div>
<b-modal
id="modal-prevent-closing"
centered
ref="modal"
title="Account Deletion"
title-tag="h2"
@show="resetModal"
@hidden="resetModal"
@ok="handleOk"
>
<p>
<b-alert variant="danger" :show="showDeleteError">{{ deleteError }}</b-alert>
<b>
This action cannot be undone. Your account will be permanently deleted, along with the
data contained in it.
</b>
</p>
<b-form ref="form" @submit.prevent="handleSubmit">
<b-form-group
:state="nameState"
label="Enter your user email for this account as confirmation."
label-for="Email"
invalid-feedback="Incorrect email"
>
<b-form-input id="name-input" v-model="name" :state="nameState" required></b-form-input>
</b-form-group>
</b-form>
</b-modal>
</div>
</b-row>
</ConfigProvider>
<p class="mt-2">
You are using <strong>{{ diskUsage }}</strong> of disk space in this Galaxy instance.
<span v-html="quotaUsageString"></span>
@@ -86,6 +88,7 @@ import _l from "utils/localization";
import axios from "axios";
import QueryStringParsing from "utils/query-string-parsing";
import { getUserPreferencesModel } from "components/User/UserPreferencesModel";
import ConfigProvider from "components/providers/ConfigProvider";
import { userLogoutAll, userLogoutClient } from "layout/menu";
import "@fortawesome/fontawesome-svg-core";
@@ -102,6 +105,9 @@ export default {
required: true,
},
},
components: {
ConfigProvider,
},
data() {
return {
email: "",
@@ -42,12 +42,14 @@ export const getUserPreferencesModel = () => {
icon: "fa-users",
submit_title: "Save Permissions",
redirect: "user",
shouldRender: !config.single_user,
},
make_data_private: {
title: _l("Make All Data Private"),
id: "edit-preferences-make-data-private",
description: _l("Click here to make all data private."),
icon: "fa-lock",
shouldRender: !config.single_user,
},
api_key: {
title: _l("Manage API Key"),
@@ -86,7 +88,7 @@ export const getUserPreferencesModel = () => {
id: "edit-preferences-sign-out",
description: _l("Click here to sign out of all sessions."),
icon: "fa-sign-out",
shouldRender: !!Galaxy.session_csrf_token,
shouldRender: !!Galaxy.session_csrf_token && !config.single_user,
},
};
};
@@ -243,15 +243,19 @@ export default {
},
onAddInput(input, terminal) {
this.inputTerminals[input.name] = terminal;
this.onRedraw();
},
onRemoveInput(input) {
delete this.inputTerminals[input.name];
this.onRedraw();
},
onAddOutput(output, terminal) {
this.outputTerminals[output.name] = terminal;
this.onRedraw();
},
onRemoveOutput(output) {
delete this.outputTerminals[output.name];
this.onRedraw();
},
onToggleOutput(name) {
this.activeOutputs.toggle(name);
+47 -35
View File
@@ -114,38 +114,49 @@ export function fetchMenu(options = {}) {
//
// 'Shared Items' or Libraries tab.
//
menu.push({
id: "shared",
title: _l("Shared Data"),
url: "javascript:void(0)",
tooltip: _l("Access published resources"),
menu: [
{
title: _l("Data Libraries"),
url: "libraries",
},
{
title: _l("Histories"),
url: "histories/list_published",
target: "__use_router__",
},
{
title: _l("Workflows"),
url: "workflows/list_published",
target: "__use_router__",
},
{
title: _l("Visualizations"),
url: "visualizations/list_published",
target: "__use_router__",
},
{
title: _l("Pages"),
url: "pages/list_published",
target: "__use_router__",
},
],
});
if (Galaxy.config.single_user) {
// Single user can still use libraries, especially as we may grow that
// functionality as a representation for external data. The rest is
// hidden though.
menu.push({
title: _l("Data Libraries"),
url: "libraries",
id: "libraries",
});
} else {
menu.push({
id: "shared",
title: _l("Shared Data"),
url: "javascript:void(0)",
tooltip: _l("Access published resources"),
menu: [
{
title: _l("Data Libraries"),
url: "libraries",
},
{
title: _l("Histories"),
url: "histories/list_published",
target: "__use_router__",
},
{
title: _l("Workflows"),
url: "workflows/list_published",
target: "__use_router__",
},
{
title: _l("Visualizations"),
url: "visualizations/list_published",
target: "__use_router__",
},
{
title: _l("Pages"),
url: "pages/list_published",
target: "__use_router__",
},
],
});
}
//
// Admin.
@@ -271,10 +282,11 @@ export function fetchMenu(options = {}) {
url: "custom_builds",
target: "__use_router__",
},
{ divider: true },
{
title: _l("Logout"),
divider: true,
onclick: userLogout,
hidden: Galaxy.config.single_user,
},
{
title: _l("Datasets"),
@@ -290,6 +302,7 @@ export function fetchMenu(options = {}) {
title: _l("Histories shared with me"),
url: "histories/list_shared",
target: "__use_router__",
hidden: Galaxy.config.single_user,
},
{
title: _l("Pages"),
@@ -311,7 +324,7 @@ export function fetchMenu(options = {}) {
});
}
if (Galaxy.config.interactivetools_enable) {
userTab.menu[userTab.menu.length - 1].divider = true;
userTab.menu.push({ divider: true });
userTab.menu.push({
title: _l("Active InteractiveTools"),
url: "interactivetool_entry_points/list",
@@ -320,6 +333,5 @@ export function fetchMenu(options = {}) {
}
}
menu.push(userTab);
return menu;
}
+4 -1
View File
@@ -140,7 +140,10 @@ export default Backbone.Model.extend({
/** Text input field */
_fieldText: function (input_def) {
// field replaces e.g. a select field
if (input_def.model_class === "SelectTagParameter" || (input_def.options && input_def.data)) {
if (
["SelectTagParameter", "ColumnListParameter"].includes(input_def.model_class) ||
(input_def.options && input_def.data)
) {
input_def.area = input_def.multiple;
if (Utils.isEmpty(input_def.value)) {
input_def.value = null;
+6
View File
@@ -32,6 +32,7 @@ var menu = [
Galaxy.router.push(`/histories/sharing?id=${Galaxy.currHistoryPanel.model.id}`);
}
},
singleUserDisable: true,
},
{
html: _l("Show Structure"),
@@ -55,6 +56,7 @@ var menu = [
Galaxy.router.push(`/histories/permissions?id=${Galaxy.currHistoryPanel.model.id}`);
}
},
singleUserDisable: true,
},
{
html: _l("Make Private"),
@@ -200,7 +202,11 @@ Webhooks.load({
});
function buildMenu(isAnon, purgeAllowed, urlRoot) {
const Galaxy = getGalaxyInstance();
return _.clone(menu).filter((menuOption) => {
if (Galaxy.config.single_user && menuOption.singleUserDisable) {
return false;
}
if (isAnon && !menuOption.anon) {
return false;
}
@@ -357,6 +357,19 @@ var View = Backbone.View.extend({
(!input_def.is_workflow && input_value !== null);
}
if (!validated) {
if (input_def.type == "hidden") {
this.modal.show({
title: _l("Workflow submission failed"),
body: `Step ${step_index}: ${
step.step_label || step.step_name
} is in an invalid state. Please remove and re-add this step in the Workflow Editor.`,
buttons: {
Close: () => {
this.modal.hide();
},
},
});
}
form.highlight(input_id);
break;
}
@@ -197,6 +197,7 @@
<datatype extension="gatk_dbsnp" type="galaxy.datatypes.tabular:Tabular" subclass="true" display_in_upload="true"/>
<datatype extension="gatk_tranche" type="galaxy.datatypes.tabular:Tabular" subclass="true" display_in_upload="true"/>
<datatype extension="gatk_recal" type="galaxy.datatypes.tabular:Tabular" subclass="true" display_in_upload="true"/>
<datatype extension="hhr" type="galaxy.datatypes.data:Text" subclass="true" display_in_upload="true"/>
<datatype extension="jpg" type="galaxy.datatypes.images:Jpg" mimetype="image/jpeg"/>
<datatype extension="tiff" type="galaxy.datatypes.images:Tiff" mimetype="image/tiff" display_in_upload="true"/>
<datatype extension="tf2" type="galaxy.datatypes.images:Tiff" subclass="true" display_in_upload="false"/>
@@ -265,6 +266,7 @@
<datatype extension="mztab2" type="galaxy.datatypes.proteomics:MzTab2" display_in_upload="true"/>
<datatype extension="mzml" type="galaxy.datatypes.proteomics:MzML" mimetype="application/xml" display_in_upload="true"/>
<datatype extension="nmrml" type="galaxy.datatypes.proteomics:NmrML" mimetype="application/xml" display_in_upload="true" description="nmrML is an open mark-up language for NMR data." description_url="http://nmrml.org/schema/"/>
<datatype extension="meryldb" type="galaxy.datatypes.binary:Binary" subclass="true" display_in_upload="true" description="MerylDB is a tar.gz archive containing 64 binaries + 64 indexes."/>
<datatype extension="mgf" type="galaxy.datatypes.proteomics:Mgf" display_in_upload="true"/>
<datatype extension="wiff" type="galaxy.datatypes.proteomics:Wiff" display_in_upload="true"/>
<datatype extension="mzxml" type="galaxy.datatypes.proteomics:MzXML" mimetype="application/xml" display_in_upload="true"/>
+4 -1
View File
@@ -1348,7 +1348,10 @@ class JobWrapper(HasResourceParameters):
ActionBox.execute(self.app, self.sa_session, pja, job)
# If the job was deleted, call tool specific fail actions (used for e.g. external metadata) and clean up
if self.tool:
self.tool.job_failed(self, message, exception)
try:
self.tool.job_failed(self, message, exception)
except Exception:
log.exception(f"Error occured while calling tool specific fail actions for job {job.id}")
cleanup_job = self.cleanup_job
delete_files = cleanup_job == 'always' or (cleanup_job == 'onsuccess' and job.state == job.states.DELETED)
self.cleanup(delete_files=delete_files)
+3 -1
View File
@@ -141,7 +141,9 @@ class BaseJobRunner:
job_state = JobState(job_wrapper=arg, job_destination={})
else:
job_state = arg
self.work_queue.put((self.fail_job, job_state))
if method != self.fail_job:
# Prevent fail_job cycle in the work_queue
self.work_queue.put((self.fail_job, job_state))
# Causes a runner's `queue_job` method to be called from a worker thread
def put(self, job_wrapper):
+4 -1
View File
@@ -122,6 +122,9 @@ class ConfigSerializer(base.ModelSerializer):
assert hasattr(config, key)
return getattr(config, key)
def _config_is_truthy(config, key, **context):
return True if config.get(key) else False
self.serializers = {
# TODO: this is available from user data, remove
'is_admin_user': lambda *a, **c: False,
@@ -151,6 +154,7 @@ class ConfigSerializer(base.ModelSerializer):
'allow_user_impersonation': _use_config,
'allow_user_creation': _defaults_to(False), # schema default is True
'use_remote_user': _defaults_to(None), # schema default is False; or config.single_user
'single_user': _config_is_truthy,
'enable_oidc': _use_config,
'oidc': _use_config,
'enable_quotas': _use_config,
@@ -160,7 +164,6 @@ class ConfigSerializer(base.ModelSerializer):
'ga_code': _use_config,
'enable_unique_workflow_defaults': _use_config,
'enable_beta_markdown_export': _use_config,
'simplified_workflow_run_ui': _use_config,
'simplified_workflow_run_ui_target_history': _use_config,
'simplified_workflow_run_ui_job_cache': _use_config,
'has_user_tool_filters': _defaults_to(False),
+1 -1
View File
@@ -401,7 +401,7 @@ class User(Dictifiable, RepresentById):
extra_user_preferences = self.preferences.get('extra_user_preferences')
if extra_user_preferences:
try:
data = json.loads(extra_user_preferences)
data.update(json.loads(extra_user_preferences))
except Exception:
pass
return data
+1
View File
@@ -361,6 +361,7 @@ tool_form:
options: '#options [data-toggle="dropdown"]'
execute: 'button#execute'
parameter_div: 'div.ui-form-element[tour_id="${parameter}"]'
parameter_textarea: 'div.ui-form-element[tour_id="${parameter}"] textarea'
reference: '.formatted-reference'
about: '.tool-footer'
+12 -2
View File
@@ -9,7 +9,14 @@ from boltons.iterutils import remap
from galaxy.util import unicodify
from galaxy.util.expressions import ExpressionContext
from galaxy.util.json import safe_loads
from .basic import DataCollectionToolParameter, DataToolParameter, is_runtime_value, runtime_to_json, SelectToolParameter
from .basic import (
DataCollectionToolParameter,
DataToolParameter,
is_runtime_value,
ParameterValueError,
runtime_to_json,
SelectToolParameter,
)
from .grouping import Conditional, Repeat, Section, UploadDataset
REPLACE_ON_TRUTHY = object()
@@ -229,7 +236,10 @@ def params_from_strings(params, param_values, app, ignore_errors=False):
# This would resolve a lot of back and forth in the various to/from methods.
value = safe_loads(value)
if param:
value = param.value_from_basic(value, app, ignore_errors)
try:
value = param.value_from_basic(value, app, ignore_errors)
except ParameterValueError:
continue
rval[key] = value
return rval
+2
View File
@@ -212,6 +212,8 @@ class ToolParameter(Dictifiable):
def value_from_basic(self, value, app, ignore_errors=False):
# Handle Runtime and Unvalidated values
if is_runtime_value(value):
if isinstance(self, HiddenToolParameter):
raise ParameterValueError(message_suffix='Runtime Parameter not valid', parameter_name=self.name)
return runtime_to_object(value)
elif isinstance(value, dict) and value.get('__class__') == 'UnvalidatedValue':
return value['value']
@@ -137,6 +137,34 @@ class WorkflowEditorTestCase(SeleniumTestCase):
self.sleep_for(self.wait_types.UX_RENDER)
self.screenshot("workflow_editor_data_collection_input_deleted")
@selenium_test
def test_data_column_input_editing(self):
self.open_in_workflow_editor("""
class: GalaxyWorkflow
steps:
column_param_list:
tool_id: column_param_list
state:
col: ["1","2","3"]
col_names: ["a", "b", "c"]
""")
editor = self.components.workflow_editor
node = editor.node._(label="column_param_list")
node.title.wait_for_and_click()
columns = self.components.tool_form.parameter_textarea(parameter='col')
textarea_columns = columns.wait_for_visible()
assert textarea_columns.get_attribute('value') == '1\n2\n3\n'
column_names = self.components.tool_form.parameter_textarea(parameter='col_names')
textarea_column_names = column_names.wait_for_visible()
assert textarea_column_names.get_attribute('value') == 'a\nb\nc\n'
self.set_text_element(columns, '4\n5\n6\n')
self.assert_has_changes_and_save()
self.sleep_for(self.wait_types.UX_RENDER)
self.driver.refresh()
node.title.wait_for_and_click()
textarea_columns = columns.wait_for_visible()
assert textarea_columns.get_attribute('value') == '4\n5\n6\n'
@selenium_test
def test_integer_input(self):
editor = self.components.workflow_editor
+7 -1
View File
@@ -6,11 +6,17 @@ History
.. to_doc
---------------------
20.5.1.dev0
21.1.1.dev0
---------------------
---------------------
21.1.0 (2021-03-19)
---------------------
* First release from the 21.01 branch of Galaxy.
---------------------
20.5.0 (2020-07-04)
---------------------
@@ -1,4 +1,4 @@
__version__ = '20.5.1.dev0'
__version__ = '21.1.1.dev0'
PROJECT_NAME = "galaxy-containers"
PROJECT_OWNER = PROJECT_USERAME = "galaxyproject"
+7 -1
View File
@@ -6,11 +6,17 @@ History
.. to_doc
---------------------
21.1.0.dev0
21.1.1.dev0
---------------------
---------------------
21.1.0 (2021-03-19)
---------------------
* First release from the 21.01 branch of Galaxy.
---------------------
20.9.1 (2020-10-28)
---------------------
@@ -1,4 +1,4 @@
__version__ = '21.1.0.dev7'
__version__ = '21.1.1.dev0'
PROJECT_NAME = "galaxy-tool-util"
PROJECT_OWNER = PROJECT_USERAME = "galaxyproject"
+7 -1
View File
@@ -6,11 +6,17 @@ History
.. to_doc
---------------------
20.9.2.dev0
21.1.1.dev0
---------------------
---------------------
21.1.0 (2021-03-19)
---------------------
* First release from the 21.01 branch of Galaxy.
---------------------
20.9.1 (2020-10-28)
---------------------
+1 -1
View File
@@ -1,4 +1,4 @@
__version__ = '20.9.2.dev0'
__version__ = '21.1.1.dev0'
PROJECT_NAME = "galaxy-util"
PROJECT_OWNER = PROJECT_USERAME = "galaxyproject"
+2 -18
View File
@@ -6,8 +6,8 @@ echo "col_names $col_names" >> '$output2'
]]></command>
<inputs>
<param name="input1" type="data" format="tabular" label="Input 1" />
<param name="col" type="data_column" multiple="true" value="1" data_ref="input1" label="Column to Use" />
<param name="col_names" type="data_column" data_ref="input1" use_header_names="true" label="Column to Use" />
<param name="col" type="data_column" multiple="true" value="1" data_ref="input1" label="Columns to use" />
<param name="col_names" type="data_column" multiple="true" data_ref="input1" use_header_names="true" label="Column names to use" />
</inputs>
<outputs>
<data name="output1" format="tabular" />
@@ -30,21 +30,5 @@ echo "col_names $col_names" >> '$output2'
</assert_contents>
</output>
</test>
<!-- test if non tabular data also creates entries by using the default
value (which is the 1st column, but empty if filling the options fails) -->
<test>
<param name="input1" value="1.bed" />
<output name="output1">
<assert_contents>
<has_line line="chr1" />
</assert_contents>
</output>
<output name="output2">
<assert_contents>
<has_line line="col 1" />
<has_line line="col_names 1" />
</assert_contents>
</output>
</test>
</tests>
</tool>