mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #8022 from jmchilton/vuejs_show_params_1
Rework dataset job properties tables into components+APIs
This commit is contained in:
@@ -100,6 +100,8 @@ 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";
|
||||
export { mountJobParameters } from "components/JobParameters";
|
||||
|
||||
// Used in common.mako
|
||||
export { default as store } from "storemodern";
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div v-if="metricsByPlugins">
|
||||
<h3 v-if="includeTitle">Job Metrics</h3>
|
||||
<div v-for="plugin in orderedPlugins" v-bind:key="plugin">
|
||||
<h4>{{ plugin }}</h4>
|
||||
<table class="tabletip info_data_table">
|
||||
<tbody>
|
||||
<tr v-for="(metricValue, metricTitle) in metricsByPlugins[plugin]" v-bind:key="metricTitle">
|
||||
<td>{{ metricTitle }}</td>
|
||||
<td>{{ metricValue }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
jobId: {
|
||||
type: String
|
||||
},
|
||||
datasetId: {
|
||||
type: String
|
||||
},
|
||||
datasetType: {
|
||||
type: String,
|
||||
default: "hda"
|
||||
},
|
||||
includeTitle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
metricsByPlugins: {}
|
||||
};
|
||||
},
|
||||
created: function() {
|
||||
let url;
|
||||
if (this.jobId) {
|
||||
url = `${getAppRoot()}api/jobs/${this.jobId}/metrics`;
|
||||
} else {
|
||||
url = `${getAppRoot()}api/datasets/${this.datasetId}/metrics?hda_ldda=${this.datasetType}`;
|
||||
}
|
||||
this.ajaxCall(url);
|
||||
},
|
||||
computed: {
|
||||
orderedPlugins: function() {
|
||||
return Object.keys(this.metricsByPlugins).sort();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ajaxCall: function(url) {
|
||||
axios
|
||||
.get(url)
|
||||
.then(response => {
|
||||
const metricsByPlugins = {};
|
||||
const metrics = response.data;
|
||||
metrics.forEach(metric => {
|
||||
if (!(metric.plugin in metricsByPlugins)) {
|
||||
metricsByPlugins[metric.plugin] = {};
|
||||
}
|
||||
const metricsForPlugin = metricsByPlugins[metric.plugin];
|
||||
metricsForPlugin[metric.title] = metric.value;
|
||||
});
|
||||
this.metricsByPlugins = metricsByPlugins;
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,4 @@
|
||||
export { default as JobMetrics } from "./JobMetrics";
|
||||
|
||||
// functions for mounting job metrics in non-Vue environments
|
||||
export { mountJobMetrics } from "./mount";
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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.jobId = jobId;
|
||||
propsData.datasetId = datasetId;
|
||||
propsData.datasetType = datasetType;
|
||||
return new component({ propsData: propsData }).$mount(el);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="tool-parameters">
|
||||
<h3 v-if="includeTitle">Tool Parameters</h3>
|
||||
<table class="tabletip" id="tool-parameters">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Input Parameter</th>
|
||||
<th>Value</th>
|
||||
<th v-if="anyNotes">Note for rerun</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(parameter, index) in parameters" v-bind:key="index">
|
||||
<td v-bind:style="{ 'padding-left': `${(parameter.depth - 1) * 10}px` }">
|
||||
{{ parameter.text }}
|
||||
</td>
|
||||
<td v-if="Array.isArray(parameter.value)">
|
||||
<ul style="padding-inline-start: 25px;">
|
||||
<li v-for="(elVal, index) in parameter.value" v-bind:key="index">
|
||||
<span v-if="elVal.src == 'hda'">
|
||||
<a :href="appRoot() + 'datasets/' + elVal.id + '/show_params'">
|
||||
{{ elVal.hid }}: {{ elVal.name }}
|
||||
</a>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ elVal.hid }}: {{ elVal.name }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td v-else>
|
||||
{{ parameter.value }}
|
||||
</td>
|
||||
<td v-if="anyNotes">
|
||||
<em v-if="parameter.notes">{{ parameter.notes }}</em>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<b-alert :show="hasParameterErrors" variant="danger">
|
||||
One or more of your original parameters may no longer be valid or displayed properly.
|
||||
</b-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import axios from "axios";
|
||||
|
||||
import Vue from "vue";
|
||||
import BootstrapVue from "bootstrap-vue";
|
||||
|
||||
Vue.use(BootstrapVue);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
jobId: {
|
||||
type: String
|
||||
},
|
||||
datasetId: {
|
||||
type: String
|
||||
},
|
||||
datasetType: {
|
||||
type: String,
|
||||
default: "hda"
|
||||
},
|
||||
includeTitle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
parameters: [],
|
||||
hasParameterErrors: false
|
||||
};
|
||||
},
|
||||
created: function() {
|
||||
let url;
|
||||
if (this.jobId) {
|
||||
url = `${getAppRoot()}api/jobs/${this.jobId}/parameters_display`;
|
||||
} else {
|
||||
url = `${getAppRoot()}api/datasets/${this.datasetId}/parameters_display?hda_ldda=${this.datasetType}`;
|
||||
}
|
||||
this.ajaxCall(url);
|
||||
},
|
||||
computed: {
|
||||
anyNotes: function() {
|
||||
let hasNotes = false;
|
||||
this.parameters.forEach(parameter => {
|
||||
hasNotes = hasNotes && parameter.note;
|
||||
});
|
||||
return hasNotes;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
appRoot: function() {
|
||||
return getAppRoot();
|
||||
},
|
||||
ajaxCall: function(url) {
|
||||
axios
|
||||
.get(url)
|
||||
.then(response => {
|
||||
this.hasParameterErrors = response.data.has_parameter_errors;
|
||||
this.parameters = response.data.parameters;
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
table.info_data_table {
|
||||
table-layout: fixed;
|
||||
word-break: break-word;
|
||||
}
|
||||
table.info_data_table td:nth-child(1) {
|
||||
width: 25%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,4 @@
|
||||
export { default as JobParameters } from "./JobParameters";
|
||||
|
||||
// functions for mounting job parameters display in non-Vue environments
|
||||
export { mountJobParameters } from "./mount";
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 = {}) => {
|
||||
$(".job-parameters").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(JobParameters);
|
||||
propsData.jobId = jobId;
|
||||
propsData.datasetId = datasetId;
|
||||
propsData.datasetType = datasetType;
|
||||
return new component({ propsData: propsData }).$mount(el);
|
||||
});
|
||||
};
|
||||
@@ -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):
|
||||
|
||||
@@ -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,163 @@ 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 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):
|
||||
"""
|
||||
@@ -306,23 +464,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):
|
||||
|
||||
@@ -890,6 +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']))
|
||||
# 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',
|
||||
|
||||
+8
-167
@@ -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%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<%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":
|
||||
<tr>
|
||||
##<!-- Get the value of the current Section parameter -->
|
||||
${inputs_recursive_indent( text=input.name, depth=depth )}
|
||||
<td></td>
|
||||
</tr>
|
||||
${ 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:
|
||||
<tr>
|
||||
${ inputs_recursive_indent( text=input.test_param.label, depth=depth )}
|
||||
##<!-- Get the value of the current Conditional parameter -->
|
||||
<td>${input.cases[current_case].value | h}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
${ inputs_recursive( input.cases[current_case].inputs, param_values[input.name], depth=depth+1, upgrade_messages=upgrade_messages.get( input.name ) ) }
|
||||
%else:
|
||||
<tr>
|
||||
${ inputs_recursive_indent( text=input.name, depth=depth )}
|
||||
<td><em>The previously used value is no longer valid</em></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
%endif
|
||||
%elif input.type == "upload_dataset":
|
||||
<tr>
|
||||
${inputs_recursive_indent( text=input.group_title( param_values ), depth=depth )}
|
||||
<td>${ len( param_values[input.name] ) } uploaded datasets</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
## files used for inputs
|
||||
%elif input.type == "data":
|
||||
<tr>
|
||||
${inputs_recursive_indent( text=input.label, depth=depth )}
|
||||
<td>
|
||||
%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 )
|
||||
%>
|
||||
<a class="input-dataset-show-params" data-hda-id="${encoded_id}"
|
||||
href="${show_params_url}">${hda.hid}: ${hda.name | h}</a>
|
||||
|
||||
%else:
|
||||
${element.hid}: ${element.name | h}
|
||||
%endif
|
||||
%endfor
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
%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
|
||||
%>
|
||||
<tr>
|
||||
${inputs_recursive_indent( text=label, depth=depth )}
|
||||
<td>${input.value_to_display_text( param_values[input.name] ) | h}</td>
|
||||
<td>${ upgrade_messages.get( input.name, '' ) | h }</td>
|
||||
</tr>
|
||||
%endif
|
||||
%else:
|
||||
## Parameter does not have a stored value.
|
||||
<tr>
|
||||
<%
|
||||
# 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 )}
|
||||
<td><em>not used (parameter was added after this job was run)</em></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
%endif
|
||||
|
||||
%endfor
|
||||
</%def>
|
||||
|
||||
## function to add a indentation depending on the depth in a <tr>
|
||||
<%def name="inputs_recursive_indent( text, depth )">
|
||||
<td style="padding-left: ${ ( depth - 1 ) * 10 }px">
|
||||
${text | h}
|
||||
</td>
|
||||
</%def>
|
||||
|
||||
<h2>
|
||||
% if tool:
|
||||
${tool.name | h}
|
||||
@@ -212,31 +87,13 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Tool Parameters</h3>
|
||||
<table class="tabletip" id="tool-parameters">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Input Parameter</th>
|
||||
<th>Value</th>
|
||||
<th>Note for rerun</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
% if params_objects and tool:
|
||||
${ inputs_recursive( tool.inputs, params_objects, depth=1, upgrade_messages=upgrade_messages ) }
|
||||
%elif params_objects is None:
|
||||
<tr><td colspan="3">Unable to load parameters.</td></tr>
|
||||
% else:
|
||||
<tr><td colspan="3">No parameters.</td></tr>
|
||||
% endif
|
||||
</tbody>
|
||||
</table>
|
||||
%if has_parameter_errors:
|
||||
<br />
|
||||
${ render_msg( 'One or more of your original parameters may no longer be valid or displayed properly.', status='warning' ) }
|
||||
%if job:
|
||||
<div class="job-parameters" dataset_id="${encoded_hda_id}" dataset_type="hda">
|
||||
</div>
|
||||
%endif
|
||||
|
||||
|
||||
|
||||
<h3>Inheritance Chain</h3>
|
||||
<div class="inherit" style="background-color: #fff; font-weight:bold;">${hda.name | h}</div>
|
||||
|
||||
@@ -256,26 +113,8 @@ ${ job.command_line | h }</pre>
|
||||
%endif
|
||||
|
||||
%if job and (trans.user_is_admin or trans.app.config.expose_potentially_sensitive_job_metrics):
|
||||
<h3>Job Metrics</h3>
|
||||
<% 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':
|
||||
<h4>${ plugin | h }</h4>
|
||||
<table class="tabletip info_data_table">
|
||||
<tbody>
|
||||
<%
|
||||
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:
|
||||
<tr><td>${ metric_title | h }</td><td>${ metric_value | h }</td></tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
</table>
|
||||
%endif
|
||||
%endfor
|
||||
<div class="job-metrics" dataset_id="${encoded_hda_id}" dataset_type="hda">
|
||||
</div>
|
||||
%endif
|
||||
|
||||
%if trans.user_is_admin:
|
||||
@@ -352,5 +191,7 @@ $(function(){
|
||||
window.parent.Galaxy.currHistoryPanel.scrollToId( 'dataset-' + $( this ).data( 'hda-id' ) );
|
||||
}
|
||||
})
|
||||
window.bundleEntries.mountJobMetrics();
|
||||
window.bundleEntries.mountJobParameters();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user