diff --git a/awx/ui/client/features/output/index.controller.js b/awx/ui/client/features/output/index.controller.js
index 238adc11f4..0b87c47552 100644
--- a/awx/ui/client/features/output/index.controller.js
+++ b/awx/ui/client/features/output/index.controller.js
@@ -48,13 +48,10 @@ function JobsIndexController (job, JobEventModel, _$sce_, _$timeout_, _$scope_,
vm.showHostDetails = showHostDetails;
vm.menu = {
- expand: menuExpand,
- scrollToBottom: menuScrollToBottom,
- scrollToTop: menuScrollToTop
- };
-
- vm.state = {
- expand: true
+ top: {
+ expand: menuExpand,
+ isExpanded: false
+ }
};
$timeout(() => {
@@ -66,22 +63,9 @@ function JobsIndexController (job, JobEventModel, _$sce_, _$timeout_, _$scope_,
}
function menuExpand () {
- vm.state.expand = !vm.state.expand;
vm.toggle(meta.parent);
}
-function menuScrollToBottom () {
- const container = $('.at-Stdout-container')[0];
-
- container.scrollTop = container.scrollHeight;
-}
-
-function menuScrollToTop () {
- const container = $('.at-Stdout-container')[0];
-
- container.scrollTop = 0;
-}
-
function parseEvents (events) {
events.sort(orderByLineNumber);
diff --git a/awx/ui/client/features/output/index.view.html b/awx/ui/client/features/output/index.view.html
index 0d92977ee5..7850adacb3 100644
--- a/awx/ui/client/features/output/index.view.html
+++ b/awx/ui/client/features/output/index.view.html
@@ -7,17 +7,7 @@
-
+
diff --git a/awx/ui/client/lib/components/code/events.directive.js b/awx/ui/client/lib/components/code/events.directive.js
new file mode 100644
index 0000000000..8426bf3ae6
--- /dev/null
+++ b/awx/ui/client/lib/components/code/events.directive.js
@@ -0,0 +1,104 @@
+import Ansi from 'ansi-to-html';
+import hasAnsi from 'has-ansi';
+
+const templateUrl = require('~components/code/events.partial.html');
+
+let $sce;
+let $timeout;
+let ansi;
+
+function atOutputEventLink (scope, element, attrs, controller) {
+ controller.init(scope, element);
+}
+
+function AtOutputEventController (_$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;
+ }
+ };
+}
+
+AtOutputEventController.$inject = [
+ '$sce',
+ '$timeout',
+];
+
+function render (stdout) {
+ 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 atOutputEvent () {
+ return {
+ restrict: 'E',
+ transclude: true,
+ replace: true,
+ require: 'atOutputEvent',
+ templateUrl,
+ controller: AtOutputEventController,
+ controllerAs: 'vm',
+ link: atOutputEventLink,
+ scope: {
+ state: '=',
+ }
+ };
+}
+
+export default atOutputEvent;
diff --git a/awx/ui/client/lib/components/code/events.partial.html b/awx/ui/client/lib/components/code/events.partial.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/awx/ui/client/lib/components/code/menu-bottom.directive.js b/awx/ui/client/lib/components/code/menu-bottom.directive.js
new file mode 100644
index 0000000000..5b15a7bc10
--- /dev/null
+++ b/awx/ui/client/lib/components/code/menu-bottom.directive.js
@@ -0,0 +1,41 @@
+const templateUrl = require('~components/code/menu-bottom.partial.html');
+
+function atCodeMenuBottomLink (scope, element, attrs, controller) {
+ controller.init(scope, element);
+}
+
+function AtCodeMenuBottomController () {
+ const vm = this || {};
+
+ let element;
+
+ vm.init = (_scope_, _element_) => {
+ element = _element_;
+ };
+
+ vm.scroll = () => {
+ const container = element.find('.at-Stdout-container')[0];
+
+ container.scrollTop = container.scrollHeight;
+ };
+}
+
+AtCodeMenuBottomController.$inject = [];
+
+function atCodeMenuBottom () {
+ return {
+ restrict: 'E',
+ transclude: true,
+ replace: true,
+ require: 'atCodeMenuBottom',
+ templateUrl,
+ controller: AtCodeMenuBottomController,
+ controllerAs: 'vm',
+ link: atCodeMenuBottomLink,
+ scope: {
+ state: '=',
+ }
+ };
+}
+
+export default atCodeMenuBottom;
diff --git a/awx/ui/client/lib/components/code/menu-bottom.partial.html b/awx/ui/client/lib/components/code/menu-bottom.partial.html
new file mode 100644
index 0000000000..1a0717a360
--- /dev/null
+++ b/awx/ui/client/lib/components/code/menu-bottom.partial.html
@@ -0,0 +1,7 @@
+
diff --git a/awx/ui/client/lib/components/code/menu-top.directive.js b/awx/ui/client/lib/components/code/menu-top.directive.js
new file mode 100644
index 0000000000..824e24123f
--- /dev/null
+++ b/awx/ui/client/lib/components/code/menu-top.directive.js
@@ -0,0 +1,52 @@
+const templateUrl = require('~components/code/menu-top.partial.html');
+
+function atCodeMenuTopLink (scope, element, attrs, controller) {
+ controller.init(scope, element);
+}
+
+function AtCodeMenuTopController () {
+ const vm = this || {};
+
+ let element;
+ let scope;
+
+ vm.init = (_scope_, _element_) => {
+ scope = _scope_;
+ element = _element_;
+
+ scope.state.isExpanded = scope.state.isExpanded || false;
+ };
+
+ vm.scroll = () => {
+ const container = element.parent().find('.at-Stdout-container')[0];
+
+ console.log(container);
+
+ container.scrollTop = 0;
+ };
+
+ vm.expand = () => {
+ scope.state.isExpanded = !scope.state.isExpanded;
+ scope.state.expand();
+ };
+}
+
+AtCodeMenuTopController.$inject = [];
+
+function atCodeMenuTop () {
+ return {
+ restrict: 'E',
+ transclude: true,
+ replace: true,
+ require: 'atCodeMenuTop',
+ templateUrl,
+ controller: AtCodeMenuTopController,
+ controllerAs: 'vm',
+ link: atCodeMenuTopLink,
+ scope: {
+ state: '=',
+ }
+ };
+}
+
+export default atCodeMenuTop;
diff --git a/awx/ui/client/lib/components/code/menu-top.partial.html b/awx/ui/client/lib/components/code/menu-top.partial.html
new file mode 100644
index 0000000000..2e21dc1b8b
--- /dev/null
+++ b/awx/ui/client/lib/components/code/menu-top.partial.html
@@ -0,0 +1,12 @@
+
diff --git a/awx/ui/client/lib/components/output/stdout.directive.js b/awx/ui/client/lib/components/code/stdout.directive.js
similarity index 95%
rename from awx/ui/client/lib/components/output/stdout.directive.js
rename to awx/ui/client/lib/components/code/stdout.directive.js
index 880e2c6eb6..1f32b5ca7f 100644
--- a/awx/ui/client/lib/components/output/stdout.directive.js
+++ b/awx/ui/client/lib/components/code/stdout.directive.js
@@ -1,7 +1,7 @@
import Ansi from 'ansi-to-html';
import hasAnsi from 'has-ansi';
-const templateUrl = require('~components/output/stdout.partial.html');
+const templateUrl = require('~components/code/stdout.partial.html');
let $sce;
let $timeout;
@@ -51,7 +51,6 @@ AtOutputStdoutController.$inject = [
];
function render (stdout) {
- console.log('render');
const html = $sce.trustAsHtml(parseStdout(stdout));
$timeout(() => {
diff --git a/awx/ui/client/lib/components/output/stdout.partial.html b/awx/ui/client/lib/components/code/stdout.partial.html
similarity index 100%
rename from awx/ui/client/lib/components/output/stdout.partial.html
rename to awx/ui/client/lib/components/code/stdout.partial.html
diff --git a/awx/ui/client/lib/components/index.js b/awx/ui/client/lib/components/index.js
index 339747ad67..bf45c63a6d 100644
--- a/awx/ui/client/lib/components/index.js
+++ b/awx/ui/client/lib/components/index.js
@@ -1,6 +1,10 @@
import atLibServices from '~services';
import actionGroup from '~components/action/action-group.directive';
+import codeMenuBottom from '~components/code/menu-bottom.directive';
+import codeMenuTop from '~components/code/menu-top.directive';
+import codeEvents from '~components/code/events.directive';
+import codeStdout from '~components/code/stdout.directive';
import divider from '~components/utility/divider.directive';
import form from '~components/form/form.directive';
import formAction from '~components/form/action.directive';
@@ -20,7 +24,6 @@ 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';
@@ -46,6 +49,10 @@ angular
atLibServices
])
.directive('atActionGroup', actionGroup)
+ .directive('atCodeEvents', codeEvents)
+ .directive('atCodeMenuBottom', codeMenuBottom)
+ .directive('atCodeMenuTop', codeMenuTop)
+ .directive('atCodeStdout', codeStdout)
.directive('atDivider', divider)
.directive('atForm', form)
.directive('atFormAction', formAction)
@@ -69,7 +76,6 @@ angular
.directive('atRowItem', rowItem)
.directive('atRowAction', rowAction)
.directive('atModal', modal)
- .directive('atOutputStdout', outputStdout)
.directive('atPanel', panel)
.directive('atPanelBody', panelBody)
.directive('atPanelHeading', panelHeading)