diff --git a/client/galaxy/scripts/components/admin/Jobs.vue b/client/galaxy/scripts/components/admin/Jobs.vue
new file mode 100644
index 00000000000..5efa1cec465
--- /dev/null
+++ b/client/galaxy/scripts/components/admin/Jobs.vue
@@ -0,0 +1,371 @@
+
+
+
+ Jobs (vue)
+
+
+
+
+ Unfinished and recently finished jobs are displayed on this page. The 'cutoff' input box will do two
+ things -- it will limit the display of unfinished jobs to only those jobs that have not had their job
+ state updated recently, and it will limit the recently finished jobs list to only displaying jobs that
+ have finished since the cutoff.
+
+ If any jobs are displayed, you may choose to stop them. Your stop message will be displayed to the user as:
+ "This job was stopped by an administrator: <YOUR MESSAGE> For more information or
+ help, report this error".
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+ Job dispatching is currently
+ {{ jobLockDisplay ? "locked" : "unlocked" }}.
+
+
+
+
+
+ Prevent jobs from dispatching
+
+
+
+ Update
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear (esc)
+
+
+
+
+ {{ showCommandLine ? "Hide" : "Show" }} Command Line
+
+
+
+
+
+
+
+
+
+
+ Submit
+
+
+
+
+
+
+
+
+
+ There are no unfinished jobs to show with current cutoff time.
+
+
+
+ Unfinished Jobs: These jobs are unfinished and have had their state updated in the previous
+ {{ cutoffDisplay }} seconds.
+
+
+
+
+
+
+
+
+
+
+
+ {{ data.value["id"] }}
+
+
+
+
+ Command Line
+ {{ row.item.command_line }}
+
+
+
+
+ There are no recently finished jobs to show with current cutoff time.
+
+
+
+ Recent Jobs: These jobs have completed in the previous {{ cutoffDisplay }} seconds.
+
+
+
+
+
+ {{ data.value["id"] }}
+
+
+
+
+ Command Line
+ {{ row.item.command_line }}
+
+
+
+
+
+
+
+
+
+
diff --git a/client/galaxy/scripts/entry/admin/AdminRouter.js b/client/galaxy/scripts/entry/admin/AdminRouter.js
index 1eeae6a2138..8e8aa024e06 100644
--- a/client/galaxy/scripts/entry/admin/AdminRouter.js
+++ b/client/galaxy/scripts/entry/admin/AdminRouter.js
@@ -7,6 +7,7 @@ import QueryStringParsing from "utils/query-string-parsing";
import Router from "layout/router";
import DataTables from "components/admin/DataTables.vue";
import DataTypes from "components/admin/DataTypes.vue";
+import Jobs from "components/admin/Jobs.vue";
import DataManagerView from "components/admin/DataManager/DataManagerView.vue";
import DataManagerRouter from "components/admin/DataManager/DataManagerRouter.vue";
import Register from "components/login/Register.vue";
@@ -33,6 +34,7 @@ export const getAdminRouter = (Galaxy, options) => {
"(/)admin(/)form(/)(:form_id)": "show_form",
"(/)admin/data_tables": "show_data_tables",
"(/)admin/data_types": "show_data_types",
+ "(/)admin/jobs": "show_jobs",
"(/)admin/data_manager*path": "show_data_manager",
"*notFound": "not_found"
},
@@ -115,6 +117,10 @@ export const getAdminRouter = (Galaxy, options) => {
this._display_vue_helper(DataTypes);
},
+ show_jobs: function() {
+ this._display_vue_helper(Jobs);
+ },
+
show_error_stack: function() {
this._display_vue_helper(ErrorStack);
},
diff --git a/client/galaxy/scripts/entry/panels/admin-panel.js b/client/galaxy/scripts/entry/panels/admin-panel.js
index a94035e382e..44e60acc517 100644
--- a/client/galaxy/scripts/entry/panels/admin-panel.js
+++ b/client/galaxy/scripts/entry/panels/admin-panel.js
@@ -39,6 +39,7 @@ var AdminPanel = Backbone.View.extend({
{
title: _l("Manage jobs"),
url: "admin/jobs",
+ target: "__use_router__",
id: "admin-link-jobs"
},
{
diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py
index 6eb8fa7a76c..9289ab0b1f5 100644
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -101,6 +101,7 @@ def app_factory(global_conf, load_app_kwds={}, **kwargs):
webapp.add_client_route('/admin/data_tables', 'admin')
webapp.add_client_route('/admin/data_types', 'admin')
+ webapp.add_client_route('/admin/jobs', 'admin')
webapp.add_client_route('/admin/data_manager{path_info:.*}', 'admin')
webapp.add_client_route('/admin/error_stack', 'admin')
webapp.add_client_route('/admin/users', 'admin')
diff --git a/lib/galaxy/webapps/galaxy/controllers/admin.py b/lib/galaxy/webapps/galaxy/controllers/admin.py
index f001821285a..63d0f2039a1 100644
--- a/lib/galaxy/webapps/galaxy/controllers/admin.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin.py
@@ -1600,14 +1600,25 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
return {'message' : 'User \'%s\' has been updated with %d associated roles and %d associated groups (private roles are not displayed).' % (user.email, len(in_roles) - 1, len(in_groups))}
@web.expose
+ @web.json
@web.require_admin
- def jobs(self, trans, stop=[], stop_msg=None, cutoff=180, job_lock=None, ajl_submit=None, **kwd):
+ def jobs_control(self, trans, job_lock=None, **kwd):
+ if job_lock is not None:
+ job_lock = True if job_lock == 'true' else False
+ galaxy.queue_worker.send_control_task(trans.app, 'admin_job_lock', kwargs={'job_lock': job_lock})
+ job_lock = trans.app.job_manager.job_lock
+ return {'job_lock': job_lock}
+
+ @web.expose
+ @web.json
+ @web.require_admin
+ def jobs_list(self, trans, stop=[], stop_msg=None, cutoff=180, **kwd):
deleted = []
- msg = None
- status = None
+ message = kwd.get('message', '')
+ status = kwd.get('status', 'info')
job_ids = util.listify(stop)
if job_ids and stop_msg in [None, '']:
- msg = 'Please enter an error message to display to the user describing why the job was terminated'
+ message = 'Please enter an error message to display to the user describing why the job was terminated'
status = 'error'
elif job_ids:
if stop_msg[-1] not in PUNCTUATION:
@@ -1624,24 +1635,14 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
trans.app.job_manager.stop(job, message=error_msg)
deleted.append(str(job_id))
if deleted:
- msg = 'Queued job'
+ message = 'Queued job'
if len(deleted) > 1:
- msg += 's'
- msg += ' for deletion: '
- msg += ', '.join(deleted)
+ message += 's'
+ message += ' for deletion: '
+ message += ', '.join(deleted)
status = 'done'
trans.sa_session.flush()
- if ajl_submit:
- if job_lock == 'on':
- galaxy.queue_worker.send_control_task(trans.app, 'admin_job_lock',
- kwargs={'job_lock': True})
- job_lock = True
- else:
- galaxy.queue_worker.send_control_task(trans.app, 'admin_job_lock',
- kwargs={'job_lock': False})
- job_lock = False
- else:
- job_lock = trans.app.job_manager.job_lock
+ job_lock = trans.app.job_manager.job_lock
cutoff_time = datetime.utcnow() - timedelta(seconds=int(cutoff))
jobs = trans.sa_session.query(trans.app.model.Job) \
.filter(and_(trans.app.model.Job.table.c.update_time < cutoff_time,
@@ -1655,33 +1656,44 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
or_(trans.app.model.Job.state == trans.app.model.Job.states.ERROR,
trans.app.model.Job.state == trans.app.model.Job.states.OK))) \
.order_by(trans.app.model.Job.table.c.update_time.desc()).all()
- last_updated = {}
- for job in jobs:
- delta = datetime.utcnow() - job.update_time
- if delta.days > 0:
- last_updated[job.id] = '%s hours' % (delta.days * 24 + int(delta.seconds / 60 / 60))
- elif delta > timedelta(minutes=59):
- last_updated[job.id] = '%s hours' % int(delta.seconds / 60 / 60)
- else:
- last_updated[job.id] = '%s minutes' % int(delta.seconds / 60)
- finished = {}
- for job in recent_jobs:
- delta = datetime.utcnow() - job.update_time
- if delta.days > 0:
- finished[job.id] = '%s hours' % (delta.days * 24 + int(delta.seconds / 60 / 60))
- elif delta > timedelta(minutes=59):
- finished[job.id] = '%s hours' % int(delta.seconds / 60 / 60)
- else:
- finished[job.id] = '%s minutes' % int(delta.seconds / 60)
- return trans.fill_template('/admin/jobs.mako',
- jobs=jobs,
- recent_jobs=recent_jobs,
- last_updated=last_updated,
- finished=finished,
- cutoff=cutoff,
- msg=msg,
- status=status,
- job_lock=job_lock)
+
+ def prepare_jobs_list(jobs):
+ res = []
+ for job in jobs:
+ delta = datetime.utcnow() - job.update_time
+ update_time = ""
+ if delta.days > 0:
+ update_time = '%s hours ago' % (delta.days * 24 + int(delta.seconds / 60 / 60))
+ elif delta > timedelta(minutes=59):
+ update_time = '%s hours ago' % int(delta.seconds / 60 / 60)
+ else:
+ update_time = '%s minutes ago' % int(delta.seconds / 60)
+ inputs = ""
+ try:
+ inputs = ", ".join(['{} {}'.format(da.dataset.id, da.dataset.state) for da in job.input_datasets])
+ except Exception:
+ inputs = 'Unable to determine inputs'
+ res.append({
+ 'job_info': {
+ 'id': job.id,
+ 'info_url': "{}?jobid={}".format(web.url_for(controller="admin", action="job_info"), job.id)
+ },
+ 'user': job.history.user.email if job.history and job.history.user else 'anonymous',
+ 'update_time': update_time,
+ 'tool_id': job.tool_id,
+ 'state': job.state,
+ 'input_dataset': inputs,
+ 'command_line': job.command_line,
+ 'job_runner_name': job.job_runner_name,
+ 'job_runner_external_id': job.job_runner_external_id
+ })
+ return res
+ return {'jobs': prepare_jobs_list(jobs),
+ 'recent_jobs': prepare_jobs_list(recent_jobs),
+ 'cutoff': cutoff,
+ 'message': message,
+ 'status': status,
+ 'job_lock': job_lock}
@web.expose
@web.require_admin
diff --git a/templates/admin/jobs.mako b/templates/admin/jobs.mako
deleted file mode 100644
index 36a372044f9..00000000000
--- a/templates/admin/jobs.mako
+++ /dev/null
@@ -1,209 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-<%def name="javascripts()">
- ${parent.javascripts()}
-
-%def>
-
-<%def name="title()">Jobs%def>
-
-
Jobs
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-
- Unfinished and recently finished jobs are displayed on this page. The
- 'cutoff' input box will do two things -- it will limit the display of
- unfinished jobs to only those jobs that have not had their job state
- updated recently, and it will limit the recently finished jobs list to only
- displaying jobs that have finished since the cutoff.
-
-
- If any jobs are displayed, you may choose to stop them. Your stop message
- will be displayed to the user as: "This job was stopped by an
- administrator: <YOUR MESSAGE> For more information or help,
- report this error".
-
-
-%if jobs:
-
-%else:
- There are no unfinished jobs to show with current cutoff time.
-
-%endif
-
-%if recent_jobs:
-
- Recent Jobs: These jobs have completed in the previous ${cutoff} seconds.
-
-
-
- %for job in recent_jobs:
- | ${job.id} |
- %if job.history and job.history.user:
- ${job.history.user.email|h} |
- %else:
- anonymous |
- %endif
- ${finished[job.id]} ago |
- ${job.tool_id|h} |
- ${job.state} |
- <%
- try:
- inputs = ", ".join( [ '%s %s' % ( da.dataset.id, da.dataset.state ) for da in job.input_datasets ] )
- except:
- inputs = 'Unable to determine inputs'
- %>
- ${inputs} |
- ${job.command_line|h} |
- ${job.job_runner_name|h} |
- ${job.job_runner_external_id|h} |
-
- %endfor
-
-
-%else:
- There are no recently finished jobs to show with current cutoff time.
-
-%endif
-
-
-
-