diff --git a/awx/ui/client/legacy-styles/ansible-ui.less b/awx/ui/client/legacy-styles/ansible-ui.less
index 5a825ba5c634..ce073116bbe7 100644
--- a/awx/ui/client/legacy-styles/ansible-ui.less
+++ b/awx/ui/client/legacy-styles/ansible-ui.less
@@ -1713,33 +1713,6 @@ tr td button i {
}
}
-/* Activity Stream Widget */
-
- #stream-container {
- display: none;
- border-radius: 8px;
- z-index: 20; /* has to be greater than tree selector */
-
- .nav-path {
- margin-bottom: 15px;
- margin-top: 5px;
- }
-
- padding-left: 10px;
- padding-right: 10px;
- }
-
- #stream-content {
- border: 1px solid @grey;
- border-radius: 8px;
- padding: 8px;
-
- h5 {
- margin-top: 0;
- margin-bottom: 20px;
- }
- }
-
/* job stdout */
#pre-container {
diff --git a/awx/ui/client/src/activity-stream/activitystream.controller.js b/awx/ui/client/src/activity-stream/activitystream.controller.js
new file mode 100644
index 000000000000..13d2ccecce89
--- /dev/null
+++ b/awx/ui/client/src/activity-stream/activitystream.controller.js
@@ -0,0 +1,21 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+/**
+ * @ngdoc function
+ * @name controllers.function:Activity Stream
+ * @description This controller controls the activity stream.
+*/
+function activityStreamController($scope, Stream) {
+
+ // Open the stream
+ Stream({
+ scope: $scope
+ });
+
+}
+
+export default ['$scope', 'Stream', activityStreamController];
diff --git a/awx/ui/client/src/activity-stream/activitystream.partial.html b/awx/ui/client/src/activity-stream/activitystream.partial.html
new file mode 100644
index 000000000000..8c6263b11d2c
--- /dev/null
+++ b/awx/ui/client/src/activity-stream/activitystream.partial.html
@@ -0,0 +1,3 @@
+
diff --git a/awx/ui/client/src/activity-stream/activitystream.route.js b/awx/ui/client/src/activity-stream/activitystream.route.js
new file mode 100644
index 000000000000..e334363e9c47
--- /dev/null
+++ b/awx/ui/client/src/activity-stream/activitystream.route.js
@@ -0,0 +1,17 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ import {templateUrl} from '../shared/template-url/template-url.factory';
+
+export default {
+ name: 'activityStream',
+ route: '/activity_stream?target&id',
+ templateUrl: templateUrl('activity-stream/activitystream'),
+ controller: 'activityStreamController',
+ ncyBreadcrumb: {
+ label: "ACTIVITY STREAM"
+ },
+};
diff --git a/awx/ui/client/src/activity-stream/main.js b/awx/ui/client/src/activity-stream/main.js
new file mode 100644
index 000000000000..1b3f169de24a
--- /dev/null
+++ b/awx/ui/client/src/activity-stream/main.js
@@ -0,0 +1,14 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+import activityStreamRoute from './activitystream.route';
+import activityStreamController from './activitystream.controller';
+
+export default angular.module('activityStream', [])
+ .controller('activityStreamController', activityStreamController)
+ .run(['$stateExtender', function($stateExtender) {
+ $stateExtender.addState(activityStreamRoute);
+ }]);
diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js
index 4283b1943fb0..40f874cf6b4a 100644
--- a/awx/ui/client/src/app.js
+++ b/awx/ui/client/src/app.js
@@ -42,6 +42,7 @@ import moment from './shared/moment/main';
import templateUrl from './shared/template-url/main';
import adhoc from './adhoc/main';
import login from './login/main';
+import activityStream from './activity-stream/main';
import {JobDetailController} from './controllers/JobDetail';
import {JobStdoutController} from './controllers/JobStdout';
import {JobTemplatesList, JobTemplatesAdd, JobTemplatesEdit} from './controllers/JobTemplates';
@@ -91,6 +92,7 @@ var tower = angular.module('Tower', [
templateUrl.name,
adhoc.name,
login.name,
+ activityStream.name,
footer.name,
'templates',
'Utilities',
@@ -209,6 +211,9 @@ var tower = angular.module('Tower', [
url: '/home',
templateUrl: urlPrefix + 'partials/home.html',
controller: Home,
+ data: {
+ activityStream: true
+ },
ncyBreadcrumb: {
label: "DASHBOARD"
},
@@ -241,6 +246,10 @@ var tower = angular.module('Tower', [
url: '/home/hosts?has_active_failures',
templateUrl: urlPrefix + 'partials/subhome.html',
controller: HomeHosts,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'host'
+ },
ncyBreadcrumb: {
parent: 'dashboard',
label: "HOSTS"
@@ -361,6 +370,10 @@ var tower = angular.module('Tower', [
url: '/job_templates',
templateUrl: urlPrefix + 'partials/job_templates.html',
controller: JobTemplatesList,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'job_template'
+ },
ncyBreadcrumb: {
label: "JOB TEMPLATES"
},
@@ -390,6 +403,9 @@ var tower = angular.module('Tower', [
url: '/:template_id',
templateUrl: urlPrefix + 'partials/job_templates.html',
controller: JobTemplatesEdit,
+ data: {
+ activityStreamId: 'template_id'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -401,6 +417,10 @@ var tower = angular.module('Tower', [
url: '/job_templates/:id/schedules',
templateUrl: urlPrefix + 'partials/schedule_detail.html',
controller: ScheduleEditController,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'schedule'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -412,6 +432,10 @@ var tower = angular.module('Tower', [
url: '/projects',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsList,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'project'
+ },
ncyBreadcrumb: {
label: "PROJECTS"
},
@@ -441,6 +465,9 @@ var tower = angular.module('Tower', [
url: '/:id',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsEdit,
+ data: {
+ activityStreamId: 'id'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -452,6 +479,10 @@ var tower = angular.module('Tower', [
url: '/projects/:id/schedules',
templateUrl: urlPrefix + 'partials/schedule_detail.html',
controller: ScheduleEditController,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'schedule'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -485,6 +516,10 @@ var tower = angular.module('Tower', [
url: '/inventories',
templateUrl: urlPrefix + 'partials/inventories.html',
controller: InventoriesList,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'inventory'
+ },
ncyBreadcrumb: {
label: "INVENTORIES"
},
@@ -514,6 +549,9 @@ var tower = angular.module('Tower', [
url: '/:inventory_id',
templateUrl: urlPrefix + 'partials/inventories.html',
controller: InventoriesEdit,
+ data: {
+ activityStreamId: 'inventory_id'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -558,6 +596,10 @@ var tower = angular.module('Tower', [
url: '/organizations',
templateUrl: urlPrefix + 'partials/organizations.html',
controller: OrganizationsList,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'organization'
+ },
ncyBreadcrumb: {
parent: function($scope) {
$scope.$parent.$emit("ReloadOrgListView");
@@ -591,6 +633,9 @@ var tower = angular.module('Tower', [
url: '/:organization_id',
templateUrl: urlPrefix + 'partials/organizations.crud.html',
controller: OrganizationsEdit,
+ data: {
+ activityStreamId: 'organization_id'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -646,6 +691,10 @@ var tower = angular.module('Tower', [
url: '/teams',
templateUrl: urlPrefix + 'partials/teams.html',
controller: TeamsList,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'team'
+ },
ncyBreadcrumb: {
parent: 'setup',
label: 'TEAMS'
@@ -676,6 +725,9 @@ var tower = angular.module('Tower', [
url: '/:team_id',
templateUrl: urlPrefix + 'partials/teams.html',
controller: TeamsEdit,
+ data: {
+ activityStreamId: 'team_id'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -775,6 +827,10 @@ var tower = angular.module('Tower', [
url: '/credentials',
templateUrl: urlPrefix + 'partials/credentials.html',
controller: CredentialsList,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'credential'
+ },
ncyBreadcrumb: {
parent: 'setup',
label: 'CREDENTIALS'
@@ -805,6 +861,9 @@ var tower = angular.module('Tower', [
url: '/:credential_id',
templateUrl: urlPrefix + 'partials/credentials.html',
controller: CredentialsEdit,
+ data: {
+ activityStreamId: 'credential_id'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -816,6 +875,10 @@ var tower = angular.module('Tower', [
url: '/users',
templateUrl: urlPrefix + 'partials/users.html',
controller: UsersList,
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'user'
+ },
ncyBreadcrumb: {
parent: 'setup',
label: 'USERS'
@@ -846,6 +909,9 @@ var tower = angular.module('Tower', [
url: '/:user_id',
templateUrl: urlPrefix + 'partials/users.html',
controller: UsersEdit,
+ data: {
+ activityStreamId: 'user_id'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
@@ -925,9 +991,9 @@ var tower = angular.module('Tower', [
}]);
}])
- .run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'HideStream', 'Socket',
+ .run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'Socket',
'LoadConfig', 'Store', 'ShowSocketHelp', 'AboutAnsibleHelp', 'pendoService',
- function ($q, $compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, HideStream, Socket,
+ function ($q, $compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, Socket,
LoadConfig, Store, ShowSocketHelp, AboutAnsibleHelp, pendoService) {
@@ -1068,11 +1134,6 @@ var tower = angular.module('Tower', [
$location.replace($location.search('').$$url);
}
- // Before navigating away from current tab, make sure the primary view is visible
- if ($('#stream-container').is(':visible')) {
- HideStream();
- }
-
// remove any lingering intervals
if ($rootScope.jobDetailInterval) {
window.clearInterval($rootScope.jobDetailInterval);
diff --git a/awx/ui/client/src/bread-crumb/bread-crumb.directive.js b/awx/ui/client/src/bread-crumb/bread-crumb.directive.js
index f7da02fcaa90..3a0f2ac876c0 100644
--- a/awx/ui/client/src/bread-crumb/bread-crumb.directive.js
+++ b/awx/ui/client/src/bread-crumb/bread-crumb.directive.js
@@ -6,15 +6,39 @@ export default
restrict: 'E',
templateUrl: templateUrl('bread-crumb/bread-crumb'),
link: function(scope, element, attrs) {
- scope.activityStreamActive = 0;
- scope.toggleActivityStreamActive = function(){
- scope.activityStreamActive = !scope.activityStreamActive;
- };
+ var streamConfig = {};
+
+ scope.showActivityStreamButton = false;
+
+ scope.openActivityStream = function() {
+
+ var stateGoParams = {};
+
+ if(streamConfig && streamConfig.activityStream) {
+ if(streamConfig.activityStreamTarget) {
+ stateGoParams['target'] = streamConfig.activityStreamTarget;
+ }
+ if(streamConfig.activityStreamId) {
+ stateGoParams['id'] = $state.params[streamConfig.activityStreamId];
+ }
+ }
+
+ $state.go('activityStream', stateGoParams);
+ }
+
+ scope.$on("$stateChangeSuccess", function updateActivityStreamButton(event, toState) {
+
+ streamConfig = (toState && toState.data) ? toState.data : {};
+
+ if(streamConfig && streamConfig.activityStream) {
+ scope.showActivityStreamButton = true;
+ }
+ else {
+ scope.showActivityStreamButton = false;
+ }
+ });
- scope.isActive = function (path) {
- return $state.is(path);
- };
}
};
}];
diff --git a/awx/ui/client/src/bread-crumb/bread-crumb.partial.html b/awx/ui/client/src/bread-crumb/bread-crumb.partial.html
index bef217bd0411..6cdae3acb23b 100644
--- a/awx/ui/client/src/bread-crumb/bread-crumb.partial.html
+++ b/awx/ui/client/src/bread-crumb/bread-crumb.partial.html
@@ -7,8 +7,8 @@
data-trigger="hover"
data-container="body"
ng-class="{'BreadCrumb-menuLinkActive' : activityStreamActive}"
- ng-if="isActive('dashboard')"
- ng-click="toggleActivityStreamActive()">
+ ng-if="showActivityStreamButton"
+ ng-click="openActivityStream()">
@@ -20,7 +20,7 @@
data-placement="left"
data-trigger="hover"
data-container="body"
- ng-if="!isActive('dashboard')">
+ ng-if="!showActivityStreamButton">
diff --git a/awx/ui/client/src/inventory-scripts/list/list.route.js b/awx/ui/client/src/inventory-scripts/list/list.route.js
index 3c897c1321c7..6557534d3c9f 100644
--- a/awx/ui/client/src/inventory-scripts/list/list.route.js
+++ b/awx/ui/client/src/inventory-scripts/list/list.route.js
@@ -11,6 +11,10 @@ export default {
route: '/inventory_scripts',
templateUrl: templateUrl('inventory-scripts/list/list'),
controller: 'inventoryScriptsListController',
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'inventory_script'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
diff --git a/awx/ui/client/src/lists/Streams.js b/awx/ui/client/src/lists/Streams.js
index 2b40c913765a..0cce80b7f9a5 100644
--- a/awx/ui/client/src/lists/Streams.js
+++ b/awx/ui/client/src/lists/Streams.js
@@ -12,6 +12,7 @@ export default
name: 'activities',
iterator: 'activity',
editTitle: 'Activity Stream',
+ listTitle: 'Activity Stream',
selectInstructions: '',
index: false,
hover: true,
@@ -252,13 +253,6 @@ export default
},
actions: {
- close: {
- mode: 'all',
- awToolTip: "Close Activity Stream view",
- ngClick: "closeStream()",
- actionClass: 'btn List-buttonDefault',
- buttonContent: 'CLOSE'
- },
refresh: {
mode: 'all',
id: 'activity-stream-refresh-btn',
diff --git a/awx/ui/client/src/management-jobs/list/list.route.js b/awx/ui/client/src/management-jobs/list/list.route.js
index 0c2d100803e2..7301ebffe2a2 100644
--- a/awx/ui/client/src/management-jobs/list/list.route.js
+++ b/awx/ui/client/src/management-jobs/list/list.route.js
@@ -11,6 +11,10 @@ export default {
route: '/management_jobs',
templateUrl: templateUrl('management-jobs/list/list'),
controller: 'managementJobsListController',
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'management_job'
+ },
resolve: {
features: ['FeaturesService', function(FeaturesService) {
return FeaturesService.get();
diff --git a/awx/ui/client/src/management-jobs/schedule/schedule.route.js b/awx/ui/client/src/management-jobs/schedule/schedule.route.js
index 060825b07576..837d6dfb86b7 100644
--- a/awx/ui/client/src/management-jobs/schedule/schedule.route.js
+++ b/awx/ui/client/src/management-jobs/schedule/schedule.route.js
@@ -11,6 +11,10 @@ export default {
route: '/management_jobs/:management_job_id/schedules',
templateUrl: templateUrl('management-jobs/schedule/schedule'),
controller: 'managementJobsScheduleController',
+ data: {
+ activityStream: true,
+ activityStreamTarget: 'schedule'
+ },
params: {management_job: null},
resolve: {
features: ['FeaturesService', function(FeaturesService) {
diff --git a/awx/ui/client/src/partials/home.html b/awx/ui/client/src/partials/home.html
index 6ff4feee70c6..491a728e6433 100644
--- a/awx/ui/client/src/partials/home.html
+++ b/awx/ui/client/src/partials/home.html
@@ -13,15 +13,6 @@
icon-name="refresh"
toolbar="true">
-
diff --git a/awx/ui/client/src/shared/stateExtender.provider.js b/awx/ui/client/src/shared/stateExtender.provider.js
index 64994189931e..aa435b7c42c4 100644
--- a/awx/ui/client/src/shared/stateExtender.provider.js
+++ b/awx/ui/client/src/shared/stateExtender.provider.js
@@ -9,6 +9,7 @@ export default function($stateProvider){
templateUrl: state.templateUrl,
resolve: state.resolve,
params: state.params,
+ data: state.data,
ncyBreadcrumb: state.ncyBreadcrumb
});
}
diff --git a/awx/ui/client/src/widgets/Stream.js b/awx/ui/client/src/widgets/Stream.js
index b793d0bab105..af44f1daf2ab 100644
--- a/awx/ui/client/src/widgets/Stream.js
+++ b/awx/ui/client/src/widgets/Stream.js
@@ -37,65 +37,6 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
}
])
-.factory('ShowStream', ['setStreamHeight', 'Authorization',
- function (setStreamHeight) {
- return function () {
- // Slide in the Stream widget
-
- // Make some style/position adjustments adjustments
- var stream = $('#stream-container');
- stream.css({
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- 'min-height': '100%',
- 'background-color': '#FFF'
- });
-
- setStreamHeight();
-
- // Slide in stream
- stream.show('slide', {
- 'direction': 'left'
- }, {
- 'duration': 500,
- 'queue': false
- });
-
- };
- }
-])
-
-.factory('HideStream', [
- function () {
- return function () {
- // Remove the stream widget
-
- var stream = $('#stream-container');
- stream.hide('slide', {
- 'direction': 'left'
- }, {
- 'duration': 500,
- 'queue': false
- });
-
- // Completely destroy the container so we don't experience random flashes of it later.
- // There was some sort of weirdness with the tab 'show' causing the stream to slide in when
- // a tab was clicked, after the stream had been hidden. Seemed like timing- wait long enough
- // before clicking a tab, and it would not happen.
- setTimeout(function () {
- stream.detach();
- stream.empty();
- stream.unbind();
- $('#main-view').css({
- 'min-height': 0
- }); //let the parent height go back to normal
- }, 500);
- };
- }
-])
-
.factory('FixUrl', [
function () {
return function (u) {
@@ -335,11 +276,11 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
}
])
-.factory('Stream', ['$rootScope', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit',
- 'PaginateInit', 'generateList', 'FormatDate', 'ShowStream', 'HideStream', 'BuildDescription', 'FixUrl', 'BuildUrl',
+.factory('Stream', ['$rootScope', '$location', '$state', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit',
+ 'PaginateInit', 'generateList', 'FormatDate', 'BuildDescription', 'FixUrl', 'BuildUrl',
'ShowDetail', 'setStreamHeight', 'Find', 'Store',
- function ($rootScope, $location, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList,
- FormatDate, ShowStream, HideStream, BuildDescription, FixUrl, BuildUrl, ShowDetail, setStreamHeight,
+ function ($rootScope, $location, $state, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList,
+ FormatDate, BuildDescription, FixUrl, BuildUrl, ShowDetail, setStreamHeight,
Find, Store) {
return function (params) {
@@ -361,63 +302,25 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
if (url) {
defaultUrl = url;
} else {
- if ($location.path() !== '/home') {
- // Restrict what we're looking at based on the path
- type = (base === 'inventories') ? 'inventory' : base.replace(/s$/, '');
- paths = $location.path().split('/');
- paths.splice(0, 1);
- if (paths.length > 1 && /^\d+/.test(paths[paths.length - 1])) {
- type = paths[paths.length - 2];
- type = (type === 'inventories') ? 'inventory' : type.replace(/s$/, '');
- //defaultUrl += '?object1=' + type + '&object1__id=' +
- defaultUrl += '?' + type + '__id=' + paths[paths.length - 1];
- } else if (paths.length > 1) {
- type = paths[paths.length - 1];
- type = (type === 'inventories') ? 'inventory' : type.replace(/s$/, '');
- defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
- } else {
- defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
+
+ if($state.params && $state.params.target) {
+ if($state.params.id) {
+ // We have a type and an ID
+ defaultUrl += '?' + $state.params.target + '__id=' + $state.params.id;
+ }
+ else {
+ // We just have a type
+ defaultUrl += '?or__object1=' + $state.params.target + '&or__object2=' + $state.params.target;
}
}
}
- // Add a container for the stream widget
- $('#main-view').append("");
-
- ShowStream();
-
// Generate the list
view.inject(list, { mode: 'edit', id: 'stream-content', searchSize: 'col-lg-3', secondWidget: true, activityStream: true, scope: scope });
// descriptive title describing what AS is showing
scope.streamTitle = (params && params.title) ? params.title : null;
- scope.closeStream = function (inUrl) {
- HideStream();
- if (scope.searchCleanup) {
- scope.searchCleanup();
- }
- // Restore prior search state
- if (PreviousSearchParams) {
- SearchInit({
- scope: parent_scope,
- set: PreviousSearchParams.set,
- list: PreviousSearchParams.list,
- url: PreviousSearchParams.defaultUrl,
- iterator: PreviousSearchParams.iterator,
- sort_order: PreviousSearchParams.sort_order,
- setWidgets: false
- });
- }
- if (inUrl) {
- $location.path(inUrl);
- }
- else if (onClose) {
- parent_scope.$emit(onClose);
- }
- scope.$destroy();
- };
-
scope.refreshStream = function () {
scope.search(list.iterator);
};