From fce3ba14ad185bec9cc53cedf7e1401b08bb27ed Mon Sep 17 00:00:00 2001 From: Ken Hoes Date: Fri, 20 May 2016 11:45:51 -0400 Subject: [PATCH 001/584] Updated icons and default interface text for marketing --- awx/ui/client/src/shared/branding/colors.default.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/awx/ui/client/src/shared/branding/colors.default.less b/awx/ui/client/src/shared/branding/colors.default.less index 2e986fdb9f..e512bc5c35 100644 --- a/awx/ui/client/src/shared/branding/colors.default.less +++ b/awx/ui/client/src/shared/branding/colors.default.less @@ -1,7 +1,7 @@ // default base colors -@default-interface-txt: #848992; +@default-interface-txt: #707070; @default-data-txt: #161B1F; -@default-icon: #B7B7B7; +@default-icon: #848992; @default-icon-hov: #D7D7D7; // also selected button @default-border: #E8E8E8; @d7grey: #D7D7D7; // used for random things, like the close button on top-right corner of panes @@ -20,6 +20,7 @@ @default-stdout-txt: #707070; @default-dark: #000000; + @default-warning: #F0AD4E; @default-warning-hov: #EC971F; @default-unreachable: #FF0000; From 3739425eb74a5108007a272d111934bd87aba185 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Mon, 23 May 2016 10:28:39 -0400 Subject: [PATCH 002/584] Moved survey buttons down beside save/cancel on job template forms --- awx/ui/client/legacy-styles/forms.less | 1 - awx/ui/client/src/forms/JobTemplates.js | 15 ++++++++------- .../survey-maker/survey-maker.block.less | 1 + awx/ui/client/src/shared/form-generator.js | 8 ++++++++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/awx/ui/client/legacy-styles/forms.less b/awx/ui/client/legacy-styles/forms.less index ed66d8de04..a54c0c6aed 100644 --- a/awx/ui/client/legacy-styles/forms.less +++ b/awx/ui/client/legacy-styles/forms.less @@ -494,7 +494,6 @@ input[type='radio']:checked:before { .Form-surveyButton { background-color: @default-link; - margin-right: 20px; color: @default-bg; text-transform: uppercase; padding-left:15px; diff --git a/awx/ui/client/src/forms/JobTemplates.js b/awx/ui/client/src/forms/JobTemplates.js index 0292a29b3d..cc82057048 100644 --- a/awx/ui/client/src/forms/JobTemplates.js +++ b/awx/ui/client/src/forms/JobTemplates.js @@ -309,17 +309,18 @@ export default dataPlacement: 'right', dataTitle: "Host Config Key", dataContainer: "body" - }, - survey: { - type: 'custom', - column: 2, - ngHide: "job_type.value === 'scan'" , - control: ''+ - '' } }, buttons: { //for now always generates \n"; - html += "\n"; - html += "

(move selected groups)

