From a7f29aac3af98ca841f91696d27ba350115e02c0 Mon Sep 17 00:00:00 2001 From: gconsidine Date: Tue, 12 Dec 2017 16:26:12 -0500 Subject: [PATCH] Add component-based stdout for host modal --- awx/ui/client/features/_index.less | 2 +- .../features/output/index.controller.js | 23 +++- awx/ui/client/features/output/index.js | 12 +- awx/ui/client/features/output/index.view.html | 7 +- awx/ui/client/lib/components/index.js | 2 + .../lib/components/output/stdout.directive.js | 105 ++++++++++++++++++ .../lib/components/output/stdout.partial.html | 19 ++++ awx/ui/client/lib/models/Job.js | 8 +- awx/ui/client/lib/models/JobEvent.js | 19 ++++ awx/ui/client/lib/models/Jobs.js | 19 ---- awx/ui/client/lib/models/index.js | 10 +- 11 files changed, 189 insertions(+), 37 deletions(-) create mode 100644 awx/ui/client/lib/components/output/stdout.directive.js create mode 100644 awx/ui/client/lib/components/output/stdout.partial.html create mode 100644 awx/ui/client/lib/models/JobEvent.js delete mode 100644 awx/ui/client/lib/models/Jobs.js diff --git a/awx/ui/client/features/_index.less b/awx/ui/client/features/_index.less index 4a69120ed9..59e8e4630b 100644 --- a/awx/ui/client/features/_index.less +++ b/awx/ui/client/features/_index.less @@ -1,3 +1,3 @@ @import 'credentials/_index'; -@import 'jobs/_index'; +@import 'output/_index'; @import 'users/tokens/_index'; diff --git a/awx/ui/client/features/output/index.controller.js b/awx/ui/client/features/output/index.controller.js index 3139c3a6f8..238adc11f4 100644 --- a/awx/ui/client/features/output/index.controller.js +++ b/awx/ui/client/features/output/index.controller.js @@ -3,6 +3,7 @@ import hasAnsi from 'has-ansi'; let vm; let ansi; +let jobEvent; let $timeout; let $sce; let $compile; @@ -26,19 +27,19 @@ const TIME_EVENTS = [ EVENT_STATS_PLAY ]; -function JobsIndexController (job, _$sce_, _$timeout_, _$scope_, _$compile_) { +function JobsIndexController (job, JobEventModel, _$sce_, _$timeout_, _$scope_, _$compile_) { $timeout = _$timeout_; $sce = _$sce_; $compile = _$compile_; $scope = _$scope_; + ansi = new Ansi(); + jobEvent = new JobEventModel(); const events = job.get('related.job_events.results'); const html = $sce.trustAsHtml(parseEvents(events)); - vm = this || {}; - - $scope.ns = 'jobs'; + vm = this || {}; $scope.ns = 'jobs'; $scope.jobs = { modal: {} }; @@ -256,7 +257,17 @@ function getTime (created) { } function showHostDetails (id) { - $scope.jobs.modal.show('title', `test${id}`); + jobEvent.request('get', id) + .then(() => { + const title = jobEvent.get('host_name'); + + vm.host = { + menu: true, + stdout: jobEvent.get('stdout') + }; + + $scope.jobs.modal.show(title); + }); } function toggle (uuid) { @@ -280,6 +291,6 @@ function toggle (uuid) { } } -JobsIndexController.$inject = ['job', '$sce', '$timeout', '$scope', '$compile']; +JobsIndexController.$inject = ['job', 'JobEventModel', '$sce', '$timeout', '$scope', '$compile']; module.exports = JobsIndexController; diff --git a/awx/ui/client/features/output/index.js b/awx/ui/client/features/output/index.js index aa98a2359a..e989329f45 100644 --- a/awx/ui/client/features/output/index.js +++ b/awx/ui/client/features/output/index.js @@ -1,3 +1,8 @@ +import JobsStrings from '~features/output/jobs.strings'; +import IndexController from '~features/output/index.controller'; +import atLibModels from '~models'; +import atLibComponents from '~components'; + import JobsStrings from '~features/output/jobs.strings'; import IndexController from '~features/output/index.controller'; @@ -24,7 +29,7 @@ function JobsRun ($stateExtender, strings) { } }, resolve: { - job: ['JobsModel', '$stateParams', (Jobs, $stateParams) => { + job: ['JobModel', '$stateParams', (Jobs, $stateParams) => { const { id } = $stateParams; return new Jobs('get', id) @@ -42,7 +47,10 @@ function JobsRun ($stateExtender, strings) { JobsRun.$inject = ['$stateExtender', 'JobsStrings']; angular - .module(MODULE_NAME, []) + .module(MODULE_NAME, [ + atLibModels, + atLibComponents + ]) .controller('indexController', IndexController) .service('JobsStrings', JobsStrings) .run(JobsRun); diff --git a/awx/ui/client/features/output/index.view.html b/awx/ui/client/features/output/index.view.html index ba1256c5cc..0d92977ee5 100644 --- a/awx/ui/client/features/output/index.view.html +++ b/awx/ui/client/features/output/index.view.html @@ -1,7 +1,7 @@
-

left

+

@@ -31,5 +31,8 @@
- + +
+ +
diff --git a/awx/ui/client/lib/components/index.js b/awx/ui/client/lib/components/index.js index 9ac933628c..339747ad67 100644 --- a/awx/ui/client/lib/components/index.js +++ b/awx/ui/client/lib/components/index.js @@ -20,6 +20,7 @@ import launchTemplate from '~components/launchTemplateButton/launchTemplateButto import layout from '~components/layout/layout.directive'; import list from '~components/list/list.directive'; import modal from '~components/modal/modal.directive'; +import outputStdout from '~components/output/stdout.directive'; import panel from '~components/panel/panel.directive'; import panelBody from '~components/panel/body.directive'; import panelHeading from '~components/panel/heading.directive'; @@ -68,6 +69,7 @@ angular .directive('atRowItem', rowItem) .directive('atRowAction', rowAction) .directive('atModal', modal) + .directive('atOutputStdout', outputStdout) .directive('atPanel', panel) .directive('atPanelBody', panelBody) .directive('atPanelHeading', panelHeading) diff --git a/awx/ui/client/lib/components/output/stdout.directive.js b/awx/ui/client/lib/components/output/stdout.directive.js new file mode 100644 index 0000000000..880e2c6eb6 --- /dev/null +++ b/awx/ui/client/lib/components/output/stdout.directive.js @@ -0,0 +1,105 @@ +import Ansi from 'ansi-to-html'; +import hasAnsi from 'has-ansi'; + +const templateUrl = require('~components/output/stdout.partial.html'); + +let $sce; +let $timeout; +let ansi; + +function atOutputStdoutLink (scope, element, attrs, controller) { + controller.init(scope, element); +} + +function AtOutputStdoutController (_$sce_, _$timeout_) { + const vm = this || {}; + + $timeout = _$timeout_; + $sce = _$sce_; + ansi = new Ansi(); + + let scope; + let element; + + vm.init = (_scope_, _element_) => { + scope = _scope_; + element = _element_; + + scope.$watch('state.stdout', curr => { + if (!curr) { + return; + } + + render(scope.state.stdout); + }); + }; + + vm.scroll = position => { + const container = element.find('.at-Stdout-container')[0]; + + if (position === 'bottom') { + container.scrollTop = container.scrollHeight; + } else { + container.scrollTop = 0; + } + }; +} + +AtOutputStdoutController.$inject = [ + '$sce', + '$timeout', +]; + +function render (stdout) { + console.log('render'); + const html = $sce.trustAsHtml(parseStdout(stdout)); + + $timeout(() => { + const table = $('#atStdoutTBody'); + + table.html($sce.getTrustedHtml(html)); + }); +} + +function parseStdout (stdout) { + const lines = stdout.split('\r\n'); + + let ln = 0; + + return lines.reduce((html, line) => { + ln++; + + return `${html}${createRow(ln, line)}`; + }, ''); +} + +function createRow (ln, content) { + content = content || ''; + + if (hasAnsi(content)) { + content = ansi.toHtml(content); + } + + return ` + + ${ln} + ${content} + `; +} +function atOutputStdout () { + return { + restrict: 'E', + transclude: true, + replace: true, + require: 'atOutputStdout', + templateUrl, + controller: AtOutputStdoutController, + controllerAs: 'vm', + link: atOutputStdoutLink, + scope: { + state: '=', + } + }; +} + +export default atOutputStdout; diff --git a/awx/ui/client/lib/components/output/stdout.partial.html b/awx/ui/client/lib/components/output/stdout.partial.html new file mode 100644 index 0000000000..ca38d736f4 --- /dev/null +++ b/awx/ui/client/lib/components/output/stdout.partial.html @@ -0,0 +1,19 @@ +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
diff --git a/awx/ui/client/lib/models/Job.js b/awx/ui/client/lib/models/Job.js index 7d87f82330..ef80c5dafb 100644 --- a/awx/ui/client/lib/models/Job.js +++ b/awx/ui/client/lib/models/Job.js @@ -1,5 +1,5 @@ -let Base; let $http; +let BaseModel; function getRelaunch (params) { const req = { @@ -24,7 +24,7 @@ function postRelaunch (params) { } function JobModel (method, resource, config) { - Base.call(this, 'jobs'); + BaseModel.call(this, 'jobs'); this.Constructor = JobModel; this.postRelaunch = postRelaunch.bind(this); @@ -33,8 +33,8 @@ function JobModel (method, resource, config) { return this.create(method, resource, config); } -function JobModelLoader (BaseModel, _$http_) { - Base = BaseModel; +function JobModelLoader (_BaseModel_, _$http_) { + BaseModel = _BaseModel_; $http = _$http_; return JobModel; diff --git a/awx/ui/client/lib/models/JobEvent.js b/awx/ui/client/lib/models/JobEvent.js new file mode 100644 index 0000000000..1c71ba9c54 --- /dev/null +++ b/awx/ui/client/lib/models/JobEvent.js @@ -0,0 +1,19 @@ +let BaseModel; + +function JobEventModel (method, resource, config) { + BaseModel.call(this, 'job_events'); + + this.Constructor = JobEventModel; + + return this.create(method, resource, config); +} + +function JobEventModelLoader (_BaseModel_) { + BaseModel = _BaseModel_; + + return JobEventModel; +} + +JobEventModel.$inject = ['BaseModel']; + +export default JobEventModelLoader; diff --git a/awx/ui/client/lib/models/Jobs.js b/awx/ui/client/lib/models/Jobs.js deleted file mode 100644 index e82b3e04af..0000000000 --- a/awx/ui/client/lib/models/Jobs.js +++ /dev/null @@ -1,19 +0,0 @@ -let BaseModel; - -function JobsModel (method, resource, config) { - BaseModel.call(this, 'jobs'); - - this.Constructor = JobsModel; - - return this.create(method, resource, config); -} - -function JobsModelLoader (_BaseModel_) { - BaseModel = _BaseModel_; - - return JobsModel; -} - -JobsModelLoader.$inject = ['BaseModel']; - -export default JobsModelLoader; diff --git a/awx/ui/client/lib/models/index.js b/awx/ui/client/lib/models/index.js index 0e5ab2c6b3..91eb3742ee 100644 --- a/awx/ui/client/lib/models/index.js +++ b/awx/ui/client/lib/models/index.js @@ -12,10 +12,10 @@ import Inventory from '~models/Inventory'; import InventoryScript from '~models/InventoryScript'; import InventorySource from '~models/InventorySource'; import Job from '~models/Job'; +import JobEvent from '~models/JobEvent'; import JobTemplate from '~models/JobTemplate'; import Jobs from '~models/Jobs'; import Me from '~models/Me'; -import ModelsStrings from '~models/models.strings'; import NotificationTemplate from '~models/NotificationTemplate'; import Organization from '~models/Organization'; import Project from '~models/Project'; @@ -26,6 +26,8 @@ import WorkflowJobTemplate from '~models/WorkflowJobTemplate'; import WorkflowJobTemplateNode from '~models/WorkflowJobTemplateNode'; import UnifiedJob from '~models/UnifiedJob'; +import ModelsStrings from '~models/models.strings'; + const MODULE_NAME = 'at.lib.models'; angular @@ -43,11 +45,11 @@ angular .service('InventoryModel', Inventory) .service('InventoryScriptModel', InventoryScript) .service('InventorySourceModel', InventorySource) + .service('JobEventModel', JobEvent) .service('JobModel', Job) .service('JobTemplateModel', JobTemplate) .service('JobsModel', Jobs) .service('MeModel', Me) - .service('ModelsStrings', ModelsStrings) .service('NotificationTemplate', NotificationTemplate) .service('OrganizationModel', Organization) .service('ProjectModel', Project) @@ -56,6 +58,8 @@ angular .service('UnifiedJobTemplateModel', UnifiedJobTemplate) .service('WorkflowJobModel', WorkflowJob) .service('WorkflowJobTemplateModel', WorkflowJobTemplate) - .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode); + .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode) + .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode) + .service('ModelsStrings', ModelsStrings); export default MODULE_NAME;