From 8477cb150eededf7f9410739b7a391130d343964 Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Fri, 27 Jun 2014 15:41:50 -0400 Subject: [PATCH] Dashboard Built the job status dashboard widget. --- awx/ui/static/js/controllers/Jobs.js | 2 +- awx/ui/static/js/helpers/JobSubmission.js | 9 +- awx/ui/static/js/helpers/Jobs.js | 11 ++ awx/ui/static/js/lists/CompletedJobs.js | 14 +-- awx/ui/static/js/lists/Jobs.js | 130 ++++++++++------------ awx/ui/static/js/lists/RunningJobs.js | 2 +- awx/ui/static/js/lists/ScheduledJobs.js | 16 +-- awx/ui/static/js/widgets/DashboardJobs.js | 73 +++++++++++- awx/ui/static/partials/home.html | 33 +++--- 9 files changed, 166 insertions(+), 124 deletions(-) diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index 0dc3a99914..39aaab194d 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -20,7 +20,7 @@ function JobsListController ($scope, $compile, $routeParams, ClearScope, Breadcr listCount = 0, api_complete = false, event_socket, - event_queue = [{"status":"pending","endpoint":"/socket.io/jobs","unified_job_id":4129,"event":"status_changed"}], + event_queue = [], expecting = 0, max_rows; diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 6c6d174c14..f66cd5724b 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -372,7 +372,6 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi return function (params) { var scope = params.scope, id = params.id, - base = $location.path().replace(/^\//, '').split('/')[0], url, job_template, new_job_id, @@ -381,13 +380,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi prompt_for_vars = false, passwords; - if (!Empty($routeParams.template_id)) { - // launching a job from job_template detail page - url = GetBasePath('jobs') + id + '/'; - } - else { - url = GetBasePath(base) + id + '/'; - } + url = GetBasePath('jobs') + id + '/'; if (scope.removePostTheJob) { scope.removePostTheJob(); diff --git a/awx/ui/static/js/helpers/Jobs.js b/awx/ui/static/js/helpers/Jobs.js index 9f0bfbef1b..784f7e068b 100644 --- a/awx/ui/static/js/helpers/Jobs.js +++ b/awx/ui/static/js/helpers/Jobs.js @@ -46,7 +46,12 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job else if (scope.queued_jobs) { list = scope.queued_jobs; } + else if (scope.jobs) { + list = scope.jobs; + } job = Find({ list: list, key: 'id', val: id }); + console.log('found job:'); + console.log(job); if (job.type === 'inventory_update') { typeId = job.inventory_source; } @@ -81,6 +86,9 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job else if (scope.queued_jobs) { list = scope.queued_jobs; } + else if (scope.jobs) { + list = scope.jobs; + } job = Find({ list: list, key: 'id', val: id }); if (job.type === 'job') { $location.url('/jobs/' + job.id); @@ -432,6 +440,9 @@ function(Find, GetBasePath, Rest, Wait, ProcessErrors, Prompt, Alert){ else if (scope.queued_jobs) { jobs = scope.queued_jobs; } + else if (scope.jobs) { + jobs = scope.jobs; + } job = Find({list: jobs, key: 'id', val: id }); if (job.status === 'pending' || job.status === 'running' || job.status === 'waiting') { diff --git a/awx/ui/static/js/lists/CompletedJobs.js b/awx/ui/static/js/lists/CompletedJobs.js index c092e30e33..e8b4b6f80c 100644 --- a/awx/ui/static/js/lists/CompletedJobs.js +++ b/awx/ui/static/js/lists/CompletedJobs.js @@ -105,20 +105,8 @@ angular.module('CompletedJobsDefinition', []) stdout: { mode: 'all', href: '/#/jobs/{{ completed_job.id }}/stdout', - awToolTip: 'View standard output. Opens in a new window or tab.', + awToolTip: 'View standard output', dataPlacement: 'top' } - /*dropdown: { - type: 'DropDown', - ngShow: "completed_job.type === 'job'", - label: 'View', - icon: 'fa-search-plus', - 'class': 'btn-default btn-xs', - options: [ - //{ ngHref: '/#/jobs/{{ completed_job.id }}', label: 'Status' }, - { ngHref: '/#/job_events/{{ completed_job.id }}', label: 'Events', ngHide: "completed_job.status == 'new'" }, - { ngHref: '/#/job_host_summaries/{{ completed_job.id }}', label: 'Host Summary' } - ] - }*/ } }); diff --git a/awx/ui/static/js/lists/Jobs.js b/awx/ui/static/js/lists/Jobs.js index 058fd9d97d..811da12fc7 100644 --- a/awx/ui/static/js/lists/Jobs.js +++ b/awx/ui/static/js/lists/Jobs.js @@ -2,8 +2,10 @@ * Copyright (c) 2014 AnsibleWorks, Inc. * * Jobs.js - * List view object for Team data model. + * List view object for job data model. * + * Used on dashboard to provide a list of all jobs, regardless of + * status. * */ @@ -15,112 +17,92 @@ angular.module('JobsListDefinition', []) name: 'jobs', iterator: 'job', editTitle: 'Jobs', - showTitle: false, + 'class': 'table-condensed', index: false, hover: true, well: false, - "class": 'jobs-table', fields: { id: { label: 'ID', + ngClick:"viewJobLog(job.id)", key: true, desc: true, - searchType: 'int' - }, - inventory: { - label: 'Inventory ID', searchType: 'int', - searchOnly: true - }, - created: { - label: 'Create On', - link: false, - searchable: false, - filter: "date:'MM/dd HH:mm:ss'" - }, - name: { - label: 'Name', - link: false - }, - failed: { - label: 'Job failed?', - searchSingleValue: true, - searchType: 'boolean', - searchValue: 'true', - searchOnly: true, - nosort: true + columnClass: 'col-md-1 col-sm-2 col-xs-2', + awToolTip: "{{ job.status_tip }}", + awTipPlacement: "top", }, status: { label: 'Status', - "class": 'job-{{ job.status }}', + columnClass: 'col-lg-1 col-md-2 col-sm-2 col-xs-2', + awToolTip: "{{ job.status_tip }}", + awTipPlacement: "top", + dataTitle: "{{ job.status_popover_title }}", + icon: 'icon-job-{{ job.status }}', + iconOnly: true, + ngClick:"viewJobLog(job.id)", + searchable: false + }, + started: { + label: 'Started On', + noLink: true, + searchable: false, + filter: "date:'MM/dd HH:mm:ss'", + columnClass: "col-lg-1 col-md-2 hidden-xs" + }, + type: { + label: 'Type', + ngBind: 'job.type_label', + link: false, + columnClass: "col-lg-1 col-md-2 hidden-sm hidden-xs", + searchable: true, searchType: 'select', - linkTo: "{{ job.statusLinkTo }}", - searchOptions: [ - { name: "new", value: "new" }, - { name: "waiting", value: "waiting" }, - { name: "pending", value: "pending" }, - { name: "running", value: "running" }, - { name: "successful", value: "successful" }, - { name: "error", value: "error" }, - { name: "failed", value: "failed" }, - { name: "canceled", value: "canceled" } - ], - badgeIcon: 'fa icon-job-{{ job.status }}', - badgePlacement: 'left', - badgeToolTip: "{{ job.statusBadgeToolTip }}", - badgeTipPlacement: 'top', - badgeNgHref: "{{ job.statusLinkTo }}", - awToolTip: "{{ job.statusBadgeToolTip }}", - dataPlacement: 'top' + searchOptions: [] // populated via GetChoices() in controller + }, + name: { + label: 'Name', + columnClass: 'col-md-3 col-xs-5', + ngClick: "viewJobLog(job.id, job.nameHref)", + defaultSearchField: true } }, - actions: { - refresh: { - mode: 'all', - awToolTip: "Refresh the page", - ngClick: "refresh()" - } - }, + actions: { }, fieldActions: { submit: { - label: 'Relaunch', - icon: 'icon-rocket', mode: 'all', - ngClick: 'submitJob(job.id, job.summary_fields.job_template.name)', - awToolTip: 'Start the job', + icon: 'icon-rocket', + ngClick: 'relaunchJob($event, job.id)', + awToolTip: 'Relaunch using the same parameters', dataPlacement: 'top' }, cancel: { - label: 'Stop', mode: 'all', ngClick: 'deleteJob(job.id)', - awToolTip: 'Cancel a running or pending job', - ngShow: "job.status == 'pending' || job.status == 'running' || job.status == 'waiting'", - dataPlacement: 'top' + awToolTip: 'Cancel the job', + dataPlacement: 'top', + ngShow: "job.status == 'running'" }, "delete": { - label: 'Delete', mode: 'all', ngClick: 'deleteJob(job.id)', awToolTip: 'Delete the job', - ngShow: "job.status != 'pending' && job.status != 'running' && job.status != 'waiting'", + dataPlacement: 'top', + ngShow: "job.status != 'running'" + }, + job_details: { + mode: 'all', + href: '/#/jobs/{{ job.id }}', + awToolTip: 'View job details', dataPlacement: 'top' }, - dropdown: { - type: 'DropDown', - label: 'View', - icon: 'fa-search-plus', - 'class': 'btn-default btn-xs', - options: [ - { ngClick: 'editJob(job.id, job.summary_fields.job_template.name)', label: 'Status' }, - { ngClick: 'viewEvents(job.id, job.summary_fields.job_template.name)', label: 'Events', - ngHide: "job.status == 'new'" }, - { ngClick: 'viewSummary(job.id, job.summary_fields.job_template.name)', label: 'Host Summary', - ngHide: "job.status == 'new'" } - ] + stdout: { + mode: 'all', + href: '/#/jobs/{{ job.id }}/stdout', + awToolTip: 'View standard output', + dataPlacement: 'top' } } }); diff --git a/awx/ui/static/js/lists/RunningJobs.js b/awx/ui/static/js/lists/RunningJobs.js index db18e1a611..46f88a591e 100644 --- a/awx/ui/static/js/lists/RunningJobs.js +++ b/awx/ui/static/js/lists/RunningJobs.js @@ -90,7 +90,7 @@ angular.module('RunningJobsDefinition', []) stdout: { mode: 'all', href: '/#/jobs/{{ running_job.id }}/stdout', - awToolTip: 'View standard output. Opens in a new window or tab.', + awToolTip: 'View standard output', dataPlacement: 'top' } /*dropdown: { diff --git a/awx/ui/static/js/lists/ScheduledJobs.js b/awx/ui/static/js/lists/ScheduledJobs.js index 265f720e24..e94c653d11 100644 --- a/awx/ui/static/js/lists/ScheduledJobs.js +++ b/awx/ui/static/js/lists/ScheduledJobs.js @@ -1,16 +1,16 @@ /********************************************* * Copyright (c) 2014 AnsibleWorks, Inc. * - * ScheduledJobs.js + * ScheduledJobs.js + * * - * */ 'use strict'; angular.module('ScheduledJobsDefinition', []) .value( 'ScheduledJobsList', { - + name: 'schedules', iterator: 'schedule', editTitle: 'Scheduled Jobs', @@ -18,11 +18,11 @@ angular.module('ScheduledJobsDefinition', []) index: true, hover: true, well: false, - + fields: { status: { label: 'Status', - columnClass: 'col-md-2 col-sm-2 col-xs-2', + columnClass: 'col-lg-1 col-md-2 col-sm-2 col-xs-2', awToolTip: "{{ schedule.status_tip }}", awTipPlacement: "top", icon: 'icon-job-{{ schedule.status }}', @@ -35,14 +35,14 @@ angular.module('ScheduledJobsDefinition', []) label: 'Next Run', noLink: true, searchable: false, - columnClass: "col-md-2 hidden-xs", + columnClass: "col-lg-1 col-md-2 hidden-xs", filter: "date:'MM/dd HH:mm:ss'", key: true }, type: { label: 'Type', noLink: true, - columnClass: "col-md-2 hidden-sm hidden-xs", + columnClass: "col-lg-1 col-md-2 hidden-sm hidden-xs", sourceModel: 'unified_job_template', sourceField: 'unified_job_type', ngBind: 'schedule.type_label', @@ -62,7 +62,7 @@ angular.module('ScheduledJobsDefinition', []) }, actions: { }, - + fieldActions: { "play": { mode: "all", diff --git a/awx/ui/static/js/widgets/DashboardJobs.js b/awx/ui/static/js/widgets/DashboardJobs.js index b6f938dacc..07c5a9ba32 100644 --- a/awx/ui/static/js/widgets/DashboardJobs.js +++ b/awx/ui/static/js/widgets/DashboardJobs.js @@ -10,13 +10,19 @@ 'use strict'; angular.module('DashboardJobsWidget', ['RestServices', 'Utilities']) -.factory('DashboardJobs', ['$rootScope', '$compile', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', function ($rootScope, $compile) { +.factory('DashboardJobs', ['$rootScope', '$compile', 'LoadSchedulesScope', 'LoadJobsScope', 'JobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', + function ($rootScope, $compile, LoadSchedulesScope, LoadJobsScope, JobsList, ScheduledJobsList, GetChoices, GetBasePath) { return function (params) { - var scope = params.scope, target = params.target, + choicesCount = 0, + listCount = 0, + jobs_scope = scope.$new(true), + scheduled_scope = scope.$new(true), + max_rows = 15, html, e; + html = ''; html += "