From f9b46b7c3d17a7554d947cbeee6015ef3445d7a5 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Wed, 5 Apr 2017 11:45:02 -0400 Subject: [PATCH] Set up new inventory directory and states --- awx/ui/client/legacy-styles/forms.less | 4 + awx/ui/client/src/app.js | 2 + .../list/inventory-list.controller.js | 2 +- .../add/inventory-add.controller.js | 104 ++++++ awx/ui/client/src/inventoriesnew/add/main.js | 11 + .../edit/inventory-edit.controller.js | 136 ++++++++ awx/ui/client/src/inventoriesnew/edit/main.js | 11 + .../hosts/add/host-add.controller.js | 14 + .../src/inventoriesnew/hosts/add/main.js | 11 + .../hosts/edit/host-edit.controller.js | 14 + .../src/inventoriesnew/hosts/edit/main.js | 11 + .../src/inventoriesnew/hosts/host.form.js | 103 ++++++ .../src/inventoriesnew/hosts/host.list.js | 121 +++++++ .../hosts/list/host-list.controller.js | 80 +++++ .../src/inventoriesnew/hosts/list/main.js | 11 + .../client/src/inventoriesnew/hosts/main.js | 20 ++ .../inventoriesnew/inventories.partial.html | 14 + .../src/inventoriesnew/inventory.form.js | 135 ++++++++ .../src/inventoriesnew/inventory.list.js | 98 ++++++ .../list/inventory-list.controller.js | 308 ++++++++++++++++++ awx/ui/client/src/inventoriesnew/list/main.js | 11 + awx/ui/client/src/inventoriesnew/main.js | 236 ++++++++++++++ .../src/main-menu/main-menu.partial.html | 17 + .../src/shared/stateDefinitions.factory.js | 21 +- 24 files changed, 1485 insertions(+), 10 deletions(-) create mode 100644 awx/ui/client/src/inventoriesnew/add/inventory-add.controller.js create mode 100644 awx/ui/client/src/inventoriesnew/add/main.js create mode 100644 awx/ui/client/src/inventoriesnew/edit/inventory-edit.controller.js create mode 100644 awx/ui/client/src/inventoriesnew/edit/main.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/add/host-add.controller.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/add/main.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/edit/host-edit.controller.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/edit/main.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/host.form.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/host.list.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/list/host-list.controller.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/list/main.js create mode 100644 awx/ui/client/src/inventoriesnew/hosts/main.js create mode 100644 awx/ui/client/src/inventoriesnew/inventories.partial.html create mode 100644 awx/ui/client/src/inventoriesnew/inventory.form.js create mode 100644 awx/ui/client/src/inventoriesnew/inventory.list.js create mode 100644 awx/ui/client/src/inventoriesnew/list/inventory-list.controller.js create mode 100644 awx/ui/client/src/inventoriesnew/list/main.js create mode 100644 awx/ui/client/src/inventoriesnew/main.js diff --git a/awx/ui/client/legacy-styles/forms.less b/awx/ui/client/legacy-styles/forms.less index dcf9154154..ce7043c7e6 100644 --- a/awx/ui/client/legacy-styles/forms.less +++ b/awx/ui/client/legacy-styles/forms.less @@ -130,6 +130,10 @@ .noselect; } +.Form-tab--notitle { + margin-bottom: 0px; +} + .Form-tab:hover { color: @btn-txt; background-color: @btn-bg-hov; diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 0649023b54..f5eaf2080b 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -40,6 +40,7 @@ if ($basePath) { import portalMode from './portal-mode/main'; import systemTracking from './system-tracking/main'; import inventories from './inventories/main'; +import inventorynew from './inventoriesnew/main'; import inventoryScripts from './inventory-scripts/main'; import credentialTypes from './credential-types/main'; import organizations from './organizations/main'; @@ -99,6 +100,7 @@ var tower = angular.module('Tower', [ configuration.name, systemTracking.name, inventories.name, + inventorynew.name, inventoryScripts.name, credentialTypes.name, organizations.name, diff --git a/awx/ui/client/src/inventories/list/inventory-list.controller.js b/awx/ui/client/src/inventories/list/inventory-list.controller.js index 2f43f48100..d900048060 100644 --- a/awx/ui/client/src/inventories/list/inventory-list.controller.js +++ b/awx/ui/client/src/inventories/list/inventory-list.controller.js @@ -250,7 +250,7 @@ function InventoriesList($scope, $rootScope, $location, }; $scope.addInventory = function () { - $state.go('inventories.add'); + $state.go('inventoriesnew.add'); }; $scope.editInventory = function (id) { diff --git a/awx/ui/client/src/inventoriesnew/add/inventory-add.controller.js b/awx/ui/client/src/inventoriesnew/add/inventory-add.controller.js new file mode 100644 index 0000000000..17f42276d0 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/add/inventory-add.controller.js @@ -0,0 +1,104 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +/** + * @ngdoc function + * @name controllers.function:Inventories + * @description This controller's for the Inventory page + */ + +function InventoriesAdd($scope, $location, + GenerateForm, InventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors, + ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON, + $state) { + + $scope.canAdd = false; + rbacUiControlService.canAdd(GetBasePath('inventory')) + .then(function(canAdd) { + $scope.canAdd = canAdd; + }); + + Rest.setUrl(GetBasePath('inventory')); + Rest.options() + .success(function(data) { + if (!data.actions.POST) { + $state.go("^"); + Alert('Permission Error', 'You do not have permission to add an inventory.', 'alert-info'); + } + }); + + ClearScope(); + + // Inject dynamic view + var defaultUrl = GetBasePath('inventory'), + form = InventoryForm; + + init(); + + function init() { + $scope.canEditOrg = true; + form.formLabelSize = null; + form.formFieldSize = null; + + // apply form definition's default field values + GenerateForm.applyDefaults(form, $scope); + + $scope.parseType = 'yaml'; + ParseTypeChange({ + scope: $scope, + variable: 'variables', + parse_variable: 'parseType', + field_id: 'inventory_variables' + }); + } + + // Save + $scope.formSave = function() { + Wait('start'); + try { + var fld, json_data, data; + + json_data = ToJSON($scope.parseType, $scope.variables, true); + + data = {}; + for (fld in form.fields) { + if (form.fields[fld].realName) { + data[form.fields[fld].realName] = $scope[fld]; + } else { + data[fld] = $scope[fld]; + } + } + + Rest.setUrl(defaultUrl); + Rest.post(data) + .success(function(data) { + var inventory_id = data.id; + Wait('stop'); + $location.path('/inventoriesnew/' + inventory_id); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, form, { + hdr: 'Error!', + msg: 'Failed to add new inventory. Post returned status: ' + status + }); + }); + } catch (err) { + Wait('stop'); + Alert("Error", "Error parsing inventory variables. Parser returned: " + err); + } + + }; + + $scope.formCancel = function() { + $state.go('inventoriesnew'); + }; +} + +export default ['$scope', '$location', + 'GenerateForm', 'InventoryForm', 'rbacUiControlService', 'Rest', 'Alert', + 'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange', + 'Wait', 'ToJSON', '$state', InventoriesAdd +]; diff --git a/awx/ui/client/src/inventoriesnew/add/main.js b/awx/ui/client/src/inventoriesnew/add/main.js new file mode 100644 index 0000000000..2d3c391495 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/add/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import controller from './inventory-add.controller'; + +export default +angular.module('newInventoryAdd', []) + .controller('NewInventoryAddController', controller); diff --git a/awx/ui/client/src/inventoriesnew/edit/inventory-edit.controller.js b/awx/ui/client/src/inventoriesnew/edit/inventory-edit.controller.js new file mode 100644 index 0000000000..98c1549499 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/edit/inventory-edit.controller.js @@ -0,0 +1,136 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +/** + * @ngdoc function + * @name controllers.function:Inventories + * @description This controller's for the Inventory page + */ + +function InventoriesEdit($scope, $location, + $stateParams, InventoriesNewForm, Rest, ProcessErrors, + ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON, + ParseVariableString, $state, OrgAdminLookup) { + + // Inject dynamic view + var defaultUrl = GetBasePath('inventory'), + form = InventoriesNewForm, + inventory_id = $stateParams.inventory_id, + master = {}, + fld, json_data, data; + + ClearScope(); + init(); + + function init() { + ClearScope(); + form.formLabelSize = null; + form.formFieldSize = null; + $scope.inventory_id = inventory_id; + + $scope.$watch('inventory_obj.summary_fields.user_capabilities.edit', function(val) { + if (val === false) { + $scope.canAdd = false; + } + }); + } + + + Wait('start'); + Rest.setUrl(GetBasePath('inventory') + inventory_id + '/'); + Rest.get() + .success(function(data) { + var fld; + for (fld in form.fields) { + if (fld === 'variables') { + $scope.variables = ParseVariableString(data.variables); + master.variables = $scope.variables; + } else if (fld === 'inventory_name') { + $scope[fld] = data.name; + master[fld] = $scope[fld]; + } else if (fld === 'inventory_description') { + $scope[fld] = data.description; + master[fld] = $scope[fld]; + } else if (data[fld]) { + $scope[fld] = data[fld]; + master[fld] = $scope[fld]; + } + if (form.fields[fld].sourceModel && data.summary_fields && + data.summary_fields[form.fields[fld].sourceModel]) { + $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = + data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; + master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = + data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; + } + } + + Wait('stop'); + $scope.parseType = 'yaml'; + ParseTypeChange({ + scope: $scope, + variable: 'variables', + parse_variable: 'parseType', + field_id: 'inventory_variables' + }); + + OrgAdminLookup.checkForAdminAccess({organization: data.organization}) + .then(function(canEditOrg){ + $scope.canEditOrg = canEditOrg; + }); + + $scope.inventory_obj = data; + $scope.name = data.name; + + $scope.$emit('inventoryLoaded'); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, null, { + hdr: 'Error!', + msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status + }); + }); + // Save + $scope.formSave = function() { + Wait('start'); + + // Make sure we have valid variable data + json_data = ToJSON($scope.parseType, $scope.variables); + + data = {}; + for (fld in form.fields) { + if (form.fields[fld].realName) { + data[form.fields[fld].realName] = $scope[fld]; + } else { + data[fld] = $scope[fld]; + } + } + + Rest.setUrl(defaultUrl + inventory_id + '/'); + Rest.put(data) + .success(function() { + Wait('stop'); + $state.go($state.current, {}, { reload: true }); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, form, { + hdr: 'Error!', + msg: 'Failed to update inventory. PUT returned status: ' + status + }); + }); + }; + + $scope.formCancel = function() { + $state.go('inventoriesnew'); + }; + +} + +export default ['$scope', '$location', + '$stateParams', 'InventoriesNewForm', 'Rest', + 'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange', 'Wait', + 'ToJSON', 'ParseVariableString', + '$state', 'OrgAdminLookup', InventoriesEdit, +]; diff --git a/awx/ui/client/src/inventoriesnew/edit/main.js b/awx/ui/client/src/inventoriesnew/edit/main.js new file mode 100644 index 0000000000..a6a404a869 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/edit/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import controller from './inventory-edit.controller'; + +export default + angular.module('newInventoryEdit', []) + .controller('NewInventoryEditController', controller); diff --git a/awx/ui/client/src/inventoriesnew/hosts/add/host-add.controller.js b/awx/ui/client/src/inventoriesnew/hosts/add/host-add.controller.js new file mode 100644 index 0000000000..151d75401d --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/add/host-add.controller.js @@ -0,0 +1,14 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +function HostsAdd($scope) { + +console.log('inside host add'); + +} + +export default ['$scope', HostsAdd +]; diff --git a/awx/ui/client/src/inventoriesnew/hosts/add/main.js b/awx/ui/client/src/inventoriesnew/hosts/add/main.js new file mode 100644 index 0000000000..8205e986c6 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/add/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import controller from './host-add.controller'; + +export default +angular.module('hostsAdd', []) + .controller('NewHostAddController', controller); diff --git a/awx/ui/client/src/inventoriesnew/hosts/edit/host-edit.controller.js b/awx/ui/client/src/inventoriesnew/hosts/edit/host-edit.controller.js new file mode 100644 index 0000000000..d1d1092085 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/edit/host-edit.controller.js @@ -0,0 +1,14 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +function HostsEdit($scope) { + + console.log('inside host edit'); + +} + +export default ['$scope', HostsEdit +]; diff --git a/awx/ui/client/src/inventoriesnew/hosts/edit/main.js b/awx/ui/client/src/inventoriesnew/hosts/edit/main.js new file mode 100644 index 0000000000..420e870e99 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/edit/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import controller from './host-edit.controller'; + +export default +angular.module('hostsEdit', []) + .controller('NewHostEditController', controller); diff --git a/awx/ui/client/src/inventoriesnew/hosts/host.form.js b/awx/ui/client/src/inventoriesnew/hosts/host.form.js new file mode 100644 index 0000000000..efb64a4785 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/host.form.js @@ -0,0 +1,103 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + /** + * @ngdoc function + * @name forms.function:Hosts + * @description This form is for adding/editing a host on the inventory page +*/ + +export default ['i18n', function(i18n) { + return { + + addTitle: i18n._('CREATE HOST'), + editTitle: '{{ host.name }}', + name: 'host', + basePath: 'hosts', + well: false, + formLabelSize: 'col-lg-3', + formFieldSize: 'col-lg-9', + iterator: 'host', + headerFields:{ + enabled: { + class: 'Form-header-field', + ngClick: 'toggleHostEnabled(host)', + type: 'toggle', + awToolTip: "

" + + i18n._("Indicates if a host is available and should be included in running jobs.") + + "

" + + i18n._("For hosts that are part of an external" + + " inventory, this flag cannot be changed. It will be" + + " set by the inventory sync process.") + + "

", + dataTitle: i18n._('Host Enabled'), + ngDisabled: 'host.has_inventory_sources' + } + }, + fields: { + name: { + label: i18n._('Host Name'), + type: 'text', + required: true, + awPopOver: "

" + + i18n._("Provide a host name, ip address, or ip address:port. Examples include:") + + "

" + + "
myserver.domain.com
" + + "127.0.0.1
" + + "10.1.0.140:25
" + + "server.example.com:25" + + "
", + dataTitle: i18n._('Host Name'), + dataPlacement: 'right', + dataContainer: 'body', + ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)' + }, + description: { + label: i18n._('Description'), + ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)', + type: 'text' + }, + variables: { + label: i18n._('Variables'), + type: 'textarea', + rows: 6, + class: 'Form-formGroup--fullWidth', + "default": "---", + awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + + "JSON:
\n" + + "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "YAML:
\n" + + "
---
somevar: somevalue
password: magic
\n" + + '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + + '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', + dataTitle: i18n._('Host Variables'), + dataPlacement: 'right', + dataContainer: 'body' + }, + inventory: { + type: 'hidden', + includeOnEdit: true, + includeOnAdd: true + } + }, + + buttons: { + cancel: { + ngClick: 'formCancel()', + ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)' + }, + close: { + ngClick: 'formCancel()', + ngShow: '!(host.summary_fields.user_capabilities.edit || canAdd)' + }, + save: { + ngClick: 'formSave()', + ngDisabled: true, + ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)' + } + }, + }; + }]; diff --git a/awx/ui/client/src/inventoriesnew/hosts/host.list.js b/awx/ui/client/src/inventoriesnew/hosts/host.list.js new file mode 100644 index 0000000000..632a38129b --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/host.list.js @@ -0,0 +1,121 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['i18n', function(i18n) { + return { + name: 'hosts', + iterator: 'host', + editTitle: '{{ selected_group }}', + searchSize: 'col-lg-12 col-md-12 col-sm-12 col-xs-12', + showTitle: false, + well: true, + index: false, + hover: true, + hasChildren: true, + 'class': 'table-no-border', + trackBy: 'host.id', + title: false, + + fields: { + toggleHost: { + ngDisabled: "!host.summary_fields.user_capabilities.edit", + label: '', + columnClass: 'List-staticColumn--toggle', + type: "toggle", + ngClick: "toggleHost($event, host)", + awToolTip: "

" + + i18n._("Indicates if a host is available and should be included in running jobs.") + + "

" + + i18n._("For hosts that are part of an external" + + " inventory, this flag cannot be changed. It will be" + + " set by the inventory sync process.") + + "

", + dataPlacement: "right", + nosort: true, + }, + active_failures: { + label: '', + iconOnly: true, + nosort: true, + // do not remove this ng-click directive + // the list generator case to handle fields without ng-click + // cannot handle the aw-* directives + ngClick: 'noop()', + awPopOver: "{{ host.job_status_html }}", + dataTitle: "{{ host.job_status_title }}", + awToolTip: "{{ host.badgeToolTip }}", + dataPlacement: 'top', + icon: "{{ 'fa icon-job-' + host.active_failures }}", + id: 'active-failures-action', + columnClass: 'status-column List-staticColumn--smallStatus' + }, + name: { + key: true, + label: 'Name', + ngClick: "editHost(host.id)", + columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', + dataHostId: "{{ host.id }}", + dataType: "host", + class: 'InventoryManage-breakWord' + } + }, + + fieldActions: { + + columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', + copy: { + mode: 'all', + ngClick: "copyMoveHost(host.id)", + awToolTip: 'Copy or move host to another group', + dataPlacement: "top", + ngShow: 'host.summary_fields.user_capabilities.edit' + }, + edit: { + //label: 'Edit', + ngClick: "editHost(host.id)", + icon: 'icon-edit', + awToolTip: 'Edit host', + dataPlacement: 'top', + ngShow: 'host.summary_fields.user_capabilities.edit' + }, + view: { + //label: 'Edit', + ngClick: "editHost(host.id)", + awToolTip: 'View host', + dataPlacement: 'top', + ngShow: '!host.summary_fields.user_capabilities.edit' + }, + "delete": { + //label: 'Delete', + ngClick: "deleteHost(host.id, host.name)", + icon: 'icon-trash', + awToolTip: 'Delete host', + dataPlacement: 'top', + ngShow: 'host.summary_fields.user_capabilities.delete' + } + }, + + actions: { + refresh: { + mode: 'all', + awToolTip: "Refresh the page", + ngClick: "refreshGroups()", + ngShow: "socketStatus == 'error'", + actionClass: 'btn List-buttonDefault', + buttonContent: 'REFRESH' + }, + smart_inventory: { + mode: 'all', + ngClick: "smartInventory()", + awToolTip: "Create a new Smart Inventory from results.", + actionClass: 'btn List-buttonDefault', + buttonContent: 'SMART INVENTORY', + ngShow: 'canAdd', + dataPlacement: "top", + } + } + }; +}]; diff --git a/awx/ui/client/src/inventoriesnew/hosts/list/host-list.controller.js b/awx/ui/client/src/inventoriesnew/hosts/list/host-list.controller.js new file mode 100644 index 0000000000..3f5ac46872 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/list/host-list.controller.js @@ -0,0 +1,80 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +function HostsList($scope, HostsNewList, $rootScope, GetBasePath, + rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, HostManageService) { + + let list = HostsNewList; + + init(); + + function init(){ + $scope.canAdd = false; + + rbacUiControlService.canAdd('hosts') + .then(function(canAdd) { + $scope.canAdd = canAdd; + }); + + // Search init + $scope.list = list; + $scope[`${list.iterator}_dataset`] = Dataset.data; + $scope[list.name] = $scope[`${list.iterator}_dataset`].results; + + $rootScope.flashMessage = null; + + } + + $scope.createHost = function(){ + $state.go('hostsnew.add'); + }; + $scope.editHost = function(id){ + $state.go('hostsnew.edit', {host_id: id}); + }; + $scope.deleteHost = function(id, name){ + var body = '
Are you sure you want to permanently delete the host below from the inventory?
' + $filter('sanitize')(name) + '
'; + var action = function(){ + delete $rootScope.promptActionBtnClass; + Wait('start'); + HostManageService.delete(id).then(() => { + $('#prompt-modal').modal('hide'); + if (parseInt($state.params.host_id) === id) { + $state.go("hostsnew", null, {reload: true}); + } else { + $state.go($state.current.name, null, {reload: true}); + } + Wait('stop'); + }); + }; + // Prompt depends on having $rootScope.promptActionBtnClass available... + Prompt({ + hdr: 'Delete Host', + body: body, + action: action, + actionText: 'DELETE', + }); + $rootScope.promptActionBtnClass = 'Modal-errorButton'; + }; + + $scope.toggleHost = function(event, host) { + try { + $(event.target).tooltip('hide'); + } catch (e) { + // ignore + } + + host.enabled = !host.enabled; + + HostManageService.put(host).then(function(){ + $state.go($state.current, null, {reload: true}); + }); + }; + +} + +export default ['$scope', 'HostsNewList', '$rootScope', 'GetBasePath', + 'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', 'HostManageService', HostsList +]; diff --git a/awx/ui/client/src/inventoriesnew/hosts/list/main.js b/awx/ui/client/src/inventoriesnew/hosts/list/main.js new file mode 100644 index 0000000000..4e603ef45d --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/list/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import controller from './host-list.controller'; + +export default +angular.module('hostsList', []) + .controller('NewHostListController', controller); diff --git a/awx/ui/client/src/inventoriesnew/hosts/main.js b/awx/ui/client/src/inventoriesnew/hosts/main.js new file mode 100644 index 0000000000..7363b267f9 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/hosts/main.js @@ -0,0 +1,20 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + import hostAdd from './add/main'; + import hostEdit from './edit/main'; + import hostList from './list/main'; + import HostsNewList from './host.list'; + import HostsNewForm from './host.form'; + +export default +angular.module('hostnew', [ + hostAdd.name, + hostEdit.name, + hostList.name + ]) + .factory('HostsNewForm', HostsNewForm) + .factory('HostsNewList', HostsNewList); diff --git a/awx/ui/client/src/inventoriesnew/inventories.partial.html b/awx/ui/client/src/inventoriesnew/inventories.partial.html new file mode 100644 index 0000000000..524ead4a7f --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/inventories.partial.html @@ -0,0 +1,14 @@ +
+
+
+
+
+
+
INVENTORIES
+
HOSTS
+
+
+
+
+
+
diff --git a/awx/ui/client/src/inventoriesnew/inventory.form.js b/awx/ui/client/src/inventoriesnew/inventory.form.js new file mode 100644 index 0000000000..a138461f49 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/inventory.form.js @@ -0,0 +1,135 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +/** + * @ngdoc function + * @name forms.function:Inventories + * @description This form is for adding/editing an inventory + */ + +export default ['i18n', function(i18n) { + return { + + addTitle: i18n._('NEW INVENTORY'), + editTitle: '{{ inventory_name }}', + name: 'inventory', + basePath: 'inventory', + // the top-most node of this generated state tree + stateTree: 'inventoriesnew', + tabs: true, + + fields: { + inventory_name: { + realName: 'name', + label: i18n._('Name'), + type: 'text', + required: true, + capitalize: false, + ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + inventory_description: { + realName: 'description', + label: i18n._('Description'), + type: 'text', + ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + organization: { + label: i18n._('Organization'), + type: 'lookup', + basePath: 'organizations', + list: 'OrganizationList', + sourceModel: 'organization', + sourceField: 'name', + awRequiredWhen: { + reqExpression: "organizationrequired", + init: "true" + }, + ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg', + awLookupWhen: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd) && canEditOrg' + }, + variables: { + label: i18n._('Variables'), + type: 'textarea', + class: 'Form-formGroup--fullWidth', + rows: 6, + "default": "---", + awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + + "JSON:
\n" + + "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "YAML:
\n" + + "
---
somevar: somevalue
password: magic
\n" + + '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + + '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', + dataTitle: i18n._('Inventory Variables'), + dataPlacement: 'right', + dataContainer: 'body', + ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working + } + }, + + buttons: { + cancel: { + ngClick: 'formCancel()', + ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + close: { + ngClick: 'formCancel()', + ngShow: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + save: { + ngClick: 'formSave()', + ngDisabled: true, + ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + } + }, + related: { + permissions: { + name: 'permissions', + awToolTip: i18n._('Please save before assigning permissions'), + dataPlacement: 'top', + basePath: 'api/v1/inventories/{{$stateParams.inventory_id}}/access_list/', + type: 'collection', + title: i18n._('Permissions'), + iterator: 'permission', + index: false, + open: false, + search: { + order_by: 'username' + }, + actions: { + add: { + label: i18n._('Add'), + ngClick: "$state.go('.add')", + awToolTip: i18n._('Add a permission'), + actionClass: 'btn List-buttonSubmit', + buttonContent: '+ ADD', + ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + + } + }, + fields: { + username: { + label: i18n._('User'), + linkBase: 'users', + class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' + }, + role: { + label: i18n._('Role'), + type: 'role', + nosort: true, + class: 'col-lg-4 col-md-4 col-sm-4 col-xs-4', + }, + team_roles: { + label: i18n._('Team Roles'), + type: 'team_roles', + nosort: true, + class: 'col-lg-5 col-md-5 col-sm-5 col-xs-4', + } + } + } + } + + };}]; diff --git a/awx/ui/client/src/inventoriesnew/inventory.list.js b/awx/ui/client/src/inventoriesnew/inventory.list.js new file mode 100644 index 0000000000..c06f3703ec --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/inventory.list.js @@ -0,0 +1,98 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + +export default ['i18n', function(i18n) { + return { + + name: 'inventoriesnew', + iterator: 'inventory', + selectTitle: i18n._('Add Inventories'), + editTitle: i18n._('INVENTORIES'), + listTitle: i18n._('INVENTORIES'), + selectInstructions: i18n.sprintf(i18n._("Click on a row to select it, and click Finished when done. Click the %s button to create a new inventory."), " "), + index: false, + hover: true, + basePath: 'inventory', + title: false, + + fields: { + status: { + label: '', + columnClass: 'List-staticColumn--mediumStatus', + nosort: true, + ngClick: "null", + iconOnly: true, + excludeModal: true, + icons: [{ + icon: "{{ 'icon-cloud-' + inventory.syncStatus }}", + awToolTip: "{{ inventory.syncTip }}", + awTipPlacement: "right", + ngClick: "showGroupSummary($event, inventory.id)", + ngClass: "inventory.launch_class" + },{ + icon: "{{ 'icon-job-' + inventory.hostsStatus }}", + awToolTip: false, + ngClick: "showHostSummary($event, inventory.id)", + ngClass: "" + }] + }, + name: { + key: true, + label: i18n._('Name'), + columnClass: 'col-md-5 col-sm-5 col-xs-8 List-staticColumnAdjacent', + modalColumnClass: 'col-md-11', + linkTo: '/#/inventoriesnew/{{inventory.id}}' + }, + organization: { + label: i18n._('Organization'), + ngBind: 'inventory.summary_fields.organization.name', + linkTo: '/#/organizations/{{ inventory.organization }}', + sourceModel: 'organization', + sourceField: 'name', + excludeModal: true, + columnClass: 'col-md-5 col-sm-3 hidden-xs' + } + }, + + actions: { + add: { + mode: 'all', // One of: edit, select, all + ngClick: 'addInventory()', + awToolTip: i18n._('Create a new inventory'), + actionClass: 'btn List-buttonSubmit', + buttonContent: '+ ' + i18n._('ADD'), + ngShow: 'canAdd' + } + }, + + fieldActions: { + + columnClass: 'col-md-2 col-sm-4 col-xs-4', + + edit: { + label: i18n._('Edit'), + ngClick: 'editInventory(inventory.id)', + awToolTip: i18n._('Edit inventory'), + dataPlacement: 'top', + ngShow: 'inventory.summary_fields.user_capabilities.edit' + }, + view: { + label: i18n._('View'), + ngClick: 'editInventory(inventory.id)', + awToolTip: i18n._('View inventory'), + dataPlacement: 'top', + ngShow: '!inventory.summary_fields.user_capabilities.edit' + }, + "delete": { + label: i18n._('Delete'), + ngClick: "deleteInventory(inventory.id, inventory.name)", + awToolTip: i18n._('Delete inventory'), + dataPlacement: 'top', + ngShow: 'inventory.summary_fields.user_capabilities.delete' + } + } + };}]; diff --git a/awx/ui/client/src/inventoriesnew/list/inventory-list.controller.js b/awx/ui/client/src/inventoriesnew/list/inventory-list.controller.js new file mode 100644 index 0000000000..e37f9ab6e8 --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/list/inventory-list.controller.js @@ -0,0 +1,308 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +/** + * @ngdoc function + * @name controllers.function:Inventories + * @description This controller's for the Inventory page + */ + +function InventoriesList($scope, $rootScope, $location, + $compile, $filter, Rest, InventoriesNewList, Prompt, + ProcessErrors, GetBasePath, Wait, Find, Empty, $state, rbacUiControlService, Dataset) { + + let list = InventoriesNewList, + defaultUrl = GetBasePath('inventory'); + + init(); + + function init(){ + $scope.canAdd = false; + + rbacUiControlService.canAdd('inventory') + .then(function(canAdd) { + $scope.canAdd = canAdd; + }); + + $scope.$watchCollection(list.name, function(){ + _.forEach($scope[list.name], buildStatusIndicators); + }); + + // Search init + $scope.list = list; + $scope[`${list.iterator}_dataset`] = Dataset.data; + $scope[list.name] = $scope[`${list.iterator}_dataset`].results; + + $rootScope.flashMessage = null; + + } + + function buildStatusIndicators(inventory){ + inventory.launch_class = ""; + if (inventory.has_inventory_sources) { + if (inventory.inventory_sources_with_failures > 0) { + inventory.syncStatus = 'error'; + inventory.syncTip = inventory.inventory_sources_with_failures + ' groups with sync failures. Click for details'; + } + else { + inventory.syncStatus = 'successful'; + inventory.syncTip = 'No inventory sync failures. Click for details.'; + } + } + else { + inventory.syncStatus = 'na'; + inventory.syncTip = 'Not configured for inventory sync.'; + inventory.launch_class = "btn-disabled"; + } + if (inventory.has_active_failures) { + inventory.hostsStatus = 'error'; + inventory.hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.'; + } + else if (inventory.total_hosts) { + inventory.hostsStatus = 'successful'; + inventory.hostsTip = 'No hosts with failures. Click for details.'; + } + else { + inventory.hostsStatus = 'none'; + inventory.hostsTip = 'Inventory contains 0 hosts.'; + } + } + + function ellipsis(a) { + if (a.length > 20) { + return a.substr(0,20) + '...'; + } + return a; + } + + function attachElem(event, html, title) { + var elem = $(event.target).parent(); + try { + elem.tooltip('hide'); + elem.popover('destroy'); + } + catch(err) { + //ignore + } + $('.popover').each(function() { + // remove lingering popover
. Seems to be a bug in TB3 RC1 + $(this).remove(); + }); + $('.tooltip').each( function() { + // close any lingering tool tipss + $(this).hide(); + }); + elem.attr({ + "aw-pop-over": html, + "data-popover-title": title, + "data-placement": "right" }); + elem.removeAttr('ng-click'); + $compile(elem)($scope); + $scope.triggerPopover(event); + } + if ($scope.removeHostSummaryReady) { + $scope.removeHostSummaryReady(); + } + $scope.removeHostSummaryReady = $scope.$on('HostSummaryReady', function(e, event, data) { + + var html, title = "Recent Jobs"; + Wait('stop'); + if (data.count > 0) { + html = "\n"; + html += "\n"; + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + html += "\n"; + html += "\n"; + + data.results.forEach(function(row) { + html += "\n"; + html += "\n"; + html += ""; + html += ""; + html += "\n"; + }); + html += "\n"; + html += "
StatusFinishedName
" + ($filter('longDate')(row.finished)).replace(/ /,'
') + "
" + $filter('sanitize')(ellipsis(row.name)) + "
\n"; + } + else { + html = "

No recent job data available for this inventory.

\n"; + } + attachElem(event, html, title); + }); + + if ($scope.removeGroupSummaryReady) { + $scope.removeGroupSummaryReady(); + } + $scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) { + var html, title; + + Wait('stop'); + + // Build the html for our popover + html = "\n"; + html += "\n"; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + html += "\n"; + data.results.forEach( function(row) { + if (row.related.last_update) { + html += ""; + html += ``; + html += ""; + html += ""; + html += "\n"; + } + else { + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + } + }); + html += "\n"; + html += "
StatusLast SyncGroup
" + ($filter('longDate')(row.last_updated)).replace(/ /,'
') + "
" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "
NA" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + "
\n"; + title = "Sync Status"; + attachElem(event, html, title); + }); + + $scope.showGroupSummary = function(event, id) { + try{ + var elem = $(event.target).parent(); + // if the popover is visible already, then exit the function here + if(elem.data()['bs.popover'].tip().hasClass('in')){ + return; + } + } + catch(err){ + var inventory; + if (!Empty(id)) { + inventory = Find({ list: $scope.inventories, key: 'id', val: id }); + if (inventory.syncStatus !== 'na') { + Wait('start'); + Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5'); + Rest.get() + .success(function(data) { + $scope.$emit('GroupSummaryReady', event, inventory, data); + }) + .error(function(data, status) { + ProcessErrors( $scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status + }); + }); + } + } + } + }; + + $scope.showHostSummary = function(event, id) { + try{ + var elem = $(event.target).parent(); + // if the popover is visible already, then exit the function here + if(elem.data()['bs.popover'].tip().hasClass('in')){ + return; + } + } + catch(err){ + var url, inventory; + if (!Empty(id)) { + inventory = Find({ list: $scope.inventories, key: 'id', val: id }); + if (inventory.total_hosts > 0) { + Wait('start'); + url = GetBasePath('jobs') + "?type=job&inventory=" + id + "&failed="; + url += (inventory.has_active_failures) ? 'true' : "false"; + url += "&order_by=-finished&page_size=5"; + Rest.setUrl(url); + Rest.get() + .success( function(data) { + $scope.$emit('HostSummaryReady', event, data); + }) + .error( function(data, status) { + ProcessErrors( $scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + ' failed. GET returned: ' + status + }); + }); + } + } + } + }; + + $scope.viewJob = function(url) { + + // Pull the id out of the URL + var id = url.replace(/^\//, '').split('/')[3]; + + $state.go('inventorySyncStdout', {id: id}); + + }; + + $scope.addInventory = function () { + $state.go('inventoriesnew.add'); + }; + + $scope.editInventory = function (id) { + $state.go('inventoriesnew.edit', {inventory_id: id}); + }; + + $scope.manageInventory = function(id){ + $location.path($location.path() + '/' + id + '/manage'); + }; + + $scope.deleteInventory = function (id, name) { + + var action = function () { + var url = defaultUrl + id + '/'; + Wait('start'); + $('#prompt-modal').modal('hide'); + Rest.setUrl(url); + Rest.destroy() + .success(function () { + if (parseInt($state.params.inventory_id) === id) { + $state.go("^", null, {reload: true}); + } else { + $state.go('.', null, {reload: true}); + Wait('stop'); + } + }) + .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 inventory below?
' + $filter('sanitize')(name) + '
', + action: action, + actionText: 'DELETE' + }); + }; + + // Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status + $scope.viewJobs = function (id) { + $location.url('/jobs/?inventory__int=' + id); + }; + + $scope.viewFailedJobs = function (id) { + $location.url('/jobs/?inventory__int=' + id + '&status=failed'); + }; +} + +export default ['$scope', '$rootScope', '$location', + '$compile', '$filter', 'Rest', 'InventoriesNewList', + 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'rbacUiControlService', 'Dataset', InventoriesList +]; diff --git a/awx/ui/client/src/inventoriesnew/list/main.js b/awx/ui/client/src/inventoriesnew/list/main.js new file mode 100644 index 0000000000..09550f45ca --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/list/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import controller from './inventory-list.controller'; + +export default +angular.module('newInventoryList', []) + .controller('NewInventoryListController', controller); diff --git a/awx/ui/client/src/inventoriesnew/main.js b/awx/ui/client/src/inventoriesnew/main.js new file mode 100644 index 0000000000..4e736caf9a --- /dev/null +++ b/awx/ui/client/src/inventoriesnew/main.js @@ -0,0 +1,236 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import hostnew from './hosts/main'; +import inventoryAdd from './add/main'; +import inventoryEdit from './edit/main'; +import inventoryList from './list/main'; +import { templateUrl } from '../shared/template-url/template-url.factory'; +import { N_ } from '../i18n'; +// import inventoriesnewRoute from './inventories.route'; +import InventoriesNewList from './inventory.list'; +import InventoriesNewForm from './inventory.form'; +export default +angular.module('inventorynew', [ + hostnew.name, + inventoryAdd.name, + inventoryEdit.name, + inventoryList.name + ]) + .factory('InventoriesNewForm', InventoriesNewForm) + .factory('InventoriesNewList', InventoriesNewList) + .config(['$stateProvider', '$stateExtenderProvider', 'stateDefinitionsProvider', + function($stateProvider, $stateExtenderProvider, stateDefinitionsProvider) { + // When stateDefinition.lazyLoad() resolves, states matching name.** or /url** will be de-registered and replaced with resolved states + // This means inventoryManage states will not be registered correctly on page refresh, unless they're registered at the same time as the inventories state tree + let stateDefinitions = stateDefinitionsProvider.$get(); + + $stateProvider.state({ + name: 'inventoriesnew', + url: '/inventoriesnew', + lazyLoad: () => stateDefinitions.generateTree({ + parent: 'inventoriesnew', // top-most node in the generated tree (will replace this state definition) + modes: ['add', 'edit'], + list: 'InventoriesNewList', + form: 'InventoriesNewForm', + controllers: { + list: 'NewInventoryListController', + add: 'NewInventoryAddController', + edit: 'NewInventoryEditController' + }, + ncyBreadcrumb: { + label: N_('INVENTORIESNEW') + }, + views: { + '@': { + templateUrl: templateUrl('inventoriesnew/inventories') + }, + 'list@inventoriesnew': { + templateProvider: function(InventoriesNewList, generateList) { + let html = generateList.build({ + list: InventoriesNewList, + mode: 'edit' + }); + return html; + }, + controller: 'NewInventoryListController' + } + } + }) + }); + + $stateProvider.state({ + name: 'hostsnew', + url: '/hostsnew', + lazyLoad: () => stateDefinitions.generateTree({ + parent: 'hostsnew', // top-most node in the generated tree (will replace this state definition) + modes: ['add', 'edit'], + list: 'HostsNewList', + form: 'HostsNewForm', + controllers: { + list: 'NewHostListController', + add: 'NewHostAddController', + edit: 'NewHostEditController' + }, + ncyBreadcrumb: { + label: N_('HOSTSNEW') + }, + views: { + '@': { + templateUrl: templateUrl('inventoriesnew/inventories') + }, + 'list@hostsnew': { + templateProvider: function(HostsNewList, generateList) { + let html = generateList.build({ + list: HostsNewList, + mode: 'edit' + }); + return html; + }, + controller: 'NewHostListController' + } + } + }) + }); + + + + // function generateInvAddStateTree() { + // + // let addInventory = stateDefinitions.generateTree({ + // url: '/add', + // name: 'inventoriesnew.add', + // modes: ['add'], + // form: 'InventoriesNewForm', + // controllers: { + // add: 'NewInventoryAddController' + // } + // }); + // + // return Promise.all([ + // addInventory, + // ]).then((generated) => { + // return { + // states: _.reduce(generated, (result, definition) => { + // return result.concat(definition.states); + // }, []) + // }; + // }); + // } + // + // function generateInvEditStateTree() { + // + // let editInventory = stateDefinitions.generateTree({ + // url: '/:inventory_id', + // name: 'inventoriesnew.edit', + // modes: ['edit'], + // form: 'InventoriesNewForm', + // controllers: { + // edit: 'NewInventoryEditController' + // } + // }); + // + // return Promise.all([ + // editInventory, + // ]).then((generated) => { + // return { + // states: _.reduce(generated, (result, definition) => { + // return result.concat(definition.states); + // }, []) + // }; + // }); + // } + // + // let inventoriesnew = { + // name: 'inventoriesnew', + // route: '/inventoriesnew', + // ncyBreadcrumb: { + // label: N_("INVENTORIESNEW") + // }, + // params: { + // inventory_search: { + // value: {order_by: 'name', page_size: '20', role_level: 'admin_role'}, + // dynamic: true + // } + // }, + // resolve: { + // Dataset: ['InventoriesNewList', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => { + // let path = GetBasePath(list.basePath) || GetBasePath(list.name); + // return qs.search(path, $stateParams[`${list.iterator}_search`]); + // }], + // ListDefinition: ['InventoriesNewList', (list) => { + // return list; + // }] + // }, + // views: { + // '@': { + // templateUrl: templateUrl('inventoriesnew/inventories') + // }, + // 'list@inventoriesnew': { + // templateProvider: function(InventoriesNewList, generateList) { + // let html = generateList.build({ + // list: InventoriesNewList, + // mode: 'edit' + // }); + // return html; + // }, + // controller: 'NewInventoryListController' + // } + // } + // }; + // stateExtender.addState(inventoriesnew); + // + // let hostsnew = { + // name: 'inventoriesnew.hosts', + // route: '/hosts', + // ncyBreadcrumb: { + // label: N_("HOSTS") + // }, + // params: { + // host_search: { + // value: {order_by: 'name', page_size: '20'}, + // dynamic: true + // } + // }, + // resolve: { + // Dataset: ['HostsNewList', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => { + // let path = GetBasePath(list.basePath) || GetBasePath(list.name); + // return qs.search(path, $stateParams[`${list.iterator}_search`]); + // }], + // ListDefinition: ['HostsNewList', (list) => { + // return list; + // }] + // }, + // views: { + // 'list@inventoriesnew': { + // templateProvider: function(HostsNewList, generateList) { + // let html = generateList.build({ + // list: HostsNewList, + // mode: 'edit' + // }); + // return html; + // }, + // controller: 'NewHostListController' + // } + // } + // }; + // stateExtender.addState(hostsnew); + // + // let addInventoryTree = { + // name: 'inventoriesnew.add', + // url: '/add', + // lazyLoad: () => generateInvAddStateTree() + // }; + // $stateProvider.state(addInventoryTree); + // + // let editInventoryTree = { + // name: 'inventoriesnew.edit', + // url: '/:inventory_id', + // lazyLoad: () => generateInvEditStateTree() + // }; + // $stateProvider.state(editInventoryTree); + } + ]); diff --git a/awx/ui/client/src/main-menu/main-menu.partial.html b/awx/ui/client/src/main-menu/main-menu.partial.html index 398488add7..4d28ea22e8 100644 --- a/awx/ui/client/src/main-menu/main-menu.partial.html +++ b/awx/ui/client/src/main-menu/main-menu.partial.html @@ -27,6 +27,14 @@ INVENTORIES + + + INVENTORIES NEW + + INVENTORIES + + + INVENTORIES NEW + + list }, - views: { - '@': { - // resolves to a variable property name: - // 'templateUrl' OR 'templateProvider' - [params.templates && params.templates.list ? 'templateUrl' : 'templateProvider']: generateTemplateBlock(), - controller: params.controllers.list, - } - } + views: views }); // allow passed-in params to override default resolve block if (params.resolve && params.resolve.list) { @@ -125,7 +128,7 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto } if (list.search) { state.params[`${list.iterator}_search`].value = _.merge(state.params[`${list.iterator}_search`].value, list.search); - } + }if(state.name === 'inventoriesnew'){console.log(state);} return state; }, /**