From e46191820168dad5a20c45c84667c91456f7f68b Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sun, 19 May 2019 15:40:04 -0400 Subject: [PATCH 1/3] VueJs component to show job metrics. - Can operate from a job_id or dataset_id. - New API endpoint to support this. --- client/galaxy/scripts/bundleEntries.js | 1 + .../components/JobMetrics/JobMetrics.vue | 80 +++++++++++++++++ .../scripts/components/JobMetrics/index.js | 4 + .../scripts/components/JobMetrics/mount.js | 20 +++++ lib/galaxy/managers/jobs.py | 28 +++++- lib/galaxy/webapps/galaxy/api/jobs.py | 89 ++++++++++++++----- lib/galaxy/webapps/galaxy/buildapp.py | 3 + templates/show_params.mako | 23 +---- test/base/populators.py | 2 +- 9 files changed, 204 insertions(+), 46 deletions(-) create mode 100644 client/galaxy/scripts/components/JobMetrics/JobMetrics.vue create mode 100644 client/galaxy/scripts/components/JobMetrics/index.js create mode 100644 client/galaxy/scripts/components/JobMetrics/mount.js diff --git a/client/galaxy/scripts/bundleEntries.js b/client/galaxy/scripts/bundleEntries.js index abc8be4d625..6da4be1cd77 100644 --- a/client/galaxy/scripts/bundleEntries.js +++ b/client/galaxy/scripts/bundleEntries.js @@ -100,6 +100,7 @@ export const chartUtilities = { export { initMasthead } from "components/Masthead/initMasthead"; export { panelManagement } from "onload/globalInits/panelManagement"; export { mountMakoTags } from "components/Tags"; +export { mountJobMetrics } from "components/JobMetrics"; // Used in common.mako export { default as store } from "storemodern"; diff --git a/client/galaxy/scripts/components/JobMetrics/JobMetrics.vue b/client/galaxy/scripts/components/JobMetrics/JobMetrics.vue new file mode 100644 index 00000000000..67fcd9c829e --- /dev/null +++ b/client/galaxy/scripts/components/JobMetrics/JobMetrics.vue @@ -0,0 +1,80 @@ + + + diff --git a/client/galaxy/scripts/components/JobMetrics/index.js b/client/galaxy/scripts/components/JobMetrics/index.js new file mode 100644 index 00000000000..416a80e8339 --- /dev/null +++ b/client/galaxy/scripts/components/JobMetrics/index.js @@ -0,0 +1,4 @@ +export { default as JobMetrics } from "./JobMetrics"; + +// functions for mounting job metrics in non-Vue environments +export { mountJobMetrics } from "./mount"; diff --git a/client/galaxy/scripts/components/JobMetrics/mount.js b/client/galaxy/scripts/components/JobMetrics/mount.js new file mode 100644 index 00000000000..e9fa95b350a --- /dev/null +++ b/client/galaxy/scripts/components/JobMetrics/mount.js @@ -0,0 +1,20 @@ +/** + * Endpoint for mounting job metrics from non-Vue environment. + */ +import $ from "jquery"; +import Vue from "vue"; +import JobMetrics from "./JobMetrics.vue"; + +export const mountJobMetrics = propsData => { + $(".job-metrics").each((index, el) => { + const jobId = $(el).attr("job_id"); + const datasetId = $(el).attr("dataset_id"); + const datasetType = $(el).attr("dataset_type") || "hda"; + const component = Vue.extend(JobMetrics); + propsData = propsData || {}; + propsData["jobId"] = jobId; + propsData["datasetId"] = datasetId; + propsData["datasetType"] = datasetType; + return new component({ propsData: propsData }).$mount(el); + }); +}; diff --git a/lib/galaxy/managers/jobs.py b/lib/galaxy/managers/jobs.py index 8941171de7a..3940e20c4eb 100644 --- a/lib/galaxy/managers/jobs.py +++ b/lib/galaxy/managers/jobs.py @@ -8,8 +8,13 @@ from sqlalchemy.orm import aliased from sqlalchemy.sql import select from galaxy import model -from galaxy.exceptions import RequestParameterInvalidException +from galaxy.exceptions import ( + ItemAccessibilityException, + ObjectNotFound, + RequestParameterInvalidException, +) from galaxy.managers.collections import DatasetCollectionManager +from galaxy.managers.datasets import DatasetManager from galaxy.managers.hdas import HDAManager from galaxy.managers.lddas import LDDAManager from galaxy.util import ( @@ -39,6 +44,27 @@ def get_path_key(path_tuple): return path_key +class JobManager(object): + + def __init__(self, app): + self.app = app + self.dataset_manager = DatasetManager(app) + + def get_accessible_job(self, trans, decoded_job_id): + job = trans.sa_session.query(trans.app.model.Job).filter(trans.app.model.Job.id == decoded_job_id).first() + if job is None: + raise ObjectNotFound() + belongs_to_user = (job.user == trans.user) if job.user else (job.session_id == trans.get_galaxy_session().id) + if not trans.user_is_admin and not belongs_to_user: + # Check access granted via output datasets. + if not job.output_datasets: + raise ItemAccessibilityException("Job has no output datasets.") + for data_assoc in job.output_datasets: + if not self.dataset_manager.is_accessible(data_assoc.dataset.dataset, trans.user): + raise ItemAccessibilityException("You are not allowed to rerun this job.") + return job + + class JobSearch(object): """Search for jobs using tool inputs or other jobs""" def __init__(self, app): diff --git a/lib/galaxy/webapps/galaxy/api/jobs.py b/lib/galaxy/webapps/galaxy/api/jobs.py index f42c83a998b..8025cfd19fe 100644 --- a/lib/galaxy/webapps/galaxy/api/jobs.py +++ b/lib/galaxy/webapps/galaxy/api/jobs.py @@ -12,24 +12,25 @@ from sqlalchemy import or_ from galaxy import exceptions from galaxy import model from galaxy import util -from galaxy.managers.datasets import DatasetManager -from galaxy.managers.jobs import JobSearch +from galaxy.managers.jobs import JobManager, JobSearch from galaxy.web import ( expose_api, expose_api_anonymous, ) -from galaxy.web.base.controller import BaseAPIController -from galaxy.web.base.controller import UsesLibraryMixinItems +from galaxy.web.base.controller import ( + BaseAPIController, + UsesVisualizationMixin +) from galaxy.work.context import WorkRequestContext log = logging.getLogger(__name__) -class JobController(BaseAPIController, UsesLibraryMixinItems): +class JobController(BaseAPIController, UsesVisualizationMixin): def __init__(self, app): super(JobController, self).__init__(app) - self.dataset_manager = DatasetManager(app) + self.job_manager = JobManager(app) self.job_search = JobSearch(app) @expose_api @@ -166,7 +167,7 @@ class JobController(BaseAPIController, UsesLibraryMixinItems): raw_value=str(metric_value), ) - job_dict['job_metrics'] = [metric_to_dict(metric) for metric in job.metrics] + job_dict['job_metrics'] = self._metrics_as_dict(trans, job) return job_dict @expose_api @@ -265,6 +266,51 @@ class JobController(BaseAPIController, UsesLibraryMixinItems): exceptions.RequestParameterInvalidException("Job with id '%s' is not paused" % (job.tool_id)) return self.__dictify_associations(trans, job.output_datasets, job.output_library_datasets) + @expose_api_anonymous + def metrics(self, trans, **kwd): + """ + * GET /api/jobs/{job_id}/metrics + * GET /api/datasets/{dataset_id}/metrics + Return job metrics for specified job. Job accessibility checks are slightly + different than dataset checks, so both methods are available. + + :type job_id: string + :param job_id: Encoded job id + + :type dataset_id: string + :param dataset_id: Encoded HDA or LDDA id + + :type hda_ldda: string + :param hda_ldda: hda if dataset_id is an HDA id (default), ldda if + it is an ldda id. + + :rtype: list + :returns: list containing job metrics + """ + job = self.__get_job(trans, **kwd) + if not trans.user_is_admin and not trans.app.config.expose_potentially_sensitive_job_metrics: + return [] + + return self._metrics_as_dict(trans, job) + + def _metrics_as_dict(self, trans, job): + + def metric_to_dict(metric): + metric_name = metric.metric_name + metric_value = metric.metric_value + metric_plugin = metric.plugin + title, value = trans.app.job_metrics.format(metric_plugin, metric_name, metric_value) + return dict( + title=title, + value=value, + plugin=metric_plugin, + name=metric_name, + raw_value=str(metric_value), + ) + + metrics = [m for m in job.metrics if m.plugin != 'env' or trans.user_is_admin] + return list(map(metric_to_dict, metrics)) + @expose_api_anonymous def build_for_rerun(self, trans, id, **kwd): """ @@ -306,23 +352,18 @@ class JobController(BaseAPIController, UsesLibraryMixinItems): dataset_dict = dict(src="ldda", id=trans.security.encode_id(dataset.id)) return dict(name=job_dataset_association.name, dataset=dataset_dict) - def __get_job(self, trans, id): - try: - decoded_job_id = self.decode_id(id) - except Exception: - raise exceptions.MalformedId() - job = trans.sa_session.query(trans.app.model.Job).filter(trans.app.model.Job.id == decoded_job_id).first() - if job is None: - raise exceptions.ObjectNotFound() - belongs_to_user = (job.user == trans.user) if job.user else (job.session_id == trans.get_galaxy_session().id) - if not trans.user_is_admin and not belongs_to_user: - # Check access granted via output datasets. - if not job.output_datasets: - raise exceptions.ItemAccessibilityException("Job has no output datasets.") - for data_assoc in job.output_datasets: - if not self.dataset_manager.is_accessible(data_assoc.dataset.dataset, trans.user): - raise exceptions.ItemAccessibilityException("You are not allowed to rerun this job.") - return job + def __get_job(self, trans, job_id=None, dataset_id=None, **kwd): + if job_id is not None: + try: + decoded_job_id = self.decode_id(job_id) + except Exception: + raise exceptions.MalformedId() + return self.job_manager.get_accessible_job(trans, decoded_job_id) + else: + hda_ldda = kwd.get("hda_ldda", "hda") + # Following checks dataset accessible + dataset_instance = self.get_hda_or_ldda(trans, hda_ldda=hda_ldda, dataset_id=dataset_id) + return dataset_instance.creating_job @expose_api def create(self, trans, payload, **kwd): diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 9289ab0b1f5..3b4dea9e265 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -890,6 +890,9 @@ def populate_api_routes(webapp, app): webapp.mapper.connect('resume', '/api/jobs/{id}/resume', controller='jobs', action='resume', conditions=dict(method=['PUT'])) webapp.mapper.connect('job_error', '/api/jobs/{id}/error', controller='jobs', action='error', conditions=dict(method=['POST'])) webapp.mapper.connect('common_problems', '/api/jobs/{id}/common_problems', controller='jobs', action='common_problems', conditions=dict(method=['GET'])) + # Metrics by job id or dataset id + webapp.mapper.connect('metrics', '/api/jobs/{job_id}/metrics', controller='jobs', action='metrics', conditions=dict(method=['GET'])) + webapp.mapper.connect('dataset_metrics', '/api/datasets/{dataset_id}/metrics', controller='jobs', action='metrics', conditions=dict(method=['GET'])) # Job files controllers. Only for consumption by remote job runners. webapp.mapper.resource('file', diff --git a/templates/show_params.mako b/templates/show_params.mako index daeeb837d84..0f660c79adb 100644 --- a/templates/show_params.mako +++ b/templates/show_params.mako @@ -256,26 +256,8 @@ ${ job.command_line | h } %endif %if job and (trans.user_is_admin or trans.app.config.expose_potentially_sensitive_job_metrics): -

Job Metrics

-<% job_metrics = trans.app.job_metrics %> -<% plugins = set([metric.plugin for metric in job.metrics]) %> - %for plugin in sorted(plugins): - %if trans.user_is_admin or plugin != 'env': -

${ plugin | h }

- - - <% - plugin_metrics = filter(lambda x: x.plugin == plugin, job.metrics) - plugin_metric_displays = [job_metrics.format( metric.plugin, metric.metric_name, metric.metric_value ) for metric in plugin_metrics] - plugin_metric_displays = sorted(plugin_metric_displays, key=lambda pair: pair[0]) # Sort on displayed title - %> - %for metric_title, metric_value in plugin_metric_displays: - - %endfor - -
${ metric_title | h }${ metric_value | h }
- %endif - %endfor +
+
%endif %if trans.user_is_admin: @@ -352,5 +334,6 @@ $(function(){ window.parent.Galaxy.currHistoryPanel.scrollToId( 'dataset-' + $( this ).data( 'hda-id' ) ); } }) + window.bundleEntries.mountJobMetrics(); }); diff --git a/test/base/populators.py b/test/base/populators.py index e06b8d23f0f..0ee8b19d416 100644 --- a/test/base/populators.py +++ b/test/base/populators.py @@ -1372,7 +1372,7 @@ def load_data_dict(history_id, test_data, dataset_populator, dataset_collection_ def wait_on_state(state_func, desc="state", skip_states=["running", "queued", "new", "ready"], assert_ok=False, timeout=DEFAULT_TIMEOUT): def get_state(): response = state_func() - assert response.status_code == 200, "Failed to fetch state update while waiting." + assert response.status_code == 200, "Failed to fetch state update while waiting. [%s]" % response.content state = response.json()["state"] if state in skip_states: return None From b80cf2744b07295bdc24df6e9dbc9b8b48c2db64 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 21 May 2019 07:23:50 -0400 Subject: [PATCH 2/3] VueJs component to show tool parameters. - Can operate on a job_id or dataset_id. - New API endpoint to support. This endpoint is very tied to the client and so is documented as being unstable. This API endpoint isn't the most wonderfully general creature but hopefully everyone is excited to see less mako and more use of APIs and reusable JS components. --- client/galaxy/scripts/bundleEntries.js | 1 + .../JobParameters/JobParameters.vue | 122 ++++++++++++++ .../scripts/components/JobParameters/index.js | 4 + .../scripts/components/JobParameters/mount.js | 20 +++ lib/galaxy/webapps/galaxy/api/jobs.py | 112 +++++++++++++ lib/galaxy/webapps/galaxy/buildapp.py | 4 +- templates/show_params.mako | 152 +----------------- 7 files changed, 267 insertions(+), 148 deletions(-) create mode 100644 client/galaxy/scripts/components/JobParameters/JobParameters.vue create mode 100644 client/galaxy/scripts/components/JobParameters/index.js create mode 100644 client/galaxy/scripts/components/JobParameters/mount.js diff --git a/client/galaxy/scripts/bundleEntries.js b/client/galaxy/scripts/bundleEntries.js index 6da4be1cd77..c666d664310 100644 --- a/client/galaxy/scripts/bundleEntries.js +++ b/client/galaxy/scripts/bundleEntries.js @@ -101,6 +101,7 @@ export { initMasthead } from "components/Masthead/initMasthead"; export { panelManagement } from "onload/globalInits/panelManagement"; export { mountMakoTags } from "components/Tags"; export { mountJobMetrics } from "components/JobMetrics"; +export { mountJobParameters } from "components/JobParameters"; // Used in common.mako export { default as store } from "storemodern"; diff --git a/client/galaxy/scripts/components/JobParameters/JobParameters.vue b/client/galaxy/scripts/components/JobParameters/JobParameters.vue new file mode 100644 index 00000000000..fc9a94b6f0d --- /dev/null +++ b/client/galaxy/scripts/components/JobParameters/JobParameters.vue @@ -0,0 +1,122 @@ + + + + diff --git a/client/galaxy/scripts/components/JobParameters/index.js b/client/galaxy/scripts/components/JobParameters/index.js new file mode 100644 index 00000000000..8d76729387f --- /dev/null +++ b/client/galaxy/scripts/components/JobParameters/index.js @@ -0,0 +1,4 @@ +export { default as JobParameters } from "./JobParameters"; + +// functions for mounting job parameters display in non-Vue environments +export { mountJobParameters } from "./mount"; diff --git a/client/galaxy/scripts/components/JobParameters/mount.js b/client/galaxy/scripts/components/JobParameters/mount.js new file mode 100644 index 00000000000..6c49609db92 --- /dev/null +++ b/client/galaxy/scripts/components/JobParameters/mount.js @@ -0,0 +1,20 @@ +/** + * Endpoint for mounting job metrics from non-Vue environment. + */ +import $ from "jquery"; +import Vue from "vue"; +import JobParameters from "./JobParameters.vue"; + +export const mountJobParameters = propsData => { + $(".job-parameters").each((index, el) => { + const component = Vue.extend(JobParameters); + const jobId = $(el).attr("job_id"); + const datasetId = $(el).attr("dataset_id"); + const datasetType = $(el).attr("dataset_type") || "hda"; + propsData = propsData || {}; + propsData["jobId"] = jobId; + propsData["datasetId"] = datasetId; + propsData["datasetType"] = datasetType; + return new component({ propsData: propsData }).$mount(el); + }); +}; diff --git a/lib/galaxy/webapps/galaxy/api/jobs.py b/lib/galaxy/webapps/galaxy/api/jobs.py index 8025cfd19fe..1f54f4e7aea 100644 --- a/lib/galaxy/webapps/galaxy/api/jobs.py +++ b/lib/galaxy/webapps/galaxy/api/jobs.py @@ -311,6 +311,118 @@ class JobController(BaseAPIController, UsesVisualizationMixin): metrics = [m for m in job.metrics if m.plugin != 'env' or trans.user_is_admin] return list(map(metric_to_dict, metrics)) + @expose_api_anonymous + def parameters_display(self, trans, **kwd): + """ + * GET /api/jobs/{job_id}/parameters_display + * GET /api/datasets/{dataset_id}/parameters_display + + Resolve parameters as a list for nested display. More client logic + here than is ideal but it is hard to reason about tool parameter + types on the client relative to the server. Job accessibility checks + are slightly different than dataset checks, so both methods are + available. + + This API endpoint is unstable and tied heavily to Galaxy's JS client code, + this endpoint will change frequently. + + :type job_id: string + :param job_id: Encoded job id + + :type dataset_id: string + :param dataset_id: Encoded HDA or LDDA id + + :type hda_ldda: string + :param hda_ldda: hda if dataset_id is an HDA id (default), ldda if + it is an ldda id. + + :rtype: list + :returns: job parameters for for display + """ + job = self.__get_job(trans, **kwd) + + def inputs_recursive(input_params, param_values, depth=1, upgrade_messages=None): + if upgrade_messages is None: + upgrade_messages = {} + + rval = [] + + for input_index, input in enumerate(input_params.values()): + if input.name in param_values: + if input.type == "repeat": + for i in range(len(param_values[input.name])): + rval.extend(inputs_recursive(input.inputs, param_values[input.name][i], depth=depth + 1)) + elif input.type == "section": + # Get the value of the current Section parameter + rval.append(dict(text=input.name, depth=depth)) + rval.extend(inputs_recursive(input.inputs, param_values[input.name], depth=depth + 1, upgrade_messages=upgrade_messages.get(input.name))) + elif input.type == "conditional": + try: + current_case = param_values[input.name]['__current_case__'] + is_valid = True + except Exception: + current_case = None + is_valid = False + if is_valid: + rval.append(dict(text=input.test_param.label, depth=depth, value=input.cases[current_case].value)) + rval.extend(inputs_recursive(input.cases[current_case].inputs, param_values[input.name], depth=depth + 1, upgrade_messages=upgrade_messages.get(input.name))) + else: + rval.append(dict(text=input.name, depth=depth, notes="The previously used value is no longer valid.", error=True)) + elif input.type == "upload_dataset": + rval.append(dict(text=input.group_title(param_values), depth=depth, value="%s uploaded datasets" % len(param_values[input.name]))) + elif input.type == "data": + value = [] + for i, element in enumerate(util.listify(param_values[input.name])): + if element.history_content_type == "dataset": + hda = element + encoded_id = trans.security.encode_id(hda.id) + value.append({"src": "hda", "id": encoded_id, "hid": hda.hid, "name": hda.name}) + else: + value.append({"hid": element.hid, "name": element.name}) + rval.append(dict(text=input.label, depth=depth, value=value)) + elif input.visible: + if hasattr(input, "label") and input.label: + label = input.label + else: + # value for label not required, fallback to input name (same as tool panel) + label = input.name + rval.append(dict(text=label, depth=depth, value=input.value_to_display_text(param_values[input.name]), notes=upgrade_messages.get(input.name, ''))) + else: + # Parameter does not have a stored value. + # Get parameter label. + if input.type == "conditional": + label = input.test_param.label + elif input.type == "repeat": + label = input.label() + else: + label = input.label or input.name + rval.append(dict(text=label, depth=depth, notes="not used (parameter was added after this job was run)")) + + return rval + + # Load the tool + toolbox = self.app.toolbox + tool = toolbox.get_tool(job.tool_id, job.tool_version) + assert tool is not None, 'Requested tool has not been loaded.' + + params_objects = None + upgrade_messages = {} + has_parameter_errors = False + + # Load parameter objects, if a parameter type has changed, it's possible for the value to no longer be valid + try: + params_objects = job.get_param_values(self.app, ignore_errors=False) + except Exception: + params_objects = job.get_param_values(self.app, ignore_errors=True) + # use different param_objects in the following line, since we want to display original values as much as possible + upgrade_messages = tool.check_and_update_param_values(job.get_param_values(self.app, ignore_errors=True), + trans, + update_values=False) + has_parameter_errors = True + + parameters = inputs_recursive(tool.inputs, params_objects, depth=1, upgrade_messages=upgrade_messages) + return {"parameters": parameters, "has_parameter_errors": has_parameter_errors} + @expose_api_anonymous def build_for_rerun(self, trans, id, **kwd): """ diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 3b4dea9e265..8f9825ed845 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -890,9 +890,11 @@ def populate_api_routes(webapp, app): webapp.mapper.connect('resume', '/api/jobs/{id}/resume', controller='jobs', action='resume', conditions=dict(method=['PUT'])) webapp.mapper.connect('job_error', '/api/jobs/{id}/error', controller='jobs', action='error', conditions=dict(method=['POST'])) webapp.mapper.connect('common_problems', '/api/jobs/{id}/common_problems', controller='jobs', action='common_problems', conditions=dict(method=['GET'])) - # Metrics by job id or dataset id + # Job metrics and parameters by job id or dataset id (for slightly different accessibility checking) webapp.mapper.connect('metrics', '/api/jobs/{job_id}/metrics', controller='jobs', action='metrics', conditions=dict(method=['GET'])) webapp.mapper.connect('dataset_metrics', '/api/datasets/{dataset_id}/metrics', controller='jobs', action='metrics', conditions=dict(method=['GET'])) + webapp.mapper.connect('parameters_display', '/api/jobs/{job_id}/parameters_display', controller='jobs', action='parameters_display', conditions=dict(method=['GET'])) + webapp.mapper.connect('dataset_parameters_display', '/api/datasets/{dataset_id}/parameters_display', controller='jobs', action='parameters_display', conditions=dict(method=['GET'])) # Job files controllers. Only for consumption by remote job runners. webapp.mapper.resource('file', diff --git a/templates/show_params.mako b/templates/show_params.mako index 0f660c79adb..2a4e8f3549c 100644 --- a/templates/show_params.mako +++ b/templates/show_params.mako @@ -9,133 +9,8 @@ text-align: center; background-color: #eee; } - - table.info_data_table { - table-layout: fixed; - word-break: break-word; - } - table.info_data_table td:nth-child(1) { - width: 25%; - } - -<%def name="inputs_recursive( input_params, param_values, depth=1, upgrade_messages=None )"> - <% - from galaxy.util import listify - if upgrade_messages is None: - upgrade_messages = {} - %> - %for input_index, input in enumerate( input_params.values() ): - %if input.name in param_values: - %if input.type == "repeat": - %for i in range( len(param_values[input.name]) ): - ${ inputs_recursive(input.inputs, param_values[input.name][i], depth=depth+1) } - %endfor - %elif input.type == "section": - - ## - ${inputs_recursive_indent( text=input.name, depth=depth )} - - - ${ inputs_recursive( input.inputs, param_values[input.name], depth=depth+1, upgrade_messages=upgrade_messages.get( input.name ) ) } - %elif input.type == "conditional": - <% - try: - current_case = param_values[input.name]['__current_case__'] - is_valid = True - except: - current_case = None - is_valid = False - %> - %if is_valid: - - ${ inputs_recursive_indent( text=input.test_param.label, depth=depth )} - ## - ${input.cases[current_case].value | h} - - - ${ inputs_recursive( input.cases[current_case].inputs, param_values[input.name], depth=depth+1, upgrade_messages=upgrade_messages.get( input.name ) ) } - %else: - - ${ inputs_recursive_indent( text=input.name, depth=depth )} - The previously used value is no longer valid - - - %endif - %elif input.type == "upload_dataset": - - ${inputs_recursive_indent( text=input.group_title( param_values ), depth=depth )} - ${ len( param_values[input.name] ) } uploaded datasets - - - ## files used for inputs - %elif input.type == "data": - - ${inputs_recursive_indent( text=input.label, depth=depth )} - - %for i, element in enumerate(listify(param_values[input.name])): - %if i > 0: - , - %endif - %if element.history_content_type == "dataset": - <% - hda = element - encoded_id = trans.security.encode_id( hda.id ) - show_params_url = h.url_for( controller='dataset', action='show_params', dataset_id=encoded_id ) - %> - ${hda.hid}: ${hda.name | h} - - %else: - ${element.hid}: ${element.name | h} - %endif - %endfor - - - - %elif input.visible: - <% - if hasattr( input, "label" ) and input.label: - label = input.label - else: - #value for label not required, fallback to input name (same as tool panel) - label = input.name - %> - - ${inputs_recursive_indent( text=label, depth=depth )} - ${input.value_to_display_text( param_values[input.name] ) | h} - ${ upgrade_messages.get( input.name, '' ) | h } - - %endif - %else: - ## Parameter does not have a stored value. - - <% - # Get parameter label. - if input.type == "conditional": - label = input.test_param.label - elif input.type == "repeat": - label = input.label() - else: - label = input.label or input.name - %> - ${inputs_recursive_indent( text=label, depth=depth )} - not used (parameter was added after this job was run) - - - %endif - - %endfor - - - ## function to add a indentation depending on the depth in a -<%def name="inputs_recursive_indent( text, depth )"> - - ${text | h} - - -

% if tool: ${tool.name | h} @@ -212,31 +87,13 @@ -

Tool Parameters

- - - - - - - - - - % if params_objects and tool: - ${ inputs_recursive( tool.inputs, params_objects, depth=1, upgrade_messages=upgrade_messages ) } - %elif params_objects is None: - - % else: - - % endif - -
Input ParameterValueNote for rerun
Unable to load parameters.
No parameters.
-%if has_parameter_errors: -
- ${ render_msg( 'One or more of your original parameters may no longer be valid or displayed properly.', status='warning' ) } +%if job: +
+
%endif +

Inheritance Chain

${hda.name | h}
@@ -335,5 +192,6 @@ $(function(){ } }) window.bundleEntries.mountJobMetrics(); + window.bundleEntries.mountJobParameters(); }); From 8efaf565a04cd05a382664454c3bf964fdaf16ac Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Fri, 24 May 2019 07:57:24 -0400 Subject: [PATCH 3/3] Use default function params, dot notation for attribute access. Fix module comment. --- .../galaxy/scripts/components/JobMetrics/mount.js | 9 ++++----- .../scripts/components/JobParameters/mount.js | 13 ++++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/client/galaxy/scripts/components/JobMetrics/mount.js b/client/galaxy/scripts/components/JobMetrics/mount.js index e9fa95b350a..52206d987fe 100644 --- a/client/galaxy/scripts/components/JobMetrics/mount.js +++ b/client/galaxy/scripts/components/JobMetrics/mount.js @@ -5,16 +5,15 @@ import $ from "jquery"; import Vue from "vue"; import JobMetrics from "./JobMetrics.vue"; -export const mountJobMetrics = propsData => { +export const mountJobMetrics = (propsData = {}) => { $(".job-metrics").each((index, el) => { const jobId = $(el).attr("job_id"); const datasetId = $(el).attr("dataset_id"); const datasetType = $(el).attr("dataset_type") || "hda"; const component = Vue.extend(JobMetrics); - propsData = propsData || {}; - propsData["jobId"] = jobId; - propsData["datasetId"] = datasetId; - propsData["datasetType"] = datasetType; + propsData.jobId = jobId; + propsData.datasetId = datasetId; + propsData.datasetType = datasetType; return new component({ propsData: propsData }).$mount(el); }); }; diff --git a/client/galaxy/scripts/components/JobParameters/mount.js b/client/galaxy/scripts/components/JobParameters/mount.js index 6c49609db92..4e7e9f67fb6 100644 --- a/client/galaxy/scripts/components/JobParameters/mount.js +++ b/client/galaxy/scripts/components/JobParameters/mount.js @@ -1,20 +1,19 @@ /** - * Endpoint for mounting job metrics from non-Vue environment. + * Endpoint for mounting job parameters from non-Vue environment. */ import $ from "jquery"; import Vue from "vue"; import JobParameters from "./JobParameters.vue"; -export const mountJobParameters = propsData => { +export const mountJobParameters = (propsData = {}) => { $(".job-parameters").each((index, el) => { - const component = Vue.extend(JobParameters); const jobId = $(el).attr("job_id"); const datasetId = $(el).attr("dataset_id"); const datasetType = $(el).attr("dataset_type") || "hda"; - propsData = propsData || {}; - propsData["jobId"] = jobId; - propsData["datasetId"] = datasetId; - propsData["datasetType"] = datasetType; + const component = Vue.extend(JobParameters); + propsData.jobId = jobId; + propsData.datasetId = datasetId; + propsData.datasetType = datasetType; return new component({ propsData: propsData }).$mount(el); }); };