From 007f33c1860e5a611bf9fcb2f64da31b4432c6dc Mon Sep 17 00:00:00 2001 From: Alex Corey Date: Fri, 23 Aug 2019 09:51:55 -0400 Subject: [PATCH] Add Container Group Form Render and cred type modal pops up modal render proper cred WIP modal rendering properly card for edit CG renders, no fields add code mirror and some list styling address PR issues --- awx/ui/client/legacy/styles/forms.less | 3 + .../lib/components/input/lookup.directive.js | 3 - awx/ui/client/lib/components/list/_index.less | 4 + .../add-container-group.controller.js | 62 +++++ .../add-container-group.view.html | 22 ++ .../edit-container-group.controller.js | 65 ++++++ .../instance-groups/instance-group.block.less | 9 + .../instance-groups.partial.html | 2 + .../instance-groups.strings.js | 19 +- .../list/instance-groups-list.partial.html | 119 ++++++---- awx/ui/client/src/instance-groups/main.js | 211 +++++++++++++++++- .../shared/lookup/lookup-modal.directive.js | 4 +- 12 files changed, 455 insertions(+), 68 deletions(-) create mode 100644 awx/ui/client/src/instance-groups/container-groups/add-container-group.controller.js create mode 100644 awx/ui/client/src/instance-groups/container-groups/add-container-group.view.html create mode 100644 awx/ui/client/src/instance-groups/container-groups/edit-container-group.controller.js diff --git a/awx/ui/client/legacy/styles/forms.less b/awx/ui/client/legacy/styles/forms.less index f36914df31..cb8e9c726e 100644 --- a/awx/ui/client/legacy/styles/forms.less +++ b/awx/ui/client/legacy/styles/forms.less @@ -209,6 +209,9 @@ width: 100% !important; padding-right: 0px !important; } +.containerGroups-codeMirror{ + margin: 20px; +} .Form-formGroup--checkbox{ display: flex; diff --git a/awx/ui/client/lib/components/input/lookup.directive.js b/awx/ui/client/lib/components/input/lookup.directive.js index 13632d8eb3..43810d1796 100644 --- a/awx/ui/client/lib/components/input/lookup.directive.js +++ b/awx/ui/client/lib/components/input/lookup.directive.js @@ -88,17 +88,14 @@ function AtInputLookupController (baseInputController, $q, $state) { scope.state._value = null; return vm.check({ isValid: true }); } - searchParams = searchParams || { [search.key]: scope.state._displayValue }; return model.search(searchParams, search.config) .then(found => { if (!found) { vm.reset(); - return; } - scope[scope.state._resource] = model.get('id'); scope.state._value = model.get('id'); scope.state._displayValue = model.get('name'); diff --git a/awx/ui/client/lib/components/list/_index.less b/awx/ui/client/lib/components/list/_index.less index 48d7bdb2b9..b84d220809 100644 --- a/awx/ui/client/lib/components/list/_index.less +++ b/awx/ui/client/lib/components/list/_index.less @@ -241,6 +241,10 @@ align-items: center; } +.at-Row-rightSide{ + justify-content: flex-end; +} + .at-Row-container--wrapped { display: flex; flex-wrap: wrap; diff --git a/awx/ui/client/src/instance-groups/container-groups/add-container-group.controller.js b/awx/ui/client/src/instance-groups/container-groups/add-container-group.controller.js new file mode 100644 index 0000000000..094d390071 --- /dev/null +++ b/awx/ui/client/src/instance-groups/container-groups/add-container-group.controller.js @@ -0,0 +1,62 @@ +function AddContainerGroupController(ToJSON, $scope, $state, models, strings, i18n, DataSet) { + const vm = this || {}; + const { + instanceGroup, + credential + } = models; + + vm.mode = 'add'; + vm.strings = strings; + vm.panelTitle = strings.get('state.ADD_CONTAINER_GROUP_BREADCRUMB_LABEL'); + vm.lookUpTitle = strings.get('container.LOOK_UP_TITLE'); + + vm.form = instanceGroup.createFormSchema('post'); + vm.form.name.required = true; + + vm.form.credential = { + type: 'field', + label: i18n._('Credential'), + id: 'credential' + }; + vm.form.credential._resource = 'credential'; + vm.form.credential._route = "instanceGroups.addContainerGroup.credentials"; + vm.form.credential._model = credential; + vm.form.credential._placeholder = strings.get('container.CREDENTIAL_PLACEHOLDER'); + vm.form.credential.required = true; + + vm.form.extraVars = { + label: strings.get('container.POD_SPEC_LABEL'), + value: DataSet.data.actions.POST.pod_spec_override.default, + name: 'extraVars' + }; + + $scope.variables = vm.form.extraVars.value; + $scope.name = vm.form.extraVars.name; + vm.panelTitle = strings.get('container.PANEL_TITLE'); + + + $scope.$watch('credential', () => { + if ($scope.credential) { + vm.form.credential._idFromModal= $scope.credential; + } + }); + vm.form.save = (data) => { + data.pod_spec_override = vm.form.extraVars.value; + return instanceGroup.request('post', { data: data }).then((res) => { + $state.go('instanceGroups.editContainerGroup', { instance_group_id: res.data.id }, { reload: true }); + }); + }; +} + + +AddContainerGroupController.$inject = [ + 'ToJSON', + '$scope', + '$state', + 'resolvedModels', + 'InstanceGroupsStrings', + 'i18n', + 'DataSet' +]; + +export default AddContainerGroupController; diff --git a/awx/ui/client/src/instance-groups/container-groups/add-container-group.view.html b/awx/ui/client/src/instance-groups/container-groups/add-container-group.view.html new file mode 100644 index 0000000000..1d7f779487 --- /dev/null +++ b/awx/ui/client/src/instance-groups/container-groups/add-container-group.view.html @@ -0,0 +1,22 @@ +
+ + + + + + + + + + + + + + + diff --git a/awx/ui/client/src/instance-groups/container-groups/edit-container-group.controller.js b/awx/ui/client/src/instance-groups/container-groups/edit-container-group.controller.js new file mode 100644 index 0000000000..463b289947 --- /dev/null +++ b/awx/ui/client/src/instance-groups/container-groups/edit-container-group.controller.js @@ -0,0 +1,65 @@ +function EditContainerGroupController($rootScope, $scope, $state, models, strings, i18n, EditContainerGroupDataset) { + + const vm = this || {}; + const { + instanceGroup, + credential + } = models; + $rootScope.breadcrumb.instance_group_name = instanceGroup.get('name'); + + vm.mode = 'add'; + vm.strings = strings; + vm.panelTitle = EditContainerGroupDataset.data.name; + vm.lookUpTitle = strings.get('container.LOOK_UP_TITLE'); + + vm.form = instanceGroup.createFormSchema('post'); + vm.form.name.required = true; + vm.form.credential = { + type: 'field', + label: i18n._('Credential'), + id: 'credential' + }; + vm.form.credential._resource = 'credential'; + vm.form.credential._route = "instanceGroups.editContainerGroup.credentials"; + vm.form.credential._model = credential; + vm.form.credential._displayValue = EditContainerGroupDataset.data.summary_fields.credential.name; + vm.form.credential.required = true; + vm.form.credential._value = EditContainerGroupDataset.data.summary_fields.credential.id; + vm.podSpec = { + type: 'textarea', + id: 'pod_spec' + }; + + vm.podSpec.label = strings.get('container.POD_SPEC_LABEL'); + + vm.form.extraVars = { + label: strings.get('container.POD_SPEC_LABEL'), + value: EditContainerGroupDataset.data.pod_spec_override, + name: 'extraVars' + }; + + $scope.$watch('credential', () => { + if ($scope.credential) { + vm.form.credential._idFromModal= $scope.credential; + } + }); + vm.form.save = (data) => { + data.pod_spec_override = vm.form.extraVars.value; + return instanceGroup.request('put', { data: data }).then((res) => { + $state.go('instanceGroups.editContainerGroup', { instance_group_id: res.data.id }, { reload: true }); + } ); + + }; +} + +EditContainerGroupController.$inject = [ + '$rootScope', + '$scope', + '$state', + 'resolvedModels', + 'InstanceGroupsStrings', + 'i18n', + 'EditContainerGroupDataset' +]; + +export default EditContainerGroupController; diff --git a/awx/ui/client/src/instance-groups/instance-group.block.less b/awx/ui/client/src/instance-groups/instance-group.block.less index ec5279eb8d..eedfd05e94 100644 --- a/awx/ui/client/src/instance-groups/instance-group.block.less +++ b/awx/ui/client/src/instance-groups/instance-group.block.less @@ -1,4 +1,8 @@ .InstanceGroups { + .at-Row-actions{ + width: 700px; + justify-content: flex-end; + } .BreadCrumb-menuLinkImage:hover { color: @default-link; @@ -75,3 +79,8 @@ } } } +.at-Row-links { +justify-content: flex-end; +display: flex; +flex-grow: 1; +} diff --git a/awx/ui/client/src/instance-groups/instance-groups.partial.html b/awx/ui/client/src/instance-groups/instance-groups.partial.html index 562676ffdc..7bec7b2624 100644 --- a/awx/ui/client/src/instance-groups/instance-groups.partial.html +++ b/awx/ui/client/src/instance-groups/instance-groups.partial.html @@ -2,6 +2,8 @@
+
+
diff --git a/awx/ui/client/src/instance-groups/instance-groups.strings.js b/awx/ui/client/src/instance-groups/instance-groups.strings.js index ad4fff924b..2f3d9865ab 100644 --- a/awx/ui/client/src/instance-groups/instance-groups.strings.js +++ b/awx/ui/client/src/instance-groups/instance-groups.strings.js @@ -1,13 +1,16 @@ -function InstanceGroupsStrings (BaseString) { +function InstanceGroupsStrings(BaseString) { BaseString.call(this, 'instanceGroups'); - const { t } = this; + const { + t + } = this; const ns = this.instanceGroups; ns.state = { INSTANCE_GROUPS_BREADCRUMB_LABEL: t.s('INSTANCE GROUPS'), INSTANCES_BREADCRUMB_LABEL: t.s('INSTANCES'), - ADD_BREADCRUMB_LABEL: t.s('CREATE INSTANCE GROUP') + ADD_BREADCRUMB_LABEL: t.s('CREATE INSTANCE GROUP'), + ADD_CONTAINER_GROUP_BREADCRUMB_LABEL: t.s('CREATE CONTAINER GROUP') }; ns.list = { @@ -33,7 +36,8 @@ function InstanceGroupsStrings (BaseString) { }; ns.instance = { - PANEL_TITLE: t.s('SELECT INSTANCE') + PANEL_TITLE: t.s('SELECT INSTANCE'), + BADGE_TEXT: t.s('Instance Group') }; ns.capacityBar = { @@ -62,6 +66,13 @@ function InstanceGroupsStrings (BaseString) { ns.alert = { MISSING_PARAMETER: t.s('Instance Group parameter is missing.'), }; + ns.container = { + PANEL_TITLE: t.s('Add Container Group'), + LOOK_UP_TITLE: t.s('Add Credential'), + CREDENTIAL_PLACEHOLDER: t.s('SELECT A CREDENTIAL'), + POD_SPEC_LABEL: t.s('Pod Spec Override'), + BADGE_TEXT: t.s('Container Group') + }; } InstanceGroupsStrings.$inject = ['BaseStringService']; diff --git a/awx/ui/client/src/instance-groups/list/instance-groups-list.partial.html b/awx/ui/client/src/instance-groups/list/instance-groups-list.partial.html index 2a3314ed3b..cac555dbb0 100644 --- a/awx/ui/client/src/instance-groups/list/instance-groups-list.partial.html +++ b/awx/ui/client/src/instance-groups/list/instance-groups-list.partial.html @@ -18,19 +18,20 @@ search-tags="searchTags">
- +
+ - + ng-class="{'at-Row--active': (instance_group.id === vm.activeId)}" >
- - - -
- - - - - - +
+
+ + + + +
+
+
+ {{vm.strings.get('container.BADGE_TEXT') }} +
+
+
+
+
+
+ {{vm.strings.get('instance.BADGE_TEXT') }} +
+
+
+
+ +
+ + + +
- -
- - - -
diff --git a/awx/ui/client/src/instance-groups/main.js b/awx/ui/client/src/instance-groups/main.js index bfd33a9c55..78858592f1 100644 --- a/awx/ui/client/src/instance-groups/main.js +++ b/awx/ui/client/src/instance-groups/main.js @@ -1,5 +1,10 @@ -import { templateUrl } from '../shared/template-url/template-url.factory'; +import { + templateUrl +} from '../shared/template-url/template-url.factory'; import CapacityAdjuster from './capacity-adjuster/capacity-adjuster.directive'; +import AddContainerGroup from './container-groups/add-container-group.view.html'; +import EditContainerGroupController from './container-groups/edit-container-group.controller'; +import AddContainerGroupController from './container-groups/add-container-group.controller'; import CapacityBar from './capacity-bar/capacity-bar.directive'; import instanceGroupsMultiselect from '../shared/instance-groups-multiselect/instance-groups.directive'; import instanceGroupsModal from '../shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive'; @@ -25,34 +30,55 @@ import InstanceGroupsStrings from './instance-groups.strings'; import instanceGroupJobsRoute from '~features/jobs/routes/instanceGroupJobs.route.js'; import instanceJobsRoute from '~features/jobs/routes/instanceJobs.route.js'; + const MODULE_NAME = 'instanceGroups'; -function InstanceGroupsResolve ($q, $stateParams, InstanceGroup, Instance, ProcessErrors, strings) { +function InstanceGroupsResolve($q, $stateParams, InstanceGroup, Credential, Instance, ProcessErrors, strings) { const instanceGroupId = $stateParams.instance_group_id; const instanceId = $stateParams.instance_id; let promises = {}; if (!instanceGroupId && !instanceId) { promises.instanceGroup = new InstanceGroup(['get', 'options']); + promises.credential = new Credential(['get', 'options']); return $q.all(promises); } if (instanceGroupId && instanceId) { promises.instance = new Instance(['get', 'options'], [instanceId, instanceId]) - .then((instance) => instance.extend('get', 'jobs', {params: {page_size: "10", order_by: "-finished"}})); + .then((instance) => instance.extend('get', 'jobs', { + params: { + page_size: "10", + order_by: "-finished" + } + })); return $q.all(promises); } promises.instanceGroup = new InstanceGroup(['get', 'options'], [instanceGroupId, instanceGroupId]) - .then((instanceGroup) => instanceGroup.extend('get', 'jobs', {params: {page_size: "10", order_by: "-finished"}})) - .then((instanceGroup) => instanceGroup.extend('get', 'instances')); + .then((instanceGroup) => instanceGroup.extend('get', 'jobs', { + params: { + page_size: "10", + order_by: "-finished" + } + })) + .then((instanceGroup) => instanceGroup.extend('get', 'instances')); + + promises.credential = new Credential(); return $q.all(promises) .then(models => models) - .catch(({ data, status, config }) => { + .catch(({ + data, + status, + config + }) => { ProcessErrors(null, data, status, null, { hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', { path: `${config.url}`, status }) + msg: strings.get('error.CALL', { + path: `${config.url}`, + status + }) }); return $q.reject(); }); @@ -62,12 +88,13 @@ InstanceGroupsResolve.$inject = [ '$q', '$stateParams', 'InstanceGroupModel', + 'CredentialModel', 'InstanceModel', 'ProcessErrors', 'InstanceGroupsStrings' ]; -function InstanceGroupsRun ($stateExtender, strings) { +function InstanceGroupsRun($stateExtender, strings) { $stateExtender.addState({ name: 'instanceGroups', url: '/instance_groups', @@ -100,7 +127,7 @@ function InstanceGroupsRun ($stateExtender, strings) { resolve: { resolvedModels: InstanceGroupsResolve, Dataset: ['InstanceGroupList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { + function (list, qs, $stateParams, GetBasePath) { let path = GetBasePath(list.basePath) || GetBasePath(list.name); return qs.search(path, $stateParams[`${list.iterator}_search`]); } @@ -143,6 +170,165 @@ function InstanceGroupsRun ($stateExtender, strings) { ] } }); + $stateExtender.addState({ + name: 'instanceGroups.addContainerGroup', + url: '/container_group', + views: { + 'addContainerGroup@instanceGroups': { + templateUrl: AddContainerGroup, + controller: AddContainerGroupController, + controllerAs: 'vm' + } + }, + resolve: { + resolvedModels: InstanceGroupsResolve, + DataSet: ['Rest', 'GetBasePath', (Rest, GetBasePath) => { + Rest.setUrl(`${GetBasePath('instance_groups')}`); + return Rest.options(); + }] + }, + ncyBreadcrumb: { + label: strings.get('state.ADD_CONTAINER_GROUP_BREADCRUMB_LABEL') + }, + }); + + $stateExtender.addState({ + name: 'instanceGroups.addContainerGroup.credentials', + url: '/credential?selected', + searchPrefix: 'credential', + params: { + credential_search: { + value: { + order_by: 'name', + page_size: 5, + }, + dynamic: true, + squash: '' + } + }, + data: { + basePath: 'credentials', + formChildState: true + }, + ncyBreadcrumb: { + skip: true + }, + views: { + 'credentials@instanceGroups.addContainerGroup': { + templateProvider: (ListDefinition, generateList) => { + const html = generateList.build({ + mode: 'lookup', + list: ListDefinition, + input_type: 'radio' + }); + return `${html}`; + } + } + }, + resolve: { + ListDefinition: ['CredentialList', list => list], + Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => { + const params = { + credential_type__kind: 'kubernetes', + }; + const searchPath = GetBasePath('credentials'); + return qs.search( + searchPath, params, + $stateParams[`${list.iterator}_search`] + ); + }] + }, + onExit ($state) { + if ($state.transition) { + $('#form-modal').modal('hide'); + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } + } + }); + + + + + $stateExtender.addState({ + name: 'instanceGroups.editContainerGroup', + url: '/container_group/edit/:instance_group_id', + views: { + 'editContainerGroup@instanceGroups': { + templateUrl: AddContainerGroup, + controller: EditContainerGroupController, + controllerAs: 'vm' + } + }, + resolve: { + resolvedModels: InstanceGroupsResolve, + EditContainerGroupDataset: ['GetBasePath', 'QuerySet', '$stateParams', + function (GetBasePath, qs, $stateParams) { + let path = `${GetBasePath('instance_groups')}${$stateParams.instance_group_id}`; + return qs.search(path, $stateParams); + } + ], + }, + ncyBreadcrumb: { + label: '{{breadcrumb.instance_group_name}}' + }, + }); + + $stateExtender.addState({ + name: 'instanceGroups.editContainerGroup.credentials', + url: '/credential?selected', + searchPrefix: 'credential', + params: { + credential_search: { + value: { + order_by: 'name', + page_size: 5, + }, + dynamic: true, + squash: '' + } + }, + data: { + basePath: 'credentials', + formChildState: true + }, + views: { + 'credentials@instanceGroups.editContainerGroup': { + templateProvider: (ListDefinition, generateList) => { + const html = generateList.build({ + mode: 'lookup', + list: ListDefinition, + input_type: 'radio' + }); + return `${html}`; + } + } + }, + resolve: { + ListDefinition: ['CredentialList', list => list], + Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => { + const params = { + credential_type__kind: 'kubernetes', + }; + const searchPath = GetBasePath('credentials'); + return qs.search( + searchPath, params, + $stateParams[`${list.iterator}_search`] + ); + }] + }, + onExit ($state) { + if ($state.transition) { + $('#form-modal').modal('hide'); + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } + } + }); + + + + $stateExtender.addState({ name: 'instanceGroups.edit', @@ -207,7 +393,7 @@ function InstanceGroupsRun ($stateExtender, strings) { resolve: { resolvedModels: InstanceGroupsResolve, Dataset: ['GetBasePath', 'QuerySet', '$stateParams', - function(GetBasePath, qs, $stateParams) { + function (GetBasePath, qs, $stateParams) { let path = `${GetBasePath('instance_groups')}${$stateParams.instance_group_id}/instances`; return qs.search(path, $stateParams[`instance_search`]); } @@ -255,7 +441,7 @@ function InstanceGroupsRun ($stateExtender, strings) { resolve: { resolvedModels: InstanceGroupsResolve, Dataset: ['GetBasePath', 'QuerySet', '$stateParams', - function(GetBasePath, qs, $stateParams) { + function (GetBasePath, qs, $stateParams) { let path = `${GetBasePath('instances')}`; return qs.search(path, $stateParams[`add_instance_search`]); } @@ -269,7 +455,8 @@ function InstanceGroupsRun ($stateExtender, strings) { InstanceGroupsRun.$inject = [ '$stateExtender', - 'InstanceGroupsStrings' + 'InstanceGroupsStrings', + 'Rest' ]; angular.module(MODULE_NAME, []) diff --git a/awx/ui/client/src/shared/lookup/lookup-modal.directive.js b/awx/ui/client/src/shared/lookup/lookup-modal.directive.js index bfc362a257..cee16d2e1c 100644 --- a/awx/ui/client/src/shared/lookup/lookup-modal.directive.js +++ b/awx/ui/client/src/shared/lookup/lookup-modal.directive.js @@ -74,7 +74,7 @@ export default ['templateUrl', 'i18n', function(templateUrl, i18n) { } } - $scope.saveForm = function() { + $scope.saveForm = function () { eventService.remove(listeners); let list = $scope.list; if($scope.currentSelection.name !== null) { @@ -89,7 +89,7 @@ export default ['templateUrl', 'i18n', function(templateUrl, i18n) { $state.go('^'); }; - $scope.toggle_row = function(selectedRow) { + $scope.toggle_row = function (selectedRow) { let list = $scope.list; let count = 0; $scope[list.name].forEach(function(row) {