From a3fdd244b55de1aa744e2455cd63f487330e95bb Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Mon, 7 May 2018 00:48:55 -0400 Subject: [PATCH 1/3] add message service --- awx/ui/client/features/output/index.js | 2 + .../client/features/output/message.service.js | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 awx/ui/client/features/output/message.service.js diff --git a/awx/ui/client/features/output/index.js b/awx/ui/client/features/output/index.js index 0bb295a714..372d28221f 100644 --- a/awx/ui/client/features/output/index.js +++ b/awx/ui/client/features/output/index.js @@ -8,6 +8,7 @@ import RenderService from '~features/output/render.service'; import ScrollService from '~features/output/scroll.service'; import EngineService from '~features/output/engine.service'; import StatusService from '~features/output/status.service'; +import MessageService from '~features/output/message.service'; import LegacyRedirect from '~features/output/legacy.route'; import DetailsDirective from '~features/output/details.directive'; @@ -221,6 +222,7 @@ angular .service('JobRenderService', RenderService) .service('JobEventEngine', EngineService) .service('JobStatusService', StatusService) + .service('JobMessageService', MessageService) .directive('atJobDetails', DetailsDirective) .directive('atJobSearch', SearchDirective) .directive('atJobStats', StatsDirective) diff --git a/awx/ui/client/features/output/message.service.js b/awx/ui/client/features/output/message.service.js new file mode 100644 index 0000000000..7e15ff302f --- /dev/null +++ b/awx/ui/client/features/output/message.service.js @@ -0,0 +1,41 @@ +function MessageService () { + const listeners = {}; + const registry = {}; + + this.subscribe = (key, listener) => { + registry[key] = registry[key] || 0; + + listeners[key] = listeners[key] || {}; + listeners[key][registry[key]] = listener; + + const unsubscribe = this.createCallback(key, registry[key]); + + registry[key]++; + + return unsubscribe; + }; + + this.dispatch = (key, data) => { + if (!listeners[key]) { + return; + } + + const indices = Object.keys(listeners[key]); + + for (let i = 0; i < indices.length; i++) { + listeners[key][indices[i]](data); + } + }; + + this.createCallback = (key, index) => { + const callback = () => { + if (listeners[key]) { + delete listeners[key][index]; + } + }; + + return callback; + }; +} + +export default MessageService; From 58beb9640c92d0f77e4f0f77f8eeba0bc5890b10 Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Mon, 7 May 2018 01:00:48 -0400 Subject: [PATCH 2/3] remove watchers --- .../features/output/details.directive.js | 25 +-- .../features/output/search.directive.js | 12 +- .../client/features/output/stats.directive.js | 26 ++- .../client/features/output/status.service.js | 162 ++++++++++-------- 4 files changed, 119 insertions(+), 106 deletions(-) diff --git a/awx/ui/client/features/output/details.directive.js b/awx/ui/client/features/output/details.directive.js index f13de2821b..510173d9ad 100644 --- a/awx/ui/client/features/output/details.directive.js +++ b/awx/ui/client/features/output/details.directive.js @@ -10,7 +10,6 @@ let parse; let prompt; let resource; let strings; -let status; let wait; let vm; @@ -553,9 +552,9 @@ function AtJobDetailsController ( _error_, _prompt_, _strings_, - _status_, _wait_, _parse_, + { subscribe } ) { vm = this || {}; @@ -567,7 +566,6 @@ function AtJobDetailsController ( parse = _parse_; prompt = _prompt_; strings = _strings_; - status = _status_; wait = _wait_; vm.init = _$scope_ => { @@ -610,18 +608,13 @@ function AtJobDetailsController ( vm.toggleJobTags = toggleJobTags; vm.toggleSkipTags = toggleSkipTags; - const observe = (getter, transform, key) => { - $scope.$watch(getter, value => { vm[key] = transform(value); }); - }; - - observe(status.getStarted, getStartDetails, 'started'); - observe(status.getFinished, getFinishDetails, 'finished'); - observe(status.getProjectUpdateId, getProjectUpdateDetails, 'projectUpdate'); - observe(status.getProjectStatus, getProjectStatusDetails, 'projectStatus'); - - $scope.$watch(status.getJobStatus, jobStatus => { - vm.status = getStatusDetails(jobStatus); - vm.job.status = jobStatus; + subscribe(({ status, started, finished, scm }) => { + vm.job.status = status; + vm.status = getStatusDetails(status); + vm.started = getStartDetails(started); + vm.finished = getFinishDetails(finished); + vm.projectUpdate = getProjectUpdateDetails(scm.id); + vm.projectStatus = getProjectStatusDetails(scm.status); }); }; } @@ -633,9 +626,9 @@ AtJobDetailsController.$inject = [ 'ProcessErrors', 'Prompt', 'JobStrings', - 'JobStatusService', 'Wait', 'ParseVariableString', + 'JobStatusService', ]; function atJobDetailsLink (scope, el, attrs, controllers) { diff --git a/awx/ui/client/features/output/search.directive.js b/awx/ui/client/features/output/search.directive.js index 0a688f92bb..6259013200 100644 --- a/awx/ui/client/features/output/search.directive.js +++ b/awx/ui/client/features/output/search.directive.js @@ -8,7 +8,6 @@ const PLACEHOLDER_RUNNING = 'CANNOT SEARCH RUNNING JOB'; const PLACEHOLDER_DEFAULT = 'SEARCH'; let $state; -let status; let qs; let vm; @@ -71,9 +70,8 @@ function atJobSearchLink (scope, el, attrs, controllers) { atJobSearchController.init(scope); } -function AtJobSearchController (_$state_, _status_, _qs_) { +function AtJobSearchController (_$state_, _qs_, { subscribe }) { $state = _$state_; - status = _status_; qs = _qs_; vm = this || {}; @@ -97,17 +95,17 @@ function AtJobSearchController (_$state_, _status_, _qs_) { vm.placeholder = PLACEHOLDER_DEFAULT; vm.relatedFields = scope.relatedFields || []; - scope.$watch(status.isRunning, value => { - vm.disabled = value; - vm.placeholder = value ? PLACEHOLDER_RUNNING : PLACEHOLDER_DEFAULT; + subscribe(({ running }) => { + vm.disabled = running; + vm.placeholder = running ? PLACEHOLDER_RUNNING : PLACEHOLDER_DEFAULT; }); }; } AtJobSearchController.$inject = [ '$state', - 'JobStatusService', 'QuerySet', + 'JobStatusService', ]; function atJobSearch () { diff --git a/awx/ui/client/features/output/stats.directive.js b/awx/ui/client/features/output/stats.directive.js index 789fc29de6..182ab27479 100644 --- a/awx/ui/client/features/output/stats.directive.js +++ b/awx/ui/client/features/output/stats.directive.js @@ -1,6 +1,5 @@ const templateUrl = require('~features/output/stats.partial.html'); -let status; let strings; function createStatsBarTooltip (key, count) { @@ -16,8 +15,7 @@ function atJobStatsLink (scope, el, attrs, controllers) { atJobStatsController.init(scope); } -function AtJobStatsController (_strings_, _status_) { - status = _status_; +function AtJobStatsController (_strings_, { subscribe }) { strings = _strings_; const vm = this || {}; @@ -36,18 +34,17 @@ function AtJobStatsController (_strings_, _status_) { vm.toggleStdoutFullscreenTooltip = strings.get('expandCollapse.EXPAND'); - vm.setHostStatusCounts(status.getHostStatusCounts()); - - scope.$watch(status.getPlayCount, value => { vm.plays = value; }); - scope.$watch(status.getTaskCount, value => { vm.tasks = value; }); - scope.$watch(status.getElapsed, value => { vm.elapsed = value; }); - scope.$watch(status.getHostCount, value => { vm.hosts = value; }); - scope.$watch(status.isRunning, value => { vm.running = value; }); - - scope.$watchCollection(status.getHostStatusCounts, vm.setHostStatusCounts); + subscribe(({ running, elapsed, counts, stats, hosts }) => { + vm.plays = counts.plays; + vm.tasks = counts.tasks; + vm.hosts = counts.hosts; + vm.elapsed = elapsed; + vm.running = running; + vm.setHostStatusCounts(stats, hosts); + }); }; - vm.setHostStatusCounts = counts => { + vm.setHostStatusCounts = (stats, counts) => { Object.keys(counts).forEach(key => { const count = counts[key]; const statusBarElement = $(`.HostStatusBar-${key}`); @@ -57,7 +54,7 @@ function AtJobStatsController (_strings_, _status_) { vm.tooltips[key] = createStatsBarTooltip(key, count); }); - vm.statsAreAvailable = Boolean(status.getStatsEvent()); + vm.statsAreAvailable = stats; }; vm.toggleFullscreen = () => { @@ -78,7 +75,6 @@ function atJobStats () { controller: [ 'JobStrings', 'JobStatusService', - '$scope', AtJobStatsController ], scope: { diff --git a/awx/ui/client/features/output/status.service.js b/awx/ui/client/features/output/status.service.js index 638d2ff399..12e3fd2544 100644 --- a/awx/ui/client/features/output/status.service.js +++ b/awx/ui/client/features/output/status.service.js @@ -6,34 +6,46 @@ const TASK_START = 'playbook_on_task_start'; const HOST_STATUS_KEYS = ['dark', 'failures', 'changed', 'ok', 'skipped']; const FINISHED = ['successful', 'failed', 'error']; -let moment; - -function JobStatusService (_moment_) { - moment = _moment_; +function JobStatusService (moment, message) { + this.dispatch = () => message.dispatch('status', this.state); + this.subscribe = listener => message.subscribe('status', listener); this.init = ({ resource }) => { + const { model } = resource; + + this.created = model.get('created'); + this.job = model.get('id'); + this.jobType = model.get('type'); + this.project = model.get('project'); + + this.active = false; + this.latestTime = null; this.counter = -1; - this.created = resource.model.get('created'); - this.job = resource.model.get('id'); - this.jobType = resource.model.get('type'); - this.project = resource.model.get('project'); - this.elapsed = resource.model.get('elapsed'); - this.started = resource.model.get('started'); - this.finished = resource.model.get('finished'); - this.jobStatus = resource.model.get('status'); - this.projectStatus = resource.model.get('summary_fields.project_update.status'); - this.projectUpdateId = resource.model.get('summary_fields.project_update.id'); + this.state = { + running: false, + stats: false, + counts: { + plays: null, + tasks: null, + hosts: null, + }, + hosts: {}, + status: model.get('status'), + elapsed: model.get('elapsed'), + started: model.get('started'), + finished: model.get('finished'), + scm: { + id: model.get('summary_fields.project_update.id'), + status: model.get('summary_fields.project_update.status') + }, + }; - this.latestTime = null; - this.playCount = null; - this.taskCount = null; - this.hostCount = null; - this.active = false; - this.hostStatusCounts = {}; - - this.statsEvent = resource.stats; + this.setStatsEvent(resource.stats); this.updateStats(); + this.updateRunningState(); + + this.dispatch(); }; this.pushStatusEvent = data => { @@ -59,24 +71,46 @@ function JobStatusService (_moment_) { if (isLatest) { this.counter = data.counter; this.latestTime = data.created; - this.elapsed = moment(data.created).diff(this.created, 'seconds'); + this.setElapsed(moment(data.created).diff(this.created, 'seconds')); } if (data.event === JOB_START) { - this.started = this.started || data.created; + this.setStarted(this.state.started || data.created); } if (data.event === PLAY_START) { - this.playCount++; + this.state.counts.plays++; } if (data.event === TASK_START) { - this.taskCount++; + this.state.counts.tasks++; } if (data.event === JOB_END) { - this.statsEvent = data; + this.setStatsEvent(data); } + + this.dispatch(); + }; + + this.isExpectingStatsEvent = () => (this.jobType === 'job') || + (this.jobType === 'project_update'); + + this.updateStats = () => { + this.updateHostCounts(); + + if (this.statsEvent) { + this.state.stats = true; + this.setFinished(this.statsEvent.created); + this.setJobStatus(this.statsEvent.failed ? 'failed' : 'successful'); + } + }; + + this.updateRunningState = () => { + this.state.running = (Boolean(this.state.started) && !this.state.finished) || + (this.state.status === 'running') || + (this.state.status === 'pending') || + (this.state.status === 'waiting'); }; this.updateHostCounts = () => { @@ -98,74 +132,66 @@ function JobStatusService (_moment_) { }); }); - this.hostCount = countedHostNames.length; - this.hostStatusCounts = counts; + this.state.counts.hosts = countedHostNames.length; + this.setHostStatusCounts(counts); }; - this.updateStats = () => { - this.updateHostCounts(); - - if (this.statsEvent) { - this.setFinished(this.statsEvent.created); - this.setJobStatus(this.statsEvent.failed ? 'failed' : 'successful'); - } - }; - - this.isRunning = () => (Boolean(this.started) && !this.finished) || - (this.jobStatus === 'running') || - (this.jobStatus === 'pending') || - (this.jobStatus === 'waiting'); - - this.isExpectingStatsEvent = () => (this.jobType === 'job') || - (this.jobType === 'project_update'); - - this.getPlayCount = () => this.playCount; - this.getTaskCount = () => this.taskCount; - this.getHostCount = () => this.hostCount; - this.getHostStatusCounts = () => this.hostStatusCounts || {}; - this.getJobStatus = () => this.jobStatus; - this.getProjectStatus = () => this.projectStatus; - this.getProjectUpdateId = () => this.projectUpdateId; - this.getElapsed = () => this.elapsed; - this.getStatsEvent = () => this.statsEvent; - this.getStarted = () => this.started; - this.getFinished = () => this.finished; - this.setJobStatus = status => { - this.jobStatus = status; + this.state.status = status; if (!this.isExpectingStatsEvent() && _.includes(FINISHED, status)) { if (this.latestTime) { this.setFinished(this.latestTime); - - if (!this.started && this.elapsed) { - this.started = moment(this.latestTime).subtract(this.elapsed, 'seconds'); + if (!this.state.started && this.state.elapsed) { + this.setStarted(moment(this.latestTime) + .subtract(this.state.elapsed, 'seconds')); } } } + + this.updateRunningState(); + }; + + this.setElapsed = elapsed => { + this.state.elapsed = elapsed; + }; + + this.setStarted = started => { + this.state.started = started; + this.updateRunningState(); }; this.setProjectStatus = status => { - this.projectStatus = status; + this.state.scm.status = status; }; this.setProjectUpdateId = id => { - this.projectUpdateId = id; + this.state.scm.id = id; }; this.setFinished = time => { - this.finished = time; + this.state.finished = time; + this.updateRunningState(); + }; + + this.setStatsEvent = data => { + this.statsEvent = data; + }; + + this.setHostStatusCounts = counts => { + this.state.hosts = counts; }; this.resetCounts = () => { - this.playCount = 0; - this.taskCount = 0; - this.hostCount = 0; + this.state.counts.plays = 0; + this.state.counts.tasks = 0; + this.state.counts.hosts = 0; }; } JobStatusService.$inject = [ 'moment', + 'JobMessageService', ]; export default JobStatusService; From 42b88c640083b935c948d4b188e459bddf04c723 Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Mon, 7 May 2018 01:07:28 -0400 Subject: [PATCH 3/3] move directive code to components --- ...ails.directive.js => details.component.js} | 65 ++++++++---------- .../features/output/index.controller.js | 18 ++--- awx/ui/client/features/output/index.js | 14 ++-- awx/ui/client/features/output/index.view.html | 14 ++-- ...earch.directive.js => search.component.js} | 50 ++++++-------- ...{stats.directive.js => stats.component.js} | 67 ++++++++----------- .../client/features/output/stats.partial.html | 4 +- 7 files changed, 99 insertions(+), 133 deletions(-) rename awx/ui/client/features/output/{details.directive.js => details.component.js} (93%) rename awx/ui/client/features/output/{search.directive.js => search.component.js} (76%) rename awx/ui/client/features/output/{stats.directive.js => stats.component.js} (54%) diff --git a/awx/ui/client/features/output/details.directive.js b/awx/ui/client/features/output/details.component.js similarity index 93% rename from awx/ui/client/features/output/details.directive.js rename to awx/ui/client/features/output/details.component.js index 510173d9ad..d74cea977a 100644 --- a/awx/ui/client/features/output/details.directive.js +++ b/awx/ui/client/features/output/details.component.js @@ -2,7 +2,6 @@ const templateUrl = require('~features/output/details.partial.html'); let $http; let $filter; -let $scope; let $state; let error; @@ -371,7 +370,7 @@ function getJobTagDetails () { let jobTags; if (tagString) { - jobTags = tagString.split(','); + jobTags = tagString.split(',').filter(tag => tag !== ''); } else { jobTags = []; } @@ -383,7 +382,7 @@ function getJobTagDetails () { const label = 'Job Tags'; const more = false; - const value = jobTags.filter(tag => tag !== '').map($filter('sanitize')); + const value = jobTags.map($filter('sanitize')); return { label, more, value }; } @@ -394,7 +393,7 @@ function getSkipTagDetails () { let skipTags; if (tagString) { - skipTags = tagString.split(','); + skipTags = tagString.split(',').filter(tag => tag !== ''); } else { skipTags = []; } @@ -405,7 +404,7 @@ function getSkipTagDetails () { const label = 'Skip Tags'; const more = false; - const value = skipTags.filter(tag => tag !== '').map($filter('sanitize')); + const value = skipTags.map($filter('sanitize')); return { label, more, value }; } @@ -445,7 +444,7 @@ function createErrorHandler (path, action) { const hdr = strings.get('error.HEADER'); const msg = strings.get('error.CALL', { path, action, status: res.status }); - error($scope, res.data, res.status, null, { hdr, msg }); + error(null, res.data, res.status, null, { hdr, msg }); }; } @@ -545,7 +544,7 @@ function deleteJob () { prompt({ hdr, resourceName, body, actionText, action }); } -function AtJobDetailsController ( +function JobDetailsController ( _$http_, _$filter_, _$state_, @@ -554,23 +553,24 @@ function AtJobDetailsController ( _strings_, _wait_, _parse_, - { subscribe } + { subscribe }, ) { vm = this || {}; $http = _$http_; $filter = _$filter_; $state = _$state_; - error = _error_; + parse = _parse_; prompt = _prompt_; strings = _strings_; wait = _wait_; - vm.init = _$scope_ => { - $scope = _$scope_; - resource = $scope.resource; // eslint-disable-line prefer-destructuring + let unsubscribe; + + vm.$onInit = () => { + resource = this.resource; // eslint-disable-line prefer-destructuring vm.status = getStatusDetails(); vm.started = getStartDetails(); @@ -604,22 +604,26 @@ function AtJobDetailsController ( vm.cancelJob = cancelJob; vm.deleteJob = deleteJob; - vm.toggleLabels = toggleLabels; vm.toggleJobTags = toggleJobTags; vm.toggleSkipTags = toggleSkipTags; + vm.toggleLabels = toggleLabels; - subscribe(({ status, started, finished, scm }) => { - vm.job.status = status; - vm.status = getStatusDetails(status); + unsubscribe = subscribe(({ status, started, finished, scm }) => { vm.started = getStartDetails(started); vm.finished = getFinishDetails(finished); vm.projectUpdate = getProjectUpdateDetails(scm.id); vm.projectStatus = getProjectStatusDetails(scm.status); + vm.status = getStatusDetails(status); + vm.job.status = status; }); }; + + vm.$onDestroy = () => { + unsubscribe(); + }; } -AtJobDetailsController.$inject = [ +JobDetailsController.$inject = [ '$http', '$filter', '$state', @@ -631,22 +635,11 @@ AtJobDetailsController.$inject = [ 'JobStatusService', ]; -function atJobDetailsLink (scope, el, attrs, controllers) { - const [atDetailsController] = controllers; - - atDetailsController.init(scope); -} - -function atJobDetails () { - return { - templateUrl, - restrict: 'E', - require: ['atJobDetails'], - controllerAs: 'vm', - link: atJobDetailsLink, - controller: AtJobDetailsController, - scope: { resource: '=', }, - }; -} - -export default atJobDetails; +export default { + templateUrl, + controller: JobDetailsController, + controllerAs: 'vm', + bindings: { + resource: '<' + }, +}; diff --git a/awx/ui/client/features/output/index.controller.js b/awx/ui/client/features/output/index.controller.js index 488d994dc2..e84c93d708 100644 --- a/awx/ui/client/features/output/index.controller.js +++ b/awx/ui/client/features/output/index.controller.js @@ -38,9 +38,8 @@ function JobsIndexController ( vm.clear = devClear; // Expand/collapse - // vm.toggle = toggle; - // vm.expand = expand; - vm.isExpanded = true; + vm.expanded = false; + vm.toggleExpanded = toggleExpanded; // Panel vm.resource = resource; @@ -55,10 +54,6 @@ function JobsIndexController ( up: scrollPageUp }; - vm.fullscreen = { - isFullscreen: false - }; - render.requestAnimationFrame(() => init()); } @@ -96,13 +91,14 @@ function init () { }, onStop () { status.updateStats(); + status.dispatch(); } }); $scope.$on(resource.ws.events, handleJobEvent); $scope.$on(resource.ws.status, handleStatusEvent); - if (!status.isRunning()) { + if (!status.state.running) { next(); } } @@ -281,9 +277,9 @@ function scrollIsAtRest (isAtRest) { vm.scroll.showBackToTop = !isAtRest; } -// function expand () { -// vm.toggle(parent, true); -// } +function toggleExpanded () { + vm.expanded = !vm.expanded; +} // function showHostDetails (id) { // jobEvent.request('get', id) diff --git a/awx/ui/client/features/output/index.js b/awx/ui/client/features/output/index.js index 372d28221f..6b14296553 100644 --- a/awx/ui/client/features/output/index.js +++ b/awx/ui/client/features/output/index.js @@ -11,9 +11,9 @@ import StatusService from '~features/output/status.service'; import MessageService from '~features/output/message.service'; import LegacyRedirect from '~features/output/legacy.route'; -import DetailsDirective from '~features/output/details.directive'; -import SearchDirective from '~features/output/search.directive'; -import StatsDirective from '~features/output/stats.directive'; +import DetailsComponent from '~features/output/details.component'; +import SearchComponent from '~features/output/search.component'; +import StatsComponent from '~features/output/stats.component'; import HostEvent from './host-event/index'; const Template = require('~features/output/index.view.html'); @@ -176,7 +176,7 @@ function JobsRun ($stateRegistry, strings) { templateUrl: Template, controller: Controller, controllerAs: 'vm' - } + }, }, resolve: { webSocketConnection: [ @@ -223,9 +223,9 @@ angular .service('JobEventEngine', EngineService) .service('JobStatusService', StatusService) .service('JobMessageService', MessageService) - .directive('atJobDetails', DetailsDirective) - .directive('atJobSearch', SearchDirective) - .directive('atJobStats', StatsDirective) + .component('atJobSearch', SearchComponent) + .component('atJobStats', StatsComponent) + .component('atJobDetails', DetailsComponent) .run(JobsRun) .run(LegacyRedirect); diff --git a/awx/ui/client/features/output/index.view.html b/awx/ui/client/features/output/index.view.html index f25171f9f2..cb932fafd3 100644 --- a/awx/ui/client/features/output/index.view.html +++ b/awx/ui/client/features/output/index.view.html @@ -1,23 +1,25 @@
- - + + + - +
{{ vm.title }}
+ expanded="vm.expanded">
-
+
+ ng-class="{ 'fa-minus': vm.expanded, 'fa-plus': !vm.expanded }">
diff --git a/awx/ui/client/features/output/search.directive.js b/awx/ui/client/features/output/search.component.js similarity index 76% rename from awx/ui/client/features/output/search.directive.js rename to awx/ui/client/features/output/search.component.js index 6259013200..d1e37edd14 100644 --- a/awx/ui/client/features/output/search.directive.js +++ b/awx/ui/client/features/output/search.component.js @@ -64,13 +64,7 @@ function clearSearch () { $state.transitionTo($state.current, $state.params, searchReloadOptions); } -function atJobSearchLink (scope, el, attrs, controllers) { - const [atJobSearchController] = controllers; - - atJobSearchController.init(scope); -} - -function AtJobSearchController (_$state_, _qs_, { subscribe }) { +function JobSearchController (_$state_, _qs_, { subscribe }) { $state = _$state_; qs = _qs_; @@ -89,39 +83,33 @@ function AtJobSearchController (_$state_, _qs_, { subscribe }) { vm.removeSearchTag = removeSearchTag; vm.submitSearch = submitSearch; - vm.init = scope => { - vm.examples = scope.examples || searchKeyExamples; - vm.fields = scope.fields || searchKeyFields; - vm.placeholder = PLACEHOLDER_DEFAULT; - vm.relatedFields = scope.relatedFields || []; + let unsubscribe; - subscribe(({ running }) => { + vm.$onInit = () => { + vm.examples = searchKeyExamples; + vm.fields = searchKeyFields; + vm.placeholder = PLACEHOLDER_DEFAULT; + vm.relatedFields = []; + + unsubscribe = subscribe(({ running }) => { vm.disabled = running; vm.placeholder = running ? PLACEHOLDER_RUNNING : PLACEHOLDER_DEFAULT; }); }; + + vm.$onDestroy = () => { + unsubscribe(); + }; } -AtJobSearchController.$inject = [ +JobSearchController.$inject = [ '$state', 'QuerySet', 'JobStatusService', ]; -function atJobSearch () { - return { - templateUrl, - restrict: 'E', - require: ['atJobSearch'], - controllerAs: 'vm', - link: atJobSearchLink, - controller: AtJobSearchController, - scope: { - examples: '=', - fields: '=', - relatedFields: '=', - }, - }; -} - -export default atJobSearch; +export default { + templateUrl, + controller: JobSearchController, + controllerAs: 'vm', +}; diff --git a/awx/ui/client/features/output/stats.directive.js b/awx/ui/client/features/output/stats.component.js similarity index 54% rename from awx/ui/client/features/output/stats.directive.js rename to awx/ui/client/features/output/stats.component.js index 182ab27479..a7a0ec61f3 100644 --- a/awx/ui/client/features/output/stats.directive.js +++ b/awx/ui/client/features/output/stats.component.js @@ -1,6 +1,6 @@ const templateUrl = require('~features/output/stats.partial.html'); -let strings; +let vm; function createStatsBarTooltip (key, count) { const label = `${key}`; @@ -9,32 +9,21 @@ function createStatsBarTooltip (key, count) { return `${label}${badge}`; } -function atJobStatsLink (scope, el, attrs, controllers) { - const [atJobStatsController] = controllers; +function JobStatsController (strings, { subscribe }) { + vm = this || {}; - atJobStatsController.init(scope); -} - -function AtJobStatsController (_strings_, { subscribe }) { - strings = _strings_; - - const vm = this || {}; + let unsubscribe; vm.tooltips = { running: strings.get('status.RUNNING'), unavailable: strings.get('status.UNAVAILABLE'), }; - vm.init = scope => { - const { resource } = scope; - - vm.fullscreen = scope.fullscreen; - - vm.download = resource.model.get('related.stdout'); - + vm.$onInit = () => { + vm.download = vm.resource.model.get('related.stdout'); vm.toggleStdoutFullscreenTooltip = strings.get('expandCollapse.EXPAND'); - subscribe(({ running, elapsed, counts, stats, hosts }) => { + unsubscribe = subscribe(({ running, elapsed, counts, stats, hosts }) => { vm.plays = counts.plays; vm.tasks = counts.tasks; vm.hosts = counts.hosts; @@ -44,6 +33,10 @@ function AtJobStatsController (_strings_, { subscribe }) { }); }; + vm.$onDestroy = () => { + unsubscribe(); + }; + vm.setHostStatusCounts = (stats, counts) => { Object.keys(counts).forEach(key => { const count = counts[key]; @@ -57,31 +50,25 @@ function AtJobStatsController (_strings_, { subscribe }) { vm.statsAreAvailable = stats; }; - vm.toggleFullscreen = () => { - vm.fullscreen.isFullscreen = !vm.fullscreen.isFullscreen; - vm.toggleStdoutFullscreenTooltip = vm.fullscreen.isFullscreen ? + vm.toggleExpanded = () => { + vm.expanded = !vm.expanded; + vm.toggleStdoutFullscreenTooltip = vm.expanded ? strings.get('expandCollapse.COLLAPSE') : strings.get('expandCollapse.EXPAND'); }; } -function atJobStats () { - return { - templateUrl, - restrict: 'E', - require: ['atJobStats'], - controllerAs: 'vm', - link: atJobStatsLink, - controller: [ - 'JobStrings', - 'JobStatusService', - AtJobStatsController - ], - scope: { - resource: '=', - fullscreen: '=' - } - }; -} +JobStatsController.$inject = [ + 'JobStrings', + 'JobStatusService', +]; -export default atJobStats; +export default { + templateUrl, + controller: JobStatsController, + controllerAs: 'vm', + bindings: { + resource: '<', + expanded: '=', + }, +}; diff --git a/awx/ui/client/features/output/stats.partial.html b/awx/ui/client/features/output/stats.partial.html index 6427735236..c55ba4bc8d 100644 --- a/awx/ui/client/features/output/stats.partial.html +++ b/awx/ui/client/features/output/stats.partial.html @@ -31,8 +31,8 @@ aw-tool-tip="{{ vm.toggleStdoutFullscreenTooltip }}" data-tip-watch="vm.toggleStdoutFullscreenTooltip" data-placement="top" - ng-class="{'at-Input-button--active': vm.fullscreen.isFullscreen}" - ng-click="vm.toggleFullscreen()"> + ng-class="{'at-Input-button--active': vm.expanded}" + ng-click="vm.toggleExpanded()">