diff --git a/client/src/bundleEntries.js b/client/src/bundleEntries.js
index 19f6a629f5a..a4bfdcd9dcd 100644
--- a/client/src/bundleEntries.js
+++ b/client/src/bundleEntries.js
@@ -100,6 +100,7 @@ export { mountPageDisplay } from "components/PageDisplay";
export { mountDestinationParams } from "components/JobDestinationParams";
export { mountDatasetInformation } from "components/DatasetInformation";
export { mountDatasetStorage } from "components/Dataset/DatasetStorage";
+export { mountJobInformation } from "components/JobInformation";
// Used in common.mako
export { default as store } from "storemodern";
diff --git a/client/src/components/JobInformation/JobInformation.vue b/client/src/components/JobInformation/JobInformation.vue
new file mode 100644
index 00000000000..dae49573684
--- /dev/null
+++ b/client/src/components/JobInformation/JobInformation.vue
@@ -0,0 +1,130 @@
+
+
+
Job Information
+
+
+ | Galaxy Tool ID: |
+ {{ jobInformation.tool_id }} |
+
+
+ | Galaxy Tool Version: |
+ {{ jobInformation.tool_version }} |
+
+
+ | Tool Version: |
+ {{ dataset.tool_version }} |
+
+
+ | Tool Standard Output: |
+ stdout |
+
+
+ | Tool Standard Error: |
+ stdout |
+
+
+
+ | Tool Exit Code: |
+ {{ jobInformation.exit_code }} |
+
+
+
+ | Job Messages |
+
+
+ |
+
+
+
+ | History Content API ID: |
+
+ {{ dataset.id }}
+ ({{ dataset.dataset_id }})
+ |
+
+
+
+ | Job API ID: |
+
+ {{ jobInformation.encoded_id }}
+ {{ jobInformation.id }}
+ |
+
+
+ | Copied from Job API ID: |
+
+ {{ jobInformation.encoded_copied_from_job_id }}
+ ({{ jobInformation.copied_from_job_id }})
+ |
+
+
+ | Copied from Job API ID: |
+
+ {{ jobInformation.encoded_copied_from_job_id }}
+ ({{ jobInformation.copied_from_job_id }})
+ |
+
+
+ | History API ID: |
+
+ {{ dataset.id }}
+
+
+
+
+ |
+
+
+
+ | UUID: |
+ {{ dataset.uuid }} |
+
+
+
+ | Full Path: |
+ {{ dataset.file_name }} |
+
+
+
+
+
+
diff --git a/client/src/components/JobInformation/index.js b/client/src/components/JobInformation/index.js
new file mode 100644
index 00000000000..7e2949fd7d9
--- /dev/null
+++ b/client/src/components/JobInformation/index.js
@@ -0,0 +1,3 @@
+export { default as JobInformation } from "./JobInformation";
+
+export { mountJobInformation } from "./mount";
diff --git a/client/src/components/JobInformation/mount.js b/client/src/components/JobInformation/mount.js
new file mode 100644
index 00000000000..de7b30d5d33
--- /dev/null
+++ b/client/src/components/JobInformation/mount.js
@@ -0,0 +1,13 @@
+/**
+ * Endpoint for mounting job metrics from non-Vue environment.
+ */
+import JobInformation from "./JobInformation";
+import { mountVueComponent } from "utils/mountVueComponent";
+
+export const mountJobInformation = (propsData = {}) => {
+ document.querySelectorAll(".job-information").forEach((element) => {
+ propsData.hda_id = element.getAttribute("hda_id");
+ propsData.job_id = element.getAttribute("job_id");
+ mountVueComponent(JobInformation)(propsData, element);
+ });
+};
diff --git a/client/src/store/index.js b/client/src/store/index.js
index 4a51630d465..ef5ac982cff 100644
--- a/client/src/store/index.js
+++ b/client/src/store/index.js
@@ -18,6 +18,7 @@ import { workflowStore } from "./workflowStore";
import { datasetPathDestinationStore } from "./datasetPathDestinationStore";
import { datasetExtFilesStore } from "./datasetExtFilesStore";
import { datasetsStore } from "./datasetsStore";
+import { jobInformationStore } from "./jobInformationStore";
Vue.use(Vuex);
@@ -43,6 +44,7 @@ export function createStore() {
config: configStore,
workflows: workflowStore,
datasets: datasetsStore,
+ informationStore: jobInformationStore,
},
});
}
diff --git a/client/src/store/jobInformationStore.js b/client/src/store/jobInformationStore.js
new file mode 100644
index 00000000000..88f747b8096
--- /dev/null
+++ b/client/src/store/jobInformationStore.js
@@ -0,0 +1,33 @@
+export const state = {
+ jobInformationJobId: {},
+};
+
+import Vue from "vue";
+import { getAppRoot } from "onload/loadConfig";
+import axios from "axios";
+
+const getters = {
+ jobInformation: (state) => (jobId) => {
+ return state.jobInformationJobId[jobId] || [];
+ },
+};
+
+const actions = {
+ fetchJobInformation: async ({ commit }, jobId) => {
+ const { data } = await axios.get(`${getAppRoot()}api/jobs/${jobId}/job_information`);
+ commit("saveJobInformationForJobId", { jobId, jobInformation: data });
+ },
+};
+
+const mutations = {
+ saveJobInformationForJobId: (state, { jobId, jobInformation }) => {
+ Vue.set(state.jobInformationJobId, jobId, jobInformation);
+ },
+};
+
+export const jobInformationStore = {
+ state,
+ getters,
+ actions,
+ mutations,
+};
diff --git a/lib/galaxy/managers/jobs.py b/lib/galaxy/managers/jobs.py
index 560be6ddcb4..5306a980789 100644
--- a/lib/galaxy/managers/jobs.py
+++ b/lib/galaxy/managers/jobs.py
@@ -662,3 +662,24 @@ def summarize_job_parameters(trans, job):
parameters = inputs_recursive(tool.inputs, params_objects, depth=1, upgrade_messages=upgrade_messages)
return {"parameters": parameters, "has_parameter_errors": has_parameter_errors}
+
+
+def summarize_job_information(trans, job):
+ """Produce a dict-ified version of job information
+
+ Precondition: the caller has verified the job is accessible to the user
+ represented by the trans parameter.
+ """
+
+ job_information = {'tool_id': job.tool_id,
+ 'tool_version': job.tool_version,
+ 'exit_code': job.exit_code,
+ 'job_messages': job.job_messages,
+ 'encoded_id': trans.security.encode_id(job.id),
+ 'encoded_copied_from_job_id': trans.security.encode_id(job.copied_from_job_id) if job.copied_from_job_id else "",
+ }
+ if trans.user_is_admin:
+ job_information['id'] = job.id
+ job_information['copied_from_job_id'] = job.copied_from_job_id if job.copied_from_job_id else "",
+
+ return job_information
diff --git a/lib/galaxy/webapps/galaxy/api/jobs.py b/lib/galaxy/webapps/galaxy/api/jobs.py
index 1f7c8043359..b71fd90ec47 100644
--- a/lib/galaxy/webapps/galaxy/api/jobs.py
+++ b/lib/galaxy/webapps/galaxy/api/jobs.py
@@ -18,6 +18,7 @@ from galaxy.managers.jobs import (
JobManager,
JobSearch,
summarize_destination_params,
+ summarize_job_information,
summarize_job_metrics,
summarize_job_parameters,
)
@@ -334,6 +335,22 @@ class JobController(BaseAPIController, UsesVisualizationMixin):
job = self.__get_job(trans, **kwd)
return summarize_job_parameters(trans, job)
+ @require_admin
+ @expose_api
+ def job_information(self, trans, **kwd):
+ """
+ * GET /api/jobs/{job_id}/summarize_job_information
+ Return job information for specified job.
+
+ :type job_id: string
+ :param job_id: Encoded job id
+
+ :rtype: list
+ :returns: list containing job information
+ """
+ job = self.__get_job(trans, **kwd)
+ return summarize_job_information(trans, job)
+
@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 c18c421e95e..7dccdca768f 100644
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -1022,6 +1022,7 @@ def populate_api_routes(webapp, app):
# 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('destination_params', '/api/jobs/{job_id}/destination_params', controller='jobs', action='destination_params', conditions=dict(method=['GET']))
+ webapp.mapper.connect('job_information', '/api/jobs/{job_id}/job_information', controller='jobs', action='job_information', conditions=dict(method=['GET']))
webapp.mapper.connect('show_job_lock', '/api/job_lock', controller='jobs', action='show_job_lock', conditions=dict(method=['GET']))
webapp.mapper.connect('update_job_lock', '/api/job_lock', controller='jobs', action='update_job_lock', conditions=dict(method=['PUT']))
webapp.mapper.connect('dataset_metrics', '/api/datasets/{dataset_id}/metrics', controller='jobs', action='metrics', conditions=dict(method=['GET']))
diff --git a/templates/show_params.mako b/templates/show_params.mako
index d58b62d4082..2ef09fa8bce 100644
--- a/templates/show_params.mako
+++ b/templates/show_params.mako
@@ -25,65 +25,7 @@ encoded_history_id = trans.security.encode_id( hda.history_id )
%>
-
-Job Information
-
-
- %if job:
- | Galaxy Tool ID: | ${ job.tool_id | h } |
- | Galaxy Tool Version: | ${ job.tool_version | h } |
- %endif
- | Tool Version: | ${hda.tool_version | h} |
- | Tool Standard Output: | stdout |
- | Tool Standard Error: | stderr |
- %if job:
- | Tool Exit Code: | ${ job.exit_code | h } |
- %if job.job_messages:
- | Job Messages |
- %for job_message in job.job_messages:
- - ${ job_message['desc'] |h }
- %endfor
- |
- %endif
- %endif
- | History Content API ID: |
- ${encoded_hda_id}
- %if trans.user_is_admin:
- (${hda.id})
- %endif
- |
- %if job:
- | Job API ID: |
- ${trans.security.encode_id( job.id )}
- %if trans.user_is_admin:
- (${job.id})
- %endif
- |
- %if job.copied_from_job_id:
- | Copied from Job API ID: |
- ${trans.security.encode_id( job.copied_from_job_id )}
- %if trans.user_is_admin:
- (${job.copied_from_job_id})
- %endif
- |
- %endif
- %endif
- | History API ID: |
- ${encoded_history_id}
- %if trans.user_is_admin:
- (${hda.history_id})
- %endif
- |
- %if hda.dataset.uuid:
- | UUID: | ${hda.dataset.uuid} |
- %endif
- %if trans.user_is_admin or trans.app.config.expose_dataset_path:
- %if not hda.purged:
- | Full Path: | ${hda.file_name | h} |
- %endif
- %endif
-
-
+
@@ -174,10 +116,8 @@ $(function(){
window.parent.Galaxy.currHistoryPanel.scrollToId( 'dataset-' + $( this ).data( 'hda-id' ) );
}
})
- window.bundleEntries.mountJobMetrics();
- window.bundleEntries.mountJobParameters();
- window.bundleEntries.mountDestinationParams();
- window.bundleEntries.mountDatasetInformation();
- window.bundleEntries.mountDatasetStorage();
+
+ const mountComponents = ["mountJobMetrics", "mountJobParameters", "mountDestinationParams","mountDatasetInformation","mountJobInformation", "mountDatasetStorage"]
+ mountComponents.forEach(component => window.bundleEntries[component]())
});