From 85a9e14ced14e23c27af0349234606103147a096 Mon Sep 17 00:00:00 2001 From: Ken Hoes Date: Tue, 15 Mar 2016 14:55:12 -0400 Subject: [PATCH 1/3] Split up and modularized organizations --- awx/ui/client/src/app.js | 112 ++--- .../client/src/controllers/Organizations.js | 382 ------------------ awx/ui/client/src/organizations/add/main.js | 14 + .../add/organizations-add.controller.js | 66 +++ .../add/organizations-add.partial.html | 4 + .../add/organizations-add.route.js | 24 ++ awx/ui/client/src/organizations/edit/main.js | 15 + .../edit/organizations-edit.controller.js | 150 +++++++ .../edit/organizations-edit.route.js | 29 ++ awx/ui/client/src/organizations/list/main.js | 14 + .../list/organizations-list.controller.js | 182 +++++++++ .../list/organizations-list.partial.html | 62 +++ .../list/organizations-list.route.js | 31 ++ awx/ui/client/src/organizations/main.js | 16 + 14 files changed, 665 insertions(+), 436 deletions(-) delete mode 100644 awx/ui/client/src/controllers/Organizations.js create mode 100644 awx/ui/client/src/organizations/add/main.js create mode 100644 awx/ui/client/src/organizations/add/organizations-add.controller.js create mode 100644 awx/ui/client/src/organizations/add/organizations-add.partial.html create mode 100644 awx/ui/client/src/organizations/add/organizations-add.route.js create mode 100644 awx/ui/client/src/organizations/edit/main.js create mode 100644 awx/ui/client/src/organizations/edit/organizations-edit.controller.js create mode 100644 awx/ui/client/src/organizations/edit/organizations-edit.route.js create mode 100644 awx/ui/client/src/organizations/list/main.js create mode 100644 awx/ui/client/src/organizations/list/organizations-list.controller.js create mode 100644 awx/ui/client/src/organizations/list/organizations-list.partial.html create mode 100644 awx/ui/client/src/organizations/list/organizations-list.route.js create mode 100644 awx/ui/client/src/organizations/main.js diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index cbf50b22b6..a64b8c9d62 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -27,6 +27,7 @@ import {JobsListController} from './controllers/Jobs'; import {PortalController} from './controllers/Portal'; import systemTracking from './system-tracking/main'; import inventoryScripts from './inventory-scripts/main'; +import organizations from './organizations/main'; import permissions from './permissions/main'; import managementJobs from './management-jobs/main'; import jobDetail from './job-detail/main'; @@ -50,7 +51,9 @@ import lookUpHelper from './lookup/main'; import JobTemplates from './job-templates/main'; import {ScheduleEditController} from './controllers/Schedules'; import {ProjectsList, ProjectsAdd, ProjectsEdit} from './controllers/Projects'; -import {OrganizationsList, OrganizationsAdd, OrganizationsEdit} from './controllers/Organizations'; +import OrganizationsList from './organizations/list/organizations-list.controller'; +import OrganizationsAdd from './organizations/add/organizations-add.controller'; +import OrganizationsEdit from './organizations/edit/organizations-edit.controller'; import {InventoriesList, InventoriesAdd, InventoriesEdit, InventoriesManage} from './controllers/Inventories'; import {AdminsList} from './controllers/Admins'; import {UsersList, UsersAdd, UsersEdit} from './controllers/Users'; @@ -85,6 +88,7 @@ var tower = angular.module('Tower', [ browserData.name, systemTracking.name, inventoryScripts.name, + organizations.name, permissions.name, managementJobs.name, setupMenu.name, @@ -428,60 +432,60 @@ var tower = angular.module('Tower', [ } }). - state('organizations', { - url: '/organizations', - templateUrl: urlPrefix + 'partials/organizations.html', - controller: OrganizationsList, - data: { - activityStream: true, - activityStreamTarget: 'organization' - }, - ncyBreadcrumb: { - parent: function($scope) { - $scope.$parent.$emit("ReloadOrgListView"); - return "setup"; - }, - label: "ORGANIZATIONS" - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }] - } - }). + // state('organizations', { + // url: '/organizations', + // templateUrl: urlPrefix + 'partials/organizations.html', + // controller: OrganizationsList, + // data: { + // activityStream: true, + // activityStreamTarget: 'organization' + // }, + // ncyBreadcrumb: { + // parent: function($scope) { + // $scope.$parent.$emit("ReloadOrgListView"); + // return "setup"; + // }, + // label: "ORGANIZATIONS" + // }, + // resolve: { + // features: ['FeaturesService', function(FeaturesService) { + // return FeaturesService.get(); + // }] + // } + // }). - state('organizations.add', { - url: '/add', - templateUrl: urlPrefix + 'partials/organizations.crud.html', - controller: OrganizationsAdd, - ncyBreadcrumb: { - parent: "organizations", - label: "CREATE ORGANIZATION" - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }] - } - }). - - state('organizations.edit', { - url: '/:organization_id', - templateUrl: urlPrefix + 'partials/organizations.crud.html', - controller: OrganizationsEdit, - data: { - activityStreamId: 'organization_id' - }, - ncyBreadcrumb: { - parent: "organizations", - label: "{{name}}" - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }] - } - }). + // state('organizations.add', { + // url: '/add', + // templateUrl: urlPrefix + 'partials/organizations.crud.html', + // controller: OrganizationsAdd, + // ncyBreadcrumb: { + // parent: "organizations", + // label: "CREATE ORGANIZATION" + // }, + // resolve: { + // features: ['FeaturesService', function(FeaturesService) { + // return FeaturesService.get(); + // }] + // } + // }). + // + // state('organizations.edit', { + // url: '/:organization_id', + // templateUrl: urlPrefix + 'partials/organizations.crud.html', + // controller: OrganizationsEdit, + // data: { + // activityStreamId: 'organization_id' + // }, + // ncyBreadcrumb: { + // parent: "organizations", + // label: "{{name}}" + // }, + // resolve: { + // features: ['FeaturesService', function(FeaturesService) { + // return FeaturesService.get(); + // }] + // } + // }). state('organizationAdmins', { url: '/organizations/:organization_id/admins', diff --git a/awx/ui/client/src/controllers/Organizations.js b/awx/ui/client/src/controllers/Organizations.js deleted file mode 100644 index fb1ebecfa1..0000000000 --- a/awx/ui/client/src/controllers/Organizations.js +++ /dev/null @@ -1,382 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Organizations - * @description This controller's for the Organizations page -*/ - - -export function OrganizationsList($stateParams, $scope, $rootScope, $location, - $log, $compile, Rest, PaginateWidget, PaginateInit, SearchInit, OrganizationList, Alert, Prompt, ClearScope, ProcessErrors, GetBasePath, Wait, - $state) { - - ClearScope(); - - var defaultUrl = GetBasePath('organizations'), - list = OrganizationList, - pageSize = $scope.orgCount; - - PaginateInit({ - scope: $scope, - list: list, - url: defaultUrl, - pageSize: pageSize, - }); - SearchInit({ - scope: $scope, - list: list, - url: defaultUrl, - }); - - $scope.search(list.iterator); - - $scope.PaginateWidget = PaginateWidget({ - iterator: list.iterator, - set: 'organizations' - }); - - var paginationContainer = $('#pagination-container'); - paginationContainer.html($scope.PaginateWidget); - $compile(paginationContainer.contents())($scope) - - var parseCardData = function (cards) { - return cards.map(function (card) { - var val = {}; - val.name = card.name; - val.id = card.id; - if (card.id + "" === cards.activeCard) { - val.isActiveCard = true; - } - val.description = card.description || undefined; - val.links = []; - val.links.push({ - href: card.related.users, - name: "USERS" - }); - val.links.push({ - href: card.related.teams, - name: "TEAMS" - }); - val.links.push({ - href: card.related.inventories, - name: "INVENTORIES" - }); - val.links.push({ - href: card.related.projects, - name: "PROJECTS" - }); - val.links.push({ - href: card.related.job_templates, - name: "JOB TEMPLATES" - }); - val.links.push({ - href: card.related.admins, - name: "ADMINS" - }); - return val; - }); - }; - - var getOrganization = function (id) { - Rest.setUrl(defaultUrl); - Rest.get() - .success(function (data) { - data.results.activeCard = id; - $scope.orgCount = data.count; - $scope.orgCards = parseCardData(data.results); - Wait("stop"); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + defaultUrl + ' failed. DELETE returned status: ' + status }); - }); - }; - - $scope.$on("ReloadOrgListView", function() { - if ($state.$current.self.name === "organizations") { - delete $scope.activeCard; - if ($scope.orgCards) { - $scope.orgCards = $scope.orgCards.map(function (card) { - delete card.isActiveCard; - return card; - }); - } - $scope.hideListHeader = false; - } - }); - - $scope.$on("ReloadOrganzationCards", function(e, id) { - $scope.activeCard = id; - getOrganization(id); - }); - - $scope.$on("HideOrgListHeader", function() { - $scope.hideListHeader = true; - }); - - $scope.$on("ShowOrgListHeader", function() { - $scope.hideListHeader = false; - }); - - getOrganization(); - - $rootScope.flashMessage = null; - - if ($scope.removePostRefresh) { - $scope.removePostRefresh(); - } - $scope.removePostRefresh = $scope.$on('PostRefresh', function () { - // Cleanup after a delete - Wait('stop'); - $('#prompt-modal').modal('hide'); - }); - - $scope.addOrganization = function () { - $state.transitionTo('organizations.add'); - }; - - $scope.editOrganization = function (id) { - $scope.activeCard = id; - $state.transitionTo('organizations.edit', {organization_id: id}); - }; - - $scope.deleteOrganization = function (id, name) { - - var action = function () { - $('#prompt-modal').modal('hide'); - Wait('start'); - var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() - .success(function () { - if ($state.current.name !== "organzations") { - $state.transitionTo("organizations"); - } - $scope.$emit("ReloadOrganzationCards"); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status }); - }); - }; - - Prompt({ - hdr: 'Delete', - body: '
Are you sure you want to delete the organization below?
' + name + '
', - action: action, - actionText: 'DELETE' - }); - }; -} - -OrganizationsList.$inject = ['$stateParams', '$scope', '$rootScope', - '$location', '$log', '$compile', 'Rest', 'PaginateWidget', 'PaginateInit', 'SearchInit', 'OrganizationList', 'Alert', 'Prompt', 'ClearScope', - 'ProcessErrors', 'GetBasePath', 'Wait', - '$state' -]; - - -export function OrganizationsAdd($scope, $rootScope, $compile, $location, $log, - $stateParams, OrganizationForm, GenerateForm, Rest, Alert, ProcessErrors, - ClearScope, GetBasePath, ReturnToCaller, Wait, $state) { - - ClearScope(); - - // Inject dynamic view - var generator = GenerateForm, - form = OrganizationForm, - base = $location.path().replace(/^\//, '').split('/')[0]; - - generator.inject(form, { mode: 'add', related: false, scope: $scope}); - generator.reset(); - - $scope.$emit("HideOrgListHeader"); - - // Save - $scope.formSave = function () { - generator.clearApiErrors(); - Wait('start'); - var url = GetBasePath(base); - url += (base !== 'organizations') ? $stateParams.project_id + '/organizations/' : ''; - Rest.setUrl(url); - Rest.post({ name: $scope.name, description: $scope.description }) - .success(function (data) { - Wait('stop'); - $scope.$emit("ReloadOrganzationCards", data.id); - if (base === 'organizations') { - $rootScope.flashMessage = "New organization successfully created!"; - $location.path('/organizations/' + data.id); - } else { - ReturnToCaller(1); - } - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to add new organization. Post returned status: ' + status }); - }); - }; - - $scope.formCancel = function () { - $scope.$emit("ReloadOrganzationCards"); - $scope.$emit("ShowOrgListHeader"); - $state.transitionTo('organizations'); - }; -} - -OrganizationsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', - '$log', '$stateParams', 'OrganizationForm', 'GenerateForm', 'Rest', 'Alert', - 'ProcessErrors', 'ClearScope', 'GetBasePath', 'ReturnToCaller', 'Wait', - '$state' -]; - - -export function OrganizationsEdit($scope, $rootScope, $compile, $location, $log, - $stateParams, OrganizationForm, GenerateForm, Rest, Alert, ProcessErrors, - RelatedSearchInit, RelatedPaginateInit, Prompt, ClearScope, GetBasePath, - Wait, $state) { - - ClearScope(); - - // Inject dynamic view - var form = OrganizationForm, - generator = GenerateForm, - defaultUrl = GetBasePath('organizations'), - base = $location.path().replace(/^\//, '').split('/')[0], - master = {}, - id = $stateParams.organization_id, - relatedSets = {}; - - $scope.$emit("HideOrgListHeader"); - - $scope.$emit("ReloadOrganzationCards", id); - - $scope.organization_id = id; - - generator.inject(form, { mode: 'edit', related: true, scope: $scope}); - generator.reset(); - - // After the Organization is loaded, retrieve each related set - if ($scope.organizationLoadedRemove) { - $scope.organizationLoadedRemove(); - } - $scope.organizationLoadedRemove = $scope.$on('organizationLoaded', function () { - for (var set in relatedSets) { - $scope.search(relatedSets[set].iterator); - } - Wait('stop'); - }); - - // Retrieve detail record and prepopulate the form - Wait('start'); - Rest.setUrl(defaultUrl + id + '/'); - Rest.get() - .success(function (data) { - var fld, related, set; - $scope.organization_name = data.name; - for (fld in form.fields) { - if (data[fld]) { - $scope[fld] = data[fld]; - master[fld] = data[fld]; - } - } - related = data.related; - for (set in form.related) { - if (related[set]) { - relatedSets[set] = { - url: related[set], - iterator: form.related[set].iterator - }; - } - } - // Initialize related search functions. Doing it here to make sure relatedSets object is populated. - RelatedSearchInit({ scope: $scope, form: form, relatedSets: relatedSets }); - RelatedPaginateInit({ scope: $scope, relatedSets: relatedSets }); - $scope.$emit('organizationLoaded'); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to retrieve organization: ' + $stateParams.id + '. GET status: ' + status }); - }); - - - // Save changes to the parent - $scope.formSave = function () { - var fld, params = {}; - generator.clearApiErrors(); - Wait('start'); - for (fld in form.fields) { - params[fld] = $scope[fld]; - } - Rest.setUrl(defaultUrl + id + '/'); - Rest.put(params) - .success(function (data) { - Wait('stop'); - $scope.organization_name = $scope.name; - master = params; - $rootScope.flashMessage = "Your changes were successfully saved!"; - $scope.$emit("ReloadOrganzationCards", data.id); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, OrganizationForm, { hdr: 'Error!', - msg: 'Failed to update organization: ' + id + '. PUT status: ' + status }); - }); - }; - - $scope.formCancel = function () { - $scope.$emit("ReloadOrganzationCards"); - $scope.$emit("ShowOrgListHeader"); - $state.transitionTo('organizations'); - }; - - // Related set: Add button - $scope.add = function (set) { - $rootScope.flashMessage = null; - $location.path('/' + base + '/' + $stateParams.organization_id + '/' + set); - }; - - // Related set: Edit button - $scope.edit = function (set, id) { - $rootScope.flashMessage = null; - $location.path('/' + set + '/' + id); - }; - - // Related set: Delete button - $scope['delete'] = function (set, itm_id, name, title) { - $rootScope.flashMessage = null; - - var action = function () { - Wait('start'); - var url = defaultUrl + $stateParams.organization_id + '/' + set + '/'; - Rest.setUrl(url); - Rest.post({ id: itm_id, disassociate: 1 }) - .success(function () { - $('#prompt-modal').modal('hide'); - $scope.search(form.related[set].iterator); - }) - .error(function (data, status) { - $('#prompt-modal').modal('hide'); - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. POST returned status: ' + status }); - }); - }; - - Prompt({ - hdr: 'Delete', - body: '
Are you sure you want to remove the ' + title + ' below from ' + $scope.name + '?
' + name + '
', - action: action, - actionText: 'DELETE' - }); - - }; -} - -OrganizationsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', - '$log', '$stateParams', 'OrganizationForm', 'GenerateForm', 'Rest', 'Alert', - 'ProcessErrors', 'RelatedSearchInit', 'RelatedPaginateInit', 'Prompt', - 'ClearScope', 'GetBasePath', 'Wait', '$state' -]; \ No newline at end of file diff --git a/awx/ui/client/src/organizations/add/main.js b/awx/ui/client/src/organizations/add/main.js new file mode 100644 index 0000000000..27b8406e0b --- /dev/null +++ b/awx/ui/client/src/organizations/add/main.js @@ -0,0 +1,14 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import route from './organizations-add.route'; +import controller from './organizations-add.controller'; + +export default + angular.module('organizationsAdd', []) + .run(['$stateExtender', function($stateExtender) { + $stateExtender.addState(route); + }]); diff --git a/awx/ui/client/src/organizations/add/organizations-add.controller.js b/awx/ui/client/src/organizations/add/organizations-add.controller.js new file mode 100644 index 0000000000..00c7ad9579 --- /dev/null +++ b/awx/ui/client/src/organizations/add/organizations-add.controller.js @@ -0,0 +1,66 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['$scope', '$rootScope', '$compile', '$location', + '$log', '$stateParams', 'OrganizationForm', 'GenerateForm', 'Rest', 'Alert', + 'ProcessErrors', 'ClearScope', 'GetBasePath', 'ReturnToCaller', 'Wait', + '$state', + function($scope, $rootScope, $compile, $location, $log, + $stateParams, OrganizationForm, GenerateForm, Rest, Alert, ProcessErrors, + ClearScope, GetBasePath, ReturnToCaller, Wait, $state) { + + ClearScope(); + + // Inject dynamic view + var generator = GenerateForm, + form = OrganizationForm, + base = $location.path().replace(/^\//, '').split('/')[0]; + + generator.inject(form, { + mode: 'add', + related: false, + scope: $scope + }); + generator.reset(); + + $scope.$emit("HideOrgListHeader"); + + // Save + $scope.formSave = function() { + generator.clearApiErrors(); + Wait('start'); + var url = GetBasePath(base); + url += (base !== 'organizations') ? $stateParams.project_id + '/organizations/' : ''; + Rest.setUrl(url); + Rest.post({ + name: $scope.name, + description: $scope.description + }) + .success(function(data) { + Wait('stop'); + $scope.$emit("ReloadOrganzationCards", data.id); + if (base === 'organizations') { + $rootScope.flashMessage = "New organization successfully created!"; + $location.path('/organizations/' + data.id); + } else { + ReturnToCaller(1); + } + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, form, { + hdr: 'Error!', + msg: 'Failed to add new organization. Post returned status: ' + status + }); + }); + }; + + $scope.formCancel = function() { + $scope.$emit("ReloadOrganzationCards"); + $scope.$emit("ShowOrgListHeader"); + $state.transitionTo('organizations'); + }; + } +] diff --git a/awx/ui/client/src/organizations/add/organizations-add.partial.html b/awx/ui/client/src/organizations/add/organizations-add.partial.html new file mode 100644 index 0000000000..5db1583d13 --- /dev/null +++ b/awx/ui/client/src/organizations/add/organizations-add.partial.html @@ -0,0 +1,4 @@ +
+
+
+
diff --git a/awx/ui/client/src/organizations/add/organizations-add.route.js b/awx/ui/client/src/organizations/add/organizations-add.route.js new file mode 100644 index 0000000000..9deab323b7 --- /dev/null +++ b/awx/ui/client/src/organizations/add/organizations-add.route.js @@ -0,0 +1,24 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import {templateUrl} from '../../shared/template-url/template-url.factory'; +import OrganizationsAdd from './organizations-add.controller'; + +export default { + name: 'organizations.add', + route: '/add', + templateUrl: templateUrl('organizations/add/organizations-add'), + controller: OrganizationsAdd, + ncyBreadcrumb: { + parent: "organizations", + label: "CREATE ORGANIZATION" + }, + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } +}; diff --git a/awx/ui/client/src/organizations/edit/main.js b/awx/ui/client/src/organizations/edit/main.js new file mode 100644 index 0000000000..8f2a825df9 --- /dev/null +++ b/awx/ui/client/src/organizations/edit/main.js @@ -0,0 +1,15 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import route from './organizations-edit.route'; +import controller from './organizations-edit.controller'; + +export default + angular.module('organizationsEdit', []) + .controller('organizationsEditController', controller) + .run(['$stateExtender', function($stateExtender) { + $stateExtender.addState(route); + }]); diff --git a/awx/ui/client/src/organizations/edit/organizations-edit.controller.js b/awx/ui/client/src/organizations/edit/organizations-edit.controller.js new file mode 100644 index 0000000000..f9178a1fb1 --- /dev/null +++ b/awx/ui/client/src/organizations/edit/organizations-edit.controller.js @@ -0,0 +1,150 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['$scope', '$rootScope', '$compile', '$location', + '$log', '$stateParams', 'OrganizationForm', 'GenerateForm', 'Rest', 'Alert', + 'ProcessErrors', 'RelatedSearchInit', 'RelatedPaginateInit', 'Prompt', + 'ClearScope', 'GetBasePath', 'Wait', '$state', + function($scope, $rootScope, $compile, $location, $log, + $stateParams, OrganizationForm, GenerateForm, Rest, Alert, ProcessErrors, + RelatedSearchInit, RelatedPaginateInit, Prompt, ClearScope, GetBasePath, + Wait, $state) { + + ClearScope(); + + // Inject dynamic view + var form = OrganizationForm, + generator = GenerateForm, + defaultUrl = GetBasePath('organizations'), + base = $location.path().replace(/^\//, '').split('/')[0], + master = {}, + id = $stateParams.organization_id, + relatedSets = {}; + + $scope.$emit("HideOrgListHeader"); + + $scope.$emit("ReloadOrganzationCards", id); + + $scope.organization_id = id; + + generator.inject(form, { mode: 'edit', related: true, scope: $scope}); + generator.reset(); + + // After the Organization is loaded, retrieve each related set + if ($scope.organizationLoadedRemove) { + $scope.organizationLoadedRemove(); + } + $scope.organizationLoadedRemove = $scope.$on('organizationLoaded', function () { + for (var set in relatedSets) { + $scope.search(relatedSets[set].iterator); + } + Wait('stop'); + }); + + // Retrieve detail record and prepopulate the form + Wait('start'); + Rest.setUrl(defaultUrl + id + '/'); + Rest.get() + .success(function (data) { + var fld, related, set; + $scope.organization_name = data.name; + for (fld in form.fields) { + if (data[fld]) { + $scope[fld] = data[fld]; + master[fld] = data[fld]; + } + } + related = data.related; + for (set in form.related) { + if (related[set]) { + relatedSets[set] = { + url: related[set], + iterator: form.related[set].iterator + }; + } + } + // Initialize related search functions. Doing it here to make sure relatedSets object is populated. + RelatedSearchInit({ scope: $scope, form: form, relatedSets: relatedSets }); + RelatedPaginateInit({ scope: $scope, relatedSets: relatedSets }); + $scope.$emit('organizationLoaded'); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, form, { hdr: 'Error!', + msg: 'Failed to retrieve organization: ' + $stateParams.id + '. GET status: ' + status }); + }); + + + // Save changes to the parent + $scope.formSave = function () { + var fld, params = {}; + generator.clearApiErrors(); + Wait('start'); + for (fld in form.fields) { + params[fld] = $scope[fld]; + } + Rest.setUrl(defaultUrl + id + '/'); + Rest.put(params) + .success(function (data) { + Wait('stop'); + $scope.organization_name = $scope.name; + master = params; + $rootScope.flashMessage = "Your changes were successfully saved!"; + $scope.$emit("ReloadOrganzationCards", data.id); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, OrganizationForm, { hdr: 'Error!', + msg: 'Failed to update organization: ' + id + '. PUT status: ' + status }); + }); + }; + + $scope.formCancel = function () { + $scope.$emit("ReloadOrganzationCards"); + $scope.$emit("ShowOrgListHeader"); + $state.transitionTo('organizations'); + }; + + // Related set: Add button + $scope.add = function (set) { + $rootScope.flashMessage = null; + $location.path('/' + base + '/' + $stateParams.organization_id + '/' + set); + }; + + // Related set: Edit button + $scope.edit = function (set, id) { + $rootScope.flashMessage = null; + $location.path('/' + set + '/' + id); + }; + + // Related set: Delete button + $scope['delete'] = function (set, itm_id, name, title) { + $rootScope.flashMessage = null; + + var action = function () { + Wait('start'); + var url = defaultUrl + $stateParams.organization_id + '/' + set + '/'; + Rest.setUrl(url); + Rest.post({ id: itm_id, disassociate: 1 }) + .success(function () { + $('#prompt-modal').modal('hide'); + $scope.search(form.related[set].iterator); + }) + .error(function (data, status) { + $('#prompt-modal').modal('hide'); + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + ' failed. POST returned status: ' + status }); + }); + }; + + Prompt({ + hdr: 'Delete', + body: '
Are you sure you want to remove the ' + title + ' below from ' + $scope.name + '?
' + name + '
', + action: action, + actionText: 'DELETE' + }); + + }; +} +] diff --git a/awx/ui/client/src/organizations/edit/organizations-edit.route.js b/awx/ui/client/src/organizations/edit/organizations-edit.route.js new file mode 100644 index 0000000000..ad546e71cc --- /dev/null +++ b/awx/ui/client/src/organizations/edit/organizations-edit.route.js @@ -0,0 +1,29 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import { + templateUrl +} from '../../shared/template-url/template-url.factory'; +import OrganizationsEdit from './organizations-edit.controller'; + +export default { + name: 'organizations.edit', + route: '/:organization_id', + templateUrl: templateUrl('organizations/add/organizations-add'), + controller: OrganizationsEdit, + data: { + activityStreamId: 'organization_id' + }, + ncyBreadcrumb: { + parent: "organizations", + label: "{{name}}" + }, + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } +}; diff --git a/awx/ui/client/src/organizations/list/main.js b/awx/ui/client/src/organizations/list/main.js new file mode 100644 index 0000000000..0250a5f5f8 --- /dev/null +++ b/awx/ui/client/src/organizations/list/main.js @@ -0,0 +1,14 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import route from './organizations-list.route'; +import controller from './organizations-list.controller'; + +export default + angular.module('organizationsList', []) + .run(['$stateExtender', function($stateExtender) { + $stateExtender.addState(route); + }]); diff --git a/awx/ui/client/src/organizations/list/organizations-list.controller.js b/awx/ui/client/src/organizations/list/organizations-list.controller.js new file mode 100644 index 0000000000..2a21b03ffb --- /dev/null +++ b/awx/ui/client/src/organizations/list/organizations-list.controller.js @@ -0,0 +1,182 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['$stateParams', '$scope', '$rootScope', '$location', + '$log', '$compile', 'Rest', 'PaginateWidget', 'PaginateInit', + 'SearchInit', 'OrganizationList', 'Alert', 'Prompt', 'ClearScope', + 'ProcessErrors', 'GetBasePath', 'Wait', + '$state', + function($stateParams, $scope, $rootScope, $location, + $log, $compile, Rest, PaginateWidget, PaginateInit, + SearchInit, OrganizationList, Alert, Prompt, ClearScope, + ProcessErrors, GetBasePath, Wait, + $state) { + + ClearScope(); + + var defaultUrl = GetBasePath('organizations'), + list = OrganizationList, + pageSize = $scope.orgCount; + + PaginateInit({ + scope: $scope, + list: list, + url: defaultUrl, + pageSize: pageSize, + }); + SearchInit({ + scope: $scope, + list: list, + url: defaultUrl, + }); + + $scope.search(list.iterator); + + $scope.PaginateWidget = PaginateWidget({ + iterator: list.iterator, + set: 'organizations' + }); + + var paginationContainer = $('#pagination-container'); + paginationContainer.html($scope.PaginateWidget); + $compile(paginationContainer.contents())($scope) + + var parseCardData = function(cards) { + return cards.map(function(card) { + var val = {}; + val.name = card.name; + val.id = card.id; + if (card.id + "" === cards.activeCard) { + val.isActiveCard = true; + } + val.description = card.description || undefined; + val.links = []; + val.links.push({ + href: card.related.users, + name: "USERS" + }); + val.links.push({ + href: card.related.teams, + name: "TEAMS" + }); + val.links.push({ + href: card.related.inventories, + name: "INVENTORIES" + }); + val.links.push({ + href: card.related.projects, + name: "PROJECTS" + }); + val.links.push({ + href: card.related.job_templates, + name: "JOB TEMPLATES" + }); + val.links.push({ + href: card.related.admins, + name: "ADMINS" + }); + return val; + }); + }; + + var getOrganization = function(id) { + Rest.setUrl(defaultUrl); + Rest.get() + .success(function(data) { + data.results.activeCard = id; + $scope.orgCount = data.count; + $scope.orgCards = parseCardData(data.results); + Wait("stop"); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, null, { + hdr: 'Error!', + msg: 'Call to ' + defaultUrl + ' failed. DELETE returned status: ' + status + }); + }); + }; + + $scope.$on("ReloadOrgListView", function() { + if ($state.$current.self.name === "organizations") { + delete $scope.activeCard; + if ($scope.orgCards) { + $scope.orgCards = $scope.orgCards.map(function(card) { + delete card.isActiveCard; + return card; + }); + } + $scope.hideListHeader = false; + } + }); + + $scope.$on("ReloadOrganzationCards", function(e, id) { + $scope.activeCard = id; + getOrganization(id); + }); + + $scope.$on("HideOrgListHeader", function() { + $scope.hideListHeader = true; + }); + + $scope.$on("ShowOrgListHeader", function() { + $scope.hideListHeader = false; + }); + + getOrganization(); + + $rootScope.flashMessage = null; + + if ($scope.removePostRefresh) { + $scope.removePostRefresh(); + } + $scope.removePostRefresh = $scope.$on('PostRefresh', function() { + // Cleanup after a delete + Wait('stop'); + $('#prompt-modal').modal('hide'); + }); + + $scope.addOrganization = function() { + $state.transitionTo('organizations.add'); + }; + + $scope.editOrganization = function(id) { + $scope.activeCard = id; + $state.transitionTo('organizations.edit', { + organization_id: id + }); + }; + + $scope.deleteOrganization = function(id, name) { + + var action = function() { + $('#prompt-modal').modal('hide'); + Wait('start'); + var url = defaultUrl + id + '/'; + Rest.setUrl(url); + Rest.destroy() + .success(function() { + if ($state.current.name !== "organzations") { + $state.transitionTo("organizations"); + } + $scope.$emit("ReloadOrganzationCards"); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, null, { + hdr: 'Error!', + msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status + }); + }); + }; + + Prompt({ + hdr: 'Delete', + body: '
Are you sure you want to delete the organization below?
' + name + '
', + action: action, + actionText: 'DELETE' + }); + }; + } +] diff --git a/awx/ui/client/src/organizations/list/organizations-list.partial.html b/awx/ui/client/src/organizations/list/organizations-list.partial.html new file mode 100644 index 0000000000..b6d531897a --- /dev/null +++ b/awx/ui/client/src/organizations/list/organizations-list.partial.html @@ -0,0 +1,62 @@ +
+
+
+
+
+
+ organizations +
+ + {{ orgCount }} + +
+
+ +
+
+
+
+
+
+

{{ card.name }}

+
+ + +
+
+

{{ card.description || "Place organization description here" }}

+ +
+
+
+
+
diff --git a/awx/ui/client/src/organizations/list/organizations-list.route.js b/awx/ui/client/src/organizations/list/organizations-list.route.js new file mode 100644 index 0000000000..a97b939c01 --- /dev/null +++ b/awx/ui/client/src/organizations/list/organizations-list.route.js @@ -0,0 +1,31 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import {templateUrl} from '../../shared/template-url/template-url.factory'; +import OrganizationsList from './organizations-list.controller'; + +export default { + name: 'organizations', + route: '/organizations', + templateUrl: templateUrl('organizations/list/organizations-list'), + controller: OrganizationsList, + data: { + activityStream: true, + activityStreamTarget: 'organization' + }, + ncyBreadcrumb: { + parent: function($scope) { + $scope.$parent.$emit("ReloadOrgListView"); + return "setup"; + }, + label: "ORGANIZATIONS" + }, + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } +}; diff --git a/awx/ui/client/src/organizations/main.js b/awx/ui/client/src/organizations/main.js new file mode 100644 index 0000000000..b846961f8d --- /dev/null +++ b/awx/ui/client/src/organizations/main.js @@ -0,0 +1,16 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import organizationsList from './list/main'; +import organizationsAdd from './add/main'; +import organizationsEdit from './edit/main'; + +export default +angular.module('organizations', [ + organizationsList.name, + organizationsAdd.name, + organizationsEdit.name, +]); From 8ca3a6b2bfd5d130af947e9820a745ffede6fcea Mon Sep 17 00:00:00 2001 From: Ken Hoes Date: Wed, 16 Mar 2016 13:23:37 -0400 Subject: [PATCH 2/3] Added counts to organizations listing --- .../list/organizations-list.controller.js | 18 ++++++++++++------ .../list/organizations-list.partial.html | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/awx/ui/client/src/organizations/list/organizations-list.controller.js b/awx/ui/client/src/organizations/list/organizations-list.controller.js index 2a21b03ffb..7316f145b9 100644 --- a/awx/ui/client/src/organizations/list/organizations-list.controller.js +++ b/awx/ui/client/src/organizations/list/organizations-list.controller.js @@ -56,27 +56,33 @@ export default ['$stateParams', '$scope', '$rootScope', '$location', val.links = []; val.links.push({ href: card.related.users, - name: "USERS" + name: "USERS", + count: card.summary_fields.related_field_counts.users }); val.links.push({ href: card.related.teams, - name: "TEAMS" + name: "TEAMS", + count: card.summary_fields.related_field_counts.teams }); val.links.push({ href: card.related.inventories, - name: "INVENTORIES" + name: "INVENTORIES", + count: card.summary_fields.related_field_counts.inventories }); val.links.push({ href: card.related.projects, - name: "PROJECTS" + name: "PROJECTS", + count: card.summary_fields.related_field_counts.projects }); val.links.push({ href: card.related.job_templates, - name: "JOB TEMPLATES" + name: "JOB TEMPLATES", + count: card.summary_fields.related_field_counts.job_templates }); val.links.push({ href: card.related.admins, - name: "ADMINS" + name: "ADMINS", + count: card.summary_fields.related_field_counts.admins }); return val; }); diff --git a/awx/ui/client/src/organizations/list/organizations-list.partial.html b/awx/ui/client/src/organizations/list/organizations-list.partial.html index b6d531897a..73bfa908e9 100644 --- a/awx/ui/client/src/organizations/list/organizations-list.partial.html +++ b/awx/ui/client/src/organizations/list/organizations-list.partial.html @@ -47,7 +47,7 @@