cleanup activity stream

This commit is contained in:
John Mitchell 2017-03-02 12:54:54 -05:00
parent a6c57fc060
commit e784dba612
14 changed files with 404 additions and 414 deletions

View File

@ -16,9 +16,7 @@
* @description This form is for activity detail modal that can be shown on most pages.
*/
export default
angular.module('ActivityDetailDefinition', [])
.factory('ActivityDetailForm', ['i18n', function(i18n) {
export default ['i18n', function(i18n) {
return {
name: 'activity',
@ -48,4 +46,4 @@ export default
}
}
};}]); //Form
};}];

View File

@ -9,45 +9,47 @@
* @name controllers.function:Activity Stream
* @description This controller controls the activity stream.
*/
function activityStreamController($scope, $state, subTitle, Stream, GetTargetTitle, list, Dataset) {
export default ['$scope', '$state', 'subTitle', 'Stream', 'GetTargetTitle',
'StreamList', 'Dataset',
function activityStreamController($scope, $state, subTitle, Stream,
GetTargetTitle, list, Dataset) {
init();
initOmitSmartTags();
init();
initOmitSmartTags();
function init() {
// search init
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
function init() {
// search init
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
// subTitle is passed in via a resolve on the route. If there is no subtitle
// generated in the resolve then we go get the targets generic title.
// subTitle is passed in via a resolve on the route. If there is no subtitle
// generated in the resolve then we go get the targets generic title.
// Get the streams sub-title based on the target. This scope variable is leveraged
// when we define the activity stream list. Specifically it is included in the list
// title.
$scope.streamSubTitle = subTitle ? subTitle : GetTargetTitle($state.params.target);
// Get the streams sub-title based on the target. This scope variable is leveraged
// when we define the activity stream list. Specifically it is included in the list
// title.
$scope.streamSubTitle = subTitle ? subTitle : GetTargetTitle($state.params.target);
// Open the stream
Stream({
scope: $scope
});
}
// Open the stream
Stream({
scope: $scope
});
}
// Specification of smart-tags omission from the UI is done in the route/state init.
// A limitation is that this specficiation is static and the key for which to be omitted from
// the smart-tags must be known at that time.
// In the case of activity stream, we won't to dynamically ommit the resource for which we are
// displaying the activity stream for. i.e. 'project', 'credential', etc.
function initOmitSmartTags() {
let defaults, route = _.find($state.$current.path, (step) => {
return step.params.hasOwnProperty('activity_search');
});
if (route && $state.params.target !== undefined) {
defaults = route.params.activity_search.config.value;
defaults[$state.params.target] = null;
// Specification of smart-tags omission from the UI is done in the route/state init.
// A limitation is that this specficiation is static and the key for which to be omitted from
// the smart-tags must be known at that time.
// In the case of activity stream, we won't to dynamically ommit the resource for which we are
// displaying the activity stream for. i.e. 'project', 'credential', etc.
function initOmitSmartTags() {
let defaults, route = _.find($state.$current.path, (step) => {
return step.params.hasOwnProperty('activity_search');
});
if (route && $state.params.target !== undefined) {
defaults = route.params.activity_search.config.value;
defaults[$state.params.target] = null;
}
}
}
}
export default ['$scope', '$state', 'subTitle', 'Stream', 'GetTargetTitle', 'StreamList', 'Dataset', activityStreamController];
];

View File

@ -60,8 +60,8 @@ export default {
return qs.search(path, stateParams);
}
],
features: ['FeaturesService', 'ProcessErrors', '$state', '$rootScope',
function(FeaturesService, ProcessErrors, $state, $rootScope) {
features: ['FeaturesService', '$state', '$rootScope',
function(FeaturesService, $state, $rootScope) {
var features = FeaturesService.get();
if (features) {
if (FeaturesService.featureEnabled('activity_streams')) {
@ -81,12 +81,10 @@ export default {
});
}
],
subTitle: ['$stateParams',
'Rest',
'ModelToBasePathKey',
'GetBasePath',
subTitle: ['$stateParams', 'Rest', 'ModelToBasePathKey', 'GetBasePath',
'ProcessErrors',
function($stateParams, rest, ModelToBasePathKey, getBasePath, ProcessErrors) {
function($stateParams, rest, ModelToBasePathKey, getBasePath,
ProcessErrors) {
// If we have a target and an ID then we want to go grab the name of the object
// that we're examining with the activity stream. This name will be used in the
// subtitle.

View File

@ -1,78 +1,77 @@
export default
function BuildAnchor($log, $filter) {
// Returns a full <a href=''>resource_name</a> HTML string if link can be derived from supplied context
// returns name of resource if activity stream object doesn't contain enough data to build a UI url
// arguments are: a summary_field object, a resource type, an activity stream object
return function (obj, resource, activity) {
var url = '/#/';
// try/except pattern asserts that:
// if we encounter a case where a UI url can't or shouldn't be generated, just supply the name of the resource
try {
// catch-all case to avoid generating urls if a resource has been deleted
// if a resource still exists, it'll be serialized in the activity's summary_fields
if (!activity.summary_fields[resource]){
throw {name : 'ResourceDeleted', message: 'The referenced resource no longer exists'};
}
switch (resource) {
case 'custom_inventory_script':
url += 'inventory_scripts/' + obj.id + '/';
break;
case 'group':
if (activity.operation === 'create' || activity.operation === 'delete'){
// the API formats the changes.inventory field as str 'myInventoryName-PrimaryKey'
var inventory_id = _.last(activity.changes.inventory.split('-'));
url += 'inventories/' + inventory_id + '/manage?group=' + activity.changes.id;
}
else {
url += 'inventories/' + activity.summary_fields.inventory[0].id + '/manage?group=' + (activity.changes.id || activity.changes.object1_pk);
}
break;
case 'host':
url += 'home/hosts/' + obj.id;
break;
case 'job':
url += 'jobs/' + obj.id;
break;
case 'inventory':
url += 'inventories/' + obj.id + '/';
break;
case 'schedule':
// schedule urls depend on the resource they're associated with
if (activity.summary_fields.job_template){
url += 'job_templates/' + activity.summary_fields.job_template.id + '/schedules/' + obj.id;
}
else if (activity.summary_fields.project){
url += 'projects/' + activity.summary_fields.project.id + '/schedules/' + obj.id;
}
else if (activity.summary_fields.system_job_template){
url += 'management_jobs/' + activity.summary_fields.system_job_template.id + '/schedules/edit/' + obj.id;
}
// urls for inventory sync schedules currently depend on having an inventory id and group id
else {
throw {name : 'NotImplementedError', message : 'activity.summary_fields to build this url not implemented yet'};
}
break;
case 'notification_template':
url += `notification_templates/${obj.id}`;
break;
case 'role':
throw {name : 'NotImplementedError', message : 'role object management is not consolidated to a single UI view'};
case 'job_template':
url += `templates/job_template/${obj.id}`;
break;
case 'workflow_job_template':
url += `templates/workflow_job_template/${obj.id}`;
break;
default:
url += resource + 's/' + obj.id + '/';
}
return ' <a href=\"' + url + '\"> ' + $filter('sanitize')(obj.name || obj.username) + ' </a> ';
export default function BuildAnchor($log, $filter) {
// Returns a full <a href=''>resource_name</a> HTML string if link can be derived from supplied context
// returns name of resource if activity stream object doesn't contain enough data to build a UI url
// arguments are: a summary_field object, a resource type, an activity stream object
return function (obj, resource, activity) {
var url = '/#/';
// try/except pattern asserts that:
// if we encounter a case where a UI url can't or shouldn't be generated, just supply the name of the resource
try {
// catch-all case to avoid generating urls if a resource has been deleted
// if a resource still exists, it'll be serialized in the activity's summary_fields
if (!activity.summary_fields[resource]){
throw {name : 'ResourceDeleted', message: 'The referenced resource no longer exists'};
}
catch(err){
$log.debug(err);
return ' ' + $filter('sanitize')(obj.name || obj.username || '') + ' ';
switch (resource) {
case 'custom_inventory_script':
url += 'inventory_scripts/' + obj.id + '/';
break;
case 'group':
if (activity.operation === 'create' || activity.operation === 'delete'){
// the API formats the changes.inventory field as str 'myInventoryName-PrimaryKey'
var inventory_id = _.last(activity.changes.inventory.split('-'));
url += 'inventories/' + inventory_id + '/manage?group=' + activity.changes.id;
}
else {
url += 'inventories/' + activity.summary_fields.inventory[0].id + '/manage?group=' + (activity.changes.id || activity.changes.object1_pk);
}
break;
case 'host':
url += 'home/hosts/' + obj.id;
break;
case 'job':
url += 'jobs/' + obj.id;
break;
case 'inventory':
url += 'inventories/' + obj.id + '/';
break;
case 'schedule':
// schedule urls depend on the resource they're associated with
if (activity.summary_fields.job_template){
url += 'job_templates/' + activity.summary_fields.job_template.id + '/schedules/' + obj.id;
}
else if (activity.summary_fields.project){
url += 'projects/' + activity.summary_fields.project.id + '/schedules/' + obj.id;
}
else if (activity.summary_fields.system_job_template){
url += 'management_jobs/' + activity.summary_fields.system_job_template.id + '/schedules/edit/' + obj.id;
}
// urls for inventory sync schedules currently depend on having an inventory id and group id
else {
throw {name : 'NotImplementedError', message : 'activity.summary_fields to build this url not implemented yet'};
}
break;
case 'notification_template':
url += `notification_templates/${obj.id}`;
break;
case 'role':
throw {name : 'NotImplementedError', message : 'role object management is not consolidated to a single UI view'};
case 'job_template':
url += `templates/job_template/${obj.id}`;
break;
case 'workflow_job_template':
url += `templates/workflow_job_template/${obj.id}`;
break;
default:
url += resource + 's/' + obj.id + '/';
}
};
}
return ' <a href=\"' + url + '\"> ' + $filter('sanitize')(obj.name || obj.username) + ' </a> ';
}
catch(err){
$log.debug(err);
return ' ' + $filter('sanitize')(obj.name || obj.username || '') + ' ';
}
};
}
BuildAnchor.$inject = ['$log', '$filter'];

View File

@ -1,126 +1,125 @@
export default
function BuildDescription(BuildAnchor, $log, i18n) {
return function (activity) {
export default function BuildDescription(BuildAnchor, $log, i18n) {
return function (activity) {
var pastTense = function(operation){
return (/e$/.test(activity.operation)) ? operation + 'd ' : operation + 'ed ';
};
// convenience method to see if dis+association operation involves 2 groups
// the group cases are slightly different because groups can be dis+associated into each other
var isGroupRelationship = function(activity){
return activity.object1 === 'group' && activity.object2 === 'group' && activity.summary_fields.group.length > 1;
};
// Activity stream objects will outlive the resources they reference
// in that case, summary_fields will not be available - show generic error text instead
try {
activity.description = pastTense(activity.operation);
switch(activity.object_association){
// explicit role dis+associations
case 'role':
// object1 field is resource targeted by the dis+association
// object2 field is the resource the role is inherited from
// summary_field.role[0] contains ref info about the role
switch(activity.operation){
// expected outcome: "disassociated <object2> role_name from <object1>"
case 'disassociate':
if (isGroupRelationship(activity)){
activity.description += BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' from ' + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' from ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
// expected outcome: "associated <object2> role_name to <object1>"
case 'associate':
if (isGroupRelationship(activity)){
activity.description += BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' to ' + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' to ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
}
break;
// inherited role dis+associations (logic identical to case 'role')
case 'parents':
// object1 field is resource targeted by the dis+association
// object2 field is the resource the role is inherited from
// summary_field.role[0] contains ref info about the role
switch(activity.operation){
// expected outcome: "disassociated <object2> role_name from <object1>"
case 'disassociate':
if (isGroupRelationship(activity)){
activity.description += activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) +
'from ' + activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' from ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
// expected outcome: "associated <object2> role_name to <object1>"
case 'associate':
if (isGroupRelationship(activity)){
activity.description += activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity) +
'to ' + activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' to ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
}
break;
// CRUD operations / resource on resource dis+associations
default:
switch(activity.operation){
// expected outcome: "disassociated <object2> from <object1>"
case 'disassociate' :
if (isGroupRelationship(activity)){
activity.description += activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) +
'from ' + activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else {
activity.description += activity.object2 + BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) +
'from ' + activity.object1 + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
// expected outcome "associated <object2> to <object1>"
case 'associate':
// groups are the only resource that can be associated/disassociated into each other
if (isGroupRelationship(activity)){
activity.description += activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity) +
'to ' + activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity);
}
else {
activity.description += activity.object1 + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity) +
'to ' + activity.object2 + BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity);
}
break;
case 'delete':
activity.description += activity.object1 + BuildAnchor(activity.changes, activity.object1, activity);
break;
// expected outcome: "operation <object1>"
case 'update':
activity.description += activity.object1 + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
break;
case 'create':
activity.description += activity.object1 + BuildAnchor(activity.changes, activity.object1, activity);
break;
}
break;
}
}
catch(err){
$log.debug(err);
activity.description = i18n._('Event summary not available');
}
var pastTense = function(operation){
return (/e$/.test(activity.operation)) ? operation + 'd ' : operation + 'ed ';
};
// convenience method to see if dis+association operation involves 2 groups
// the group cases are slightly different because groups can be dis+associated into each other
var isGroupRelationship = function(activity){
return activity.object1 === 'group' && activity.object2 === 'group' && activity.summary_fields.group.length > 1;
};
}
BuildDescription.$inject = ['BuildAnchor', '$log', 'i18n'];
// Activity stream objects will outlive the resources they reference
// in that case, summary_fields will not be available - show generic error text instead
try {
activity.description = pastTense(activity.operation);
switch(activity.object_association){
// explicit role dis+associations
case 'role':
// object1 field is resource targeted by the dis+association
// object2 field is the resource the role is inherited from
// summary_field.role[0] contains ref info about the role
switch(activity.operation){
// expected outcome: "disassociated <object2> role_name from <object1>"
case 'disassociate':
if (isGroupRelationship(activity)){
activity.description += BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' from ' + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' from ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
// expected outcome: "associated <object2> role_name to <object1>"
case 'associate':
if (isGroupRelationship(activity)){
activity.description += BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' to ' + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' to ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
}
break;
// inherited role dis+associations (logic identical to case 'role')
case 'parents':
// object1 field is resource targeted by the dis+association
// object2 field is the resource the role is inherited from
// summary_field.role[0] contains ref info about the role
switch(activity.operation){
// expected outcome: "disassociated <object2> role_name from <object1>"
case 'disassociate':
if (isGroupRelationship(activity)){
activity.description += activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) +
'from ' + activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' from ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
// expected outcome: "associated <object2> role_name to <object1>"
case 'associate':
if (isGroupRelationship(activity)){
activity.description += activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity) +
'to ' + activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity);
}
else{
activity.description += BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) + activity.summary_fields.role[0].role_field +
' to ' + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
}
break;
// CRUD operations / resource on resource dis+associations
default:
switch(activity.operation){
// expected outcome: "disassociated <object2> from <object1>"
case 'disassociate' :
if (isGroupRelationship(activity)){
activity.description += activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity) +
'from ' + activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity);
}
else {
activity.description += activity.object2 + BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity) +
'from ' + activity.object1 + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
}
break;
// expected outcome "associated <object2> to <object1>"
case 'associate':
// groups are the only resource that can be associated/disassociated into each other
if (isGroupRelationship(activity)){
activity.description += activity.object1 + BuildAnchor(activity.summary_fields.group[0], activity.object1, activity) +
'to ' + activity.object2 + BuildAnchor(activity.summary_fields.group[1], activity.object2, activity);
}
else {
activity.description += activity.object1 + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity) +
'to ' + activity.object2 + BuildAnchor(activity.summary_fields[activity.object2][0], activity.object2, activity);
}
break;
case 'delete':
activity.description += activity.object1 + BuildAnchor(activity.changes, activity.object1, activity);
break;
// expected outcome: "operation <object1>"
case 'update':
activity.description += activity.object1 + BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity);
break;
case 'create':
activity.description += activity.object1 + BuildAnchor(activity.changes, activity.object1, activity);
break;
}
break;
}
}
catch(err){
$log.debug(err);
activity.description = i18n._('Event summary not available');
}
};
}
BuildDescription.$inject = ['BuildAnchor', '$log', 'i18n'];

View File

@ -1,39 +1,40 @@
export default
function ShowDetail($filter, $rootScope, Rest, Alert, GenerateForm, ProcessErrors, GetBasePath, FormatDate, ActivityDetailForm, Empty, Find) {
return function (params, scope) {
export default function ShowDetail($filter, $rootScope, Rest, Alert,
GenerateForm, ProcessErrors, GetBasePath, FormatDate, ActivityDetailForm,
Empty, Find) {
return function (params, scope) {
var activity_id = params.activity_id,
activity = Find({ list: params.scope.activities, key: 'id', val: activity_id }),
element;
var activity_id = params.activity_id,
activity = Find({ list: params.scope.activities, key: 'id', val: activity_id }),
element;
if (activity) {
if (activity) {
// Grab our element out of the dom
element = angular.element(document.getElementById('stream-detail-modal'));
// Grab our element out of the dom
element = angular.element(document.getElementById('stream-detail-modal'));
// Grab the modal's scope so that we can set a few variables
scope = element.scope();
// Grab the modal's scope so that we can set a few variables
scope = element.scope();
scope.changes = activity.changes;
scope.user = ((activity.summary_fields.actor) ? activity.summary_fields.actor.username : 'system') +
' on ' + $filter('longDate')(activity.timestamp);
scope.operation = activity.description;
scope.header = "Event " + activity.id;
scope.changes = activity.changes;
scope.user = ((activity.summary_fields.actor) ? activity.summary_fields.actor.username : 'system') +
' on ' + $filter('longDate')(activity.timestamp);
scope.operation = activity.description;
scope.header = "Event " + activity.id;
// Open the modal
$('#stream-detail-modal').modal({
show: true,
backdrop: 'static',
keyboard: true
});
// Open the modal
$('#stream-detail-modal').modal({
show: true,
backdrop: 'static',
keyboard: true
});
if (!scope.$$phase) {
scope.$digest();
}
if (!scope.$$phase) {
scope.$digest();
}
}
};
}
};
}
ShowDetail.$inject = ['$filter', '$rootScope', 'Rest', 'Alert', 'GenerateForm', 'ProcessErrors', 'GetBasePath', 'FormatDate',
'ActivityDetailForm', 'Empty', 'Find'];

View File

@ -1,53 +1,52 @@
export default
function Stream($rootScope, $location, $state, Rest, GetBasePath, ProcessErrors,
Wait, StreamList, GenerateList, FormatDate,
BuildDescription, ShowDetail) {
return function (params) {
export default function Stream($rootScope, $location, $state, Rest, GetBasePath,
ProcessErrors, Wait, StreamList, GenerateList, FormatDate, BuildDescription,
ShowDetail) {
return function (params) {
var scope = params.scope;
var scope = params.scope;
$rootScope.flashMessage = null;
$rootScope.flashMessage = null;
// descriptive title describing what AS is showing
scope.streamTitle = (params && params.title) ? params.title : null;
scope.refreshStream = function () {
$state.go('.', null, {reload: true});
};
scope.showDetail = function (id) {
ShowDetail({
scope: scope,
activity_id: id
});
};
if(scope.activities && scope.activities.length > 0) {
buildUserAndDescription();
}
scope.$watch('activities', function(){
// Watch for future update to scope.activities (like page change, column sort, search, etc)
buildUserAndDescription();
});
function buildUserAndDescription(){
scope.activities.forEach(function(activity, i) {
// build activity.user
if (scope.activities[i].summary_fields.actor) {
scope.activities[i].user = "<a href=\"/#/users/" + scope.activities[i].summary_fields.actor.id + "\">" +
scope.activities[i].summary_fields.actor.username + "</a>";
} else {
scope.activities[i].user = 'system';
}
// build description column / action text
BuildDescription(scope.activities[i]);
});
}
// descriptive title describing what AS is showing
scope.streamTitle = (params && params.title) ? params.title : null;
scope.refreshStream = function () {
$state.go('.', null, {reload: true});
};
}
scope.showDetail = function (id) {
ShowDetail({
scope: scope,
activity_id: id
});
};
if(scope.activities && scope.activities.length > 0) {
buildUserAndDescription();
}
scope.$watch('activities', function(){
// Watch for future update to scope.activities (like page change, column sort, search, etc)
buildUserAndDescription();
});
function buildUserAndDescription(){
scope.activities.forEach(function(activity, i) {
// build activity.user
if (scope.activities[i].summary_fields.actor) {
scope.activities[i].user = "<a href=\"/#/users/" + scope.activities[i].summary_fields.actor.id + "\">" +
scope.activities[i].summary_fields.actor.username + "</a>";
} else {
scope.activities[i].user = 'system';
}
// build description column / action text
BuildDescription(scope.activities[i]);
});
}
};
}
Stream.$inject = ['$rootScope', '$location', '$state', 'Rest', 'GetBasePath',
'ProcessErrors', 'Wait', 'StreamList', 'generateList', 'FormatDate', 'BuildDescription',

View File

@ -1,51 +1,50 @@
export default
function GetTargetTitle(i18n) {
return function (target) {
export default function GetTargetTitle(i18n) {
return function (target) {
var rtnTitle = i18n._('ALL ACTIVITY');
var rtnTitle = i18n._('ALL ACTIVITY');
switch(target) {
case 'project':
rtnTitle = i18n._('PROJECTS');
break;
case 'inventory':
rtnTitle = i18n._('INVENTORIES');
break;
case 'credential':
rtnTitle = i18n._('CREDENTIALS');
break;
case 'user':
rtnTitle = i18n._('USERS');
break;
case 'team':
rtnTitle = i18n._('TEAMS');
break;
case 'notification_template':
rtnTitle = i18n._('NOTIFICATION TEMPLATES');
break;
case 'organization':
rtnTitle = i18n._('ORGANIZATIONS');
break;
case 'job':
rtnTitle = i18n._('JOBS');
break;
case 'custom_inventory_script':
rtnTitle = i18n._('INVENTORY SCRIPTS');
break;
case 'schedule':
rtnTitle = i18n._('SCHEDULES');
break;
case 'host':
rtnTitle = i18n._('HOSTS');
break;
case 'template':
rtnTitle = i18n._('TEMPLATES');
break;
}
switch(target) {
case 'project':
rtnTitle = i18n._('PROJECTS');
break;
case 'inventory':
rtnTitle = i18n._('INVENTORIES');
break;
case 'credential':
rtnTitle = i18n._('CREDENTIALS');
break;
case 'user':
rtnTitle = i18n._('USERS');
break;
case 'team':
rtnTitle = i18n._('TEAMS');
break;
case 'notification_template':
rtnTitle = i18n._('NOTIFICATION TEMPLATES');
break;
case 'organization':
rtnTitle = i18n._('ORGANIZATIONS');
break;
case 'job':
rtnTitle = i18n._('JOBS');
break;
case 'custom_inventory_script':
rtnTitle = i18n._('INVENTORY SCRIPTS');
break;
case 'schedule':
rtnTitle = i18n._('SCHEDULES');
break;
case 'host':
rtnTitle = i18n._('HOSTS');
break;
case 'template':
rtnTitle = i18n._('TEMPLATES');
break;
}
return rtnTitle;
return rtnTitle;
};
}
};
}
GetTargetTitle.$inject = ['i18n'];

View File

@ -14,6 +14,8 @@ import ShowDetail from './factories/show-detail.factory';
import Stream from './factories/stream.factory';
import GetTargetTitle from './get-target-title.factory';
import ModelToBasePathKey from './model-to-base-path-key.factory';
import ActivityDetailForm from './activity-detail.form';
import StreamList from './streams.list';
export default angular.module('activityStream', [streamDetailModal.name])
.controller('activityStreamController', activityStreamController)
@ -24,6 +26,8 @@ export default angular.module('activityStream', [streamDetailModal.name])
.factory('Stream', Stream)
.factory('GetTargetTitle', GetTargetTitle)
.factory('ModelToBasePathKey', ModelToBasePathKey)
.factory('ActivityDetailForm', ActivityDetailForm)
.factory('StreamList', StreamList)
.run(['$stateExtender', function($stateExtender) {
$stateExtender.addState(activityStreamRoute);
}]);

View File

@ -10,50 +10,49 @@
* @description Helper functions to convert singular/plural versions of our models to the opposite
*/
export default
function ModelToBasePathKey() {
return function(model) {
// This function takes in the singular model string and returns the key needed
// to get the base path from $rootScope/local storage.
export default function ModelToBasePathKey() {
return function(model) {
// This function takes in the singular model string and returns the key needed
// to get the base path from $rootScope/local storage.
var basePathKey;
var basePathKey;
switch(model) {
case 'project':
basePathKey = 'projects';
break;
case 'inventory':
basePathKey = 'inventory';
break;
case 'job_template':
basePathKey = 'job_templates';
break;
case 'credential':
basePathKey = 'credentials';
break;
case 'user':
basePathKey = 'users';
break;
case 'team':
basePathKey = 'teams';
break;
case 'notification_template':
basePathKey = 'notification_templates';
break;
case 'organization':
basePathKey = 'organizations';
break;
case 'management_job':
basePathKey = 'management_jobs';
break;
case 'custom_inventory_script':
basePathKey = 'inventory_scripts';
break;
case 'workflow_job_template':
basePathKey = 'workflow_job_templates';
break;
}
switch(model) {
case 'project':
basePathKey = 'projects';
break;
case 'inventory':
basePathKey = 'inventory';
break;
case 'job_template':
basePathKey = 'job_templates';
break;
case 'credential':
basePathKey = 'credentials';
break;
case 'user':
basePathKey = 'users';
break;
case 'team':
basePathKey = 'teams';
break;
case 'notification_template':
basePathKey = 'notification_templates';
break;
case 'organization':
basePathKey = 'organizations';
break;
case 'management_job':
basePathKey = 'management_jobs';
break;
case 'custom_inventory_script':
basePathKey = 'inventory_scripts';
break;
case 'workflow_job_template':
basePathKey = 'workflow_job_templates';
break;
}
return basePathKey;
};
}
return basePathKey;
};
}

View File

@ -5,9 +5,7 @@
*************************************************/
export default
angular.module('StreamListDefinition', [])
.factory('StreamList', ['i18n', function(i18n) {
export default ['i18n', function(i18n) {
return {
name: 'activities',
@ -72,4 +70,4 @@ export default
}
}
};}]);
};}];

View File

@ -143,8 +143,6 @@ var tower = angular.module('Tower', [
'AllJobsDefinition',
'JobSummaryDefinition',
'HostGroupsFormDefinition',
'StreamListDefinition',
'ActivityDetailDefinition',
'ScheduledJobsDefinition',
'JobsListDefinition',
'LogViewerStatusDefinition',

View File

@ -4,7 +4,6 @@
* All Rights Reserved
*************************************************/
import ActivityDetail from "./forms/ActivityDetail";
import EventsViewer from "./forms/EventsViewer";
import Groups from "./forms/Groups";
import HostGroups from "./forms/HostGroups";
@ -23,8 +22,7 @@ import Workflows from "./forms/Workflows";
export
{ ActivityDetail,
EventsViewer,
{ EventsViewer,
Groups,
HostGroups,
Hosts,

View File

@ -19,7 +19,6 @@ import Organizations from "./lists/Organizations";
import PortalJobTemplates from "./lists/PortalJobTemplates";
import PortalJobs from "./lists/PortalJobs";
import ScheduledJobs from "./lists/ScheduledJobs";
import Streams from "./lists/Streams";
import Templates from "./lists/Templates";
export
@ -38,6 +37,5 @@ export
PortalJobTemplates,
PortalJobs,
ScheduledJobs,
Streams,
Templates
};