From 8b91b16beac4f24e578fa76924ace57cc54c910c Mon Sep 17 00:00:00 2001 From: gconsidine Date: Tue, 16 May 2017 17:00:49 -0400 Subject: [PATCH] Add working dynamic component insertion --- .../credentials/add-credentials.controller.js | 4 +- .../credentials/add-credentials.view.html | 3 +- .../dynamic/input-group.directive.js | 82 +++++++++++++++++-- .../dynamic/input-group.partial.html | 2 - .../lib/components/form/action.directive.js | 1 - .../lib/components/form/form.directive.js | 62 ++++++-------- .../lib/components/input/select.directive.js | 6 +- .../lib/components/input/select.partial.html | 3 +- .../lib/components/input/text.directive.js | 4 - .../lib/components/input/text.partial.html | 5 +- awx/ui/client/lib/models/CredentialType.js | 57 ++++++++----- 11 files changed, 144 insertions(+), 85 deletions(-) diff --git a/awx/ui/client/features/credentials/add-credentials.controller.js b/awx/ui/client/features/credentials/add-credentials.controller.js index a1925811ac..05d9c4ce89 100644 --- a/awx/ui/client/features/credentials/add-credentials.controller.js +++ b/awx/ui/client/features/credentials/add-credentials.controller.js @@ -23,7 +23,9 @@ function AddCredentialsController (models) { }; vm.dynamic = { - model: credential + getInputs: credentialType.getTypeFromName, + source: vm.kind, + reference: 'vm.dynamic' }; } diff --git a/awx/ui/client/features/credentials/add-credentials.view.html b/awx/ui/client/features/credentials/add-credentials.view.html index 056394743e..64850ec4b6 100644 --- a/awx/ui/client/features/credentials/add-credentials.view.html +++ b/awx/ui/client/features/credentials/add-credentials.view.html @@ -12,8 +12,7 @@ - - + diff --git a/awx/ui/client/lib/components/dynamic/input-group.directive.js b/awx/ui/client/lib/components/dynamic/input-group.directive.js index 014d032dea..0f6fb05d76 100644 --- a/awx/ui/client/lib/components/dynamic/input-group.directive.js +++ b/awx/ui/client/lib/components/dynamic/input-group.directive.js @@ -1,36 +1,100 @@ function link (scope, el, attrs, controllers) { - let dynamicController = controllers[0]; + let formController = controllers[0]; + let dynamicController = controllers[1]; + el = el[0]; - dynamicController.init(scope); + dynamicController.init(scope, formController, el); } -function atDynamicInputGroupController () { +function atDynamicInputGroupController ($scope, $compile) { let vm = this || {}; let state; let scope; - let input; + let source; let form; + let el; - vm.init = (_scope_) => { + vm.init = (_scope_, _form_, _el_) => { + form = _form_; scope = _scope_; - console.log(scope.watch); - // scope.form = form.use('input', state); + el = _el_; + + scope.config.state = scope.config.state || {}; + state = scope.config.state; + source = scope.config.source; + + $scope.$watch('config.source.state.value', vm.update); + }; + + vm.update = () => { + if (!source.state.value || source.state.value === state.value) { + return; + } + + state.value = source.state.value; + + let inputs = scope.config.getInputs(source.state.value); + let components = vm.createComponentConfigs(inputs); + + vm.insert(components); + scope.config.components = components; + vm.compile(components); + }; + + vm.createComponentConfigs = inputs => { + let components = []; + + inputs.forEach((input, i) => { + if (input.type === 'string') { + if (input.secret) { + input.component = 'at-input-secret'; + } else if (input.multiline) { + input.component = 'at-input-textarea'; + } else { + input.component = 'at-input-text'; + } + } + + let html = angular.element(` + <${input.component} + col="${scope.col}" + config="${scope.config.reference}.components[${i}]"> + + `); + + components.push({ + options: input, + html + }); + }); + + return components; + }; + + vm.insert = components => { + components.forEach(component => el.appendChild(component.html[0])); + }; + + vm.compile = components => { + components.forEach(component => $compile(component.html[0])(scope.$parent)); }; } +atDynamicInputGroupController.$inject = ['$scope', '$compile']; + function atDynamicInputGroup (pathService) { return { restrict: 'E', replace: true, - require: ['atDynamicInputGroup'], + require: ['^^atForm', 'atDynamicInputGroup'], templateUrl: pathService.getPartialPath('components/dynamic/input-group'), controller: atDynamicInputGroupController, controllerAs: 'vm', link, scope: { config: '=', - watch: '=' + col: '@' } }; } diff --git a/awx/ui/client/lib/components/dynamic/input-group.partial.html b/awx/ui/client/lib/components/dynamic/input-group.partial.html index d9709b4a71..d58db9e7bf 100644 --- a/awx/ui/client/lib/components/dynamic/input-group.partial.html +++ b/awx/ui/client/lib/components/dynamic/input-group.partial.html @@ -1,4 +1,2 @@
- {{ watch.state.value }} - {{ watch.data[watch.state.value] }}
diff --git a/awx/ui/client/lib/components/form/action.directive.js b/awx/ui/client/lib/components/form/action.directive.js index 0b8cd80f78..04094d6c28 100644 --- a/awx/ui/client/lib/components/form/action.directive.js +++ b/awx/ui/client/lib/components/form/action.directive.js @@ -10,7 +10,6 @@ function atFormActionController ($state) { let form; let scope; - let el; let state; vm.init = (_form_, _scope_) => { diff --git a/awx/ui/client/lib/components/form/form.directive.js b/awx/ui/client/lib/components/form/form.directive.js index 634ea910de..d7559c4381 100644 --- a/awx/ui/client/lib/components/form/form.directive.js +++ b/awx/ui/client/lib/components/form/form.directive.js @@ -1,59 +1,44 @@ function AtFormController () { let vm = this || {}; - vm.inputs = []; - vm.actions = []; + vm.components = []; + vm.state = { isValid: false }; vm.use = (type, component, el) => { - let state; - - switch (type) { - case 'input': - state = vm.trackInput(component, el); - break; - case 'action': - state = vm.trackAction(component, el); - break; - default: - throw new Error('An at-form cannot use component type:', type); - } - - return state; + return vm.trackComponent(type, component, el); }; - vm.trackInput = (input, el) => { - let form = { + vm.trackComponent = (type, component, el) => { + let meta = { + el, + type, state: vm.state, - disabled: false + disabled: false, + tabindex: vm.components.length + 1 }; - vm.inputs.push(input) + if (!vm.components.length) { + el.focus(); + } - return form; - }; + vm.components.push(meta) - vm.trackAction = action => { - let form = { - state: vm.state, - disabled: false - }; - - vm.actions.push(action); - - return form; + return meta; }; vm.validate = () => { let isValid = true; - vm.inputs.forEach(input => { - if (!input.isValid) { - isValid = false; - } - }); + vm.components + .filter(component => component.type === 'input') + .forEach(input => { + if (input.isValid) { + isValid = false; + } + }); return isValid; }; @@ -71,6 +56,10 @@ function AtFormController () { }; } +function link (scope, el, attrs, controller, fn) { + //console.log(fn); +} + function atForm (pathService) { return { restrict: 'E', @@ -78,6 +67,7 @@ function atForm (pathService) { templateUrl: pathService.getPartialPath('components/form/form'), controller: AtFormController, controllerAs: 'vm', + link, scope: { config: '=' } diff --git a/awx/ui/client/lib/components/input/select.directive.js b/awx/ui/client/lib/components/input/select.directive.js index 766d40c25b..040658dbb4 100644 --- a/awx/ui/client/lib/components/input/select.directive.js +++ b/awx/ui/client/lib/components/input/select.directive.js @@ -25,15 +25,11 @@ function AtInputSelectController (eventService) { scope.config.state = scope.config.state || {}; state = scope.config.state; - if (scope.tab === 1) { - select.focus(); - } - state.isValid = state.isValid || false; state.message = state.message || ''; state.required = scope.config.options.required || false; - scope.form = form.use('input', state); + scope.form = form.use('input', state, input); vm.setListeners(); vm.check(); diff --git a/awx/ui/client/lib/components/input/select.partial.html b/awx/ui/client/lib/components/input/select.partial.html index 3445daf4a5..bf08067022 100644 --- a/awx/ui/client/lib/components/input/select.partial.html +++ b/awx/ui/client/lib/components/input/select.partial.html @@ -8,7 +8,8 @@ ng-change="vm.check()" /> diff --git a/awx/ui/client/lib/models/CredentialType.js b/awx/ui/client/lib/models/CredentialType.js index 9a2c742294..d5217b9c3b 100644 --- a/awx/ui/client/lib/models/CredentialType.js +++ b/awx/ui/client/lib/models/CredentialType.js @@ -1,30 +1,43 @@ -function categorizeByKind () { - let group = {}; - - this.model.data.results.forEach(result => { - group[result.kind] = group[result.kind] || []; - group[result.kind].push(result); - }); - - return Object.keys(group).map(category => ({ - data: group[category], - category - })); -} - -function getTypeFromName (name) { - let type = this.model.data.results.filter(result => result.name === name); - - return type.length ? type[0] : null; -} - function CredentialType (BaseModel) { Object.assign(this, BaseModel()); this.path = this.normalizePath('credential_types'); - this.categorizeByKind = categorizeByKind; - this.getTypeFromName = getTypeFromName; + this.categorizeByKind = () => { + let group = {}; + + this.model.data.results.forEach(result => { + group[result.kind] = group[result.kind] || []; + group[result.kind].push(result); + }); + + return Object.keys(group).map(category => ({ + data: group[category], + category + })); + }; + + this.getTypeFromName = name => { + let type = this.model.data.results.filter(result => result.name === name); + + if (!type.length) { + return null; + } + + return this.mergeInputProperties(type[0]); + }; + + this.mergeInputProperties = type => { + return type.inputs.fields.map(field => { + if (!type.inputs.required || type.inputs.required.indexOf(field.id) !== -1) { + field.required = false; + } else { + field.required = true; + } + + return field; + }); + }; } CredentialType.$inject = ['BaseModel'];