\n"; - html += "\n"; - html += "\n"; - - defaultUrl = GetBasePath('hosts') + host_id + '/'; - scope = generator.inject(null, { mode: 'edit', modal: true, related: false, html: html }); - - for (i=0; i < scope.hosts.length; i++) { - if (scope.hosts[i].id === host_id) { - scope.host = scope.hosts[i]; - } - } - - scope.selectedGroups = null; - scope.assignedGroups = null; - scope.leftButtonDisabled = true; - scope.rightButtonDisabled = true; - - scope.formModalActionLabel = 'Save'; - //scope.formModalHeader = 'Host Groups'; - scope.formModalHeader = scope.host.name + ' - Groups'; - scope.formModalCancelShow = true; - scope.formModalActionDisabled = true; - - $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); - - if (scope.hostGroupChangeRemove) { - scope.hostGroupChangeRemove(); - } - scope.hostGroupChangeRemove = scope.$on('hostGroupChange', function() { - actions.pop(); - if (actions.length === 0) { - postAction = function() { - setTimeout(function() { Wait('stop'); }, 500); - }; - HostsReload({ scope: scope, inventory_id: inventory_id, group_id: scope.group_id , action: postAction }); - } - }); - - // Save changes - scope.formModalAction = function() { - var i, j, found; - - $('#form-modal').modal('hide'); - Wait('start'); - - // removed host from deleted groups - for (i=0; i < scope.original_groups.length; i++) { - found = false; - for (j=0; j < scope.host_groups.length; j++) { - if (scope.original_groups[i].id === scope.host_groups[j].id) { - found = true; - } - } - if (!found) { - // group was removed - actions.push({ group_id: scope.original_groups[i].id , action: 'delete' }); - Rest.setUrl(GetBasePath('groups') + scope.original_groups[i].id + '/hosts/'); - Rest.post({ id: host_id, disassociate: 1 }) - .success( function() { - scope.$emit('hostGroupChange'); - }) - .error( function(data, status) { - scope.$emit('hostGroupChange'); - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Attempt to remove host from group ' + scope.original_groups[i].name + - ' failed. POST returned status: ' + status }); - }); - } - } - - // add host to new groups - for (i=0; i < scope.host_groups.length; i++) { - found = false; - for (j=0; j < scope.original_groups.length; j++) { - if (scope.original_groups[j].id === scope.host_groups[i].id) { - found = true; - } - } - if (!found) { - // group was added - actions.push({ group_id: scope.host_groups[i].id , action: 'add' }); - Rest.setUrl(GetBasePath('groups') + scope.host_groups[i].id + '/hosts/'); - Rest.post(scope.host) - .success( function() { - scope.$emit('hostGroupChange'); - }) - .error( function(data, status) { - scope.$emit('hostGroupChange'); - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Attempt to add host to group ' + scope.host_groups[i].name + - ' failed. POST returned status: ' + status }); - }); - } - } - }; - - scope.leftChange = function() { - // Select/deselect on available groups list - if (scope.selectedGroups !== null && scope.selectedGroups.length > 0) { - scope.assignedGroups = null; - scope.leftButtonDisabled = true; - scope.rightButtonDisabled = false; - } - else { - scope.rightButtonDisabled = true; - } - }; - - scope.rightChange = function() { - // Select/deselect made on host groups list - if (scope.assignedGroups !== null && scope.assignedGroups.length > 0) { - scope.selectedGroups = null; - scope.leftButtonDisabled = false; - scope.rightButtonDisabled = true; - } - else { - scope.leftButtonDisabled = true; - } - }; - - scope.moveLeft = function() { - // Remove selected groups from the list of assigned groups - - var i, j, found, placed; - - for (i=0; i < scope.assignedGroups.length; i++){ - for (j=0 ; j < scope.host_groups.length; j++) { - if (scope.host_groups[j].id === scope.assignedGroups[i].id) { - scope.host_groups.splice(j,1); - break; - } - } - } - for (i=0; i < scope.assignedGroups.length; i++){ - found = false; - for (j=0; j < scope.available_groups.length && !found; j++){ - if (scope.available_groups[j].id === scope.assignedGroups[i].id) { - found=true; - } - } - if (!found) { - placed = false; - for (j=0; j < scope.available_groups.length && !placed; j++){ - if (j === 0 && scope.assignedGroups[i].name.toLowerCase() < scope.available_groups[j].name.toLowerCase()) { - // prepend to the beginning of the array - placed=true; - scope.available_groups.unshift(scope.assignedGroups[i]); - } - else if (j + 1 < scope.available_groups.length) { - if (scope.assignedGroups[i].name.toLowerCase() > scope.available_groups[j].name.toLowerCase() && - scope.assignedGroups[i].name.toLowerCase() < scope.available_groups[j + 1].name.toLowerCase() ) { - // insert into the middle of the array - placed = true; - scope.available_groups.splice(j + 1, 0, scope.assignedGroups[i]); - } - } - } - if (!placed) { - // append to the end of the array - scope.available_groups.push(scope.assignedGroups[i]); - } - } - } - scope.assignedGroups = null; - scope.leftButtonDisabled = true; - scope.rightButtonDisabled = true; - scope.formModalActionDisabled = false; - }; - - scope.moveRight = function() { - // Remove selected groups from list of available groups - - var i, j, found, placed; - - for (i=0; i < scope.selectedGroups.length; i++){ - for (j=0 ; j < scope.available_groups.length; j++) { - if (scope.available_groups[j].id === scope.selectedGroups[i].id) { - scope.available_groups.splice(j,1); - break; - } - } - } - for (i=0; i < scope.selectedGroups.length; i++){ - found = false; - for (j=0; j < scope.host_groups.length && !found; j++){ - if (scope.host_groups[j].id === scope.selectedGroups[i].id) { - found=true; - } - } - if (!found) { - placed = false; - for (j=0; j < scope.host_groups.length && !placed; j++) { - if (j === 0 && scope.selectedGroups[i].name.toLowerCase() < scope.host_groups[j].name.toLowerCase()) { - // prepend to the beginning of the array - placed=true; - scope.host_groups.unshift(scope.selectedGroups[i]); - } - else if (j + 1 < scope.host_groups.length) { - if (scope.selectedGroups[i].name.toLowerCase() > scope.host_groups[j].name.toLowerCase() && - scope.selectedGroups[i].name.toLowerCase() < scope.host_groups[j + 1].name.toLowerCase() ) { - // insert into the middle of the array - placed = true; - scope.host_groups.splice(j + 1, 0, scope.selectedGroups[i]); - } - } - } - if (!placed) { - // append to the end of the array - scope.host_groups.push(scope.selectedGroups[i]); - } - } - } - scope.selectedGroups = null; - scope.leftButtonDisabled = true; - scope.rightButtonDisabled = true; - scope.formModalActionDisabled = false; - }; - - - // Load the host's current list of groups - scope.host_groups = []; - scope.original_groups = []; - scope.available_groups = []; - Rest.setUrl(scope.host.related.groups + '?order_by=name'); - Rest.get() - .success( function(data) { - var i, j, found; - for (i=0; i < data.results.length; i++) { - scope.host_groups.push({ - id: data.results[i].id, - name: data.results[i].name, - description: data.results[i].description - }); - scope.original_groups.push({ - id: data.results[i].id, - name: data.results[i].name, - description: data.results[i].description - }); - } - for (i=0; i < scope.inventory_groups.length; i++) { - found = false; - for (j=0; j < scope.host_groups.length; j++) { - if (scope.inventory_groups[i].id === scope.host_groups[j].id) { - found = true; - } - } - if (!found) { - scope.available_groups.push(scope.inventory_groups[i]); - } - } - }) - .error( function(data, status) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Failed to get current groups for host: ' + host_id + '. GET returned: ' + status }); - }); - - if (scope.removeHostsReload) { - scope.removeHostsReload(); - } - scope.removeHostsReload = scope.$on('hostsReload', function() { - HostsReload(params); - }); - - if (!scope.$$phase) { - scope.$digest(); - } - }; - }]); +}]); \ No newline at end of file diff --git a/awx/ui/client/src/helpers/Jobs.js b/awx/ui/client/src/helpers/Jobs.js index 7d8fee0d62..9d764d449f 100644 --- a/awx/ui/client/src/helpers/Jobs.js +++ b/awx/ui/client/src/helpers/Jobs.js @@ -156,126 +156,7 @@ export default }; } ]) - - .factory('ShowJobSummary', ['Rest', 'Wait', 'GetBasePath', 'FormatDate', 'ProcessErrors', 'GenerateForm', 'JobSummary', - function (Rest, Wait, GetBasePath, FormatDate, ProcessErrors, GenerateForm, JobSummary) { - return function (params) { - // Display status info in a modal dialog- called from inventory edit page - - var job_id = params.job_id, - generator = GenerateForm, - form = JobSummary, - scope, ww, wh, x, y, maxrows, url, html; - - html = '
' + - '
\n'; - - $('#inventory-modal-container').empty().append(html); - - scope = generator.inject(form, { mode: 'edit', id: 'form-container', related: false }); - - // Set modal dimensions based on viewport width - ww = $(document).width(); - wh = $('body').height(); - if (ww > 1199) { - // desktop - x = 675; - y = (750 > wh) ? wh - 20 : 750; - maxrows = 20; - } else if (ww <= 1199 && ww >= 768) { - x = 550; - y = (620 > wh) ? wh - 15 : 620; - maxrows = 15; - } else { - x = (ww - 20); - y = (500 > wh) ? wh : 500; - maxrows = 10; - } - - // Create the modal - $('#status-modal-dialog').dialog({ - buttons: { - 'OK': function () { - $(this).dialog('close'); - } - }, - modal: true, - width: x, - height: y, - autoOpen: false, - closeOnEscape: false, - create: function () { - // fix the close button - $('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button') - .empty().attr({ - 'class': 'close' - }).text('x'); - // fix the OK button - $('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first') - .attr({ - 'class': 'btn btn-primary' - }); - }, - resizeStop: function () { - // for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100% - var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]'), - titleHeight = dialog.find('.ui-dialog-titlebar').outerHeight(), - buttonHeight = dialog.find('.ui-dialog-buttonpane').outerHeight(), - content = dialog.find('#status-modal-dialog'); - content.width(dialog.width() - 28); - content.css({ height: (dialog.height() - titleHeight - buttonHeight - 10) }); - }, - close: function () { - // Destroy on close - $('.tooltip').each(function () { - // Remove any lingering tooltip
elements - $(this).remove(); - }); - $('.popover').each(function () { - // remove lingering popover
elements - $(this).remove(); - }); - $('#status-modal-dialog').dialog('destroy'); - $('#inventory-modal-container').empty(); - }, - open: function () { - Wait('stop'); - } - }); - - function calcRows(content) { - var n = content.match(/\n/g), - rows = (n) ? n.length : 1; - return (rows > maxrows) ? 20 : rows; - } - - Wait('start'); - url = GetBasePath('jobs') + job_id + '/'; - Rest.setUrl(url); - Rest.get() - .success(function (data) { - var cDate; - scope.id = data.id; - scope.name = data.name; - scope.status = data.status; - scope.result_stdout = data.result_stdout; - scope.result_traceback = data.result_traceback; - scope.stdout_rows = calcRows(scope.result_stdout); - scope.traceback_rows = calcRows(scope.result_traceback); - cDate = new Date(data.created); - scope.created = FormatDate(cDate); - $('#status-modal-dialog').dialog('open'); - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Attempt to load job failed. GET returned status: ' + status }); - }); - }; - - } - ]) - - + .factory('JobsListUpdate', ['Rest', function(Rest) { return function(params) { var scope = params.scope, diff --git a/awx/ui/client/src/helpers/inventory.js b/awx/ui/client/src/helpers/inventory.js index 9becb2dbb9..18a8b27883 100644 --- a/awx/ui/client/src/helpers/inventory.js +++ b/awx/ui/client/src/helpers/inventory.js @@ -81,217 +81,4 @@ export default }); }; } - ]) - - .factory('EditInventoryProperties', ['InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList', - 'GetBasePath', 'ParseTypeChange', 'SaveInventory', 'Wait', 'Store', 'SearchInit', 'ParseVariableString', 'CreateDialog', 'TextareaResize', - function (InventoryForm, GenerateForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, SaveInventory, - Wait, Store, SearchInit, ParseVariableString, CreateDialog, TextareaResize) { - return function (params) { - - var parent_scope = params.scope, - inventory_id = params.inventory_id, - generator = GenerateForm, - form = InventoryForm, - master = {}, - //PreviousSearchParams = Store('CurrentSearchParams'), - buttons, - scope = parent_scope.$new(); - - form.well = false; - - var form_scope = - generator.inject(form, { - mode: 'edit', - showButtons: false, - showActions: false, - id: 'inventory-edit-modal-dialog', - related: false, - scope: scope - }); - - /* Reset form properties. Otherwise it screws up future requests of the Inventories detail page */ - form.well = true; - - buttons = [{ - label: "Cancel", - onClick: function() { - scope.cancelModal(); - }, - icon: "fa-times", - "class": "btn btn-default", - "id": "inventory-edit-cancel-button" - },{ - label: "Save", - onClick: function() { - scope.saveModal(); - }, - icon: "fa-check", - "class": "btn btn-primary", - "id": "inventory-edit-save-button" - }]; - - CreateDialog({ - scope: scope, - buttons: buttons, - width: 675, - height: 750, - minWidth: 400, - title: 'Inventory Properties', - id: 'inventory-edit-modal-dialog', - closeOnEscape: false, - form: form_scope.inventory_form, - onClose: function() { - Wait('stop'); - scope.codeMirror.destroy(); - $('#inventory-edit-modal-dialog').empty(); - }, - onResizeStop: function() { - TextareaResize({ - scope: scope, - textareaId: 'inventory_variables', - modalId: 'inventory-edit-modal-dialog', - formId: 'inventory_form' - }); - }, - beforeDestroy: function() { - if (scope.codeMirror) { - scope.codeMirror.destroy(); - } - $('#inventory-edit-modal-dialog').empty(); - }, - onOpen: function() { - $('#inventory_name').focus(); - setTimeout(function() { - TextareaResize({ - scope: scope, - textareaId: 'inventory_variables', - modalId: 'inventory-edit-modal-dialog', - formId: 'inventory_form', - parse: true - }); - }, 300); - }, - callback: 'InventoryEditDialogReady' - }); - - scope.parseType = 'yaml'; - - if (scope.removeInventoryPropertiesLoaded) { - scope.removeInventoryPropertiesLoaded(); - } - scope.removeInventoryPropertiesLoaded = scope.$on('inventoryPropertiesLoaded', function() { - Wait('stop'); - $('#inventory-edit-modal-dialog').dialog('open'); - }); - - scope.formModalActionLabel = 'Save'; - scope.formModalCancelShow = true; - scope.formModalInfo = false; - scope.formModalHeader = 'Inventory Properties'; - - 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]; - } - } - - LookUpInit({ - scope: scope, - form: form, - current_item: scope.organization, - list: OrganizationList, - field: 'organization', - input_type: 'radio' - }); - - scope.$emit('inventoryPropertiesLoaded'); - - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status }); - }); - - if (scope.removeInventorySaved) { - scope.removeInventorySaved(); - } - scope.removeInventorySaved = scope.$on('InventorySaved', function () { - //$('#form-modal').modal('hide'); - // Restore prior search state - //if (scope.searchCleanp) { - // scope.searchCleanup(); - //} - //SearchInit({ - // scope: parent_scope, - // set: PreviousSearchParams.set, - // list: PreviousSearchParams.list, - // url: PreviousSearchParams.defaultUrl, - // iterator: PreviousSearchParams.iterator, - // sort_order: PreviousSearchParams.sort_order, - // setWidgets: false - //}); - //parent_scope.$emit('RefreshInventories'); - try { - $('#inventory-edit-modal-dialog').dialog('close'); - } - catch(err) { - // ignore - } - parent_scope.$emit('RefreshInventories'); - scope.$destroy(); - }); - - scope.cancelModal = function () { - // Restore prior search state - /*if (scope.searchCleanp) { - scope.searchCleanup(); - } - SearchInit({ - scope: parent_scope, - set: PreviousSearchParams.set, - list: PreviousSearchParams.list, - url: PreviousSearchParams.defaultUrl, - iterator: PreviousSearchParams.iterator, - sort_order: PreviousSearchParams.sort_order, - setWidgets: false - });*/ - try { - $('#inventory-edit-modal-dialog').dialog('close'); - } - catch(err) { - // ignore - } - scope.$destroy(); - }; - - scope.saveModal = function () { - scope.inventory_id = inventory_id; - SaveInventory({ scope: scope, parent_scope: parent_scope }); - }; - - }; - } ]); diff --git a/awx/ui/client/src/inventories/inventories.partial.html b/awx/ui/client/src/inventories/inventories.partial.html index 46d04b20dd..0284089d54 100644 --- a/awx/ui/client/src/inventories/inventories.partial.html +++ b/awx/ui/client/src/inventories/inventories.partial.html @@ -1,13 +1,5 @@
-
+
-
-
diff --git a/awx/ui/client/src/adhoc/adhoc.controller.js b/awx/ui/client/src/inventories/manage/adhoc/adhoc.controller.js similarity index 97% rename from awx/ui/client/src/adhoc/adhoc.controller.js rename to awx/ui/client/src/inventories/manage/adhoc/adhoc.controller.js index 4ccf56ca54..a1be88d05c 100644 --- a/awx/ui/client/src/adhoc/adhoc.controller.js +++ b/awx/ui/client/src/inventories/manage/adhoc/adhoc.controller.js @@ -9,7 +9,7 @@ * @name controllers.function:Adhoc * @description This controller controls the adhoc form creation, command launching and navigating to standard out after command has been succesfully ran. */ -function adhocController($q, $scope, $rootScope, $location, $stateParams, +function adhocController($q, $scope, $location, $stateParams, $state, CheckPasswords, PromptForPasswords, CreateLaunchDialog, adhocForm, GenerateForm, Rest, ProcessErrors, ClearScope, GetBasePath, GetChoices, KindChange, LookUpInit, CredentialList, Empty, Wait) { @@ -23,7 +23,7 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams, this.privateFn = privateFn; var id = $stateParams.inventory_id, - hostPattern = $rootScope.hostPatterns || "all"; + hostPattern = $stateParams.pattern; // note: put any urls that the controller will use in here!!!! privateFn.setAvailableUrls = function() { @@ -102,7 +102,6 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams, privateFn.instantiateHostPatterns = function(hostPattern) { $scope.limit = hostPattern; $scope.providedHostPatterns = $scope.limit; - delete $rootScope.hostPatterns; }; // call helpers to initialize lookup and select fields through get @@ -295,7 +294,7 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams, } -export default ['$q', '$scope', '$rootScope', '$location', '$stateParams', +export default ['$q', '$scope', '$location', '$stateParams', '$state', 'CheckPasswords', 'PromptForPasswords', 'CreateLaunchDialog', 'adhocForm', 'GenerateForm', 'Rest', 'ProcessErrors', 'ClearScope', 'GetBasePath', 'GetChoices', 'KindChange', 'LookUpInit', 'CredentialList', 'Empty', 'Wait', diff --git a/awx/ui/client/src/adhoc/adhoc.form.js b/awx/ui/client/src/inventories/manage/adhoc/adhoc.form.js similarity index 97% rename from awx/ui/client/src/adhoc/adhoc.form.js rename to awx/ui/client/src/inventories/manage/adhoc/adhoc.form.js index 44a5c3ba6d..6c61349352 100644 --- a/awx/ui/client/src/adhoc/adhoc.form.js +++ b/awx/ui/client/src/inventories/manage/adhoc/adhoc.form.js @@ -122,20 +122,19 @@ export default function() { dataContainer: "body" }, }, - buttons: { - reset: { - ngClick: 'formReset()', - ngDisabled: true, - label: 'Reset', - 'class': 'Form-buttonDefault Form-button' - }, launch: { label: 'Save', ngClick: 'launchJob()', ngDisabled: true, - 'class': 'Form-buttonDefault Form-button' - } + 'class': 'btn btn-sm List-buttonSubmit' + }, + reset: { + ngClick: 'formReset()', + ngDisabled: true, + label: 'Reset', + 'class': 'btn btn-sm Form-cancelButton' + } }, related: {} diff --git a/awx/ui/client/src/adhoc/adhoc.partial.html b/awx/ui/client/src/inventories/manage/adhoc/adhoc.partial.html similarity index 100% rename from awx/ui/client/src/adhoc/adhoc.partial.html rename to awx/ui/client/src/inventories/manage/adhoc/adhoc.partial.html diff --git a/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js b/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js new file mode 100644 index 0000000000..17307ff562 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js @@ -0,0 +1,24 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + import {templateUrl} from '../../../shared/template-url/template-url.factory'; + +export default { + route: '/adhoc', + params:{ + pattern: { + value: 'all', + squash: true + } + }, + name: 'inventoryManage.adhoc', + views: { + 'form@inventoryManage': { + templateUrl: templateUrl('inventories/manage/adhoc/adhoc'), + controller: 'adhocController' + } + } +}; diff --git a/awx/ui/client/src/inventories/manage/adhoc/main.js b/awx/ui/client/src/inventories/manage/adhoc/main.js new file mode 100644 index 0000000000..7072a23063 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/adhoc/main.js @@ -0,0 +1,11 @@ +import route from './adhoc.route'; +import adhocController from './adhoc.controller'; +import form from './adhoc.form'; + +export default + angular.module('adhoc', []) + .controller('adhocController', adhocController) + .run(['$stateExtender', function($stateExtender) { + $stateExtender.addState(route); + }]) + .factory('adhocForm', form); diff --git a/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.block.less b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.block.less new file mode 100644 index 0000000000..d53e9174c8 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.block.less @@ -0,0 +1,25 @@ +.InventoryManageBreadCrumbs .BreadCrumb-list{ + padding-right: 0px; +} +.InventoryManageBreadCrumb-ncy.BreadCrumb-list{ + padding-left: 5px; +} +.InventoryManageBreadCrumbs-separator{ + content: "/"; + padding: 0 5px; + color: #B7B7B7; +} +.InventoryManageBreadCrumbs{ + position: relative; + height: auto; + top: -40px; + .BreadCrumb-list{ + margin-bottom: 0px; + } +} +.InventoryManage-breakWord{ + word-break: break-all; +} +ol.BreadCrumb-list{ + display: inline-block; +} \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.controller.js b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.controller.js new file mode 100644 index 0000000000..c04f014df2 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.controller.js @@ -0,0 +1,27 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default + ['$state', '$stateParams', '$scope', 'inventoryData', 'breadCrumbData', function($state, $stateParams, $scope, inventoryData, breadCrumbData){ + // process result data into the same order specified in the traversal path + $scope.groups = _.sortBy(breadCrumbData, function(item){ + var index = _.indexOf($stateParams.group, item.id); + return (index === -1) ? $stateParams.group.length : index; + }); + $scope.inventory = inventoryData; + // slices the group stack at $index to supply new group params to $state.go() + $scope.goToGroup = function($index){ + var group = $stateParams.group.slice(0, $index); + $state.go('inventoryManage', {group: group}, {reload: true}); + }; + $scope.state = $state; + $scope.isRootState = function(){ + return $state.current.name === 'inventoryManage'; + }; + $scope.goToInventory = function(){ + $state.go('inventoryManage', {group: undefined}, {reload: true}); + }; + }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.partial.html b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.partial.html new file mode 100644 index 0000000000..16a59d4031 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.partial.html @@ -0,0 +1,50 @@ + diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move-groups.controller.js b/awx/ui/client/src/inventories/manage/copy-move/copy-move-groups.controller.js new file mode 100644 index 0000000000..90ce9c5fda --- /dev/null +++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move-groups.controller.js @@ -0,0 +1,68 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$scope', '$state', '$stateParams', 'generateList', 'SearchInit', 'PaginateInit', 'GroupManageService', 'GetBasePath', 'CopyMoveGroupList', 'group', + function($scope, $state, $stateParams, GenerateList, SearchInit, PaginateInit, GroupManageService, GetBasePath, CopyMoveGroupList, group){ + var list = CopyMoveGroupList, + view = GenerateList; + $scope.item = group; + $scope.submitMode = $stateParams.groups === undefined ? 'move' : 'copy'; + $scope['toggle_'+ list.iterator] = function(id){ + // toggle off anything else currently selected + _.forEach($scope.groups, (item) => {return item.id === id ? item.checked = 1 : item.checked = null;}); + // yoink the currently selected thing + $scope.selected = _.find($scope.groups, (item) => {return item.id === id;}); + }; + $scope.formCancel = function(){ + $state.go('^'); + }; + $scope.formSave = function(){ + switch($scope.submitMode) { + case 'copy': + GroupManageService.associateGroup(group, $scope.selected.id).then(() => $state.go('^', null, {reload: true})); + break; + case 'move': + // at the root group level, no dissassociation is needed + if (!$stateParams.group){ + GroupManageService.associateGroup(group, $scope.selected.id).then(() => $state.go('^', null, {reload: true})); + } + else{ + // unsure if orphaned resources get garbage collected, safe bet is to associate before disassociate + GroupManageService.associateGroup(group, $scope.selected.id).then(() => { + GroupManageService.disassociateGroup(group, _.last($stateParams.group)) + .then(() => $state.go('^', null, {reload: true})); + }); + } + break; + } + }; + var init = function(){ + var url = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/'; + url += $stateParams.group ? '?not__id__in=' + group.id + ',' + _.last($stateParams.group) : '?not__id=' + group.id; + list.basePath = url; + view.inject(list, { + mode: 'lookup', + id: 'copyMove-list', + scope: $scope + }); + SearchInit({ + scope: $scope, + set: list.name, + list: list, + url: url + }); + PaginateInit({ + scope: $scope, + list: list, + url : url, + mode: 'lookup' + }); + $scope.search(list.iterator, null, true, false); + // remove the current group from list + }; + init(); + }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move-hosts.controller.js b/awx/ui/client/src/inventories/manage/copy-move/copy-move-hosts.controller.js new file mode 100644 index 0000000000..14774de3ba --- /dev/null +++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move-hosts.controller.js @@ -0,0 +1,65 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$scope', '$state', '$stateParams', 'generateList', 'SearchInit', 'PaginateInit', 'HostManageService', 'GetBasePath', 'CopyMoveGroupList', 'host', + function($scope, $state, $stateParams, GenerateList, SearchInit, PaginateInit, HostManageService, GetBasePath, CopyMoveGroupList, host){ + var list = CopyMoveGroupList, + view = GenerateList; + $scope.item = host; + $scope.submitMode = 'copy'; + $scope['toggle_'+ list.iterator] = function(id){ + // toggle off anything else currently selected + _.forEach($scope.groups, (item) => {return item.id === id ? item.checked = 1 : item.checked = null;}); + // yoink the currently selected thing + $scope.selected = _.find($scope.groups, (item) => {return item.id === id;}); + }; + $scope.formCancel = function(){ + $state.go('^'); + }; + $scope.formSave = function(){ + switch($scope.submitMode) { + case 'copy': + HostManageService.associateGroup(host, $scope.selected.id).then(() => $state.go('^')); + break; + case 'move': + // at the root group level, no dissassociation is needed + if (!$stateParams.group){ + HostManageService.associateGroup(host, $scope.selected.id).then(() => $state.go('^', null, {reload: true})); + } + else{ + HostManageService.associateGroup(host, $scope.selected.id).then(() => { + HostManageService.disassociateGroup(host, _.last($stateParams.group)) + .then(() => $state.go('^', null, {reload: true})); + }); + } + break; + } + }; + var init = function(){ + var url = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/'; + list.basePath = url; + view.inject(list, { + mode: 'lookup', + id: 'copyMove-list', + scope: $scope + }); + SearchInit({ + scope: $scope, + set: list.name, + list: list, + url: url + }); + PaginateInit({ + scope: $scope, + list: list, + url : url, + mode: 'lookup' + }); + $scope.search(list.iterator, null, true, false); + }; + init(); + }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/copy/copy.block.less b/awx/ui/client/src/inventories/manage/copy-move/copy-move.block.less similarity index 69% rename from awx/ui/client/src/inventories/manage/copy/copy.block.less rename to awx/ui/client/src/inventories/manage/copy-move/copy-move.block.less index 34b93417f6..76bdc2724c 100644 --- a/awx/ui/client/src/inventories/manage/copy/copy.block.less +++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move.block.less @@ -4,13 +4,6 @@ .List-searchRow { width: 50%; } - - .ui-dialog-buttonpane.ui-widget-content { - border: none; - text-align: right; - margin-top: 15px; - } - .Form-header { width: 50%; margin-top: -20px; @@ -22,9 +15,12 @@ } } } - -.copyMove-directive--copyMoveChoices { +.copyMove-choices { float: right; width: 25%; text-align: right; } +.copyMove-buttons{ + height: 30px; + margin-top: 10px; +} \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move.partial.html b/awx/ui/client/src/inventories/manage/copy-move/copy-move.partial.html new file mode 100644 index 0000000000..a148985287 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move.partial.html @@ -0,0 +1,19 @@ +
+
+
{{item.name}}
+
+
+ + +
+
+
+
+ + +
+
diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js b/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js new file mode 100644 index 0000000000..85d856c5ed --- /dev/null +++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js @@ -0,0 +1,51 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ +import {templateUrl} from '../../../shared/template-url/template-url.factory'; + +import CopyMoveGroupsController from './copy-move-groups.controller'; +import CopyMoveHostsController from './copy-move-hosts.controller'; + +var copyMoveGroup = { + name: 'inventoryManage.copyMoveGroup', + route: '/copy-move-group/{group_id}', + data: { + group_id: 'group_id', + }, + ncyBreadcrumb: { + label: "COPY OR MOVE {{item.name}}" + }, + resolve: { + group: ['GroupManageService', '$stateParams', function(GroupManageService, $stateParams){ + return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]); + }] + }, + views: { + 'form@inventoryManage' : { + controller: CopyMoveGroupsController, + templateUrl: templateUrl('inventories/manage/copy-move/copy-move'), + } + } +}; +var copyMoveHost = { + name: 'inventoryManage.copyMoveHost', + route: '/copy-move-host/{host_id}', + ncyBreadcrumb: { + label: "COPY OR MOVE {{item.name}}" + }, + resolve: { + host: ['HostManageService', '$stateParams', function(HostManageService, $stateParams){ + return HostManageService.get({id: $stateParams.host_id}).then(res => res.data.results[0]); + }] + }, + views: { + 'form@inventoryManage': { + templateUrl: templateUrl('inventories/manage/copy-move/copy-move'), + controller: CopyMoveHostsController, + } + } +}; + +export {copyMoveGroup, copyMoveHost}; diff --git a/awx/ui/client/src/inventories/manage/copy/main.js b/awx/ui/client/src/inventories/manage/copy-move/main.js similarity index 53% rename from awx/ui/client/src/inventories/manage/copy/main.js rename to awx/ui/client/src/inventories/manage/copy-move/main.js index 898d5f9ae1..d68348cba8 100644 --- a/awx/ui/client/src/inventories/manage/copy/main.js +++ b/awx/ui/client/src/inventories/manage/copy-move/main.js @@ -4,12 +4,11 @@ * All Rights Reserved *************************************************/ -import route from './copy.route'; +import {copyMoveGroup, copyMoveHost} from './copy-move.route'; export default -angular.module('inventory-copy', []) +angular.module('manageCopyMove', []) .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(route.copy); - $stateExtender.addState(route.copyGroup); - $stateExtender.addState(route.copyHost); + $stateExtender.addState(copyMoveGroup); + $stateExtender.addState(copyMoveHost); }]); diff --git a/awx/ui/client/src/inventories/manage/copy/copy-groups.controller.js b/awx/ui/client/src/inventories/manage/copy/copy-groups.controller.js deleted file mode 100644 index 4690bb9b62..0000000000 --- a/awx/ui/client/src/inventories/manage/copy/copy-groups.controller.js +++ /dev/null @@ -1,306 +0,0 @@ -function CopyGroupsCtrl($compile, $state, $scope, $location, Rest, ProcessErrors, CreateDialog, - GetBasePath, Wait, GenerateList, GroupList, SearchInit, PaginateInit, GetRootGroups, ParamPass, Store) { - var vm = this; - var name; - - var params = ParamPass.get(), - group_id, - parent_scope, - scope; - - if (params !== undefined) { - group_id = $state.params.group_id; - parent_scope = params.scope; - scope = parent_scope.$new(); - var parent_group = parent_scope.selected_group_id, - url, group; - } else { - group_id = $state.params.group_id; - parent_scope = $scope.$new(); - scope = parent_scope.$new(); - } - - var inventory_id = $state.params.inventory_id; - var PreviousSearchParams = Store('group_current_search_params'); - - if (scope.removeGroupsCopyPostRefresh) { - scope.removeGroupsCopyPostRefresh(); - } - - scope.removeGroupCopyPostRefresh = scope.$on('PostRefresh', function() { - scope.copy_groups.forEach(function(row, i) { - scope.copy_groups[i].checked = '0'; - }); - Wait('stop'); - - // prevent backspace from navigation when not in input or textarea field - $(document).on('keydown', function(e) { - if (e.which === 8 && !$(e.target).is('input[type="text"], textarea')) { - e.preventDefault(); - } - }); - - }); - - if (scope.removeCopyDialogReady) { - scope.removeCopyDialogReady(); - } - - scope.removeCopyDialogReady = scope.$on('CopyDialogReady', function() { - var url = GetBasePath('inventory') + inventory_id + '/groups/'; - url += (parent_group) ? '?not__id__in=' + group_id + ',' + parent_group : '?not__id=' + group_id; - GenerateList.inject(GroupList, { - mode: 'lookup', - id: 'copyMove-directive--copyGroupSelect', - scope: scope - }); - SearchInit({ - scope: scope, - set: GroupList.name, - list: GroupList, - url: url - }); - PaginateInit({ - scope: scope, - list: GroupList, - url: url, - mode: 'lookup' - }); - scope.search(GroupList.iterator); - }); - - if (scope.removeShowDialog) { - scope.removeShowDialog(); - } - - scope.removeShowDialog = scope.$on('ShowDialog', function() { - var d; - scope.name = group.name; - scope.copy_choice = "copy"; - d = angular.element(document.getElementById('copyMove-directive--copyGroupSelect')); - $compile(d)(scope); - scope.$emit('CopyDialogReady'); - }); - - if (scope.removeRootGroupsReady) { - scope.removeRootGroupsReady(); - } - - scope.removeRootGroupsReady = scope.$on('RootGroupsReady', function(e, root_groups) { - scope.offer_root_group = true; - scope.use_root_group = false; - root_groups.every(function(row) { - if (row.id === group_id) { - scope.offer_root_group = false; - return false; - } - return true; - }); - url = GetBasePath('groups') + group_id + '/'; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - group = data; - vm.name = group.name; - scope.$emit('ShowDialog'); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET returned: ' + status - }); - }); - }); - - Wait('start'); - - GetRootGroups({ - scope: scope, - group_id: group_id, - inventory_id: $state.params.inventory_id, - callback: 'RootGroupsReady' - }); - - var restoreSearch = function() { - // Restore search params and related stuff, plus refresh - // groups and hosts lists - SearchInit({ - scope: $scope, - set: PreviousSearchParams.set, - list: PreviousSearchParams.list, - url: PreviousSearchParams.defaultUrl, - iterator: PreviousSearchParams.iterator, - sort_order: PreviousSearchParams.sort_order, - setWidgets: false - }); - $scope.refreshHostsOnGroupRefresh = true; - //$scope.search(InventoryGroups.iterator, null, true, false, true); - }; - - var cancel = function() { - restoreSearch(); // Restore all parent search stuff and refresh hosts and groups lists - scope.$destroy(); - $state.go('inventoryManage', {}, { - reload: true - }); - }; - - var allowSave = false; - scope['toggle_' + GroupList.iterator] = function(id) { - var count = 0, - list = GroupList; - scope[list.name].forEach(function(row, i) { - if (row.id === id) { - if (row.checked) { - scope[list.name][i].success_class = 'success'; - } else { - scope[list.name][i].success_class = ''; - } - } else { - scope[list.name][i].checked = 0; - scope[list.name][i].success_class = ''; - } - }); - // Check if any rows are checked - scope[list.name].forEach(function(row) { - if (row.checked) { - count++; - } - }); - if (count === 0) { - vm.allowSave = false; - } else { - vm.allowSave = true; - } - }; - - scope.toggleUseRootGroup = function() { - var list = GroupList; - if (scope.use_root_group) { - $('#group-copy-ok-button').removeAttr('disabled'); - } else { - // check for group selection - $('#group-copy-ok-button').attr('disabled', 'disabled'); - scope[list.name].every(function(row) { - if (row.checked === 1) { - $('#group-copy-ok-button').removeAttr('disabled'); - return false; - } - return true; - }); - } - }; - - var performCopy = function() { - var list = GroupList, - target, - url; - - Wait('start'); - - if (scope.use_root_group) { - target = null; - } else { - scope[list.name].every(function(row) { - if (row.checked === 1) { - target = row; - return false; - } - return true; - }); - } - - if (vm.copy_choice === 'move') { - // Respond to move - - // disassociate the group from the original parent - if (scope.removeGroupRemove) { - scope.removeGroupRemove(); - } - scope.removeGroupRemove = scope.$on('RemoveGroup', function() { - if (parent_group > 0) { - // Only remove a group from a parent when the parent is a group and not the inventory root - url = GetBasePath('groups') + parent_group + '/children/'; - Rest.setUrl(url); - Rest.post({ - id: group.id, - disassociate: 1 - }) - .success(function() { - vm.cancel(); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to remove ' + group.name + ' from group ' + parent_group + '. POST returned: ' + status - }); - }); - } else { - vm.cancel(); - } - }); - - // add the new group to the target - url = (target) ? - GetBasePath('groups') + target.id + '/children/' : - GetBasePath('inventory') + inventory_id + '/groups/'; - group = { - id: group.id, - name: group.name, - description: group.description, - inventory: inventory_id - }; - Rest.setUrl(url); - Rest.post(group) - .success(function() { - scope.$emit('RemoveGroup'); - }) - .error(function(data, status) { - var target_name = (target) ? target.name : 'inventory'; - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to add ' + group.name + ' to ' + target_name + '. POST returned: ' + status - }); - }); - } else { - // Respond to copy by adding the new group to the target - url = (target) ? - GetBasePath('groups') + target.id + '/children/' : - GetBasePath('inventory') + inventory_id + '/groups/'; - - group = { - id: group.id, - name: group.name, - description: group.description, - inventory: inventory_id - }; - - Rest.setUrl(url); - Rest.post(group) - .success(function() { - vm.cancel(); - }) - .error(function(data, status) { - var target_name = (target) ? target.name : 'inventory'; - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to add ' + group.name + ' to ' + target_name + '. POST returned: ' + status - }); - }); - } - }; - - var copy_choice = 'copy'; - - angular.extend(vm, { - cancel: cancel, - performCopy: performCopy, - copy_choice: copy_choice, - name: name, - allowSave: allowSave - }); -} - -export default ['$compile', '$state', '$scope', '$location', 'Rest', 'ProcessErrors', 'CreateDialog', 'GetBasePath', 'Wait', 'generateList', 'GroupList', 'SearchInit', - 'PaginateInit', 'GetRootGroups', 'ParamPass', 'Store', CopyGroupsCtrl -]; diff --git a/awx/ui/client/src/inventories/manage/copy/copy-groups.partial.html b/awx/ui/client/src/inventories/manage/copy/copy-groups.partial.html deleted file mode 100644 index d82ca6956f..0000000000 --- a/awx/ui/client/src/inventories/manage/copy/copy-groups.partial.html +++ /dev/null @@ -1,22 +0,0 @@ -
-
-
{{vm.name}}
-
-
- - -
-
-
-
- - -
-
-
diff --git a/awx/ui/client/src/inventories/manage/copy/copy-hosts.controller.js b/awx/ui/client/src/inventories/manage/copy/copy-hosts.controller.js deleted file mode 100644 index 3883fed6ad..0000000000 --- a/awx/ui/client/src/inventories/manage/copy/copy-hosts.controller.js +++ /dev/null @@ -1,239 +0,0 @@ -function CopyHostsCtrl($compile, $state, $scope, Rest, ProcessErrors, CreateDialog, GetBasePath, Wait, GenerateList, GroupList, SearchInit, PaginateInit, ParamPass, Store) { - var vm = this; - var name; - - var host_id = $state.params.host_id; - var inventory_id = $state.params.inventory_id; - var url, host, group_scope, parent_scope, scope, parent_group; - - var params = ParamPass.get(); - if (params !== undefined) { - group_scope = params.group_scope; - parent_scope = params.host_scope; - parent_group = group_scope.selected_group_id; - scope = parent_scope.$new(); - } else { - group_scope = $scope.$new(); - parent_scope = $scope.$new(); - scope = parent_scope.$new(); - } - - var PreviousSearchParams = Store('group_current_search_params'); - - if (scope.removeHostCopyPostRefresh) { - scope.removeHostCopyPostRefresh(); - } - scope.removeHostCopyPostRefresh = scope.$on('PostRefresh', function() { - scope.copy_groups.forEach(function(row, i) { - scope.copy_groups[i].checked = '0'; - }); - Wait('stop'); - // prevent backspace from navigation when not in input or textarea field - $(document).on("keydown", function(e) { - if (e.which === 8 && !$(e.target).is('input[type="text"], textarea')) { - e.preventDefault(); - } - }); - }); - - if (scope.removeHostCopyDialogReady) { - scope.removeHostCopyDialogReady(); - } - scope.removeCopyDialogReady = scope.$on('HostCopyDialogReady', function() { - var url = GetBasePath('inventory') + inventory_id + '/groups/'; - GenerateList.inject(GroupList, { - mode: 'lookup', - id: 'copyMove-directive--copyHostSelect', - scope: scope - //, - //instructions: instructions - }); - SearchInit({ - scope: scope, - set: GroupList.name, - list: GroupList, - url: url - }); - PaginateInit({ - scope: scope, - list: GroupList, - url: url, - mode: 'lookup' - }); - scope.search(GroupList.iterator, null, true, false); - }); - - if (scope.removeShowDialog) { - scope.removeShowDialog(); - } - scope.removeShowDialog = scope.$on('ShowDialog', function() { - var d; - scope.name = host.name; - d = angular.element(document.getElementById('copyMove-directive--copyHostPanel')); - $compile(d)(scope); - scope.$emit('HostCopyDialogReady'); - }); - - Wait('start'); - - url = GetBasePath('hosts') + host_id + '/'; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - host = data; - vm.name = host.name; - scope.$emit('ShowDialog'); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET returned: ' + status - }); - }); - - var restoreSearch = function() { - // Restore search params and related stuff, plus refresh - // groups and hosts lists - SearchInit({ - scope: $scope, - set: PreviousSearchParams.set, - list: PreviousSearchParams.list, - url: PreviousSearchParams.defaultUrl, - iterator: PreviousSearchParams.iterator, - sort_order: PreviousSearchParams.sort_order, - setWidgets: false - }); - $scope.refreshHostsOnGroupRefresh = true; - }; - - var cancel = function() { - $(document).off("keydown"); - restoreSearch(); // Restore all parent search stuff and refresh hosts and groups lists - scope.$destroy(); - $state.go('inventoryManage', {}, { - reload: true - }); - }; - - var allowSave = false; - scope['toggle_' + GroupList.iterator] = function(id) { - var count = 0, - list = GroupList; - scope[list.name].forEach(function(row, i) { - if (row.id === id) { - if (row.checked) { - scope[list.name][i].success_class = 'success'; - } else { - scope[list.name][i].success_class = ''; - } - } else { - scope[list.name][i].checked = 0; - scope[list.name][i].success_class = ''; - } - }); - // Check if any rows are checked - scope[list.name].forEach(function(row) { - if (row.checked) { - count++; - } - }); - if (count === 0) { - vm.allowSave = false; - } else { - vm.allowSave = true; - } - }; - - var performCopy = function() { - var list = GroupList, - target, - url; - - Wait('start'); - - if (scope.use_root_group) { - target = null; - } else { - scope[list.name].every(function(row) { - if (row.checked === 1) { - target = row; - return false; - } - return true; - }); - } - - if (vm.copy_choice === 'move') { - // Respond to move - // disassociate the host from the original parent - if (scope.removeHostRemove) { - scope.removeHostRemove(); - } - scope.removeHostRemove = scope.$on('RemoveHost', function() { - if (parent_group > 0) { - // Only remove a host from a parent when the parent is a group and not the inventory root - url = GetBasePath('groups') + parent_group + '/hosts/'; - Rest.setUrl(url); - Rest.post({ - id: host.id, - disassociate: 1 - }) - .success(function() { - vm.cancel(); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to remove ' + host.name + ' from group ' + parent_group + '. POST returned: ' + status - }); - }); - } else { - vm.cancel(); - } - }); - - // add the new host to the target - url = GetBasePath('groups') + target.id + '/hosts/'; - Rest.setUrl(url); - Rest.post(host) - .success(function() { - scope.$emit('RemoveHost'); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to add ' + host.name + ' to ' + target.name + '. POST returned: ' + status - }); - }); - } else { - // Respond to copy by adding the new host to the target - url = GetBasePath('groups') + target.id + '/hosts/'; - Rest.setUrl(url); - Rest.post(host) - .success(function() { - vm.cancel(); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to add ' + host.name + ' to ' + target.name + '. POST returned: ' + status - }); - }); - } - }; - - - var copy_choice = 'copy'; - - angular.extend(vm, { - copy_choice: copy_choice, - name: name, - cancel: cancel, - allowSave: allowSave, - performCopy: performCopy - }); -} - -export default ['$compile', '$state', '$scope', 'Rest', 'ProcessErrors', 'CreateDialog', 'GetBasePath', 'Wait', 'generateList', 'GroupList', 'SearchInit', - 'PaginateInit', 'ParamPass', 'Store', CopyHostsCtrl -]; diff --git a/awx/ui/client/src/inventories/manage/copy/copy-hosts.partial.html b/awx/ui/client/src/inventories/manage/copy/copy-hosts.partial.html deleted file mode 100644 index aa2990434a..0000000000 --- a/awx/ui/client/src/inventories/manage/copy/copy-hosts.partial.html +++ /dev/null @@ -1,23 +0,0 @@ -
-
-
{{vm.name}}
-
-
- - -
-
-
-
-
- - -
-
-
diff --git a/awx/ui/client/src/inventories/manage/copy/copy.controller.js b/awx/ui/client/src/inventories/manage/copy/copy.controller.js deleted file mode 100644 index 144f55da70..0000000000 --- a/awx/ui/client/src/inventories/manage/copy/copy.controller.js +++ /dev/null @@ -1,16 +0,0 @@ -function inventoryManageCopyCtrl($state) { - var vm = this; - - var cancelPanel = function() { - $state.go('inventoryManage', {}, { - reload: true - }); - }; - - angular.extend(vm, { - cancelPanel: cancelPanel - }); -} - -export default ['$state', inventoryManageCopyCtrl -]; diff --git a/awx/ui/client/src/inventories/manage/copy/copy.partial.html b/awx/ui/client/src/inventories/manage/copy/copy.partial.html deleted file mode 100644 index ff19016e98..0000000000 --- a/awx/ui/client/src/inventories/manage/copy/copy.partial.html +++ /dev/null @@ -1,10 +0,0 @@ -
-
-
- -
- -
-
diff --git a/awx/ui/client/src/inventories/manage/copy/copy.route.js b/awx/ui/client/src/inventories/manage/copy/copy.route.js deleted file mode 100644 index 360cc30edc..0000000000 --- a/awx/ui/client/src/inventories/manage/copy/copy.route.js +++ /dev/null @@ -1,54 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import { - templateUrl -} from '../../../shared/template-url/template-url.factory'; - -import inventoryManageCopyCtrl from './copy.controller'; -import CopyGroupsCtrl from './copy-groups.controller'; -import CopyHostsCtrl from './copy-hosts.controller'; - -export default { - copy: { - name: 'inventoryManage.copy', - route: '/copy', - templateUrl: templateUrl('inventories/manage/copy/copy'), - ncyBreadcrumb: { - label: "COPY" - }, - controller: inventoryManageCopyCtrl, - controllerAs: 'vm', - bindToController: true, - }, - copyGroup: { - name: 'inventoryManage.copy.group', - route: '/group/:group_id?groups', - templateUrl: templateUrl('inventories/manage/copy/copy-groups'), - data: { - group_id: 'group_id', - }, - ncyBreadcrumb: { - label: "GROUP" - }, - controller: CopyGroupsCtrl, - controllerAs: 'vm', - bindToController: true - }, - copyHost: { - name: 'inventoryManage.copy.host', - route: '/host/:host_id?groups', - templateUrl: templateUrl('inventories/manage/copy/copy-hosts'), - data: { - host_id: 'host_id', - }, - ncyBreadcrumb: { - label: "HOST" - }, - controller: CopyHostsCtrl, - controllerAs: 'vm', - bindToController: true - } -}; diff --git a/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js new file mode 100644 index 0000000000..dff577c546 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js @@ -0,0 +1,215 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList', 'inventoryScriptsListObject', 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'LookUpInit', + 'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', + function($state, $stateParams, $scope, GroupForm, CredentialList, InventoryScriptsList, ParseTypeChange, GenerateForm, inventoryData, LookUpInit, + GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions){ + var generator = GenerateForm, + form = GroupForm(); + + $scope.formCancel = function(){ + $state.go('^'); + }; + $scope.formSave = function(){ + var params, source; + // group fields + var group = { + variables: $scope.variables === ('---' || '{}') ? null : $scope.variables, + name: $scope.name, + description: $scope.description, + inventory: inventoryData.id + }; + if ($scope.source){ + // inventory_source fields + params = { + instance_filters: $scope.instance_filters, + source_vars: $scope[$scope.source.value + '_variables'] === ('---' || '{}') ? null : $scope[$scope.source.value + '_variables'], + source_script: $scope.inventory_script, + source: $scope.source.value, + credential: $scope.credential, + overwrite: $scope.overwrite, + overwrite_vars: $scope.overwrite_vars, + update_on_launch: $scope.update_on_launch, + update_cache_timeout: $scope.update_cache_timeout || 0, + // comma-delimited strings + group_by: _.map($scope.group_by, 'value').join(','), + source_regions: _.map($scope.source_regions, 'value').join(',') + }; + source = $scope.source.value; + } + else{ + source = null; + } + switch(source){ + // no inventory source set, just create a new group + // '' is the value supplied for Manual source type + case null || '': + GroupManageService.post(group).then(res => { + // associate + if ($stateParams.group){ + return GroupManageService.associateGroup(res.data, _.last($stateParams.group)) + .then(() => $state.go('^', null, {reload: true})); + } + else{ + $state.go('^', null, {reload: true}); + } + }); + break; + // create a new group and create/associate an inventory source + // equal to case 'rax' || 'ec2' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom' + default: + GroupManageService.post(group) + // associate to group + .then(res => { + if ($stateParams.group){ + GroupManageService.associateGroup(res.data, _.last($stateParams.group)); + return res; + } + else {return res;} + // pass the original POST response and not the association response + }) + .then(res => GroupManageService.putInventorySource( + // put the received group ID into inventory source payload + // and pass the related endpoint + _.assign(params, {group: res.data.id}), res.data.related.inventory_source)) + .then(res => $state.go('inventoryManage.editGroup', {group_id: res.data.group}, {reload: true})); + break; + } + }; + $scope.sourceChange = function(source){ + source = source.value === 'azure_rm' ? 'azure' : source.value; + if (source === 'custom'){ + LookUpInit({ + scope: $scope, + url: GetBasePath('inventory_script'), + form: form, + list: InventoryScriptsList, + field: 'inventory_script', + input_type: "radio" + }); + } + else if (source === 'ec2'){ + LookUpInit({ + scope: $scope, + url: GetBasePath('credentials') + '?kind=aws', + form: form, + list: CredentialList, + field: 'credential', + input_type: "radio" + }); + } + // equal to case 'rax' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom' + else{ + LookUpInit({ + scope: $scope, + url: GetBasePath('credentials') + (source === '' ? '' : '?kind=' + source), + form: form, + list: CredentialList, + field: 'credential', + input_type: "radio" + }); + } + // reset fields + $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null; + $scope.source_region_choices = $scope[source + '_regions']; + $scope.cloudCredentialRequired = source !== 'manual' && source !== 'custom' ? true : false; + $scope.group_by = null; + $scope.source_regions = null; + $scope.credential = null; + $scope.credential_name = null; + initRegionSelect(); + }; + var initRegionSelect = function(){ + CreateSelect2({ + element: '#group_source_regions', + multiple: true + }); + CreateSelect2({ + element: '#group_group_by', + multiple: true + }); + }; + var initSourceSelect = function(){ + CreateSelect2({ + element: '#group_source', + multiple: false + }); + }; + var initSources = function(){ + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'rax_regions', + choice_name: 'rax_region_choices', + callback: 'choicesReadyGroup' + }); + + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'ec2_regions', + choice_name: 'ec2_region_choices', + callback: 'choicesReadyGroup' + }); + + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'gce_regions', + choice_name: 'gce_region_choices', + callback: 'choicesReadyGroup' + }); + + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'azure_regions', + choice_name: 'azure_region_choices', + callback: 'choicesReadyGroup' + }); + + // Load options for group_by + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'group_by', + variable: 'ec2_group_by', + choice_name: 'ec2_group_by_choices', + callback: 'choicesReadyGroup' + }); + GetSourceTypeOptions({ + scope: $scope, + variable: 'source_type_options', + //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref + }); + }; + // region / source options callback + $scope.$on('choicesReadyGroup', function(){ + initRegionSelect(); + }); + + $scope.$on('sourceTypeOptionsReady', function(){ + initSourceSelect(); + }); + var init = function(){ + $scope.parseType = 'yaml'; + $scope.variables = '---'; + generator.inject(form, {mode: 'add', related: false, id: 'Inventory-groupManage--panel', scope: $scope}); + ParseTypeChange({ + scope: $scope, + field_id: 'group_variables', + variable: 'variables', + }); + initSources(); + }; + init(); + }]; diff --git a/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js new file mode 100644 index 0000000000..6b60ebfa38 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js @@ -0,0 +1,288 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList', 'inventoryScriptsListObject', 'ToggleNotification', + 'ParseTypeChange', 'GenerateForm', 'LookUpInit', 'RelatedSearchInit', 'RelatedPaginateInit', 'NotificationsListInit', + 'GroupManageService','GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'groupData', 'inventorySourceData', + function($state, $stateParams, $scope, GroupForm, CredentialList, InventoryScriptsList, ToggleNotification, + ParseTypeChange, GenerateForm, LookUpInit, RelatedSearchInit, RelatedPaginateInit, NotificationsListInit, + GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, groupData, inventorySourceData){ + var generator = GenerateForm, + form = GroupForm(); + $scope.formCancel = function(){ + $state.go('^'); + }; + $scope.formSave = function(){ + var params, source; + // group fields + var group = { + variables: $scope.variables === ('---' || '{}') ? null : $scope.variables, + name: $scope.name, + description: $scope.description, + inventory: $scope.inventory, + id: groupData.id + }; + if ($scope.source){ + // inventory_source fields + params = { + group: groupData.id, + source: $scope.source.value, + credential: $scope.credential, + overwrite: $scope.overwrite, + overwrite_vars: $scope.overwrite_vars, + source_script: $scope.inventory_script, + update_on_launch: $scope.update_on_launch, + update_cache_timeout: $scope.update_cache_timeout || 0, + // comma-delimited strings + group_by: _.map($scope.group_by, 'value').join(','), + source_regions: _.map($scope.source_regions, 'value').join(','), + instance_filters: $scope.instance_filters, + source_vars: $scope[$scope.source.value + '_variables'] === '' ? null : $scope[$scope.source.value + '_variables'] + }; + source = $scope.source.value; + } + else{ + source = null; + } + switch(source){ + // no inventory source set, just create a new group + // '' is the value supplied for Manual source type + case null || '': + GroupManageService.put(group).then(() => $state.go('^', null, {reload: true})); + break; + // create a new group and create/associate an inventory source + // equal to case 'rax' || 'ec2' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom' + default: + GroupManageService.put(group) + .then(() => GroupManageService.putInventorySource(params, groupData.related.inventory_source)) + .then(() => $state.go('^', null, {reload: true})); + break; + } + }; + $scope.toggleNotification = function(event, notifier_id, column) { + var notifier = this.notification; + try { + $(event.target).tooltip('hide'); + } + catch(e) { + // ignore + } + ToggleNotification({ + scope: $scope, + url: GetBasePath('inventory_sources'), + id: inventorySourceData.id, + notifier: notifier, + column: column, + callback: 'NotificationRefresh' + }); + }; + $scope.sourceChange = function(source){ + $scope.source = source; + if (source.value === 'custom'){ + LookUpInit({ + scope: $scope, + url: GetBasePath('inventory_script'), + form: form, + list: InventoryScriptsList, + field: 'inventory_script', + input_type: "radio" + }); + } + else if (source.value === 'ec2'){ + LookUpInit({ + scope: $scope, + url: GetBasePath('credentials') + '?kind=aws', + form: form, + list: CredentialList, + field: 'credential', + input_type: "radio" + }); + } + else{ + LookUpInit({ + scope: $scope, + url: GetBasePath('credentials') + (source.value === '' ? '' : '?kind=' + (source.value)), + form: form, + list: CredentialList, + field: 'credential', + input_type: "radio" + }); + } + // reset fields + $scope.source_region_choices = $scope[source + '_regions']; + $scope.cloudCredentialRequired = source !== 'manual' && source !== 'custom' ? true : false; + $scope.group_by = null; + $scope.source_regions = null; + $scope.credential = null; + $scope.credential_name = null; + initRegionSelect(); + }; + var initRegionSelect = function(){ + CreateSelect2({ + element: '#group_source_regions', + multiple: true + }); + CreateSelect2({ + element: '#group_group_by', + multiple: true + }); + }; + var initSourceSelect = function(){ + $scope.source = _.find($scope.source_type_options, {value: inventorySourceData.source}); + CreateSelect2({ + element: '#group_source', + multiple: false + }); + }; + var initRegionData = function(){ + var source = $scope.source.value === 'azure_rm' ? 'azure' : $scope.source.value; + var regions = inventorySourceData.source_regions.split(','); + $scope.source_region_choices = $scope[source + '_regions']; + $scope.source_regions = _.map(regions, (region) => _.find($scope[source+'_regions'], {value: region})); + $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null; + if (source ==='ec2'){ + var group_by = inventorySourceData.group_by.split(','); + $scope.group_by = _.map(group_by, (item) => _.find($scope.ec2_group_by, {value: item})); + } + initRegionSelect(); + }; + var initSources = function(){ + GetSourceTypeOptions({ + scope: $scope, + variable: 'source_type_options', + //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'rax_regions', + choice_name: 'rax_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'ec2_regions', + choice_name: 'ec2_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'gce_regions', + choice_name: 'gce_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'azure_regions', + choice_name: 'azure_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'group_by', + variable: 'ec2_group_by', + choice_name: 'ec2_group_by_choices', + callback: 'choicesReadyGroup' + }); + }; + // region / source options callback + $scope.$on('choicesReadyGroup', function(){ + if (angular.isObject($scope.source)){ + initRegionData(); + } + }); + + $scope.$on('sourceTypeOptionsReady', function(){ + initSourceSelect(); + }); + var init = function(){ + // instantiate expected $scope values from inventorySourceData & groupData + var relatedSets = form.relatedSets(groupData.related); + generator.inject(form, {mode: 'edit', related: false, id: 'Inventory-groupManage--panel', scope: $scope}); + _.assign($scope, + {credential: inventorySourceData.credential}, + {overwrite: inventorySourceData.overwrite}, + {overwrite_vars: inventorySourceData.overwrite_vars}, + {update_on_launch: inventorySourceData.update_on_launch}, + {update_cache_timeout: inventorySourceData.update_cache_timeout}, + {instance_filters: inventorySourceData.instance_filters}, + {inventory_script: inventorySourceData.source_script} + ); + if(inventorySourceData.source === ('ec2' || 'openstack' || 'custom' || 'vmware')){ + $scope[inventorySourceData.source + '_variables'] = inventorySourceData.source_vars; + } + if (inventorySourceData.credential){ + GroupManageService.getCredential(inventorySourceData.credential).then(res => $scope.credential_name = res.data.name); + } + $scope = angular.extend($scope, groupData); + $scope.variables = $scope.variables === (null || '') ? '---' : $scope.variables; + $scope.parseType = 'yaml'; + // instantiate lookup fields + if (inventorySourceData.source !== 'custom'){ + LookUpInit({ + scope: $scope, + url: GetBasePath('credentials') + (inventorySourceData.source === '' ? '' : 'kind=' + (inventorySourceData.source)), + form: form, + list: CredentialList, + field: 'credential', + input_type: "radio" + }); + } + else if (inventorySourceData.source === 'ec2'){ + LookUpInit({ + scope: $scope, + url: GetBasePath('credentials') + '?kind=aws', + form: form, + list: CredentialList, + field: 'credential', + input_type: "radio" + }); + } + // equal to case 'rax' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom' + else{ + $scope.inventory_script_name = inventorySourceData.summary_fields.source_script.name; + LookUpInit({ + scope: $scope, + url: GetBasePath('inventory_script'), + form: form, + list: InventoryScriptsList, + field: 'inventory_script', + input_type: "radio" + }); + } + ParseTypeChange({ + scope: $scope, + field_id: 'group_variables', + variable: 'variables', + }); + NotificationsListInit({ + scope: $scope, + url: GetBasePath('inventory_sources'), + id: inventorySourceData.id + }); + RelatedSearchInit({ + scope: $scope, + form: form, + relatedSets: relatedSets + }); + RelatedPaginateInit({ + scope: $scope, + relatedSets: relatedSets + }); + initSources(); + _.forEach(relatedSets, (value, key) => $scope.search(relatedSets[key].iterator)); + }; + init(); + }]; diff --git a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.partial.html b/awx/ui/client/src/inventories/manage/groups/groups-form.partial.html similarity index 77% rename from awx/ui/client/src/inventories/manage/manage-groups/manage-groups.partial.html rename to awx/ui/client/src/inventories/manage/groups/groups-form.partial.html index e39e0984ac..45ebffb9e3 100644 --- a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.partial.html +++ b/awx/ui/client/src/inventories/manage/groups/groups-form.partial.html @@ -1,5 +1,4 @@
-
diff --git a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js new file mode 100644 index 0000000000..b5969304bc --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js @@ -0,0 +1,145 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + export default + ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroups', 'generateList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus', + 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', + function($scope, $rootScope, $state, $stateParams, InventoryGroups, generateList, InventoryUpdate, GroupManageService, GroupsCancelUpdate, ViewUpdateStatus, + InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg){ + var list = InventoryGroups, + view = generateList, + pageSize = 20; + $scope.inventory_id = $stateParams.inventory_id; + $scope.groupSelect = function(id){ + var group = $stateParams.group === undefined ? [id] : _($stateParams.group).concat(id).value(); + $state.go('inventoryManage', {inventory_id: $stateParams.inventory_id, group: group}, {reload: true}); + }; + $scope.createGroup = function(){ + $state.go('inventoryManage.addGroup'); + }; + $scope.editGroup = function(id){ + $state.go('inventoryManage.editGroup', {group_id: id}); + }; + $scope.deleteGroup = function(group){ + $scope.toDelete = {}; + angular.extend($scope.toDelete, group); + $('#group-delete-modal').modal('show'); + }; + $scope.confirmDelete = function(){ + switch($scope.deleteOption){ + case 'promote': + GroupManageService.promote($scope.toDelete.id, $stateParams.inventory_id) + .then(() => { + $state.go('inventoryManage', null, {reload: true}); + $('#group-delete-modal').modal('hide'); + }); + break; + case 'delete': + GroupManageService.delete($scope.toDelete.id).then(() => { + $state.go('inventoryManage', null, {reload: true}); + $('#group-delete-modal').modal('hide'); + }); + } + }; + $scope.updateGroup = function(group) { + GroupManageService.getInventorySource({group: group.id}).then(res =>InventoryUpdate({ + scope: $scope, + group_id: group.id, + url: res.data.results[0].related.update, + group_name: group.name, + group_source: res.data.results[0].source + })); + $scope.$emit('WatchUpdateStatus'); // init socket io conneciton and start watching for status updates + $rootScope.$on('JobStatusChange-inventory', (event, data) => { + switch(data.status){ + case 'failed' || 'successful': + $state.reload(); + break; + default: + var status = GetSyncStatusMsg({ + status: data.status, + has_inventory_sources: group.has_inventory_sources, + source: group.source + }); + group.status = data.status; + group.status_class = status.class; + group.status_tooltip = status.tooltip; + group.launch_tooltip = status.launch_tip; + group.launch_class = status.launch_class; + } + }); + }; + $scope.cancelUpdate = function (id) { + GroupsCancelUpdate({ scope: $scope, id: id }); + }; + $scope.viewUpdateStatus = function (id) { + ViewUpdateStatus({ + scope: $scope, + group_id: id + }); + }; + $scope.showFailedHosts = function(x, y, z){ + $state.go('inventoryManage', {failed: true}, {reload: true}); + }; + $scope.scheduleGroup = function(id) { + $state.go('inventoryManage.schedules', {id: id}); + }; + // $scope.$parent governed by InventoryManageController, for unified multiSelect options + $scope.$on('multiSelectList.selectionChanged', (event, selection) => { + $scope.$parent.groupsSelected = selection.length > 0 ? true : false; + $scope.$parent.groupsSelectedItems = selection.selectedItems; + }); + $scope.$on('PostRefresh', () =>{ + $scope.groups.forEach( (group, index) => { + var group_status, hosts_status; + group_status = GetSyncStatusMsg({ + status: group.summary_fields.inventory_source.status, + has_inventory_sources: group.has_inventory_sources, + source: ( (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.source : null ) + }); + hosts_status = GetHostsStatusMsg({ + active_failures: group.hosts_with_active_failures, + total_hosts: group.total_hosts, + inventory_id: $scope.inventory_id, + group_id: group.id + }); + _.assign($scope.groups[index], + {status_class: group_status.class}, + {status_tooltip: group_status.tooltip}, + {launch_tooltip: group_status.launch_tip}, + {launch_class: group_status.launch_class}, + {hosts_status_tip: hosts_status.tooltip}, + {hosts_status_class: hosts_status.class}, + {source: group.summary_fields.inventory_source ? group.summary_fields.inventory_source.source : null}, + {status: group.summary_fields.inventory_source ? group.summary_fields.inventory_source.status : null}); + }); + }); + $scope.copyMoveGroup = function(id){ + $state.go('inventoryManage.copyMoveGroup', {group_id: id, groups: $stateParams.groups}); + }; + + var init = function(){ + list.basePath = groupsUrl; + view.inject(list,{ + id: 'groups-list', + $scope: $scope, + mode: 'edit' + }); + SearchInit({ + scope: $scope, + list: list, + url: groupsUrl, + set: 'groups' + }); + PaginateInit({ + scope: $scope, + list: list, + url: groupsUrl, + pageSize: pageSize + }); + $scope.search(list.iterator); + }; + init(); + }]; diff --git a/awx/ui/client/src/inventories/manage/groups/groups-list.partial.html b/awx/ui/client/src/inventories/manage/groups/groups-list.partial.html new file mode 100644 index 0000000000..84f0025183 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/groups-list.partial.html @@ -0,0 +1,73 @@ +
+ \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/groups/groups.block.less b/awx/ui/client/src/inventories/manage/groups/groups.block.less new file mode 100644 index 0000000000..67deadef22 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/groups.block.less @@ -0,0 +1,19 @@ +.select2-selection.select2-selection--multiple.Form-dropDown{ + height: auto !important; +} +.GroupDelete-help--container{ + margin-right: auto; +} +.GroupDelete .Modal-header{ + margin-bottom: 0; +} +.GroupDelete .modal-body{ + padding-top: 20px; +} +.Inventory-groupManage{ + // ugly hack to avoid the surface area of changing form generator's default classes + .checkbox-inline{ + display: block; + padding-bottom: 5px; + } +} \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/groups/groups.route.js b/awx/ui/client/src/inventories/manage/groups/groups.route.js new file mode 100644 index 0000000000..3f95c9a484 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/groups.route.js @@ -0,0 +1,51 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ +import {templateUrl} from '../../../shared/template-url/template-url.factory'; +import addController from './groups-add.controller'; +import editController from './groups-edit.controller'; + +var ManageGroupsEdit = { + name: 'inventoryManage.editGroup', + route: '/edit-group?group_id', + ncyBreadcrumb: { + label: "EDIT {{group.name}}" + }, + data: { + mode: 'edit' + }, + resolve: { + groupData: ['$stateParams', 'GroupManageService', function($stateParams, GroupManageService){ + return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]); + }], + inventorySourceData: ['$stateParams', 'GroupManageService', function($stateParams, GroupManageService){ + return GroupManageService.getInventorySource({group: $stateParams.group_id}).then(res => res.data.results[0]); + }] + }, + views: { + 'form@inventoryManage': { + controller: editController, + templateUrl: templateUrl('inventories/manage/groups/groups-form'), + } + } +}; +var ManageGroupsAdd = { + name: 'inventoryManage.addGroup', + route: '/add-group', + // use a query string to break regex search + ncyBreadcrumb: { + label: "ADD GROUP" + }, + data: { + mode: 'add' + }, + views: { + 'form@inventoryManage': { + controller: addController, + templateUrl: templateUrl('inventories/manage/groups/groups-form'), + } + } +}; +export {ManageGroupsAdd, ManageGroupsEdit}; diff --git a/awx/ui/client/src/inventories/manage/groups/groups.service.js b/awx/ui/client/src/inventories/manage/groups/groups.service.js new file mode 100644 index 0000000000..83b5ed224e --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/groups.service.js @@ -0,0 +1,113 @@ +export default + ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){ + return { + stringifyParams: function(params){ + return _.reduce(params, (result, value, key) => { + return result + key + '=' + value + '&'; + }, ''); + }, + // cute abstractions via fn.bind() + url: function(){ + return ''; + }, + error: function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + this.url + '. GET returned: ' + status }); + }, + success: function(data){ + return data; + }, + // HTTP methods + get: function(params){ + Wait('start'); + this.url = GetBasePath('groups') + '?' + this.stringifyParams(params); + Rest.setUrl(this.url); + return Rest.get() + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + post: function(group){ + Wait('start'); + this.url = GetBasePath('groups'); + Rest.setUrl(this.url); + return Rest.post(group) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + put: function(group){ + Wait('start'); + this.url = GetBasePath('groups') + group.id; + Rest.setUrl(this.url); + return Rest.put(group) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + delete: function(id){ + Wait('start'); + this.url = GetBasePath('groups') + id; + Rest.setUrl(this.url); + return Rest.destroy() + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + getCredential: function(id){ + Wait('start'); + this.url = GetBasePath('credentials') + id; + Rest.setUrl(this.url); + return Rest.get() + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + getInventorySource: function(params){ + Wait('start'); + this.url = GetBasePath('inventory_sources') + '?' + this.stringifyParams(params); + Rest.setUrl(this.url); + return Rest.get() + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + putInventorySource: function(params, url){ + Wait('start'); + this.url = url; + Rest.setUrl(this.url); + return Rest.put(params) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + // these relationship setters could be consolidated, but verbosity makes the operation feel more clear @ controller level + associateGroup: function(group, target){ + Wait('start'); + this.url = GetBasePath('groups') + target + '/children/'; + Rest.setUrl(this.url); + return Rest.post(group) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + disassociateGroup: function(group, parent){ + Wait('start'); + this.url = GetBasePath('groups') + parent + '/children/'; + Rest.setUrl(this.url); + return Rest.post({id: group, disassociate: 1}) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + promote: function(group, inventory){ + Wait('start'); + this.url = GetBasePath('inventory') + inventory + '/groups/'; + Rest.setUrl(this.url); + return Rest.post({id: group, disassociate: 1}) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + } + }; + }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/groups/main.js b/awx/ui/client/src/inventories/manage/groups/main.js new file mode 100644 index 0000000000..ffade1862a --- /dev/null +++ b/awx/ui/client/src/inventories/manage/groups/main.js @@ -0,0 +1,14 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import {ManageGroupsAdd, ManageGroupsEdit} from './groups.route'; + +export default + angular.module('manageGroups', []) + .run(['$stateExtender', function($stateExtender){ + $stateExtender.addState(ManageGroupsAdd); + $stateExtender.addState(ManageGroupsEdit); + }]); diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-add.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-add.controller.js similarity index 66% rename from awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-add.controller.js rename to awx/ui/client/src/inventories/manage/hosts/hosts-add.controller.js index 620a68f1ac..1eefe86020 100644 --- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-add.controller.js +++ b/awx/ui/client/src/inventories/manage/hosts/hosts-add.controller.js @@ -5,16 +5,16 @@ *************************************************/ export default - ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'ManageHostsService', - function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, ManageHostsService){ + ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService', + function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService){ var generator = GenerateForm, form = HostForm; $scope.parseType = 'yaml'; $scope.extraVars = '---'; $scope.formCancel = function(){ - $state.go('^', null, {reload: true}); + $state.go('^'); }; - $scope.toggleEnabled = function(){ + $scope.toggleHostEnabled = function(){ $scope.host.enabled = !$scope.host.enabled; }; $scope.formSave = function(){ @@ -25,8 +25,16 @@ enabled: $scope.host.enabled, inventory: $stateParams.inventory_id }; - ManageHostsService.post(params).then(function(){ - $state.go('^', null, {reload: true}); + HostManageService.post(params).then(function(res){ + // assign the host to current group if not at the root level + if ($stateParams.group){ + HostManageService.associateGroup(res.data, _.last($stateParams.group)).then(function(){ + $state.go('inventoryManage', null, {reload: true}); + }); + } + else{ + $state.go('inventoryManage', null, {reload: true}); + } }); }; var init = function(){ diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-edit.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js similarity index 88% rename from awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-edit.controller.js rename to awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js index de733124fa..8e764d95d5 100644 --- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-edit.controller.js +++ b/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js @@ -5,13 +5,13 @@ *************************************************/ export default - ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'ManageHostsService', 'host', - function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, ManageHostsService, host){ + ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService', 'host', + function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, host){ var generator = GenerateForm, form = HostForm; $scope.parseType = 'yaml'; $scope.formCancel = function(){ - $state.go('^', null, {reload: true}); + $state.go('^'); }; $scope.toggleHostEnabled = function(){ $scope.host.enabled = !$scope.host.enabled; @@ -24,7 +24,7 @@ description: $scope.description, enabled: $scope.host.enabled }; - ManageHostsService.put(host).then(function(){ + HostManageService.put(host).then(function(){ $state.go('^', null, {reload: true}); }); }; diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.partial.html b/awx/ui/client/src/inventories/manage/hosts/hosts-form.partial.html similarity index 100% rename from awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.partial.html rename to awx/ui/client/src/inventories/manage/hosts/hosts-form.partial.html diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js new file mode 100644 index 0000000000..13540fb489 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js @@ -0,0 +1,84 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + export default + ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryHosts', 'generateList', 'InventoryManageService', 'HostManageService', + 'hostsUrl', 'SearchInit', 'PaginateInit', 'SetStatus', 'Prompt', 'Wait', 'inventoryData', + function($scope, $rootScope, $state, $stateParams, InventoryHosts, generateList, InventoryManageService, HostManageService, + hostsUrl, SearchInit, PaginateInit, SetStatus, Prompt, Wait, inventoryData){ + var list = InventoryHosts, + view = generateList, + pageSize = 20; + $scope.createHost = function(){ + $state.go('inventoryManage.addHost'); + }; + $scope.editHost = function(id){ + $state.go('inventoryManage.editHost', {host_id: id}); + }; + $scope.deleteHost = function(id, name){ + var body = '
Are you sure you want to permanently delete the host below from the inventory?
' + name + '
'; + var action = function(){ + delete $rootScope.promptActionBtnClass; + Wait('start'); + HostManageService.delete(id).then(() => { + $('#prompt-modal').modal('hide'); + $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.copyMoveHost = function(id){ + $state.go('inventoryManage.copyMoveHost', {host_id: id}); + }; + $scope.systemTracking = function(){ + var hostIds = _.map($scope.$parent.hostsSelectedItems, (host) => host.id); + $state.go('systemTracking', { + inventory: inventoryData, + inventoryId: $stateParams.inventory_id, + hosts: $scope.$parent.hostsSelectedItems, + hostIds: hostIds + }); + }; + // $scope.$parent governed by InventoryManageController, for unified multiSelect options + $scope.$on('multiSelectList.selectionChanged', (event, selection) => { + $scope.$parent.hostsSelected = selection.length > 0 ? true : false; + $scope.$parent.hostsSelectedItems = selection.selectedItems; + $scope.$parent.systemTrackingDisabled = selection.length > 0 && selection.length < 3 ? false : true; + $scope.$parent.systemTrackingTooltip = selection.length === 1 ? "Compare host facts over time" : "Compare hosts' facts"; + }); + $scope.$on('PostRefresh', ()=>{ + _.forEach($scope.hosts, (host) => SetStatus({scope: $scope, host: host})); + }); + var init = function(){ + list.basePath = hostsUrl; + view.inject(list,{ + id: 'hosts-list', + scope: $scope, + mode: 'edit' + }); + SearchInit({ + scope: $scope, + list: list, + url: hostsUrl, + set: 'hosts' + }); + PaginateInit({ + scope: $scope, + list: list, + url: hostsUrl, + pageSize: pageSize + }); + $scope.search(list.iterator); + }; + init(); + }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts.route.js b/awx/ui/client/src/inventories/manage/hosts/hosts.route.js new file mode 100644 index 0000000000..54a9c3f7d0 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/hosts/hosts.route.js @@ -0,0 +1,50 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ +import {templateUrl} from '../../../shared/template-url/template-url.factory'; +import addController from './hosts-add.controller'; +import editController from './hosts-edit.controller'; + +var ManageHostsEdit = { + name: 'inventoryManage.editHost', + route: '/edit-host?host_id', + ncyBreadcrumb: { + label: "EDIT {{host.name}}", + }, + data: { + mode: 'edit' + }, + resolve: { + host: ['$stateParams', 'HostManageService', function($stateParams, HostManageService){ + return HostManageService.get({id: $stateParams.host_id}).then(function(res){ + return res.data.results[0]; + }); + }] + }, + views: { + 'form@inventoryManage': { + controller: editController, + templateUrl: templateUrl('inventories/manage/hosts/hosts-form'), + } + } +}; +var ManageHostsAdd = { + name: 'inventoryManage.addHost', + route: '/add-host', + // use a query string to break regex search + ncyBreadcrumb: { + label: "ADD HOST" + }, + data: { + mode: 'add' + }, + views: { + 'form@inventoryManage': { + controller: addController, + templateUrl: templateUrl('inventories/manage/hosts/hosts-form'), + } + } +}; +export {ManageHostsAdd, ManageHostsEdit}; diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts.service.js b/awx/ui/client/src/inventories/manage/hosts/hosts.service.js new file mode 100644 index 0000000000..a85a159c8a --- /dev/null +++ b/awx/ui/client/src/inventories/manage/hosts/hosts.service.js @@ -0,0 +1,84 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', + function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){ + return { + stringifyParams: function(params){ + return _.reduce(params, (result, value, key) => { + return result + key + '=' + value + '&'; + }, ''); + }, + // cute abstractions via fn.bind() + url: function(){ + return ''; + }, + error: function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + this.url + '. GET returned: ' + status }); + }, + success: function(data){ + return data; + }, + // HTTP methods + get: function(params){ + Wait('start'); + this.url = GetBasePath('hosts') + '?' + this.stringifyParams(params); + Rest.setUrl(this.url); + return Rest.get() + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + post: function(host){ + Wait('start'); + this.url = GetBasePath('hosts'); + Rest.setUrl(this.url); + return Rest.post(host) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + put: function(host){ + Wait('start'); + this.url = GetBasePath('hosts') + host.id; + Rest.setUrl(this.url); + return Rest.put(host) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + delete: function(id){ + Wait('start'); + this.url = GetBasePath('hosts') + id; + Rest.setUrl(this.url); + return Rest.destroy() + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + // these relationship setters could be consolidated, but verbosity makes the operation feel more clear @ controller level + associateGroup: function(host, group){ + Wait('start'); + this.url = GetBasePath('groups') + group + '/hosts/'; + Rest.setUrl(this.url); + return Rest.post(host) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + disassociateGroup: function(host, group){ + Wait('start'); + this.url = GetBasePath('groups') + group + '/hosts/'; + Rest.setUrl(this.url); + return Rest.post({id: host.id, disassociate: 1}) + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + } + }; + }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/main.js b/awx/ui/client/src/inventories/manage/hosts/main.js similarity index 60% rename from awx/ui/client/src/inventories/manage/manage-hosts/main.js rename to awx/ui/client/src/inventories/manage/hosts/main.js index 90d5cf3e70..8b71ce162a 100644 --- a/awx/ui/client/src/inventories/manage/manage-hosts/main.js +++ b/awx/ui/client/src/inventories/manage/hosts/main.js @@ -4,13 +4,11 @@ * All Rights Reserved *************************************************/ -import {ManageHostsAdd, ManageHostsEdit} from './manage-hosts.route'; -import service from './manage-hosts.service'; +import {ManageHostsAdd, ManageHostsEdit} from './hosts.route'; export default angular.module('manageHosts', []) - .service('ManageHostsService', service) - .run(['$stateExtender', function($stateExtender){ + .run(['$stateExtender', '$state', function($stateExtender, $state){ $stateExtender.addState(ManageHostsAdd); $stateExtender.addState(ManageHostsEdit); }]); diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.block.less b/awx/ui/client/src/inventories/manage/inventory-manage.block.less new file mode 100644 index 0000000000..4bf257dffe --- /dev/null +++ b/awx/ui/client/src/inventories/manage/inventory-manage.block.less @@ -0,0 +1,3 @@ +.InventoryManage-container{ + margin-top: -40px; +} \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.controller.js b/awx/ui/client/src/inventories/manage/inventory-manage.controller.js index fab1b0334e..0588e8ed17 100644 --- a/awx/ui/client/src/inventories/manage/inventory-manage.controller.js +++ b/awx/ui/client/src/inventories/manage/inventory-manage.controller.js @@ -3,532 +3,18 @@ * * All Rights Reserved *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:Inventories - * @description This controller's for the Inventory page - */ - -function InventoriesManage($log, $scope, $rootScope, $location, - $state, $compile, generateList, ClearScope, Empty, Wait, Rest, Alert, - GetBasePath, ProcessErrors, InventoryGroups, - InjectHosts, Find, HostsReload, SearchInit, PaginateInit, GetSyncStatusMsg, - GetHostsStatusMsg, GroupsEdit, InventoryUpdate, GroupsCancelUpdate, - ViewUpdateStatus, GroupsDelete, Store, HostsEdit, HostsDelete, - EditInventoryProperties, ShowJobSummary, - InventoryGroupsHelp, HelpDialog, - GroupsCopy, HostsCopy, $stateParams, ParamPass) { - - var PreviousSearchParams, - url, - hostScope = $scope.$new(); - - ClearScope(); - - // TODO: only display adhoc button if the user has permission to use it. - // TODO: figure out how to get the action-list partial to update so that - // the tooltip can be changed based off things being selected or not. - $scope.adhocButtonTipContents = "Launch adhoc command for the inventory"; - - // watcher for the group list checkbox changes - $scope.$on('multiSelectList.selectionChanged', function(e, selection) { - if (selection.length > 0) { - $scope.groupsSelected = true; - // $scope.adhocButtonTipContents = "Launch adhoc command for the " - // + "selected groups and hosts."; - } else { - $scope.groupsSelected = false; - // $scope.adhocButtonTipContents = "Launch adhoc command for the " - // + "inventory."; - } - $scope.groupsSelectedItems = selection.selectedItems; - }); - - // watcher for the host list checkbox changes - hostScope.$on('multiSelectList.selectionChanged', function(e, selection) { - // you need this so that the event doesn't bubble to the watcher above - // for the host list - e.stopPropagation(); - var trackingButton = angular.element(document.querySelector('.system-tracking')); - trackingButton.html('SYSTEM TRACKING'); - if (selection.length === 0) { - $scope.hostsSelected = false; - } else if (selection.length === 1) { - $scope.systemTrackingTooltip = "Compare host over time"; - $scope.hostsSelected = true; - $scope.systemTrackingDisabled = false; - } else if (selection.length === 2) { - $scope.systemTrackingTooltip = "Compare hosts against each other"; - $scope.hostsSelected = true; - $scope.systemTrackingDisabled = false; - } else { - $scope.hostsSelected = true; - $scope.systemTrackingDisabled = true; - } - $scope.hostsSelectedItems = selection.selectedItems; - }); - - $scope.systemTracking = function() { - var hostIds = _.map($scope.hostsSelectedItems, function(x){ - return x.id; - }); - $state.transitionTo('systemTracking', - { inventory: $scope.inventory, - inventoryId: $scope.inventory.id, - hosts: $scope.hostsSelectedItems, - hostIds: hostIds - }); - }; - - // populates host patterns based on selected hosts/groups - $scope.populateAdhocForm = function() { - var host_patterns = "all"; - if ($scope.hostsSelected || $scope.groupsSelected) { - var allSelectedItems = []; - if ($scope.groupsSelectedItems) { - allSelectedItems = allSelectedItems.concat($scope.groupsSelectedItems); - } - if ($scope.hostsSelectedItems) { - allSelectedItems = allSelectedItems.concat($scope.hostsSelectedItems); - } - if (allSelectedItems) { - host_patterns = _.pluck(allSelectedItems, "name").join(":"); - } - } - $rootScope.hostPatterns = host_patterns; - $state.go('inventoryManage.adhoc'); - }; - - $scope.refreshHostsOnGroupRefresh = false; - $scope.selected_group_id = null; - - Wait('start'); - - - if ($scope.removeHostReloadComplete) { - $scope.removeHostReloadComplete(); - } - $scope.removeHostReloadComplete = $scope.$on('HostReloadComplete', function() { - if ($scope.initial_height) { - var host_height = $('#hosts-container .well').height(), - group_height = $('#group-list-container .well').height(), - new_height; - - if (host_height > group_height) { - new_height = host_height - (host_height - group_height); - } - else if (host_height < group_height) { - new_height = host_height + (group_height - host_height); - } - if (new_height) { - $('#hosts-container .well').height(new_height); - } - $scope.initial_height = null; - } - }); - - if ($scope.removeRowCountReady) { - $scope.removeRowCountReady(); - } - $scope.removeRowCountReady = $scope.$on('RowCountReady', function(e, rows) { - // Add hosts view - $scope.show_failures = false; - InjectHosts({ - group_scope: $scope, - host_scope: hostScope, - inventory_id: $scope.inventory.id, - tree_id: null, - group_id: null, - pageSize: rows - }); - - SearchInit({ scope: $scope, set: 'groups', list: InventoryGroups, url: $scope.inventory.related.root_groups }); - PaginateInit({ scope: $scope, list: InventoryGroups , url: $scope.inventory.related.root_groups, pageSize: rows }); - $scope.search(InventoryGroups.iterator, null, true); - }); - - if ($scope.removeInventoryLoaded) { - $scope.removeInventoryLoaded(); - } - $scope.removeInventoryLoaded = $scope.$on('InventoryLoaded', function() { - var rows; - generateList.inject(InventoryGroups, { - mode: 'edit', - id: 'group-list-container', - searchSize: 'col-lg-6 col-md-6 col-sm-6 col-xs-12', - scope: $scope - }); - - rows = 20; - hostScope.host_page_size = rows; - $scope.group_page_size = rows; - - $scope.show_failures = false; - InjectHosts({ - group_scope: $scope, - host_scope: hostScope, - inventory_id: $scope.inventory.id, - tree_id: null, - group_id: null, - pageSize: rows - }); - - // Load data - SearchInit({ - scope: $scope, - set: 'groups', - list: InventoryGroups, - url: $scope.inventory.related.root_groups - }); - - PaginateInit({ - scope: $scope, - list: InventoryGroups , - url: $scope.inventory.related.root_groups, - pageSize: rows - }); - - $scope.search(InventoryGroups.iterator, null, true); - - $scope.$emit('WatchUpdateStatus'); // init socket io conneciton and start watching for status updates - }); - - if ($scope.removePostRefresh) { - $scope.removePostRefresh(); - } - $scope.removePostRefresh = $scope.$on('PostRefresh', function(e, set) { - if (set === 'groups') { - $scope.groups.forEach( function(group, idx) { - var stat, hosts_status; - stat = GetSyncStatusMsg({ - status: group.summary_fields.inventory_source.status, - has_inventory_sources: group.has_inventory_sources, - source: ( (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.source : null ) - }); // from helpers/Groups.js - $scope.groups[idx].status_class = stat['class']; - $scope.groups[idx].status_tooltip = stat.tooltip; - $scope.groups[idx].launch_tooltip = stat.launch_tip; - $scope.groups[idx].launch_class = stat.launch_class; - hosts_status = GetHostsStatusMsg({ - active_failures: group.hosts_with_active_failures, - total_hosts: group.total_hosts, - inventory_id: $scope.inventory.id, - group_id: group.id - }); // from helpers/Groups.js - $scope.groups[idx].hosts_status_tip = hosts_status.tooltip; - $scope.groups[idx].show_failures = hosts_status.failures; - $scope.groups[idx].hosts_status_class = hosts_status['class']; - - $scope.groups[idx].source = (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.source : null; - $scope.groups[idx].status = (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.status : null; - - }); - if ($scope.refreshHostsOnGroupRefresh) { - $scope.refreshHostsOnGroupRefresh = false; - HostsReload({ - scope: hostScope, - group_id: $scope.selected_group_id, - inventory_id: $scope.inventory.id, - pageSize: hostScope.host_page_size - }); - } - else { - Wait('stop'); - } - } - }); - - // Load Inventory - url = GetBasePath('inventory') + $stateParams.inventory_id + '/'; - Rest.setUrl(url); - Rest.get() - .success(function (data) { - $scope.inventory = data; - $scope.$emit('InventoryLoaded'); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve inventory: ' + $stateParams.inventory_id + - ' GET returned status: ' + status }); - }); - - // start watching for real-time updates - if ($rootScope.removeWatchUpdateStatus) { - $rootScope.removeWatchUpdateStatus(); - } - $rootScope.removeWatchUpdateStatus = $rootScope.$on('JobStatusChange-inventory', function(e, data) { - var stat, group; - if (data.group_id) { - group = Find({ list: $scope.groups, key: 'id', val: data.group_id }); - if (data.status === "failed" || data.status === "successful") { - if (data.group_id === $scope.selected_group_id || group) { - // job completed, fefresh all groups - $log.debug('Update completed. Refreshing the tree.'); - $scope.refreshGroups(); - } - } - else if (group) { - // incremental update, just update - $log.debug('Status of group: ' + data.group_id + ' changed to: ' + data.status); - stat = GetSyncStatusMsg({ - status: data.status, - has_inventory_sources: group.has_inventory_sources, - source: group.source - }); - $log.debug('changing tooltip to: ' + stat.tooltip); - group.status = data.status; - group.status_class = stat['class']; - group.status_tooltip = stat.tooltip; - group.launch_tooltip = stat.launch_tip; - group.launch_class = stat.launch_class; - } - } - }); - - // Load group on selection - function loadGroups(url) { - SearchInit({ scope: $scope, set: 'groups', list: InventoryGroups, url: url }); - PaginateInit({ scope: $scope, list: InventoryGroups , url: url, pageSize: $scope.group_page_size }); - $scope.search(InventoryGroups.iterator, null, true, false, true); - } - - $scope.refreshHosts = function() { - HostsReload({ - scope: hostScope, - group_id: $scope.selected_group_id, - inventory_id: $scope.inventory.id, - pageSize: hostScope.host_page_size - }); - }; - - $scope.refreshGroups = function() { - $scope.refreshHostsOnGroupRefresh = true; - $scope.search(InventoryGroups.iterator, null, true, false, true); - }; - - $scope.restoreSearch = function() { - // Restore search params and related stuff, plus refresh - // groups and hosts lists - SearchInit({ - scope: $scope, - set: PreviousSearchParams.set, - list: PreviousSearchParams.list, - url: PreviousSearchParams.defaultUrl, - iterator: PreviousSearchParams.iterator, - sort_order: PreviousSearchParams.sort_order, - setWidgets: false - }); - $scope.refreshHostsOnGroupRefresh = true; - $scope.search(InventoryGroups.iterator, null, true, false, true); - }; - - $scope.groupSelect = function(id) { - var groups = [], group = Find({ list: $scope.groups, key: 'id', val: id }); - if($state.params.groups){ - groups.push($state.params.groups); - } - groups.push(group.id); - groups = groups.join(); - $state.transitionTo('inventoryManage', {inventory_id: $state.params.inventory_id, groups: groups}, { notify: false}); - loadGroups(group.related.children, group.id); - $scope.selected_group_id = group.id; - HostsReload({ - scope: hostScope, - group_id: $scope.selected_group_id, - inventory_id: $scope.inventory.id, - pageSize: hostScope.host_page_size - }); - }; - - $scope.createGroup = function () { - PreviousSearchParams = Store('group_current_search_params'); - var params = { - scope: $scope, - inventory_id: $scope.inventory.id, - group_id: $scope.selected_group_id, - mode: 'add' - }; - ParamPass.set(params); - $state.go('inventoryManage.addGroup'); - }; - - $scope.editGroup = function (id) { - PreviousSearchParams = Store('group_current_search_params'); - var params = { - scope: $scope, - inventory_id: $scope.inventory.id, - group_id: id, - mode: 'edit' - }; - ParamPass.set(params); - $state.go('inventoryManage.editGroup', {group_id: id}); - }; - - // Launch inventory sync - $scope.updateGroup = function (id) { - var group = Find({ list: $scope.groups, key: 'id', val: id }); - if (group) { - if (Empty(group.source)) { - // if no source, do nothing. - } else if (group.status === 'updating') { - Alert('Update in Progress', 'The inventory update process is currently running for group ' + - group.name + ' Click the button to monitor the status.', 'alert-info', null, null, null, null, true); - } else { - Wait('start'); - Rest.setUrl(group.related.inventory_source); - Rest.get() - .success(function (data) { - InventoryUpdate({ - scope: $scope, - url: data.related.update, - group_name: data.summary_fields.group.name, - group_source: data.source, - group_id: group.id, - }); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve inventory source: ' + - group.related.inventory_source + ' GET returned status: ' + status }); - }); - } - } - }; - - $scope.cancelUpdate = function (id) { - GroupsCancelUpdate({ scope: $scope, id: id }); - }; - - $scope.viewUpdateStatus = function (id) { - ViewUpdateStatus({ - scope: $scope, - group_id: id - }); - }; - - $scope.scheduleGroup = function(id) { - $state.go('inventoryManageSchedules', { - inventory_id: $scope.inventory.id, id: id - }); - }; - - $scope.copyGroup = function(id) { - PreviousSearchParams = Store('group_current_search_params'); - var params = { - scope: $scope - }; - ParamPass.set(params); - $location.search('groups', null); - $state.go('inventoryManage.copy.group', {group_id: id}); - }; - - $scope.deleteGroup = function (id) { - GroupsDelete({ - scope: $scope, - group_id: id, - inventory_id: $scope.inventory.id - }); - }; - - $scope.editInventoryProperties = function () { - // EditInventoryProperties({ scope: $scope, inventory_id: $scope.inventory.id }); - $location.path('/inventories/' + $scope.inventory.id + '/'); - }; - - hostScope.createHost = function () { - var params = { - host_scope: hostScope, - group_scope: $scope, - mode: 'add', - host_id: null, - selected_group_id: $scope.selected_group_id, - inventory_id: $scope.inventory.id - }; - ParamPass.set(params); - $state.go('inventoryManage.addHost'); - }; - - hostScope.editHost = function (host_id) { - var params = { - host_scope: hostScope, - group_scope: $scope, - mode: 'edit', - host_id: host_id, - inventory_id: $scope.inventory.id - }; - ParamPass.set(params); - $state.go('inventoryManage.editHost', {host_id: host_id}); - }; - - hostScope.deleteHost = function (host_id, host_name) { - HostsDelete({ - parent_scope: $scope, - host_scope: hostScope, - host_id: host_id, - host_name: host_name - }); - }; - - hostScope.copyHost = function(id) { - PreviousSearchParams = Store('group_current_search_params'); - var params = { - group_scope: $scope, - host_scope: hostScope, - host_id: id - }; - - ParamPass.set(params); - - $state.go('inventoryManage.copy.host', {host_id: id}); - }; - - hostScope.showJobSummary = function (job_id) { - ShowJobSummary({ - job_id: job_id - }); - }; - - $scope.showGroupHelp = function (params) { - var opts = { - defn: InventoryGroupsHelp - }; - if (params) { - opts.autoShow = params.autoShow || false; - } - HelpDialog(opts); - } -; - $scope.showHosts = function (group_id, show_failures) { - // Clicked on group - if (group_id !== null) { - Wait('start'); - hostScope.show_failures = show_failures; - $scope.groupSelect(group_id); - hostScope.hosts = []; - $scope.show_failures = show_failures; // turn on failed hosts - // filter in hosts view - } else { - Wait('stop'); - } - }; - - if ($scope.removeGroupDeleteCompleted) { - $scope.removeGroupDeleteCompleted(); - } - $scope.removeGroupDeleteCompleted = $scope.$on('GroupDeleteCompleted', - function() { - $scope.refreshGroups(); - } - ); -} - -export default [ - '$log', '$scope', '$rootScope', '$location', - '$state', '$compile', 'generateList', 'ClearScope', 'Empty', 'Wait', - 'Rest', 'Alert', 'GetBasePath', 'ProcessErrors', - 'InventoryGroups', 'InjectHosts', 'Find', 'HostsReload', - 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', - 'GroupsEdit', 'InventoryUpdate', 'GroupsCancelUpdate', 'ViewUpdateStatus', - 'GroupsDelete', 'Store', 'HostsEdit', 'HostsDelete', - 'EditInventoryProperties', 'ShowJobSummary', 'InventoryGroupsHelp', 'HelpDialog', 'GroupsCopy', - 'HostsCopy', '$stateParams', 'ParamPass', InventoriesManage -]; + export default + ['$scope', '$state', function($scope, $state){ + $scope.groupsSelected = false; + $scope.hostsSelected = false; + $scope.hostsSelectedItems = []; + $scope.groupsSelectedItems = []; + $scope.setAdhocPattern = function(){ + var pattern = _($scope.groupsSelectedItems) + .concat($scope.hostsSelectedItems) + .map(function(item){ + return item.name; + }).value().join(':'); + $state.go('inventoryManage.adhoc', {pattern: pattern}); + }; + }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.partial.html b/awx/ui/client/src/inventories/manage/inventory-manage.partial.html index 7daf685f3f..41e8084a42 100644 --- a/awx/ui/client/src/inventories/manage/inventory-manage.partial.html +++ b/awx/ui/client/src/inventories/manage/inventory-manage.partial.html @@ -1,152 +1,10 @@ -
-
+
+
-
-
-
-
-
-
+
+
- - - - - - - - - - -
-
-
diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.route.js b/awx/ui/client/src/inventories/manage/inventory-manage.route.js index 674297bb0a..317f584930 100644 --- a/awx/ui/client/src/inventories/manage/inventory-manage.route.js +++ b/awx/ui/client/src/inventories/manage/inventory-manage.route.js @@ -6,18 +6,71 @@ import {templateUrl} from '../../shared/template-url/template-url.factory'; import InventoriesManage from './inventory-manage.controller'; +import BreadcrumbsController from './breadcrumbs/breadcrumbs.controller'; +import HostsListController from './hosts/hosts-list.controller'; +import GroupsListController from './groups/groups-list.controller'; export default { name: 'inventoryManage', - url: '/inventories/:inventory_id/manage?groups', - templateUrl: templateUrl('inventories/manage/inventory-manage'), - controller: InventoriesManage, + url: '/inventories/:inventory_id/manage?{group:int}{failed}', data: { activityStream: true, activityStreamTarget: 'inventory', activityStreamId: 'inventory_id' }, + params:{ + group:{ + array: true + }, + failed:{ + value: 'false', + squash: true + } + }, ncyBreadcrumb: { - label: "INVENTORY MANAGE" + skip: true // Never display this state in ncy-breadcrumb. + }, + // enforce uniqueness in group param + onEnter: function($stateParams){ + $stateParams.group = _.uniq($stateParams.group); + }, + resolve: { + groupsUrl: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){ + return !$stateParams.group ? + InventoryManageService.rootGroupsUrl($stateParams.inventory_id) : + InventoryManageService.childGroupsUrl(_.last($stateParams.group)); + }], + hostsUrl: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){ + // at the root group level + return !$stateParams.group ? + InventoryManageService.rootHostsUrl($stateParams.inventory_id, $stateParams.failed) : + InventoryManageService.childHostsUrl(_.last($stateParams.group, $stateParams.failed)); + }], + inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){ + return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data); + }], + breadCrumbData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){ + return ( (!$stateParams.group) ? false : InventoryManageService.getBreadcrumbs($stateParams.group).then(res => res.data.results)); + }] + }, + views:{ + // target the ui-view with name "groupBreadcrumbs" at the root template level + 'groupBreadcrumbs@': { + controller: BreadcrumbsController, + templateUrl: templateUrl('inventories/manage/breadcrumbs/breadcrumbs') + }, + '': { + templateUrl: templateUrl('inventories/manage/inventory-manage'), + controller: InventoriesManage + }, + // target ui-views with name@inventoryManage template level + 'groupsList@inventoryManage': { + templateUrl: templateUrl('inventories/manage/groups/groups-list'), + controller: GroupsListController + }, + 'hostsList@inventoryManage': { + template: '
', + controller: HostsListController + } } }; diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.service.js b/awx/ui/client/src/inventories/manage/inventory-manage.service.js new file mode 100644 index 0000000000..d61d27e758 --- /dev/null +++ b/awx/ui/client/src/inventories/manage/inventory-manage.service.js @@ -0,0 +1,63 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', + function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){ + return { + // cute abstractions via fn.bind() + url: function(){ + return ''; + }, + error: function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + this.url + '. GET returned: ' + status }); + }, + success: function(data){ + return data; + }, + // data getters + getInventory: function(id){ + Wait('start'); + this.url = GetBasePath('inventory') + id; + Rest.setUrl(this.url); + return Rest.get() + .success(this.success.bind(this)) + .error(this.error.bind(this)) + .finally(Wait('stop')); + }, + getBreadcrumbs: function(groups){ + Wait('start'); + this.url = GetBasePath('groups') + '?' + _.map(groups, function(item){ + return '&or__id=' + item; + }).join(''); + Rest.setUrl(this.url); + return Rest.get() + .success(this.success.bind(this)) + .error(this.error.bind(this)); + }, + // these methods generate a query string to pass to PaginateInit(), SearchInit() + // always supply trailing slashes and ? prefix + rootHostsUrl: function(id, failed){ + var url = GetBasePath('inventory') + id + '/hosts' + + (failed === 'true' ? '?has_active_failures=true' : '?'); + return url; + }, + childHostsUrl: function(id, failed){ + var url = GetBasePath('groups') + id + '/hosts' + + (failed === 'true' ? '?has_active_failures=true' : '?'); + return url; + }, + childGroupsUrl: function(id){ + var url = GetBasePath('groups') + id + '/children?'; + return url; + }, + rootGroupsUrl: function(id){ + var url = GetBasePath('inventory') + id+ '/root_groups/'; + return url; + } + }; + }]; diff --git a/awx/ui/client/src/inventories/manage/main.js b/awx/ui/client/src/inventories/manage/main.js index 435db696f7..df2b14469e 100644 --- a/awx/ui/client/src/inventories/manage/main.js +++ b/awx/ui/client/src/inventories/manage/main.js @@ -1,21 +1,28 @@ /************************************************* - * Copyright (c) 2015 Ansible, Inc. + * Copyright (c) 2016 Ansible, Inc. * * All Rights Reserved *************************************************/ import route from './inventory-manage.route'; - -import manageHosts from './manage-hosts/main'; -import manageGroups from './manage-groups/main'; -import copy from './copy/main'; +import InventoryManageService from './inventory-manage.service'; +import HostManageService from './hosts/hosts.service'; +import GroupManageService from './groups/groups.service'; +import hosts from './hosts/main'; +import groups from './groups/main'; +import adhoc from './adhoc/main'; +import copyMove from './copy-move/main'; export default angular.module('inventoryManage', [ - manageHosts.name, - manageGroups.name, - copy.name, + hosts.name, + groups.name, + copyMove.name, + adhoc.name ]) + .service('InventoryManageService', InventoryManageService) + .service('HostManageService', HostManageService) + .service('GroupManageService', GroupManageService) .run(['$stateExtender', function($stateExtender) { $stateExtender.addState(route); }]); diff --git a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.controller.js b/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.controller.js deleted file mode 100644 index 6bad2c274a..0000000000 --- a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.controller.js +++ /dev/null @@ -1,574 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -function manageGroupsDirectiveController($filter, $location, $log, - $stateParams, $compile, $state, $scope, Rest, Alert, GroupForm, - GenerateForm, Prompt, ProcessErrors, GetBasePath, SetNodeName, - ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, LookUpInit, Empty, - Wait, GetChoices, UpdateGroup, SourceChange, Find, ParseVariableString, - ToJSON, GroupsScheduleListInit, SetSchedulesInnerDialogSize, - CreateSelect2, ToggleNotification, NotificationsListInit, - RelatedSearchInit, RelatedPaginateInit) { - - var vm = this; - - var group_id = $stateParams.group_id, - mode = $state.current.data.mode, - inventory_id = $stateParams.inventory_id, - generator = GenerateForm, - group_created = false, - defaultUrl, - master = {}, - form = GroupForm(), - relatedSets = {}, - choicesReady, group; - - if (mode === 'edit') { - defaultUrl = GetBasePath('groups') + group_id + '/'; - } else { - defaultUrl = (group_id !== undefined) ? GetBasePath('groups') + group_id + '/children/' : - GetBasePath('inventory') + inventory_id + '/groups/'; - } - - Rest.setUrl(defaultUrl); - Rest.get() - .success(function(data) { - group = data; - for (var fld in form.fields) { - if (data[fld]) { - $scope[fld] = data[fld]; - master[fld] = $scope[fld]; - } - } - if(mode === 'edit') { - $scope.variable_url = data.related.variable_data; - $scope.source_url = data.related.inventory_source; - $scope.source_id = data.related.inventory_source.split('/')[4]; - $scope.$emit('LoadSourceData'); - } - }) - .error(function(data, status) { - ProcessErrors($scope, data, status, { - hdr: 'Error!', - msg: 'Failed to retrieve group: ' + defaultUrl + '. GET status: ' + status - }); - }); - - - $scope.parseType = 'yaml'; - - generator.inject(form, { - mode: mode, - id: 'group-manage-panel', - scope: $scope, - related: false, - cancelButton: false - }); - - generator.reset(); - - GetSourceTypeOptions({ - scope: $scope, - variable: 'source_type_options' - }); - - $scope.source = form.fields.source['default']; - $scope.sourcePathRequired = false; - $scope[form.fields.source_vars.parseTypeName] = 'yaml'; - $scope.update_cache_timeout = 0; - $scope.parseType = 'yaml'; - - - function initSourceChange() { - $scope.showSchedulesTab = (mode === 'edit' && $scope.source && $scope.source.value !== "manual") ? true : false; - SourceChange({ - scope: $scope, - form: form - }); - } - - // JT -- this gets called after the properties & properties variables are loaded, and is emitted from (groupLoaded) - if ($scope.removeLoadSourceData) { - $scope.removeLoadSourceData(); - } - $scope.removeLoadSourceData = $scope.$on('LoadSourceData', function() { - ParseTypeChange({ - scope: $scope, - variable: 'variables', - parse_variable: 'parseType', - field_id: 'group_variables' - }); - - NotificationsListInit({ - scope: $scope, - url: GetBasePath('inventory_sources'), - id: $scope.source_id - }); - - if ($scope.source_url) { - // get source data - Rest.setUrl($scope.source_url); - Rest.get() - .success(function(data) { - var fld, i, j, flag, found, set, opts, list; - for (fld in form.fields) { - if (fld === 'checkbox_group') { - for (i = 0; i < form.fields[fld].fields.length; i++) { - flag = form.fields[fld].fields[i]; - if (data[flag.name] !== undefined) { - $scope[flag.name] = data[flag.name]; - master[flag.name] = $scope[flag.name]; - } - } - } - if (fld === 'source') { - found = false; - data.source = (data.source === "") ? "manual" : data.source; - for (i = 0; i < $scope.source_type_options.length; i++) { - if ($scope.source_type_options[i].value === data.source) { - $scope.source = $scope.source_type_options[i]; - found = true; - } - } - if (!found || $scope.source.value === "manual") { - $scope.groupUpdateHide = true; - } else { - $scope.groupUpdateHide = false; - } - master.source = $scope.source; - } else if (fld === 'source_vars') { - // Parse source_vars, converting to YAML. - $scope.source_vars = ParseVariableString(data.source_vars); - master.source_vars = $scope.variables; - } else if (fld === "inventory_script") { - // the API stores it as 'source_script', we call it inventory_script - data.summary_fields.inventory_script = data.summary_fields.source_script; - $scope.inventory_script = data.source_script; - master.inventory_script = $scope.inventory_script; - } else if (fld === "source_regions") { - if (data[fld] === "") { - $scope[fld] = data[fld]; - master[fld] = $scope[fld]; - } else { - $scope[fld] = data[fld].split(","); - master[fld] = $scope[fld]; - } - } else if (data[fld] !== undefined && - fld !== "description" && - fld !== "name" && - fld !== "variables") { - $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]; - } - } - relatedSets = form.relatedSets(data.related); - RelatedSearchInit({ - scope: $scope, - form: form, - relatedSets: relatedSets - }); - - RelatedPaginateInit({ - scope: $scope, - relatedSets: relatedSets - }); - initSourceChange(); - - if (data.source_regions) { - if (data.source === 'ec2' || - data.source === 'rax' || - data.source === 'gce' || - data.source === 'azure') { - if (data.source === 'ec2') { - set = $scope.ec2_regions; - } else if (data.source === 'rax') { - set = $scope.rax_regions; - } else if (data.source === 'gce') { - set = $scope.gce_regions; - } else if (data.source === 'azure') { - set = $scope.azure_regions; - } - opts = []; - list = data.source_regions.split(','); - for (i = 0; i < list.length; i++) { - for (j = 0; j < set.length; j++) { - if (list[i] === set[j].value) { - opts.push({ - id: set [j].value, - text: set [j].label - }); - } - } - } - master.source_regions = opts; - CreateSelect2({ - element: "group_source_regions", - multiple: true, - opts: opts - }); - - } - } else { - // If empty, default to all - master.source_regions = [{ - id: 'all', - text: 'All' - }]; - } - if (data.group_by && data.source === 'ec2') { - set = $scope.ec2_group_by; - opts = []; - list = data.group_by.split(','); - for (i = 0; i < list.length; i++) { - for (j = 0; j < set.length; j++) { - if (list[i] === set[j].value) { - opts.push({ - id: set [j].value, - text: set [j].label - }); - } - } - } - master.group_by = opts; - CreateSelect2({ - element: "#group_group_by", - multiple: true, - opts: opts - }); - } - - $scope.group_update_url = data.related.update; - for (set in relatedSets) { - $scope.search(relatedSets[set].iterator); - } - }) - .error(function(data, status) { - $scope.source = ""; - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to retrieve inventory source. GET status: ' + status - }); - }); - } - }); - - if ($scope.remove$scopeSourceTypeOptionsReady) { - $scope.remove$scopeSourceTypeOptionsReady(); - } - $scope.remove$scopeSourceTypeOptionsReady = $scope.$on('sourceTypeOptionsReady', function() { - if (mode === 'add') { - $scope.source = Find({ - list: $scope.source_type_options, - key: 'value', - val: '' - }); - $scope.showSchedulesTab = false; - } - }); - - choicesReady = 0; - - if ($scope.removeChoicesReady) { - $scope.removeChoicesReady(); - } - $scope.removeChoicesReady = $scope.$on('choicesReadyGroup', function() { - CreateSelect2({ - element: '#group_source', - multiple: false - }); - $scope.$emit('LoadSourceData'); - - choicesReady++; - if (choicesReady === 5) { - if (mode !== 'edit') { - $scope.variables = "---"; - master.variables = $scope.variables; - } - } - }); - - // Load options for source regions - GetChoices({ - scope: $scope, - url: GetBasePath('inventory_sources'), - field: 'source_regions', - variable: 'rax_regions', - choice_name: 'rax_region_choices', - callback: 'choicesReadyGroup' - }); - - GetChoices({ - scope: $scope, - url: GetBasePath('inventory_sources'), - field: 'source_regions', - variable: 'ec2_regions', - choice_name: 'ec2_region_choices', - callback: 'choicesReadyGroup' - }); - - GetChoices({ - scope: $scope, - url: GetBasePath('inventory_sources'), - field: 'source_regions', - variable: 'gce_regions', - choice_name: 'gce_region_choices', - callback: 'choicesReadyGroup' - }); - - GetChoices({ - scope: $scope, - url: GetBasePath('inventory_sources'), - field: 'source_regions', - variable: 'azure_regions', - choice_name: 'azure_region_choices', - callback: 'choicesReadyGroup' - }); - - // Load options for group_by - GetChoices({ - scope: $scope, - url: GetBasePath('inventory_sources'), - field: 'group_by', - variable: 'ec2_group_by', - choice_name: 'ec2_group_by_choices', - callback: 'choicesReadyGroup' - }); - - //Wait('start'); - - if ($scope.removeAddTreeRefreshed) { - $scope.removeAddTreeRefreshed(); - } - $scope.removeAddTreeRefreshed = $scope.$on('GroupTreeRefreshed', function() { - // Clean up - Wait('stop'); - - if ($scope.searchCleanUp) { - $scope.searchCleanup(); - } - try { - //$('#group-modal-dialog').dialog('close'); - } catch (e) { - // ignore - } - }); - - if ($scope.removeSaveComplete) { - $scope.removeSaveComplete(); - } - $scope.removeSaveComplete = $scope.$on('SaveComplete', function(e, error) { - if (!error) { - $scope.formCancel(); - } - }); - - if ($scope.removeFormSaveSuccess) { - $scope.removeFormSaveSuccess(); - } - $scope.removeFormSaveSuccess = $scope.$on('formSaveSuccess', function() { - - // Source data gets stored separately from the group. Validate and store Source - // related fields, then call SaveComplete to wrap things up. - - var parseError = false, - regions, r, i, - group_by, - data = { - group: group_id, - source: (($scope.source && $scope.source.value !== 'manual') ? $scope.source.value : ''), - source_path: $scope.source_path, - credential: $scope.credential, - overwrite: $scope.overwrite, - overwrite_vars: $scope.overwrite_vars, - source_script: $scope.inventory_script, - update_on_launch: $scope.update_on_launch, - update_cache_timeout: ($scope.update_cache_timeout || 0) - }; - - // Create a string out of selected list of regions - if ($scope.source_regions) { - regions = $('#group_source_regions').select2("data"); - r = []; - for (i = 0; i < regions.length; i++) { - r.push(regions[i].id); - } - data.source_regions = r.join(); - } - - if ($scope.source && ($scope.source.value === 'ec2')) { - data.instance_filters = $scope.instance_filters; - // Create a string out of selected list of regions - group_by = $('#group_group_by').select2("data"); - r = []; - for (i = 0; i < group_by.length; i++) { - r.push(group_by[i].id); - } - data.group_by = r.join(); - } - - if ($scope.source && ($scope.source.value === 'ec2')) { - // for ec2, validate variable data - data.source_vars = ToJSON($scope.envParseType, $scope.source_vars, true); - } - - if ($scope.source && ($scope.source.value === 'custom')) { - data.source_vars = ToJSON($scope.envParseType, $scope.extra_vars, true); - } - - if ($scope.source && ($scope.source.value === 'vmware' || - $scope.source.value === 'openstack')) { - data.source_vars = ToJSON($scope.envParseType, $scope.inventory_variables, true); - } - - // the API doesn't expect the credential to be passed with a custom inv script - if ($scope.source && $scope.source.value === 'custom') { - delete(data.credential); - } - - if (!parseError) { - Rest.setUrl($scope.source_url); - Rest.put(data) - .success(function() { - $scope.$emit('SaveComplete', false); - }) - .error(function(data, status) { - $('#group_tabs a:eq(1)').tab('show'); - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update group inventory source. PUT status: ' + status - }); - }); - } - }); - $scope.toggleNotification = function(event, notifier_id, column) { - var notifier = this.notification; - try { - $(event.target).tooltip('hide'); - } - catch(e) { - // ignore - } - ToggleNotification({ - scope: $scope, - url: GetBasePath('inventory_sources'), - id: $scope.source_id, - notifier: notifier, - column: column, - callback: 'NotificationRefresh' - }); - }; - // Cancel - $scope.formCancel = function() { - Wait('stop'); - $state.go('inventoryManage', {}, {reload: true}); - }; - - // Save - $scope.saveGroup = function() { - Wait('start'); - var fld, data, json_data; - - try { - - json_data = ToJSON($scope.parseType, $scope.variables, true); - - data = {}; - for (fld in form.fields) { - data[fld] = $scope[fld]; - } - - data.inventory = inventory_id; - - Rest.setUrl(defaultUrl); - if (mode === 'edit' || (mode === 'add' && group_created)) { - Rest.put(data) - .success(function() { - $scope.$emit('formSaveSuccess'); - }) - .error(function(data, status) { - $('#group_tabs a:eq(0)').tab('show'); - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update group: ' + group_id + '. PUT status: ' + status - }); - }); - } else { - Rest.post(data) - .success(function(data) { - group_created = true; - group_id = data.id; - $scope.source_url = data.related.inventory_source; - $scope.source_id = $scope.source_url.split('/')[4]; - $scope.$emit('formSaveSuccess'); - }) - .error(function(data, status) { - $('#group_tabs a:eq(0)').tab('show'); - ProcessErrors($scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to create group: ' + group_id + '. POST status: ' + status - }); - }); - } - } catch (e) { - // ignore. ToJSON will have already alerted the user - } - }; - - // Start the update process - $scope.updateGroup = function() { - if ($scope.source === "manual" || $scope.source === null) { - Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group, provide Source settings, ' + - 'and then run an update.', 'alert-info'); - } else if ($scope.status === 'updating') { - Alert('Update in Progress', 'The inventory update process is currently running for group ' + - $filter('sanitize')($scope.summary_fields.group.name) + '. Use the Refresh button to monitor the status.', 'alert-info', null, null, null, null, true); - } else { - InventoryUpdate({ - scope: $scope, - group_id: group_id, - url: $scope.group_update_url, - group_name: $scope.name, - group_source: $scope.source.value - }); - } - }; - - // Change the lookup and regions when the source changes - $scope.sourceChange = function() { - $scope.credential_name = ""; - $scope.credential = ""; - if ($scope.credential_name_api_error) { - delete $scope.credential_name_api_error; - } - initSourceChange(); - }; - - - angular.extend(vm, { - formCancel : $scope.formCancel, - saveGroup: $scope.saveGroup - }); -} - -export default ['$filter', '$location', '$log', '$stateParams', - '$compile', '$state', '$scope', 'Rest', 'Alert', 'GroupForm', - 'GenerateForm','Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', - 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate', 'LookUpInit', - 'Empty', 'Wait', 'GetChoices', 'UpdateGroup', 'SourceChange', 'Find', - 'ParseVariableString', 'ToJSON', 'GroupsScheduleListInit', - 'SetSchedulesInnerDialogSize', 'CreateSelect2', - 'ToggleNotification', 'NotificationsListInit', 'RelatedSearchInit', - 'RelatedPaginateInit', - manageGroupsDirectiveController -]; diff --git a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.js b/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.js deleted file mode 100644 index b4c3fbff73..0000000000 --- a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.js +++ /dev/null @@ -1,25 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/* jshint unused: vars */ -import manageGroupsDirectiveController from './manage-groups.directive.controller'; - -export default ['templateUrl', 'ParamPass', - function(templateUrl, ParamPass) { - return { - restrict: 'EA', - scope: true, - replace: true, - templateUrl: templateUrl('inventories/manage/manage-groups/directive/manage-groups.directive'), - link: function(scope, element, attrs) { - - }, - controller: manageGroupsDirectiveController, - controllerAs: 'vm', - bindToController: true - }; - } -]; diff --git a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.partial.html b/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.partial.html deleted file mode 100644 index 889e561114..0000000000 --- a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.partial.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
-
-
-
diff --git a/awx/ui/client/src/inventories/manage/manage-groups/main.js b/awx/ui/client/src/inventories/manage/manage-groups/main.js deleted file mode 100644 index b015b64628..0000000000 --- a/awx/ui/client/src/inventories/manage/manage-groups/main.js +++ /dev/null @@ -1,16 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import route from './manage-groups.route'; -import manageGroupsDirective from './directive/manage-groups.directive'; - -export default - angular.module('manage-groups', []) - .directive('manageGroups', manageGroupsDirective) - .run(['$stateExtender', function($stateExtender) { - $stateExtender.addState(route.edit); - $stateExtender.addState(route.add); - }]); diff --git a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.route.js b/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.route.js deleted file mode 100644 index 8fb8b16952..0000000000 --- a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.route.js +++ /dev/null @@ -1,36 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import { - templateUrl -} from '../../../shared/template-url/template-url.factory'; - -export default { - edit: { - name: 'inventoryManage.editGroup', - route: '/:group_id/editGroup', - templateUrl: templateUrl('inventories/manage/manage-groups/manage-groups'), - data: { - group_id: 'group_id', - mode: 'edit' - }, - ncyBreadcrumb: { - label: "INVENTORY EDIT GROUPS" - } - }, - - add: { - name: 'inventoryManage.addGroup', - route: '/addGroup', - templateUrl: templateUrl('inventories/manage/manage-groups/manage-groups'), - ncyBreadcrumb: { - label: "INVENTORY ADD GROUP" - }, - data: { - mode: 'add' - } - }, - -}; diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.route.js b/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.route.js deleted file mode 100644 index bf349a9e1c..0000000000 --- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.route.js +++ /dev/null @@ -1,41 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ -import {templateUrl} from '../../../shared/template-url/template-url.factory'; -import addController from './manage-hosts-add.controller'; -import editController from './manage-hosts-edit.controller'; - -var ManageHostsEdit = { - name: 'inventoryManage.editHost', - route: '/host/:host_id', - controller: editController, - templateUrl: templateUrl('inventories/manage/manage-hosts/manage-hosts'), - ncyBreadcrumb: { - label: "INVENTORY EDIT HOSTS" - }, - data: { - mode: 'edit' - }, - resolve: { - host: ['$stateParams', 'ManageHostsService', function($stateParams, ManageHostsService){ - return ManageHostsService.get({id: $stateParams.host_id}).then(function(res){ - return res.data.results[0]; - }); - }] - } -}; -var ManageHostsAdd = { - name: 'inventoryManage.addHost', - route: '/host/add', - controller: addController, - templateUrl: templateUrl('inventories/manage/manage-hosts/manage-hosts'), - ncyBreadcrumb: { - label: "INVENTORY ADD HOST" - }, - data: { - mode: 'add' - } -}; -export {ManageHostsAdd, ManageHostsEdit}; diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.service.js b/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.service.js deleted file mode 100644 index c7a64cb60d..0000000000 --- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.service.js +++ /dev/null @@ -1,53 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', - function($rootScope, Rest, GetBasePath, ProcessErrors){ - return { - stringifyParams: function(params){ - return _.reduce(params, (result, value, key) => { - return result + key + '=' + value + '&'; - }, ''); - }, - get: function(params){ - var url = GetBasePath('hosts') + '?' + this.stringifyParams(params); - Rest.setUrl(url); - return Rest.get() - .success(function(res){ - return res; - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }, - post: function(params){ - var url = GetBasePath('hosts'); - Rest.setUrl(url); - return Rest.post(params) - .success(function(res){ - return res; - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }, - put: function(host){ - var url = GetBasePath('hosts') + host.id; - Rest.setUrl(url); - return Rest.put(host) - .success(function(res){ - return res; - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - } - }; - }]; \ No newline at end of file diff --git a/awx/ui/client/src/inventories/manage/manage.block.less b/awx/ui/client/src/inventories/manage/manage.block.less deleted file mode 100644 index 772423c2e4..0000000000 --- a/awx/ui/client/src/inventories/manage/manage.block.less +++ /dev/null @@ -1,18 +0,0 @@ -#Inventory-groupManage--panel, -#Inventory-hostManage--panel { - .ui-dialog-buttonpane.ui-widget-content { - border: none; - text-align: right; - } - - #host-panel-form, - #properties-tab { - .Form-header { - margin-top: -20px; - } - } - - .Form-textArea { - width: 100%; - } -} diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js index 2061d00df3..2e927fad2c 100644 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ b/awx/ui/client/src/job-detail/job-detail.controller.js @@ -11,22 +11,17 @@ */ export default - [ '$location', '$rootScope', '$filter', '$scope', '$compile', - '$stateParams', '$log', 'ClearScope', 'GetBasePath', 'Wait', - 'ProcessErrors', 'SelectPlay', 'SelectTask', 'GetElapsed', - 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'InitiatePlaybookRun', - 'LoadPlays', 'LoadTasks', 'HostsEdit', - 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', - 'EditSchedule', 'ParseTypeChange', 'JobDetailService', + [ '$location', '$rootScope', '$filter', '$scope', '$compile', '$stateParams', '$log', 'ClearScope', + 'GetBasePath', 'Wait', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'GetElapsed', 'JobIsFinished', + 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'InitiatePlaybookRun', 'LoadPlays', 'LoadTasks', + 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'EditSchedule', + 'ParseTypeChange', 'JobDetailService', function( - $location, $rootScope, $filter, $scope, $compile, $stateParams, - $log, ClearScope, GetBasePath, Wait, ProcessErrors, - SelectPlay, SelectTask, GetElapsed, - JobIsFinished, - SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, - InitiatePlaybookRun, LoadPlays, LoadTasks, - HostsEdit, ParseVariableString, GetChoices, fieldChoices, - fieldLabels, EditSchedule, ParseTypeChange, JobDetailService + $location, $rootScope, $filter, $scope, $compile, $stateParams, $log, ClearScope, + GetBasePath, Wait, ProcessErrors, SelectPlay, SelectTask, GetElapsed, JobIsFinished, + SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, InitiatePlaybookRun, LoadPlays, LoadTasks, + ParseVariableString, GetChoices, fieldChoices, fieldLabels, EditSchedule, + ParseTypeChange, JobDetailService ) { ClearScope(); diff --git a/awx/ui/client/src/lists/Groups.js b/awx/ui/client/src/lists/Groups.js index 33bf611371..f93162b302 100644 --- a/awx/ui/client/src/lists/Groups.js +++ b/awx/ui/client/src/lists/Groups.js @@ -9,41 +9,17 @@ export default angular.module('GroupListDefinition', []) - .value('GroupList', { + .value('CopyMoveGroupList', { - name: 'copy_groups', - iterator: 'copy_group', + name: 'groups', + iterator: 'group', selectTitle: 'Copy Groups', - editTitle: 'Groups', index: false, - well: false, - + well: false, fields: { name: { key: true, - label: 'Name' - } - }, - - actions: { }, - - fieldActions: { - edit: { - label: 'Edit', - ngClick: "editGroup(group.id)", - icon: 'icon-edit', - "class": 'btn-xs', - awToolTip: 'Edit group', - dataPlacement: 'top' - }, - - "delete": { - label: 'Delete', - ngClick: "deleteGroup(group.id, group.name)", - icon: 'icon-trash', - "class": 'btn-xs', - awToolTip: 'Delete group', - dataPlacement: 'top' + label: 'Target Group Name' } } }); diff --git a/awx/ui/client/src/lists/Inventories.js b/awx/ui/client/src/lists/Inventories.js index a40850649f..60543239c0 100644 --- a/awx/ui/client/src/lists/Inventories.js +++ b/awx/ui/client/src/lists/Inventories.js @@ -96,7 +96,7 @@ export default edit: { label: 'Edit', - ngClick: 'editInventory(inventory.id)', //'editInventoryProperties(inventory.id)', + ngClick: 'editInventory(inventory.id)', awToolTip: 'Edit inventory', dataPlacement: 'top' }, diff --git a/awx/ui/client/src/lists/InventoryGroups.js b/awx/ui/client/src/lists/InventoryGroups.js index 6002000e53..1f12a3af5a 100644 --- a/awx/ui/client/src/lists/InventoryGroups.js +++ b/awx/ui/client/src/lists/InventoryGroups.js @@ -21,18 +21,47 @@ export default multiSelect: true, fields: { + sync_status: { + label: '', + nosort: true, + searchable: false, + mode: 'all', + iconOnly: true, + ngClick: 'viewUpdateStatus(group.id)', + awToolTip: "{{ group.status_tooltip }}", + dataTipWatch: "group.status_tooltip", + icon: "{{ 'fa icon-cloud-' + group.status_class }}", + ngClass: "group.status_class", + dataPlacement: "top", + columnClass: 'status-column List-staticColumn--smallStatus' + }, + failed_hosts: { + label: '', + nosort: true, + searchable: false, + mode: 'all', + iconOnly: true, + awToolTip: "{{ group.hosts_status_tip }}", + dataPlacement: "top", + ngClick: "showFailedHosts(group)", + icon: "{{ 'fa icon-job-' + group.hosts_status_class }}", + columnClass: 'status-column List-staticColumn--smallStatus' + }, name: { label: 'Groups', key: true, ngClick: "groupSelect(group.id)", - columnClick: "groupSelect(group.id)", - columnClass: 'col-lg-3 col-md-3 col-sm-3 col-xs-3' + columnClass: 'col-lg-3 col-md-3 col-sm-3 col-xs-3', + class: 'InventoryManage-breakWord' }, total_groups: { nosort: true, label: '', type: 'badgeCount', ngHide: 'group.total_groups == 0', + noLink: true, + awToolTip: "{{group.name}} contains {{group.total_groups}} {{group.total_groups === 1 ? 'child' : 'children'}}", + }, source: { label: 'Source', @@ -100,8 +129,9 @@ export default }, launch: { mode: 'all', - ngShow: 'inventory.can_run_ad_hoc_commands', - ngClick: 'populateAdhocForm()', + // $scope.$parent is governed by InventoryManageController, + ngShow: '$parent.groupsSelected || $parent.hostsSelected', + ngClick: '$parent.setAdhocPattern()', awToolTip: "Run a command on the selected inventory", actionClass: 'btn List-buttonDefault', buttonContent: 'RUN COMMANDS' @@ -116,7 +146,7 @@ export default ngClick: "createGroup()", awToolTip: "Create a new group", actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' + buttonContent: '+ ADD GROUP' } }, @@ -124,32 +154,16 @@ export default columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right', - sync_status: { - mode: 'all', - ngClick: "viewUpdateStatus(group.id)", - awToolTip: "{{ group.status_tooltip }}", - dataTipWatch: "group.status_tooltip", - iconClass: "{{ 'fa icon-cloud-' + group.status_class }}", - ngClass: "group.status_class", - dataPlacement: "top" - }, - failed_hosts: { - mode: 'all', - awToolTip: "{{ group.hosts_status_tip }}", - dataPlacement: "top", - ngClick: "showHosts(group.id, group.group_id, group.show_failures)", - iconClass: "{{ 'fa icon-job-' + group.hosts_status_class }}" - }, group_update: { //label: 'Sync', mode: 'all', - ngClick: 'updateGroup(group.id)', + ngClick: 'updateGroup(group)', awToolTip: "{{ group.launch_tooltip }}", dataTipWatch: "group.launch_tooltip", ngShow: "group.status !== 'running' && group.status " + "!== 'pending' && group.status !== 'updating'", ngClass: "group.launch_class", - dataPlacement: "top" + dataPlacement: "top", }, cancel: { //label: 'Cancel', @@ -159,11 +173,12 @@ export default 'class': 'red-txt', ngShow: "group.status == 'running' || group.status == 'pending' " + "|| group.status == 'updating'", - dataPlacement: "top" + dataPlacement: "top", + iconClass: "fa fa-minus-circle" }, copy: { mode: 'all', - ngClick: "copyGroup(group.id)", + ngClick: "copyMoveGroup(group.id)", awToolTip: 'Copy or move group', ngShow: "group.id > 0", dataPlacement: "top" @@ -186,7 +201,7 @@ export default "delete": { //label: 'Delete', mode: 'all', - ngClick: "deleteGroup(group.id)", + ngClick: "deleteGroup(group)", awToolTip: 'Delete group', dataPlacement: "top" } diff --git a/awx/ui/client/src/lists/InventoryHosts.js b/awx/ui/client/src/lists/InventoryHosts.js index 655f8e28ac..d99589968e 100644 --- a/awx/ui/client/src/lists/InventoryHosts.js +++ b/awx/ui/client/src/lists/InventoryHosts.js @@ -22,6 +22,23 @@ export default multiSelect: true, fields: { + active_failures: { + label: '', + iconOnly: true, + searchable: false, + 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: 'Hosts', @@ -29,7 +46,8 @@ export default ngClass: "{ 'host-disabled-label': !host.enabled }", columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', dataHostId: "{{ host.id }}", - dataType: "host" + dataType: "host", + class: 'InventoryManage-breakWord' }, enabled: { label: 'Disabled?', @@ -50,20 +68,9 @@ export default fieldActions: { columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', - label: false, - - active_failures: { - awPopOver: "{{ host.job_status_html }}", - dataTitle: "{{ host.job_status_title }}", - awToolTip: "{{ host.badgeToolTip }}", - awTipPlacement: 'top', - dataPlacement: 'left', - iconClass: "{{ 'fa icon-job-' + host.active_failures }}", - id: 'active-failutes-action' - }, copy: { mode: 'all', - ngClick: "copyHost(host.id)", + ngClick: "copyMoveHost(host.id)", awToolTip: 'Copy or move host to another group', dataPlacement: "top" }, @@ -85,15 +92,15 @@ export default actions: { system_tracking: { - label: 'System Tracking', - ngClick: 'systemTracking()', //'editInventoryProperties(inventory.id)', + buttonContent: 'System Tracking', + ngClick: 'systemTracking()', awToolTip: "{{ systemTrackingTooltip }}", dataTipWatch: "systemTrackingTooltip", dataPlacement: 'top', awFeature: 'system_tracking', - ngDisabled: 'systemTrackingDisabled', actionClass: 'btn List-buttonDefault system-tracking', - ngShow: 'hostsSelected' + ngShow: 'hostsSelected', + ngDisabled: 'systemTrackingDisabled' }, refresh: { mode: 'all', @@ -108,7 +115,7 @@ export default ngClick: "createHost()", awToolTip: "Create a new host", actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' + buttonContent: '+ ADD HOST' } } diff --git a/awx/ui/client/src/main-menu/main-menu.directive.js b/awx/ui/client/src/main-menu/main-menu.directive.js index a8056e233f..8a3ea0917f 100644 --- a/awx/ui/client/src/main-menu/main-menu.directive.js +++ b/awx/ui/client/src/main-menu/main-menu.directive.js @@ -10,6 +10,9 @@ export default scope.isCurrentState = function(name){ return $state.current.name === name; }; + scope.includesCurrentState = function(name){ + return $state.includes(name); + }; // set up the user tooltip $rootScope.$on('current_user', function(user) { diff --git a/awx/ui/client/src/scheduler/main.js b/awx/ui/client/src/scheduler/main.js index b75ee987b9..faaf6ecce7 100644 --- a/awx/ui/client/src/scheduler/main.js +++ b/awx/ui/client/src/scheduler/main.js @@ -52,19 +52,26 @@ export default controller: 'schedulerEditController' }); $stateExtender.addState({ - name: 'inventoryManageSchedules', - route: '/inventory/:inventory_id/manage/:id/schedules', - templateUrl: templateUrl("scheduler/scheduler"), - controller: 'schedulerController' + name: 'inventoryManage.schedules', + route: '/schedules/:id', + views: { + 'form@inventoryManage': { + templateUrl: templateUrl("scheduler/scheduler"), + controller: 'schedulerController' + } + }, + ncyBreadcrumb: { + label: "{{name}} SCHEDULES" + }, }); $stateExtender.addState({ - name: 'inventoryManageSchedules.add', + name: 'inventoryManage.schedules.add', route: '/add', templateUrl: templateUrl("scheduler/schedulerForm"), controller: 'schedulerAddController' }); $stateExtender.addState({ - name: 'inventoryManageSchedules.edit', + name: 'inventoryManage.schedules.edit', route: '/:schedule_id', templateUrl: templateUrl("scheduler/schedulerForm"), controller: 'schedulerEditController' diff --git a/awx/ui/client/src/shared/InventoryTree.js b/awx/ui/client/src/shared/InventoryTree.js deleted file mode 100644 index f6c9ecb925..0000000000 --- a/awx/ui/client/src/shared/InventoryTree.js +++ /dev/null @@ -1,609 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - - /** - * @ngdoc function - * @name shared.function:inventoryTree - * @description - * InventoryTree.js - * - * Build data for the tree selector table used on inventory detail page. - * - */ - - -export default -angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'PromptDialog']) - -.factory('SortNodes', [ - function () { - return function (data) { - //Sort nodes by name - var i, j, names = [], newData = []; - for (i = 0; i < data.length; i++) { - names.push(data[i].name); - } - names.sort(); - for (j = 0; j < names.length; j++) { - for (i = 0; i < data.length; i++) { - if (data[i].name === names[j]) { - newData.push(data[i]); - } - } - } - return newData; - }; - } -]) - -.factory('BuildTree', ['$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Store', - function ($location, Rest, GetBasePath, ProcessErrors, SortNodes, Wait, GetSyncStatusMsg, GetHostsStatusMsg, Store) { - return function (params) { - - var inventory_id = params.inventory_id, - scope = params.scope, - refresh = params.refresh, - emit = params.emit, - new_group_id = params.new_group_id, - groups = [], - id = 1, - local_child_store, - path = $location.path(); - - function buildAllHosts(tree_data) { - // Start our tree object with All Hosts - var children = [], - sorted = SortNodes(tree_data), - j, all_hosts; - - for (j = 0; j < sorted.length; j++) { - children.push(sorted[j].id); - } - - all_hosts = { - name: 'All Hosts', - id: 1, - group_id: null, - parent: 0, - description: '', - show: true, - ngicon: null, - has_children: false, - related: {}, - selected_class: '', - show_failures: false, - isDraggable: false, - isDroppable: true, - children: children - }; - groups.push(all_hosts); - } - - function getExpandState(key) { - var result = true; - local_child_store.every(function(child) { - if (child.key === key) { - result = child.expand; - return false; - } - return true; - }); - return result; - } - - function getShowState(key) { - var result = null; - local_child_store.every(function(child) { - if (child.key === key) { - result = (child.show !== undefined) ? child.show : true; - return false; - } - return true; - }); - return result; - } - - function buildGroups(tree_data, parent, level) { - - var children, stat, hosts_status, group, - sorted = SortNodes(tree_data), - expand, show; - - sorted.forEach( function(row, i) { - id++; - - stat = GetSyncStatusMsg({ - status: sorted[i].summary_fields.inventory_source.status, - has_inventory_sources: sorted[i].has_inventory_sources, - source: ( (sorted[i].summary_fields.inventory_source) ? sorted[i].summary_fields.inventory_source.source : null ) - }); // from helpers/Groups.js - - hosts_status = GetHostsStatusMsg({ - active_failures: sorted[i].hosts_with_active_failures, - total_hosts: sorted[i].total_hosts, - inventory_id: inventory_id, - group_id: sorted[i].id - }); // from helpers/Groups.js - - children = []; - sorted[i].children.forEach( function(child, j) { - children.push(sorted[i].children[j].id); - }); - - expand = (sorted[i].children.length > 0) ? getExpandState(sorted[i].id) : false; - show = getShowState(sorted[i].id); - if (show === null) { - // this is a node we haven't seen before, so check the parent expand/collapse state - // If parent is not expanded, then child should be hidden. - show = true; - if (parent > 0) { - groups.every(function(g) { - if (g.id === parent) { - show = getExpandState(g.key); - return false; - } - return true; - }); - } - } - - group = { - name: sorted[i].name, - has_active_failures: sorted[i].has_active_failures, - total_hosts: sorted[i].total_hosts, - hosts_with_active_failures: sorted[i].hosts_with_active_failures, - total_groups: sorted[i].total_groups, - groups_with_active_failures: sorted[i].groups_with_active_failures, - parent: parent, - has_children: (sorted[i].children.length > 0) ? true : false, - has_inventory_sources: sorted[i].has_inventory_sources, - id: id, - source: sorted[i].summary_fields.inventory_source.source, - key: sorted[i].id, - group_id: sorted[i].id, - event_level: level, - children: children, - show: show, - related: sorted[i].related, - status: sorted[i].summary_fields.inventory_source.status, - status_class: stat['class'], - status_tooltip: stat.tooltip, - launch_tooltip: stat.launch_tip, - launch_class: stat.launch_class, - hosts_status_tip: hosts_status.tooltip, - show_failures: hosts_status.failures, - hosts_status_class: hosts_status['class'], - inventory_id: inventory_id, - selected_class: '', - isDraggable: true, - isDroppable: true - }; - if (sorted[i].children.length > 0) { - if (expand) { - group.ngicon = 'fa fa-minus-square-o node-toggle'; - } - else { - group.ngicon = 'fa fa-plus-square-o node-toggle'; - } - } - else { - group.ngicon = 'fa fa-square-o node-no-toggle'; - } - if (new_group_id && group.group_id === new_group_id) { - scope.selected_tree_id = id; - scope.selected_group_id = group.group_id; - } - groups.push(group); - if (sorted[i].children.length > 0) { - buildGroups(sorted[i].children, id, level + 1); - } - }); - } - - // Build the HTML for our tree - if (scope.buildAllGroupsRemove) { - scope.buildAllGroupsRemove(); - } - scope.buildAllGroupsRemove = scope.$on('buildAllGroups', function (e, inventory_name, inventory_tree) { - Rest.setUrl(inventory_tree); - Rest.get() - .success(function (data) { - buildAllHosts(data); - buildGroups(data, 0, 0); - scope.autoShowGroupHelp = (data.length === 0) ? true : false; - if (refresh) { - scope.groups = groups; - scope.$emit('GroupTreeRefreshed', inventory_name, groups, emit); - } else { - scope.$emit('GroupTreeLoaded', inventory_name, groups, emit); - } - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status - }); - }); - }); - - - function loadTreeData() { - // Load the inventory root node - Wait('start'); - Rest.setUrl(GetBasePath('inventory') + inventory_id + '/'); - Rest.get() - .success(function (data) { - scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups); - }) - .error(function (data, status) { - Wait('stop'); - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status - }); - }); - } - local_child_store = Store(path + '_children'); - if (!local_child_store) { - local_child_store = []; - } - loadTreeData(); - }; - } -]) - - -// Update a group with a set of properties -.factory('UpdateGroup', ['ApplyEllipsis', 'GetSyncStatusMsg', 'Empty', - function (ApplyEllipsis, GetSyncStatusMsg, Empty) { - return function (params) { - - var scope = params.scope, - group_id = params.group_id, - properties = params.properties, - i, p, grp, old_name, stat; - - for (i = 0; i < scope.groups.length; i++) { - if (scope.groups[i].id === group_id) { - grp = scope.groups[i]; - for (p in properties) { - if (p === 'name') { - old_name = scope.groups[i].name; - } - if (p === 'source') { - if (properties[p] !== scope.groups[i][p]) { - // User changed source - if (!Empty(properties[p]) && (scope.groups[i].status === 'none' || Empty(scope.groups[i].status))) { - // We have a source but no status, seed the status with 'never' to enable sync button - scope.groups[i].status = 'never updated'; - } else if (!properties[p]) { - // User removed source - scope.groups[i].status = 'none'; - } - // Update date sync status links/icons - stat = GetSyncStatusMsg({ - status: scope.groups[i].status, - has_inventory_sources: properties.has_inventory_sources, - source: properties.source - }); - scope.groups[i].status_class = stat['class']; - scope.groups[i].status_tooltip = stat.tooltip; - scope.groups[i].launch_tooltip = stat.launch_tip; - scope.groups[i].launch_class = stat.launch_class; - } - } - scope.groups[i][p] = properties[p]; - } - } - /*if (scope.groups[i].id === scope.selected_tree_id) { - //Make sure potential group name change gets reflected throughout the page - scope.selected_group_name = scope.groups[i].name; - scope.search_place_holder = 'Search ' + scope.groups[i].name; - scope.hostSearchPlaceholder = 'Search ' + scope.groups[i].name; - }*/ - } - - // Update any titles attributes created by ApplyEllipsis - if (old_name) { - setTimeout(function () { - $('#groups_table .group-name a[title="' + old_name + '"]').attr('title', properties.name); - ApplyEllipsis('#groups_table .group-name a'); - }, 2500); - } - - }; - } -]) - - -// Set node name and description after an update to Group properties. -.factory('SetNodeName', [ - function () { - return function (params) { - var name = params.name, - descr = params.description, - group_id = (params.group_id !== undefined) ? params.group_id : null, - inventory_id = (params.inventory_id !== undefined) ? params.inventory_id : null; - - if (group_id !== null) { - $('#inventory-tree').find('li [data-group-id="' + group_id + '"]').each(function () { - $(this).attr('data-name', name); - $(this).attr('data-description', descr); - $(this).find('.activate').first().text(name); - }); - } - - if (inventory_id !== null) { - $('#inventory-root-node').attr('data-name', name).attr('data-description', descr).find('.activate').first().text(name); - } - }; - } -]) - - -// Copy or Move a group on the tree after drag-n-drop -.factory('CopyMoveGroup', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath', - function ($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) { - return function (params) { - - var scope = params.scope, - target = Find({ list: scope.groups, key: 'id', val: params.target_tree_id }), - inbound = Find({ list: scope.groups, key: 'id', val: params.inbound_tree_id }), - e, html = ''; - - // Build the html for our prompt dialog - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "\n"; - - if (target.id === 1 || inbound.parent === 0) { - // We're moving the group to the top level, or we're moving a top level group down - html += "

Move Group

\n"; - } else { - html += "

Copy or Move?

\n"; - } - - html += "
\n"; - html += "
\n"; - - if (target.id === 1) { - html += "
Are you sure you want to move group " + inbound.name + " to the top level?
"; - } else if (inbound.parent === 0) { - html += "
Are you sure you want to move group " + inbound.name + " from the top level and make it a child of " + - target.name + "?
"; - } else { - html += "
\n"; - html += "

Would you like to copy or move group " + inbound.name + " to group " + target.name + "?

\n"; - html += "
\n"; - html += " Move\n"; - html += " Copy\n"; - html += "
\n"; - html += "
\n"; - } - - html += "
\n"; - html += "
\n"; - html += "Cancel\n"; - - if (target.id === 1 || inbound.parent === 0) { - // We're moving the group to the top level, or we're moving a top level group down - html += "Yes\n"; - } - - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - - // Inject our custom dialog - e= angular.element(document.getElementById('inventory-modal-container')); - e.empty().append(html); - $compile(e)(scope); - - // Display it - $('#copy-prompt-modal').modal({ - backdrop: 'static', - keyboard: true, - show: true - }); - - // Respond to move - scope.moveGroup = function () { - var url, group, parent; - $('#copy-prompt-modal').modal('hide'); - Wait('start'); - - // disassociate the group from the original parent - if (scope.removeGroupRemove) { - scope.removeGroupRemove(); - } - scope.removeGroupRemove = scope.$on('removeGroup', function () { - if (inbound.parent > 0) { - // Only remove a group from a parent when the parent is a group and not the inventory root - parent = Find({ list: scope.groups, key: 'id', val: inbound.parent }); - url = GetBasePath('base') + 'groups/' + parent.group_id + '/children/'; - Rest.setUrl(url); - Rest.post({ id: inbound.group_id, disassociate: 1 }) - .success(function () { - //Triggers refresh of group list in inventory controller - scope.$emit('GroupDeleteCompleted'); - }) - .error(function (data, status) { - Wait('stop'); - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Failed to remove ' + inbound.name + - ' from ' + parent.name + '. POST returned status: ' + status - }); - }); - } else { - //Triggers refresh of group list in inventory controller - scope.$emit('GroupDeleteCompleted'); - } - }); - - // add the new group to the target parent - url = (!Empty(target.group_id)) ? - GetBasePath('base') + 'groups/' + target.group_id + '/children/' : - GetBasePath('inventory') + scope.inventory_id + '/groups/'; - group = { - id: inbound.group_id, - name: inbound.name, - description: inbound.description, - inventory: scope.inventory_id - }; - Rest.setUrl(url); - Rest.post(group) - .success(function () { - scope.$emit('removeGroup'); - }) - .error(function (data, status) { - var target_name = (Empty(target.group_id)) ? 'inventory' : target.name; - Wait('stop'); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to add ' + inbound.name + ' to ' + target_name + '. POST returned status: ' + status }); - }); - }; - - - scope.copyGroup = function () { - $('#copy-prompt-modal').modal('hide'); - Wait('start'); - // add the new group to the target parent - var url = (!Empty(target.group_id)) ? - GetBasePath('base') + 'groups/' + target.group_id + '/children/' : - GetBasePath('inventory') + scope.inventory_id + '/groups/', - group = { - id: inbound.group_id, - name: inbound.name, - description: inbound.description, - inventory: scope.inventory_id - }; - - Rest.setUrl(url); - Rest.post(group) - .success(function () { - //Triggers refresh of group list in inventory controller - scope.$emit('GroupDeleteCompleted'); - }) - .error(function (data, status) { - var target_name = (Empty(target.group_id)) ? 'inventory' : target.name; - Wait('stop'); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to add ' + inbound.name + ' to ' + target_name + '. POST returned status: ' + status - }); - }); - }; - - }; - } -]) - -// Copy a host after drag-n-drop -.factory('CopyMoveHost', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath', - function ($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) { - return function (params) { - - var scope = params.scope, - target = Find({ list: scope.groups, key: 'id', val: params.target_tree_id }), - host = Find({ list: scope.hosts, key: 'id', val: params.host_id }), - found = false, e, i, html = ''; - - if (host.summary_fields.all_groups) { - for (i = 0; i < host.summary_fields.all_groups.length; i++) { - if (host.summary_fields.all_groups[i].id === target.group_id) { - found = true; - break; - } - } - } - if (found) { - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "\n"; - html += "

Already in Group

\n"; - html += "
\n"; - html += "
\n"; - html += "

Host " + host.name + " is already in group " + target.name + ".

\n"; - html += "
\n"; - html += "
\n"; - html += "OK\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - - // Inject our custom dialog - e = angular.element(document.getElementById('inventory-modal-container')); - e.empty().append(html); - $compile(e)(scope); - - // Display it - $('#copy-alert-modal').modal({ - backdrop: 'static', - keyboard: true, - show: true - }); - - } else { - // Build the html for our prompt dialog - html = ''; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "\n"; - html += "

Copy Host

\n"; - html += "
\n"; - html += "
\n"; - html += "
Are you sure you want to copy host " + host.name + ' to group ' + target.name + '?
'; - html += "
\n"; - html += "
\n"; - html += "No\n"; - html += "Yes\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - - // Inject our custom dialog - e = angular.element(document.getElementById('inventory-modal-container')); - e.empty().append(html); - $compile(e)(scope); - - // Display it - $('#copy-prompt-modal').modal({ - backdrop: 'static', - keyboard: true, - show: true - }); - - scope.copyHost = function () { - $('#copy-prompt-modal').modal('hide'); - Wait('start'); - Rest.setUrl(GetBasePath('groups') + target.group_id + '/hosts/'); - Rest.post(host) - .success(function () { - // Signal the controller to refresh the hosts view - scope.$emit('GroupTreeRefreshed'); - }) - .error(function (data, status) { - Wait('stop'); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Failed to add ' + host.name + ' to ' + - target.name + '. POST returned status: ' + status }); - }); - }; - } - }; - } -]); diff --git a/awx/ui/client/src/shared/generator-helpers.js b/awx/ui/client/src/shared/generator-helpers.js index fc62bbecbd..7a0c517a58 100644 --- a/awx/ui/client/src/shared/generator-helpers.js +++ b/awx/ui/client/src/shared/generator-helpers.js @@ -277,10 +277,14 @@ angular.module('GeneratorHelpers', [systemStatus.name]) html = "\n"; - html += ""; diff --git a/awx/ui/client/src/shared/list-generator/list-generator.factory.js b/awx/ui/client/src/shared/list-generator/list-generator.factory.js index 9e2da09fc4..a0a8258595 100644 --- a/awx/ui/client/src/shared/list-generator/list-generator.factory.js +++ b/awx/ui/client/src/shared/list-generator/list-generator.factory.js @@ -439,6 +439,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate innerTable += "ng-class-odd=\"'List-tableRow--oddRow'\" "; innerTable += "ng-class-even=\"'List-tableRow--evenRow'\" "; innerTable += "ng-repeat=\"" + list.iterator + " in " + list.name; + innerTable += (list.trackBy) ? " track by " + list.trackBy : " track by $index"; innerTable += (list.orderBy) ? " | orderBy:'" + list.orderBy + "'" : ""; innerTable += (list.filterBy) ? " | filter: " + list.filterBy : ""; innerTable += "\">\n"; @@ -459,7 +460,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate "ng-false-value=\"0\" id=\"check_" + list.iterator + "_{{" + list.iterator + ".id}}\" />"; } else { // its assumed that options.input_type = checkbox - innerTable += ""; } @@ -619,7 +620,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate html += buildSelectAll().prop('outerHTML'); } else if (options.mode === 'lookup') { - html += ""; + html += ""; } for (fld in list.fields) { if ((list.fields[fld].searchOnly === undefined || list.fields[fld].searchOnly === false) && diff --git a/awx/ui/client/tests/adhoc/adhoc.controller-test.js b/awx/ui/client/tests/adhoc/adhoc.controller-test.js index 27d61b3f30..d49c699994 100644 --- a/awx/ui/client/tests/adhoc/adhoc.controller-test.js +++ b/awx/ui/client/tests/adhoc/adhoc.controller-test.js @@ -1,6 +1,6 @@ import '../support/node'; -import adhocModule from 'adhoc/main'; +import adhocModule from 'inventories/manage/adhoc/main'; import RestStub from '../support/rest-stub'; describe("adhoc.controller", function() { diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 7960ba38c9..3e8395b3e8 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -40,7 +40,7 @@ - +
From 19dcc06c9d02e5a96ffed74987b5c3fc6e144226 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Tue, 24 May 2016 21:10:43 -0400 Subject: [PATCH 013/584] Read permissions goes to read_role, not use_role Dork. --- awx/main/migrations/_rbac.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py index c45b1ba5b1..7eeb95579d 100644 --- a/awx/main/migrations/_rbac.py +++ b/awx/main/migrations/_rbac.py @@ -219,7 +219,7 @@ def migrate_inventory(apps, schema_editor): if perm.permission_type == 'admin': return inventory.admin_role elif perm.permission_type == 'read': - return inventory.use_role + return inventory.read_role elif perm.permission_type == 'write': return inventory.update_role elif perm.permission_type == 'check' or perm.permission_type == 'run' or perm.permission_type == 'create': From 1abba522b03fb854201c141c5e72e7281d6c94fc Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Tue, 24 May 2016 22:19:51 -0400 Subject: [PATCH 014/584] Resurrect global .distinct() call (mostly) This mostly reverts 3c67971e78a12bd94536aa5464f0bc1ea46ba1ee with the minor difference that we only apply this when we're filtering, which is apparently necessary without some notable overhaul since the filtering we're doing will get stuck in as filters, which will generate inner joins, which can result in duplicates if the thing we're joining with is a one to many or many to many, which most things are. With this patch we still need to be generating naturally distinct querysets with any `get_queryset` methods, which will still be much more effecient when filtering is not involved. This fixes #2032 and probably a bunch of other undiscovered issues. --- awx/api/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/api/filters.py b/awx/api/filters.py index d023b2aa08..f4e65a8d82 100644 --- a/awx/api/filters.py +++ b/awx/api/filters.py @@ -219,7 +219,7 @@ class FieldLookupBackend(BaseFilterBackend): else: q = Q(**{k:v}) queryset = queryset.filter(q) - queryset = queryset.filter(*args) + queryset = queryset.filter(*args).distinct() return queryset except (FieldError, FieldDoesNotExist, ValueError), e: raise ParseError(e.args[0]) From 2b16c882f49bfa21b400db156f96b625859d223d Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Wed, 25 May 2016 12:45:13 -0400 Subject: [PATCH 015/584] fix infinite scrolling of job run standard out, resolves #1829 --- .../client/lib/lrInfiniteScroll/.bower.json | 32 + awx/ui/client/lib/lrInfiniteScroll/index.js | 2 + .../lib/lrInfiniteScroll/lrInfiniteScroll.js | 17 +- awx/ui/client/src/app.js | 1 + .../log/standard-out-log.controller.js | 39 +- .../log/standard-out-log.partial.html | 5 +- npm-shrinkwrap.json | 829 ++++++------------ 7 files changed, 311 insertions(+), 614 deletions(-) create mode 100644 awx/ui/client/lib/lrInfiniteScroll/.bower.json create mode 100644 awx/ui/client/lib/lrInfiniteScroll/index.js diff --git a/awx/ui/client/lib/lrInfiniteScroll/.bower.json b/awx/ui/client/lib/lrInfiniteScroll/.bower.json new file mode 100644 index 0000000000..7e27fd82a2 --- /dev/null +++ b/awx/ui/client/lib/lrInfiniteScroll/.bower.json @@ -0,0 +1,32 @@ +{ + "name": "lrInfiniteScroll", + "main": "lrInfiniteScroll.js", + "version": "1.0.0", + "homepage": "https://github.com/lorenzofox3/lrInfiniteScroll", + "authors": [ + "lorenzofox3 " + ], + "description": "angular directive to handle element scroll", + "keywords": [ + "angular", + "scroll", + "inifinite" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "_release": "1.0.0", + "_resolution": { + "type": "version", + "tag": "1.0.0", + "commit": "c833e9d8ff56d6c66e2a21ed7f27ad840f159a8b" + }, + "_source": "https://github.com/lorenzofox3/lrInfiniteScroll.git", + "_target": "~1.0.0", + "_originalSource": "lrInfiniteScroll" +} \ No newline at end of file diff --git a/awx/ui/client/lib/lrInfiniteScroll/index.js b/awx/ui/client/lib/lrInfiniteScroll/index.js new file mode 100644 index 0000000000..62f33e97b4 --- /dev/null +++ b/awx/ui/client/lib/lrInfiniteScroll/index.js @@ -0,0 +1,2 @@ +require('./lrInfiniteScroll'); +module.exports = 'lrInfiniteScroll'; diff --git a/awx/ui/client/lib/lrInfiniteScroll/lrInfiniteScroll.js b/awx/ui/client/lib/lrInfiniteScroll/lrInfiniteScroll.js index 3268a94081..ac29895c2b 100644 --- a/awx/ui/client/lib/lrInfiniteScroll/lrInfiniteScroll.js +++ b/awx/ui/client/lib/lrInfiniteScroll/lrInfiniteScroll.js @@ -2,13 +2,12 @@ 'use strict'; var module = ng.module('lrInfiniteScroll', []); - module.directive('lrInfiniteScroll', ['$log', '$timeout', function ($log, timeout) { + module.directive('lrInfiniteScroll', ['$timeout', function (timeout) { return{ link: function (scope, element, attr) { var lengthThreshold = attr.scrollThreshold || 50, timeThreshold = attr.timeThreshold || 400, - direction = attr.direction || 'down', handler = scope.$eval(attr.lrInfiniteScroll), promise = null, lastRemaining = 9999; @@ -20,14 +19,14 @@ handler = ng.noop; } - $log.debug('lrInfiniteScroll: ' + attr.lrInfiniteScroll); - element.bind('scroll', function () { - var remaining = (direction === 'down') ? element[0].scrollHeight - (element[0].clientHeight + element[0].scrollTop) : element[0].scrollTop; - // if we have reached the threshold and we scroll down - if ((direction === 'down' && remaining < lengthThreshold && (remaining - lastRemaining) < 0) || - direction === 'up' && remaining < lengthThreshold) { - //if there is already a timer running which has not expired yet we have to cancel it and restart the timer + var + remaining = element[0].scrollHeight - (element[0].clientHeight + element[0].scrollTop); + + //if we have reached the threshold and we scroll down + if (remaining < lengthThreshold && (remaining - lastRemaining) < 0) { + + //if there is already a timer running which has no expired yet we have to cancel it and restart the timer if (promise !== null) { timeout.cancel(promise); } diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 1fbd283e79..dddfdd52e2 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -79,6 +79,7 @@ __deferLoadIfEnabled(); var tower = angular.module('Tower', [ //'ngAnimate', + 'lrInfiniteScroll', 'ngSanitize', 'ngCookies', about.name, diff --git a/awx/ui/client/src/standard-out/log/standard-out-log.controller.js b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js index 631294255f..62fc00aee6 100644 --- a/awx/ui/client/src/standard-out/log/standard-out-log.controller.js +++ b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js @@ -87,7 +87,7 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce }); function loadStdout() { - Rest.setUrl($scope.stdoutEndpoint + '?format=json&start_line=-' + page_size); + Rest.setUrl($scope.stdoutEndpoint + '?format=json&start_line=0&end_line=' + page_size); Rest.get() .success(function(data) { Wait('stop'); @@ -145,38 +145,17 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce }); } - $scope.stdOutScrollToTop = function() { - // scroll up or back in time toward the beginning of the file - var start, end, url; - if (loaded_sections.length > 0 && loaded_sections[0].start > 0) { - start = (loaded_sections[0].start - page_size > 0) ? loaded_sections[0].start - page_size : 0; - end = loaded_sections[0].start - 1; - } - else if (loaded_sections.length === 0) { - start = 0; - end = page_size; - } - if (start !== undefined && end !== undefined) { - $('#stdoutMoreRowsTop').fadeIn(); - url = stdout_url + '?format=json&start_line=' + start + '&end_line=' + end; + // lrInfiniteScroll handler + // grabs the next stdout section + $scope.stdOutGetNextSection = function(){ + if (current_range.absolute_end > current_range.end){ + var url = $scope.stdoutEndpoint + '?format=json&start_line=' + current_range.end + + '&end_line=' + (current_range.end + page_size); Rest.setUrl(url); Rest.get() - .success( function(data) { - //var currentPos = $('#pre-container').scrollTop(); - var newSH, oldSH = $('#pre-container').prop('scrollHeight'), - st = $('#pre-container').scrollTop(); - - $('#pre-container-content').prepend(data.content); - - newSH = $('#pre-container').prop('scrollHeight'); - $('#pre-container').scrollTop(newSH - oldSH + st); - - loaded_sections.unshift({ - start: (data.range.start < 0) ? 0 : data.range.start, - end: data.range.end - }); + .success(function(data){ + $('#pre-container-content').append(data.content); current_range = data.range; - $('#stdoutMoreRowsTop').fadeOut(400); }) .error(function(data, status) { ProcessErrors($scope, data, status, null, { hdr: 'Error!', diff --git a/awx/ui/client/src/standard-out/log/standard-out-log.partial.html b/awx/ui/client/src/standard-out/log/standard-out-log.partial.html index 247e58b165..45d9f70cbb 100644 --- a/awx/ui/client/src/standard-out/log/standard-out-log.partial.html +++ b/awx/ui/client/src/standard-out/log/standard-out-log.partial.html @@ -1,6 +1,5 @@ -
-
+
+
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 1ad77767cb..5aac94cf48 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -938,173 +938,173 @@ }, "broccoli-babel-transpiler": { "version": "5.5.0", - "from": "broccoli-babel-transpiler@*", + "from": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.5.0.tgz", "resolved": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.5.0.tgz", "dependencies": { "babel-core": { "version": "5.8.38", - "from": "babel-core@>=5.0.0 <6.0.0", + "from": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz", "dependencies": { "babel-plugin-constant-folding": { "version": "1.0.1", - "from": "babel-plugin-constant-folding@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz" }, "babel-plugin-dead-code-elimination": { "version": "1.0.2", - "from": "babel-plugin-dead-code-elimination@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz" }, "babel-plugin-eval": { "version": "1.0.1", - "from": "babel-plugin-eval@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz" }, "babel-plugin-inline-environment-variables": { "version": "1.0.1", - "from": "babel-plugin-inline-environment-variables@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz" }, "babel-plugin-jscript": { "version": "1.0.4", - "from": "babel-plugin-jscript@>=1.0.4 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz" }, "babel-plugin-member-expression-literals": { "version": "1.0.1", - "from": "babel-plugin-member-expression-literals@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz" }, "babel-plugin-property-literals": { "version": "1.0.1", - "from": "babel-plugin-property-literals@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz" }, "babel-plugin-proto-to-assign": { "version": "1.0.4", - "from": "babel-plugin-proto-to-assign@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz" }, "babel-plugin-react-constant-elements": { "version": "1.0.3", - "from": "babel-plugin-react-constant-elements@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz" }, "babel-plugin-react-display-name": { "version": "1.0.3", - "from": "babel-plugin-react-display-name@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz" }, "babel-plugin-remove-console": { "version": "1.0.1", - "from": "babel-plugin-remove-console@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz" }, "babel-plugin-remove-debugger": { "version": "1.0.1", - "from": "babel-plugin-remove-debugger@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz" }, "babel-plugin-runtime": { "version": "1.0.7", - "from": "babel-plugin-runtime@>=1.0.7 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz" }, "babel-plugin-undeclared-variables-check": { "version": "1.0.2", - "from": "babel-plugin-undeclared-variables-check@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz", "dependencies": { "leven": { "version": "1.0.2", - "from": "leven@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz", "resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz" } } }, "babel-plugin-undefined-to-void": { "version": "1.1.6", - "from": "babel-plugin-undefined-to-void@>=1.1.6 <2.0.0", + "from": "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz" }, "babylon": { "version": "5.8.38", - "from": "babylon@>=5.8.38 <6.0.0", + "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz", "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz" }, "bluebird": { "version": "2.10.2", - "from": "bluebird@>=2.9.33 <3.0.0", + "from": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz" }, "convert-source-map": { "version": "1.2.0", - "from": "convert-source-map@>=1.1.0 <2.0.0", + "from": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.2.0.tgz", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.2.0.tgz" }, "core-js": { "version": "1.2.6", - "from": "core-js@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz" }, "detect-indent": { "version": "3.0.1", - "from": "detect-indent@>=3.0.0 <4.0.0", + "from": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", "dependencies": { "get-stdin": { "version": "4.0.1", - "from": "get-stdin@>=4.0.1 <5.0.0", + "from": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" } } }, "esutils": { "version": "2.0.2", - "from": "esutils@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz" }, "fs-readdir-recursive": { "version": "0.1.2", - "from": "fs-readdir-recursive@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz" }, "globals": { "version": "6.4.1", - "from": "globals@>=6.4.0 <7.0.0", + "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz" }, "home-or-tmp": { "version": "1.0.0", - "from": "home-or-tmp@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz", "dependencies": { "os-tmpdir": { "version": "1.0.1", - "from": "os-tmpdir@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" }, "user-home": { "version": "1.1.1", - "from": "user-home@>=1.1.1 <2.0.0", + "from": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz" } } }, "is-integer": { "version": "1.0.6", - "from": "is-integer@>=1.0.4 <2.0.0", + "from": "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz", "resolved": "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz", "dependencies": { "is-finite": { "version": "1.0.1", - "from": "is-finite@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz", "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" } } @@ -1113,32 +1113,32 @@ }, "js-tokens": { "version": "1.0.1", - "from": "js-tokens@1.0.1", + "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz" }, "json5": { "version": "0.4.0", - "from": "json5@>=0.4.0 <0.5.0", + "from": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz" }, "minimatch": { "version": "2.0.10", - "from": "minimatch@>=2.0.3 <3.0.0", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "dependencies": { "brace-expansion": { "version": "1.1.3", - "from": "brace-expansion@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "dependencies": { "balanced-match": { "version": "0.3.0", - "from": "balanced-match@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz" }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", + "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" } } @@ -1147,88 +1147,88 @@ }, "output-file-sync": { "version": "1.1.1", - "from": "output-file-sync@>=1.1.0 <2.0.0", + "from": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.1.tgz", "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.1.tgz", "dependencies": { "xtend": { "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", + "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" } } }, "path-exists": { "version": "1.0.0", - "from": "path-exists@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz" }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" }, "private": { "version": "0.1.6", - "from": "private@>=0.1.6 <0.2.0", + "from": "https://registry.npmjs.org/private/-/private-0.1.6.tgz", "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz" }, "regenerator": { "version": "0.8.40", - "from": "regenerator@0.8.40", + "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz", "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz", "dependencies": { "commoner": { "version": "0.10.4", - "from": "commoner@>=0.10.3 <0.11.0", + "from": "https://registry.npmjs.org/commoner/-/commoner-0.10.4.tgz", "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.4.tgz", "dependencies": { "detective": { "version": "4.3.1", - "from": "detective@>=4.3.1 <5.0.0", + "from": "https://registry.npmjs.org/detective/-/detective-4.3.1.tgz", "resolved": "https://registry.npmjs.org/detective/-/detective-4.3.1.tgz", "dependencies": { "acorn": { "version": "1.2.2", - "from": "acorn@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" }, "defined": { "version": "1.0.0", - "from": "defined@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz" } } }, "glob": { "version": "5.0.15", - "from": "glob@>=5.0.15 <6.0.0", + "from": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "dependencies": { "inflight": { "version": "1.0.4", - "from": "inflight@>=1.0.4 <2.0.0", + "from": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", "dependencies": { "wrappy": { "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", + "from": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "dependencies": { "wrappy": { "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" } } @@ -1237,159 +1237,159 @@ }, "graceful-fs": { "version": "4.1.3", - "from": "graceful-fs@>=4.1.2 <5.0.0", + "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz" }, "iconv-lite": { "version": "0.4.13", - "from": "iconv-lite@>=0.4.5 <0.5.0", + "from": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" }, "q": { "version": "1.4.1", - "from": "q@>=1.1.2 <2.0.0", + "from": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz" } } }, "defs": { "version": "1.1.1", - "from": "defs@>=1.1.0 <1.2.0", + "from": "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz", "resolved": "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz", "dependencies": { "alter": { "version": "0.2.0", - "from": "alter@>=0.2.0 <0.3.0", + "from": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz", "resolved": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz", "dependencies": { "stable": { "version": "0.1.5", - "from": "stable@>=0.1.3 <0.2.0", + "from": "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz" } } }, "ast-traverse": { "version": "0.1.1", - "from": "ast-traverse@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz", "resolved": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz" }, "breakable": { "version": "1.0.0", - "from": "breakable@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz", "resolved": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz" }, "simple-fmt": { "version": "0.1.0", - "from": "simple-fmt@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz", "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz" }, "simple-is": { "version": "0.2.0", - "from": "simple-is@>=0.2.0 <0.3.0", + "from": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz", "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz" }, "stringmap": { "version": "0.2.2", - "from": "stringmap@>=0.2.2 <0.3.0", + "from": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz", "resolved": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz" }, "stringset": { "version": "0.2.1", - "from": "stringset@>=0.2.1 <0.3.0", + "from": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz", "resolved": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz" }, "tryor": { "version": "0.1.2", - "from": "tryor@>=0.1.2 <0.2.0", + "from": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz", "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz" }, "yargs": { "version": "3.27.0", - "from": "yargs@>=3.27.0 <3.28.0", + "from": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz", "dependencies": { "camelcase": { "version": "1.2.1", - "from": "camelcase@>=1.2.1 <2.0.0", + "from": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" }, "cliui": { "version": "2.1.0", - "from": "cliui@>=2.1.0 <3.0.0", + "from": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "dependencies": { "center-align": { "version": "0.1.3", - "from": "center-align@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "dependencies": { "kind-of": { "version": "3.0.2", - "from": "kind-of@>=3.0.2 <4.0.0", + "from": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.2.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.2.tgz", "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", + "from": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" } } }, "lazy-cache": { "version": "1.0.3", - "from": "lazy-cache@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.3.tgz", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.3.tgz" } } }, "right-align": { "version": "0.1.3", - "from": "right-align@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "dependencies": { "kind-of": { "version": "3.0.2", - "from": "kind-of@>=3.0.2 <4.0.0", + "from": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.2.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.2.tgz", "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", + "from": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" } } @@ -1398,29 +1398,29 @@ }, "wordwrap": { "version": "0.0.2", - "from": "wordwrap@0.0.2", + "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" } } }, "decamelize": { "version": "1.2.0", - "from": "decamelize@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" }, "os-locale": { "version": "1.4.0", - "from": "os-locale@>=1.4.0 <2.0.0", + "from": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "dependencies": { "lcid": { "version": "1.0.0", - "from": "lcid@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "dependencies": { "invert-kv": { "version": "1.0.0", - "from": "invert-kv@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" } } @@ -1429,12 +1429,12 @@ }, "window-size": { "version": "0.1.4", - "from": "window-size@>=0.1.2 <0.2.0", + "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz" }, "y18n": { "version": "3.2.1", - "from": "y18n@>=3.2.0 <4.0.0", + "from": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz" } } @@ -1443,73 +1443,73 @@ }, "esprima-fb": { "version": "15001.1001.0-dev-harmony-fb", - "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", + "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz", "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" }, "recast": { "version": "0.10.33", - "from": "recast@0.10.33", + "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz", "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz", "dependencies": { "ast-types": { "version": "0.8.12", - "from": "ast-types@0.8.12", + "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz" } } }, "through": { "version": "2.3.8", - "from": "through@>=2.3.8 <2.4.0", + "from": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" } } }, "regexpu": { "version": "1.3.0", - "from": "regexpu@>=1.3.0 <2.0.0", + "from": "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz", "resolved": "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz", "dependencies": { "esprima": { "version": "2.7.2", - "from": "esprima@>=2.6.0 <3.0.0", + "from": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" }, "recast": { "version": "0.10.43", - "from": "recast@>=0.10.10 <0.11.0", + "from": "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz", "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz", "dependencies": { "esprima-fb": { "version": "15001.1001.0-dev-harmony-fb", - "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", + "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz", "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" }, "ast-types": { "version": "0.8.15", - "from": "ast-types@0.8.15", + "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz" } } }, "regenerate": { "version": "1.2.1", - "from": "regenerate@>=1.2.1 <2.0.0", + "from": "https://registry.npmjs.org/regenerate/-/regenerate-1.2.1.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.2.1.tgz" }, "regjsgen": { "version": "0.2.0", - "from": "regjsgen@>=0.2.0 <0.3.0", + "from": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz" }, "regjsparser": { "version": "0.1.5", - "from": "regjsparser@>=0.1.4 <0.2.0", + "from": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "dependencies": { "jsesc": { "version": "0.5.0", - "from": "jsesc@>=0.5.0 <0.6.0", + "from": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" } } @@ -1518,17 +1518,17 @@ }, "repeating": { "version": "1.1.3", - "from": "repeating@>=1.1.2 <2.0.0", + "from": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", "dependencies": { "is-finite": { "version": "1.0.1", - "from": "is-finite@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz", "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" } } @@ -1537,37 +1537,37 @@ }, "resolve": { "version": "1.1.7", - "from": "resolve@>=1.1.6 <2.0.0", + "from": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" }, "shebang-regex": { "version": "1.0.0", - "from": "shebang-regex@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" }, "slash": { "version": "1.0.0", - "from": "slash@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz" }, "source-map": { "version": "0.5.3", - "from": "source-map@>=0.5.0 <0.6.0", + "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz" }, "source-map-support": { "version": "0.2.10", - "from": "source-map-support@>=0.2.10 <0.3.0", + "from": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", "dependencies": { "source-map": { "version": "0.1.32", - "from": "source-map@0.1.32", + "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", "dependencies": { "amdefine": { "version": "1.0.0", - "from": "amdefine@>=0.0.4", + "from": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" } } @@ -1576,81 +1576,81 @@ }, "to-fast-properties": { "version": "1.0.2", - "from": "to-fast-properties@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz" }, "trim-right": { "version": "1.0.1", - "from": "trim-right@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz" }, "try-resolve": { "version": "1.0.1", - "from": "try-resolve@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz", "resolved": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz" } } }, "broccoli-persistent-filter": { "version": "1.2.0", - "from": "broccoli-persistent-filter@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.0.tgz", "resolved": "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.0.tgz", "dependencies": { "async-disk-cache": { "version": "1.0.3", - "from": "async-disk-cache@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.0.3.tgz", "resolved": "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.0.3.tgz" }, "blank-object": { "version": "1.0.1", - "from": "blank-object@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/blank-object/-/blank-object-1.0.1.tgz", "resolved": "https://registry.npmjs.org/blank-object/-/blank-object-1.0.1.tgz" }, "broccoli-kitchen-sink-helpers": { "version": "0.3.1", - "from": "broccoli-kitchen-sink-helpers@>=0.3.1 <0.4.0", + "from": "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz", "resolved": "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz", "dependencies": { "glob": { "version": "5.0.15", - "from": "glob@>=5.0.10 <6.0.0", + "from": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "dependencies": { "inflight": { "version": "1.0.4", - "from": "inflight@>=1.0.4 <2.0.0", + "from": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", "dependencies": { "wrappy": { "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "minimatch": { "version": "3.0.0", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", "dependencies": { "brace-expansion": { "version": "1.1.3", - "from": "brace-expansion@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "dependencies": { "balanced-match": { "version": "0.3.0", - "from": "balanced-match@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz" }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", + "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" } } @@ -1659,19 +1659,19 @@ }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", + "from": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "dependencies": { "wrappy": { "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" } } @@ -1680,27 +1680,27 @@ }, "broccoli-plugin": { "version": "1.2.1", - "from": "broccoli-plugin@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.2.1.tgz", "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.2.1.tgz", "dependencies": { "quick-temp": { "version": "0.1.5", - "from": "quick-temp@>=0.1.3 <0.2.0", + "from": "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.5.tgz", "resolved": "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.5.tgz", "dependencies": { "rimraf": { "version": "2.2.8", - "from": "rimraf@>=2.2.6 <2.3.0", + "from": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" }, "mktemp": { "version": "0.3.5", - "from": "mktemp@>=0.3.4 <0.4.0", + "from": "https://registry.npmjs.org/mktemp/-/mktemp-0.3.5.tgz", "resolved": "https://registry.npmjs.org/mktemp/-/mktemp-0.3.5.tgz" }, "underscore.string": { "version": "2.3.3", - "from": "underscore.string@>=2.3.3 <2.4.0", + "from": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz" } } @@ -1709,66 +1709,66 @@ }, "fs-tree-diff": { "version": "0.4.4", - "from": "fs-tree-diff@>=0.4.4 <0.5.0", + "from": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.4.4.tgz", "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.4.4.tgz", "dependencies": { "fast-ordered-set": { "version": "1.0.2", - "from": "fast-ordered-set@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.2.tgz", "resolved": "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.2.tgz" } } }, "hash-for-dep": { "version": "1.0.2", - "from": "hash-for-dep@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.0.2.tgz", "resolved": "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.0.2.tgz", "dependencies": { "broccoli-kitchen-sink-helpers": { "version": "0.2.9", - "from": "broccoli-kitchen-sink-helpers@>=0.2.6 <0.3.0", + "from": "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz", "resolved": "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz", "dependencies": { "glob": { "version": "5.0.15", - "from": "glob@>=5.0.10 <6.0.0", + "from": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "dependencies": { "inflight": { "version": "1.0.4", - "from": "inflight@>=1.0.4 <2.0.0", + "from": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", "dependencies": { "wrappy": { "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "minimatch": { "version": "3.0.0", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", "dependencies": { "brace-expansion": { "version": "1.1.3", - "from": "brace-expansion@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "dependencies": { "balanced-match": { "version": "0.3.0", - "from": "balanced-match@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz" }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", + "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" } } @@ -1777,19 +1777,19 @@ }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", + "from": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "dependencies": { "wrappy": { "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" } } @@ -1798,66 +1798,66 @@ }, "resolve": { "version": "1.1.7", - "from": "resolve@>=1.1.6 <2.0.0", + "from": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" } } }, "md5-hex": { "version": "1.2.1", - "from": "md5-hex@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.2.1.tgz", "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.2.1.tgz", "dependencies": { "md5-o-matic": { "version": "0.1.1", - "from": "md5-o-matic@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz" } } }, "promise-map-series": { "version": "0.2.2", - "from": "promise-map-series@>=0.2.1 <0.3.0", + "from": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.2.tgz", "resolved": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.2.tgz" }, "rsvp": { "version": "3.2.1", - "from": "rsvp@>=3.0.18 <4.0.0", + "from": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz" }, "symlink-or-copy": { "version": "1.0.1", - "from": "symlink-or-copy@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.0.1.tgz" }, "walk-sync": { "version": "0.2.6", - "from": "walk-sync@>=0.2.6 <0.3.0", + "from": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.6.tgz", "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.6.tgz", "dependencies": { "matcher-collection": { "version": "1.0.1", - "from": "matcher-collection@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.1.tgz", "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.1.tgz", "dependencies": { "minimatch": { "version": "2.0.10", - "from": "minimatch@>=2.0.10 <3.0.0", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "dependencies": { "brace-expansion": { "version": "1.1.3", - "from": "brace-expansion@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "dependencies": { "balanced-match": { "version": "0.3.0", - "from": "balanced-match@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz" }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", + "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" } } @@ -1872,54 +1872,54 @@ }, "broccoli-funnel": { "version": "1.0.1", - "from": "broccoli-funnel@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.0.1.tgz", "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.0.1.tgz", "dependencies": { "array-equal": { "version": "1.0.0", - "from": "array-equal@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz" }, "blank-object": { "version": "1.0.1", - "from": "blank-object@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/blank-object/-/blank-object-1.0.1.tgz", "resolved": "https://registry.npmjs.org/blank-object/-/blank-object-1.0.1.tgz" }, "broccoli-plugin": { "version": "1.2.1", - "from": "broccoli-plugin@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.2.1.tgz", "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.2.1.tgz", "dependencies": { "promise-map-series": { "version": "0.2.2", - "from": "promise-map-series@>=0.2.1 <0.3.0", + "from": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.2.tgz", "resolved": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.2.tgz", "dependencies": { "rsvp": { "version": "3.2.1", - "from": "rsvp@>=3.0.14 <4.0.0", + "from": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz" } } }, "quick-temp": { "version": "0.1.5", - "from": "quick-temp@>=0.1.3 <0.2.0", + "from": "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.5.tgz", "resolved": "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.5.tgz", "dependencies": { "rimraf": { "version": "2.2.8", - "from": "rimraf@>=2.2.6 <2.3.0", + "from": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" }, "mktemp": { "version": "0.3.5", - "from": "mktemp@>=0.3.4 <0.4.0", + "from": "https://registry.npmjs.org/mktemp/-/mktemp-0.3.5.tgz", "resolved": "https://registry.npmjs.org/mktemp/-/mktemp-0.3.5.tgz" }, "underscore.string": { "version": "2.3.3", - "from": "underscore.string@>=2.3.3 <2.4.0", + "from": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz" } } @@ -1928,32 +1928,32 @@ }, "fast-ordered-set": { "version": "1.0.2", - "from": "fast-ordered-set@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.2.tgz", "resolved": "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.2.tgz" }, "fs-tree-diff": { "version": "0.3.1", - "from": "fs-tree-diff@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.3.1.tgz", "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.3.1.tgz" }, "minimatch": { "version": "2.0.10", - "from": "minimatch@>=2.0.1 <3.0.0", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "dependencies": { "brace-expansion": { "version": "1.1.3", - "from": "brace-expansion@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", "dependencies": { "balanced-match": { "version": "0.3.0", - "from": "balanced-match@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz" }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", + "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" } } @@ -1962,22 +1962,22 @@ }, "path-posix": { "version": "1.0.0", - "from": "path-posix@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz", "resolved": "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz" }, "symlink-or-copy": { "version": "1.0.1", - "from": "symlink-or-copy@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.0.1.tgz" }, "walk-sync": { "version": "0.2.6", - "from": "walk-sync@>=0.2.6 <0.3.0", + "from": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.6.tgz", "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.6.tgz", "dependencies": { "matcher-collection": { "version": "1.0.1", - "from": "matcher-collection@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.1.tgz", "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.1.tgz" } } @@ -1986,44 +1986,44 @@ }, "broccoli-merge-trees": { "version": "1.1.1", - "from": "broccoli-merge-trees@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.1.1.tgz", "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.1.1.tgz", "dependencies": { "broccoli-plugin": { "version": "1.2.1", - "from": "broccoli-plugin@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.2.1.tgz", "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.2.1.tgz", "dependencies": { "promise-map-series": { "version": "0.2.2", - "from": "promise-map-series@>=0.2.1 <0.3.0", + "from": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.2.tgz", "resolved": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.2.tgz", "dependencies": { "rsvp": { "version": "3.2.1", - "from": "rsvp@>=3.0.14 <4.0.0", + "from": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz" } } }, "quick-temp": { "version": "0.1.5", - "from": "quick-temp@>=0.1.3 <0.2.0", + "from": "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.5.tgz", "resolved": "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.5.tgz", "dependencies": { "rimraf": { "version": "2.2.8", - "from": "rimraf@>=2.2.6 <2.3.0", + "from": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" }, "mktemp": { "version": "0.3.5", - "from": "mktemp@>=0.3.4 <0.4.0", + "from": "https://registry.npmjs.org/mktemp/-/mktemp-0.3.5.tgz", "resolved": "https://registry.npmjs.org/mktemp/-/mktemp-0.3.5.tgz" }, "underscore.string": { "version": "2.3.3", - "from": "underscore.string@>=2.3.3 <2.4.0", + "from": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz" } } @@ -2032,17 +2032,17 @@ }, "can-symlink": { "version": "1.0.0", - "from": "can-symlink@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz", "resolved": "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz", "dependencies": { "tmp": { "version": "0.0.28", - "from": "tmp@0.0.28", + "from": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz", "dependencies": { "os-tmpdir": { "version": "1.0.1", - "from": "os-tmpdir@>=1.0.1 <1.1.0", + "from": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" } } @@ -2051,41 +2051,41 @@ }, "fast-ordered-set": { "version": "1.0.2", - "from": "fast-ordered-set@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.2.tgz", "resolved": "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.2.tgz", "dependencies": { "blank-object": { "version": "1.0.1", - "from": "blank-object@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/blank-object/-/blank-object-1.0.1.tgz", "resolved": "https://registry.npmjs.org/blank-object/-/blank-object-1.0.1.tgz" } } }, "fs-tree-diff": { "version": "0.4.4", - "from": "fs-tree-diff@>=0.4.3 <0.5.0", + "from": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.4.4.tgz", "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.4.4.tgz" }, "symlink-or-copy": { "version": "1.0.1", - "from": "symlink-or-copy@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.0.1.tgz" } } }, "clone": { "version": "0.2.0", - "from": "clone@>=0.2.0 <0.3.0", + "from": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz" }, "json-stable-stringify": { "version": "1.0.1", - "from": "json-stable-stringify@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "dependencies": { "jsonify": { "version": "0.0.0", - "from": "jsonify@>=0.0.0 <0.1.0", + "from": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" } } @@ -5286,16 +5286,16 @@ "from": "abbrev@1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" }, - "ansi-regex": { - "version": "2.0.0", - "from": "ansi-regex@^2.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" - }, "ansi": { "version": "0.3.0", "from": "ansi@~0.3.0", "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz" }, + "ansi-regex": { + "version": "2.0.0", + "from": "ansi-regex@^2.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + }, "ansi-styles": { "version": "2.1.0", "from": "ansi-styles@^2.1.0", @@ -5331,31 +5331,31 @@ "from": "balanced-match@>=0.2.0 <0.3.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz" }, - "boom": { - "version": "2.10.1", - "from": "boom@^2.8.x", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" - }, "block-stream": { "version": "0.0.8", "from": "block-stream@*", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz" }, + "boom": { + "version": "2.10.1", + "from": "boom@^2.8.x", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" + }, "brace-expansion": { "version": "1.1.1", "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz" }, - "chalk": { - "version": "1.1.1", - "from": "chalk@^1.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz" - }, "caseless": { "version": "0.11.0", "from": "caseless@~0.11.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" }, + "chalk": { + "version": "1.1.1", + "from": "chalk@^1.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz" + }, "combined-stream": { "version": "1.0.5", "from": "combined-stream@~1.0.5", @@ -5381,16 +5381,16 @@ "from": "cryptiles@2.x.x", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" }, - "debug": { - "version": "0.7.4", - "from": "debug@~0.7.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz" - }, "ctype": { "version": "0.5.3", "from": "ctype@0.5.3", "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz" }, + "debug": { + "version": "0.7.4", + "from": "debug@~0.7.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz" + }, "deep-extend": { "version": "0.2.11", "from": "deep-extend@~0.2.5", @@ -5446,16 +5446,16 @@ "from": "generate-object-property@^1.1.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz" }, - "graceful-fs": { - "version": "4.1.2", - "from": "graceful-fs@4.1", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz" - }, "graceful-readlink": { "version": "1.0.1", "from": "graceful-readlink@>= 1.0.0", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" }, + "graceful-fs": { + "version": "4.1.2", + "from": "graceful-fs@4.1", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz" + }, "har-validator": { "version": "2.0.2", "from": "har-validator@~2.0.2", @@ -5466,11 +5466,6 @@ "from": "has-ansi@^2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" }, - "has-unicode": { - "version": "1.0.1", - "from": "has-unicode@^1.0.0", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz" - }, "hawk": { "version": "3.1.0", "from": "hawk@~3.1.0", @@ -5486,6 +5481,11 @@ "from": "http-signature@~0.11.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz" }, + "has-unicode": { + "version": "1.0.1", + "from": "has-unicode@^1.0.0", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz" + }, "inherits": { "version": "2.0.1", "from": "inherits@*", @@ -5516,11 +5516,6 @@ "from": "isstream@~0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" }, - "jsonpointer": { - "version": "2.0.0", - "from": "jsonpointer@2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" - }, "json-stringify-safe": { "version": "5.0.1", "from": "json-stringify-safe@~5.0.1", @@ -5531,15 +5526,20 @@ "from": "lodash._basetostring@^3.0.0", "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz" }, + "lodash.pad": { + "version": "3.1.1", + "from": "lodash.pad@^3.0.0", + "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz" + }, "lodash._createpadding": { "version": "3.6.1", "from": "lodash._createpadding@^3.0.0", "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz" }, - "lodash.pad": { - "version": "3.1.1", - "from": "lodash.pad@^3.0.0", - "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz" + "jsonpointer": { + "version": "2.0.0", + "from": "jsonpointer@2.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" }, "lodash.padleft": { "version": "3.1.1", @@ -5556,16 +5556,16 @@ "from": "lodash.repeat@^3.0.0", "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz" }, - "mime-db": { - "version": "1.19.0", - "from": "mime-db@~1.19.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz" - }, "mime-types": { "version": "2.1.7", "from": "mime-types@~2.1.7", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz" }, + "mime-db": { + "version": "1.19.0", + "from": "mime-db@~1.19.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz" + }, "minimist": { "version": "0.0.8", "from": "minimist@0.0.8", @@ -5616,16 +5616,16 @@ "from": "qs@~5.2.0", "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz" }, - "readable-stream": { - "version": "1.1.13", - "from": "readable-stream@^1.1.13", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz" - }, "request": { "version": "2.65.0", "from": "request@2.x", "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz" }, + "readable-stream": { + "version": "1.1.13", + "from": "readable-stream@^1.1.13", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz" + }, "semver": { "version": "5.0.3", "from": "semver@~5.0.1", @@ -5646,16 +5646,16 @@ "from": "stringstream@~0.0.4", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" }, - "strip-json-comments": { - "version": "0.1.3", - "from": "strip-json-comments@0.1.x", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz" - }, "strip-ansi": { "version": "3.0.0", "from": "strip-ansi@^3.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz" }, + "strip-json-comments": { + "version": "0.1.3", + "from": "strip-json-comments@0.1.x", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz" + }, "supports-color": { "version": "2.0.0", "from": "supports-color@^2.0.0", @@ -9694,321 +9694,6 @@ "from": "https://registry.npmjs.org/nvd3/-/nvd3-1.8.1.tgz", "resolved": "https://registry.npmjs.org/nvd3/-/nvd3-1.8.1.tgz" }, - "phantomjs": { - "version": "1.9.18", - "from": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.18.tgz", - "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.18.tgz", - "dependencies": { - "adm-zip": { - "version": "0.4.4", - "from": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz" - }, - "fs-extra": { - "version": "0.23.1", - "from": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.23.1.tgz", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.23.1.tgz", - "dependencies": { - "graceful-fs": { - "version": "4.1.2", - "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz" - }, - "jsonfile": { - "version": "2.2.3", - "from": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.2.3.tgz", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.2.3.tgz" - }, - "path-is-absolute": { - "version": "1.0.0", - "from": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" - } - } - }, - "kew": { - "version": "0.4.0", - "from": "https://registry.npmjs.org/kew/-/kew-0.4.0.tgz", - "resolved": "https://registry.npmjs.org/kew/-/kew-0.4.0.tgz" - }, - "npmconf": { - "version": "2.1.1", - "from": "https://registry.npmjs.org/npmconf/-/npmconf-2.1.1.tgz", - "resolved": "https://registry.npmjs.org/npmconf/-/npmconf-2.1.1.tgz", - "dependencies": { - "config-chain": { - "version": "1.1.9", - "from": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.9.tgz", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.9.tgz", - "dependencies": { - "proto-list": { - "version": "1.2.4", - "from": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" - } - } - }, - "inherits": { - "version": "2.0.1", - "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - }, - "ini": { - "version": "1.3.4", - "from": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz" - }, - "nopt": { - "version": "3.0.6", - "from": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "dependencies": { - "abbrev": { - "version": "1.0.7", - "from": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" - } - } - }, - "once": { - "version": "1.3.3", - "from": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "dependencies": { - "wrappy": { - "version": "1.0.1", - "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" - } - } - }, - "osenv": { - "version": "0.1.3", - "from": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", - "dependencies": { - "os-homedir": { - "version": "1.0.1", - "from": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz" - }, - "os-tmpdir": { - "version": "1.0.1", - "from": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" - } - } - }, - "semver": { - "version": "4.3.6", - "from": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz" - }, - "uid-number": { - "version": "0.0.5", - "from": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz" - } - } - }, - "progress": { - "version": "1.1.8", - "from": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz" - }, - "request": { - "version": "2.42.0", - "from": "https://registry.npmjs.org/request/-/request-2.42.0.tgz", - "resolved": "https://registry.npmjs.org/request/-/request-2.42.0.tgz", - "dependencies": { - "bl": { - "version": "0.9.4", - "from": "https://registry.npmjs.org/bl/-/bl-0.9.4.tgz", - "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.4.tgz", - "dependencies": { - "readable-stream": { - "version": "1.0.33", - "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "from": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "string_decoder": { - "version": "0.10.31", - "from": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - }, - "inherits": { - "version": "2.0.1", - "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - } - } - } - } - }, - "caseless": { - "version": "0.6.0", - "from": "https://registry.npmjs.org/caseless/-/caseless-0.6.0.tgz", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.6.0.tgz" - }, - "forever-agent": { - "version": "0.5.2", - "from": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz" - }, - "qs": { - "version": "1.2.2", - "from": "https://registry.npmjs.org/qs/-/qs-1.2.2.tgz", - "resolved": "https://registry.npmjs.org/qs/-/qs-1.2.2.tgz" - }, - "json-stringify-safe": { - "version": "5.0.1", - "from": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - }, - "mime-types": { - "version": "1.0.2", - "from": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz" - }, - "node-uuid": { - "version": "1.4.7", - "from": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" - }, - "tunnel-agent": { - "version": "0.4.1", - "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz" - }, - "tough-cookie": { - "version": "2.2.1", - "from": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz" - }, - "form-data": { - "version": "0.1.4", - "from": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", - "dependencies": { - "combined-stream": { - "version": "0.0.7", - "from": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "dependencies": { - "delayed-stream": { - "version": "0.0.5", - "from": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz" - } - } - }, - "mime": { - "version": "1.2.11", - "from": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz" - }, - "async": { - "version": "0.9.2", - "from": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" - } - } - }, - "http-signature": { - "version": "0.10.1", - "from": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "dependencies": { - "assert-plus": { - "version": "0.1.5", - "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" - }, - "asn1": { - "version": "0.1.11", - "from": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" - }, - "ctype": { - "version": "0.5.3", - "from": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", - "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz" - } - } - }, - "oauth-sign": { - "version": "0.4.0", - "from": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.4.0.tgz", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.4.0.tgz" - }, - "hawk": { - "version": "1.1.1", - "from": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", - "dependencies": { - "hoek": { - "version": "0.9.1", - "from": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz" - }, - "boom": { - "version": "0.4.2", - "from": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", - "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz" - }, - "cryptiles": { - "version": "0.2.2", - "from": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz" - }, - "sntp": { - "version": "0.2.4", - "from": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz" - } - } - }, - "aws-sign2": { - "version": "0.5.0", - "from": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz" - }, - "stringstream": { - "version": "0.0.5", - "from": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" - } - } - }, - "request-progress": { - "version": "0.3.1", - "from": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", - "dependencies": { - "throttleit": { - "version": "0.0.2", - "from": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz" - } - } - }, - "which": { - "version": "1.0.9", - "from": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz" - } - } - }, "postcss": { "version": "4.1.16", "from": "https://registry.npmjs.org/postcss/-/postcss-4.1.16.tgz", @@ -11540,7 +11225,7 @@ }, "xunit-file": { "version": "0.0.9", - "from": "xunit-file@*", + "from": "https://registry.npmjs.org/xunit-file/-/xunit-file-0.0.9.tgz", "resolved": "https://registry.npmjs.org/xunit-file/-/xunit-file-0.0.9.tgz" } } From f5a0aba47b5f7252c9836af8141e25bbe67e818c Mon Sep 17 00:00:00 2001 From: Ken Hoes Date: Wed, 25 May 2016 15:15:05 -0400 Subject: [PATCH 016/584] Updated audit items --- awx/ui/client/legacy-styles/ansible-ui.less | 4 ++ awx/ui/client/legacy-styles/forms.less | 8 +++- .../permissionsTeams.list.js | 4 +- .../permissionsUsers.list.js | 1 + awx/ui/client/src/app.js | 8 ++++ .../graphs/dashboard-graphs.block.less | 1 + awx/ui/client/src/forms/Credentials.js | 2 +- awx/ui/client/src/forms/JobTemplates.js | 2 +- awx/ui/client/src/forms/Projects.js | 8 ++-- awx/ui/client/src/forms/Teams.js | 5 ++- awx/ui/client/src/forms/Users.js | 1 + .../host-summary/host-summary.partial.html | 4 +- .../src/job-detail/job-detail.block.less | 22 +++++++++- .../src/job-detail/job-detail.controller.js | 14 +------ .../src/job-detail/job-detail.partial.html | 18 ++++---- awx/ui/client/src/lists/CompletedJobs.js | 1 + awx/ui/client/src/lists/ScheduledJobs.js | 1 + .../src/main-menu/main-menu.partial.html | 4 +- .../management-jobs/card/mgmtcards.block.less | 42 ++----------------- .../notificationTemplates.form.js | 3 +- .../notificationTemplates.list.js | 1 + .../src/notifications/notifications.list.js | 1 + awx/ui/client/src/partials/jobs.html | 2 +- .../src/portal-mode/portal-mode.route.js | 4 +- awx/ui/client/src/scheduler/main.js | 15 +++++-- .../src/scheduler/schedulerForm.partial.html | 6 +-- awx/ui/client/src/search/tagSearch.block.less | 1 - awx/ui/client/src/setup-menu/setup.route.js | 2 +- awx/ui/client/src/shared/Modal.js | 2 +- .../src/shared/branding/colors.default.less | 2 +- awx/ui/client/src/shared/form-generator.js | 6 ++- 31 files changed, 104 insertions(+), 91 deletions(-) diff --git a/awx/ui/client/legacy-styles/ansible-ui.less b/awx/ui/client/legacy-styles/ansible-ui.less index 0d0bfc9928..862bdc8b1d 100644 --- a/awx/ui/client/legacy-styles/ansible-ui.less +++ b/awx/ui/client/legacy-styles/ansible-ui.less @@ -962,6 +962,10 @@ input[type="checkbox"].checkbox-no-label { .checkbox-inline, .radio-inline { margin-right: 10px; } + + .checkbox-inline.stack-inline { + display: block; + } } .checkbox-options { diff --git a/awx/ui/client/legacy-styles/forms.less b/awx/ui/client/legacy-styles/forms.less index a54c0c6aed..e04e43860d 100644 --- a/awx/ui/client/legacy-styles/forms.less +++ b/awx/ui/client/legacy-styles/forms.less @@ -178,7 +178,7 @@ .Form-formGroup--checkbox{ display: flex; - align-items: flex-end; + align-items: flex-start; } .Form-subForm { @@ -324,6 +324,12 @@ .select2-dropdown{ border:1px solid @field-border; + +} + +.select2-container--open .select2-dropdown--below { + margin-top: -1px; + border-top: 1px solid @field-border; } .Form-dropDown:focus{ diff --git a/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsTeams.list.js b/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsTeams.list.js index dc30bfbaf5..61b1c3de46 100644 --- a/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsTeams.list.js +++ b/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsTeams.list.js @@ -15,13 +15,13 @@ multiSelectExtended: true, index: false, hover: true, - + emptyListText : 'No Teams exist', fields: { name: { key: true, label: 'name' }, - }, + } }; } diff --git a/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsUsers.list.js b/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsUsers.list.js index ced865e944..c08c45e352 100644 --- a/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsUsers.list.js +++ b/awx/ui/client/src/access/addPermissions/addPermissionsList/permissionsUsers.list.js @@ -16,6 +16,7 @@ multiSelectExtended: true, index: false, hover: true, + emptyListText : 'No Users exist', fields: { first_name: { diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 1fbd283e79..ac24f5902c 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -297,6 +297,10 @@ var tower = angular.module('Tower', [ controller: ProjectsEdit, data: { activityStreamId: 'id' + }, + ncyBreadcrumb: { + parent: 'projects', + label: 'EDIT PROJECT' } }). state('projectOrganizations', { @@ -340,6 +344,10 @@ var tower = angular.module('Tower', [ controller: TeamsEdit, data: { activityStreamId: 'team_id' + }, + ncyBreadcrumb: { + parent: "teams", + label: "EDIT TEAM" } }). diff --git a/awx/ui/client/src/dashboard/graphs/dashboard-graphs.block.less b/awx/ui/client/src/dashboard/graphs/dashboard-graphs.block.less index 8abd237d0d..e2674b8c6f 100644 --- a/awx/ui/client/src/dashboard/graphs/dashboard-graphs.block.less +++ b/awx/ui/client/src/dashboard/graphs/dashboard-graphs.block.less @@ -118,6 +118,7 @@ top: auto; box-shadow: none; text-transform: uppercase; + cursor: pointer; } .DashboardGraphs-periodDropdown, diff --git a/awx/ui/client/src/forms/Credentials.js b/awx/ui/client/src/forms/Credentials.js index 655b28e416..b31c3bed68 100644 --- a/awx/ui/client/src/forms/Credentials.js +++ b/awx/ui/client/src/forms/Credentials.js @@ -246,7 +246,7 @@ export default rows: 10, awPopOver: "SSH key description", awPopOverWatch: "key_description", - dataTitle: 'Help', + dataTitle: 'Private Key', dataPlacement: 'right', dataContainer: "body", subForm: "credentialSubForm" diff --git a/awx/ui/client/src/forms/JobTemplates.js b/awx/ui/client/src/forms/JobTemplates.js index cc82057048..ad8d8c50f1 100644 --- a/awx/ui/client/src/forms/JobTemplates.js +++ b/awx/ui/client/src/forms/JobTemplates.js @@ -204,7 +204,7 @@ export default }, job_tags: { label: 'Job Tags', - type: 'textarea', + type: 'text', rows: 1, addRequired: false, editRequired: false, diff --git a/awx/ui/client/src/forms/Projects.js b/awx/ui/client/src/forms/Projects.js index 7b01537ff6..a57e73dd25 100644 --- a/awx/ui/client/src/forms/Projects.js +++ b/awx/ui/client/src/forms/Projects.js @@ -174,7 +174,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition']) dataTitle: 'SCM Clean', dataContainer: 'body', dataPlacement: 'right', - labelClass: 'checkbox-options' + labelClass: 'checkbox-options stack-inline' }, { name: 'scm_delete_on_update', label: 'Delete on Update', @@ -186,7 +186,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition']) dataTitle: 'SCM Delete', dataContainer: 'body', dataPlacement: 'right', - labelClass: 'checkbox-options' + labelClass: 'checkbox-options stack-inline' }, { name: 'scm_update_on_launch', label: 'Update on Launch', @@ -197,7 +197,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition']) dataTitle: 'SCM Update', dataContainer: 'body', dataPlacement: 'right', - labelClass: 'checkbox-options' + labelClass: 'checkbox-options stack-inline' }] }, scm_update_cache_timeout: { @@ -273,7 +273,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition']) } }, notifications: { - include: "NotificationsList" + include: "NotificationsList", } }, diff --git a/awx/ui/client/src/forms/Teams.js b/awx/ui/client/src/forms/Teams.js index 7992cc38f2..3bea1a81cb 100644 --- a/awx/ui/client/src/forms/Teams.js +++ b/awx/ui/client/src/forms/Teams.js @@ -132,9 +132,10 @@ export default "delete": { label: 'Remove', ngClick: 'deletePermissionFromTeam(team_id, team_obj.name, role.name, role.summary_fields.resource_name, role.related.teams)', - class: "List-actionButton--delete", + 'class': "List-actionButton--delete", iconClass: 'fa fa-times', - awToolTip: 'Dissasociate permission from team' + awToolTip: 'Dissasociate permission from team', + dataPlacement: 'top' } }, hideOnSuperuser: true diff --git a/awx/ui/client/src/forms/Users.js b/awx/ui/client/src/forms/Users.js index 9ae8cde69f..febc6b8ddb 100644 --- a/awx/ui/client/src/forms/Users.js +++ b/awx/ui/client/src/forms/Users.js @@ -138,6 +138,7 @@ export default iterator: 'team', open: false, index: false, + suppressEmptyText: true, actions: {}, diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html b/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html index 546772ffc0..bd86709075 100644 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html @@ -13,7 +13,7 @@
-