diff --git a/awx/ui/client/features/credentials/add-credentials.controller.js b/awx/ui/client/features/credentials/add-credentials.controller.js
index 9193712f80..2acad45ae9 100644
--- a/awx/ui/client/features/credentials/add-credentials.controller.js
+++ b/awx/ui/client/features/credentials/add-credentials.controller.js
@@ -1,3 +1,5 @@
+/* eslint camelcase: 0 */
+/* eslint arrow-body-style: 0 */
function AddCredentialsController (
models,
$state,
@@ -6,7 +8,9 @@ function AddCredentialsController (
componentsStrings,
ConfigService,
ngToast,
- $filter
+ Wait,
+ $filter,
+ CredentialType,
) {
const vm = this || {};
@@ -40,6 +44,44 @@ function AddCredentialsController (
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
vm.isTestable = credentialType.get('kind') === 'external';
+ vm.inputSources = {
+ field: null,
+ credentialId: null,
+ credentialTypeId: null,
+ credentialTypeName: null,
+ tabs: {
+ credential: {
+ _active: true,
+ _disabled: false,
+ },
+ metadata: {
+ _active: false,
+ _disabled: false,
+ }
+ },
+ metadata: {},
+ form: {
+ inputs: {
+ _get: () => vm.inputSources.metadata,
+ _reference: 'vm.form.inputs',
+ _key: 'inputs',
+ _source: { _value: {} },
+ }
+ },
+ items: [],
+ };
+ vm.externalTest = {
+ metadata: null,
+ form: {
+ inputs: {
+ _get: () => vm.externalTest.metadata,
+ _reference: 'vm.form.inputs',
+ _key: 'inputs',
+ _source: { _value: {} },
+ }
+ },
+ };
+
const gceFileInputSchema = {
id: 'gce_service_account_key',
type: 'file',
@@ -50,10 +92,10 @@ function AddCredentialsController (
let gceFileInputPreEditValues;
vm.form.inputs = {
- _get: () => {
+ _get: ({ getSubmitData }) => {
credentialType.mergeInputProperties();
- const fields = credentialType.get('inputs.fields');
+ let fields = credentialType.get('inputs.fields');
if (credentialType.get('name') === 'Google Compute Engine') {
fields.splice(2, 0, gceFileInputSchema);
@@ -64,55 +106,196 @@ function AddCredentialsController (
become._isDynamic = true;
become._choices = Array.from(apiConfig.become_methods, method => method[0]);
}
-
vm.isTestable = credentialType.get('kind') === 'external';
+ vm.getSubmitData = getSubmitData;
+
+ fields = fields.map((field) => {
+ if (credentialType.get('kind') !== 'external') {
+ field.tagMode = true;
+ }
+ return field;
+ });
return fields;
},
+ _onRemoveTag ({ id }) {
+ vm.onInputSourceClear(id);
+ },
+ _onInputLookup ({ id }) {
+ vm.onInputSourceOpen(id);
+ },
_source: vm.form.credential_type,
_reference: 'vm.form.inputs',
_key: 'inputs'
};
- vm.form.secondary = ({ inputs }) => {
- const name = $filter('sanitize')(credentialType.get('name'));
- const endpoint = `${credentialType.get('id')}/test/`;
+ vm.onInputSourceClear = (field) => {
+ vm.form[field].tagMode = true;
+ vm.form[field].asTag = false;
+ };
- return credentialType.http.post({ url: endpoint, data: { inputs }, replace: false })
+ vm.setTab = (name) => {
+ const metaIsActive = name === 'metadata';
+ vm.inputSources.tabs.credential._active = !metaIsActive;
+ vm.inputSources.tabs.credential._disabled = false;
+ vm.inputSources.tabs.metadata._active = metaIsActive;
+ vm.inputSources.tabs.metadata._disabled = false;
+ };
+
+ vm.unsetTabs = () => {
+ vm.inputSources.tabs.credential._active = false;
+ vm.inputSources.tabs.credential._disabled = false;
+ vm.inputSources.tabs.metadata._active = false;
+ vm.inputSources.tabs.metadata._disabled = false;
+ };
+
+ vm.onInputSourceOpen = (field) => {
+ vm.inputSources.field = field;
+ vm.setTab('credential');
+ const sourceItem = vm.inputSources.items
+ .find(({ input_field_name }) => input_field_name === field);
+ if (sourceItem) {
+ const { source_credential, summary_fields } = sourceItem;
+ const { source_credential: { credential_type_id } } = summary_fields;
+ vm.inputSources.credentialId = source_credential;
+ vm.inputSources.credentialTypeId = credential_type_id;
+ vm.inputSources._value = credential_type_id;
+ }
+ };
+
+ vm.onInputSourceClose = () => {
+ vm.inputSources.field = null;
+ vm.inputSources.metadata = null;
+ vm.unsetTabs();
+ };
+
+ vm.onInputSourceNext = () => {
+ const { field, credentialId, credentialTypeId } = vm.inputSources;
+ Wait('start');
+ new CredentialType('get', credentialTypeId)
+ .then(model => {
+ model.mergeInputProperties('metadata');
+ vm.inputSources.metadata = model.get('inputs.metadata');
+ vm.inputSources.credentialTypeName = model.get('name');
+ const [metavals] = vm.inputSources.items
+ .filter(({ input_field_name }) => input_field_name === field)
+ .filter(({ source_credential }) => source_credential === credentialId)
+ .map(({ metadata }) => metadata);
+ Object.keys(metavals || {}).forEach(key => {
+ const obj = vm.inputSources.metadata.find(o => o.id === key);
+ if (obj) obj._value = metavals[key];
+ });
+ vm.setTab('metadata');
+ })
+ .finally(() => Wait('stop'));
+ };
+
+ vm.onInputSourceSelect = () => {
+ const { field, credentialId } = vm.inputSources;
+ vm.inputSources.items = vm.inputSources.items
+ .filter(({ input_field_name }) => input_field_name !== field)
+ .concat([{
+ input_field_name: field,
+ source_credential: credentialId,
+ target_credential: credential.get('id'),
+ }]);
+ vm.inputSources.field = null;
+ vm.inputSources.metadata = null;
+ vm.unsetTabs();
+ };
+
+ vm.onInputSourceTabSelect = (name) => {
+ if (name === 'metadata') {
+ vm.onInputSourceNext();
+ } else {
+ vm.setTab('credential');
+ }
+ };
+
+ vm.onInputSourceRowClick = ({ id, credential_type }) => {
+ vm.inputSources.credentialId = id;
+ vm.inputSources.credentialTypeId = credential_type;
+ vm.inputSources._value = credential_type;
+ };
+
+ vm.onInputSourceTest = () => {
+ const metadata = Object.assign({}, ...vm.inputSources.form.inputs._group
+ .filter(({ _value }) => _value !== undefined)
+ .map(({ id, _value }) => ({ [id]: _value })));
+ const name = $filter('sanitize')(vm.inputSources.credentialTypeName);
+ const endpoint = `${vm.inputSources.credentialId}/test/`;
+
+ return vm.runTest({ name, model: credential, endpoint, data: { metadata } });
+ };
+
+ vm.onExternalTestClick = () => {
+ credentialType.mergeInputProperties('metadata');
+ vm.externalTest.metadata = credentialType.get('inputs.metadata');
+ };
+
+ vm.onExternalTestClose = () => {
+ vm.externalTest.metadata = null;
+ };
+
+ vm.onExternalTest = () => {
+ const name = $filter('sanitize')(credentialType.get('name'));
+ const { inputs } = vm.getSubmitData();
+ const metadata = Object.assign({}, ...vm.externalTest.form.inputs._group
+ .filter(({ _value }) => _value !== undefined)
+ .map(({ id, _value }) => ({ [id]: _value })));
+
+ let model;
+ if (credential.get('credential_type') !== credentialType.get('id')) {
+ model = credentialType;
+ } else {
+ model = credential;
+ }
+
+ const endpoint = `${model.get('id')}/test/`;
+ return vm.runTest({ name, model, endpoint, data: { inputs, metadata } });
+ };
+ vm.form.secondary = vm.onExternalTestClick;
+
+ vm.runTest = ({ name, model, endpoint, data: { inputs, metadata } }) => {
+ return model.http.post({ url: endpoint, data: { inputs, metadata }, replace: false })
.then(() => {
ngToast.success({
- content: `
-
-
-
-
-
- ${name}: ${strings.get('edit.TEST_PASSED')}
-
-
`,
+ content: vm.buildTestNotificationContent({
+ name,
+ icon: 'fa-check-circle',
+ msg: strings.get('edit.TEST_PASSED'),
+ }),
dismissButton: false,
dismissOnTimeout: true
});
})
.catch(({ data }) => {
- const msg = data.inputs ? `${$filter('sanitize')(data.inputs)}` : strings.get('edit.TEST_FAILED');
-
+ const msg = data.inputs
+ ? `${$filter('sanitize')(data.inputs)}`
+ : strings.get('edit.TEST_FAILED');
ngToast.danger({
- content: `
-
-
-
-
-
- ${name}: ${msg}
-
-
`,
+ content: vm.buildTestNotificationContent({
+ name,
+ msg,
+ icon: 'fa-exclamation-triangle'
+ }),
dismissButton: false,
dismissOnTimeout: true
});
});
};
+ vm.buildTestNotificationContent = ({ name, msg, icon }) => (
+ `
+
+
+
+
+ ${name}: ${msg}
+
+
`
+ );
+
vm.form.save = data => {
data.user = me.get('id');
@@ -195,7 +378,9 @@ AddCredentialsController.$inject = [
'ComponentsStrings',
'ConfigService',
'ngToast',
- '$filter'
+ 'Wait',
+ '$filter',
+ 'CredentialTypeModel',
];
export default AddCredentialsController;
diff --git a/awx/ui/client/features/credentials/add-edit-credentials.view.html b/awx/ui/client/features/credentials/add-edit-credentials.view.html
index fae203e152..914c98dcfa 100644
--- a/awx/ui/client/features/credentials/add-edit-credentials.view.html
+++ b/awx/ui/client/features/credentials/add-edit-credentials.view.html
@@ -43,5 +43,22 @@
-
+
+
diff --git a/awx/ui/client/features/credentials/edit-credentials.controller.js b/awx/ui/client/features/credentials/edit-credentials.controller.js
index 1516b71d96..d3f5bf56f7 100644
--- a/awx/ui/client/features/credentials/edit-credentials.controller.js
+++ b/awx/ui/client/features/credentials/edit-credentials.controller.js
@@ -1,3 +1,5 @@
+/* eslint camelcase: 0 */
+/* eslint arrow-body-style: 0 */
function EditCredentialsController (
models,
$state,
@@ -8,10 +10,16 @@ function EditCredentialsController (
ngToast,
Wait,
$filter,
+ CredentialType,
) {
const vm = this || {};
-
- const { me, credential, credentialType, organization, isOrgCredAdmin } = models;
+ const {
+ me,
+ credential,
+ credentialType,
+ organization,
+ isOrgCredAdmin,
+ } = models;
const omit = ['user', 'team', 'inputs'];
const isEditable = credential.isEditable();
@@ -88,6 +96,44 @@ function EditCredentialsController (
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
vm.isTestable = (isEditable && credentialType.get('kind') === 'external');
+ vm.inputSources = {
+ field: null,
+ credentialId: null,
+ credentialTypeId: null,
+ credentialTypeName: null,
+ tabs: {
+ credential: {
+ _active: true,
+ _disabled: false,
+ },
+ metadata: {
+ _active: false,
+ _disabled: false,
+ }
+ },
+ metadata: {},
+ form: {
+ inputs: {
+ _get: () => vm.inputSources.metadata,
+ _reference: 'vm.form.inputs',
+ _key: 'inputs',
+ _source: { _value: {} },
+ }
+ },
+ items: credential.get('related.input_sources.results'),
+ };
+ vm.externalTest = {
+ metadata: null,
+ form: {
+ inputs: {
+ _get: () => vm.externalTest.metadata,
+ _reference: 'vm.form.inputs',
+ _key: 'inputs',
+ _source: { _value: {} },
+ }
+ },
+ };
+
const gceFileInputSchema = {
id: 'gce_service_account_key',
type: 'file',
@@ -98,7 +144,7 @@ function EditCredentialsController (
let gceFileInputPreEditValues;
vm.form.inputs = {
- _get () {
+ _get ({ getSubmitData }) {
let fields;
credentialType.mergeInputProperties();
@@ -128,54 +174,199 @@ function EditCredentialsController (
}
}
}
+
+ fields = fields.map((field) => {
+ if (isEditable && credentialType.get('kind') !== 'external') {
+ field.tagMode = true;
+ }
+ return field;
+ });
+
vm.isTestable = (isEditable && credentialType.get('kind') === 'external');
+ vm.getSubmitData = getSubmitData;
return fields;
},
+ _onRemoveTag ({ id }) {
+ vm.onInputSourceClear(id);
+ },
+ _onInputLookup ({ id }) {
+ vm.onInputSourceOpen(id);
+ },
_source: vm.form.credential_type,
_reference: 'vm.form.inputs',
- _key: 'inputs'
+ _key: 'inputs',
+ border: true,
+ title: true,
};
- vm.form.secondary = ({ inputs }) => {
- const name = $filter('sanitize')(credentialType.get('name'));
- const endpoint = `${credential.get('id')}/test/`;
+ vm.onInputSourceClear = (field) => {
+ vm.form[field].tagMode = true;
+ vm.form[field].asTag = false;
+ };
- return credential.http.post({ url: endpoint, data: { inputs }, replace: false })
+ vm.setTab = (name) => {
+ const metaIsActive = name === 'metadata';
+ vm.inputSources.tabs.credential._active = !metaIsActive;
+ vm.inputSources.tabs.credential._disabled = false;
+ vm.inputSources.tabs.metadata._active = metaIsActive;
+ vm.inputSources.tabs.metadata._disabled = false;
+ };
+
+ vm.unsetTabs = () => {
+ vm.inputSources.tabs.credential._active = false;
+ vm.inputSources.tabs.credential._disabled = false;
+ vm.inputSources.tabs.metadata._active = false;
+ vm.inputSources.tabs.metadata._disabled = false;
+ };
+
+ vm.onInputSourceOpen = (field) => {
+ vm.inputSources.field = field;
+ vm.setTab('credential');
+ const sourceItem = vm.inputSources.items
+ .find(({ input_field_name }) => input_field_name === field);
+ if (sourceItem) {
+ const { source_credential, summary_fields } = sourceItem;
+ const { source_credential: { credential_type_id } } = summary_fields;
+ vm.inputSources.credentialId = source_credential;
+ vm.inputSources.credentialTypeId = credential_type_id;
+ vm.inputSources._value = credential_type_id;
+ }
+ };
+
+ vm.onInputSourceClose = () => {
+ vm.inputSources.field = null;
+ vm.inputSources.metadata = null;
+ vm.unsetTabs();
+ };
+
+ vm.onInputSourceNext = () => {
+ const { field, credentialId, credentialTypeId } = vm.inputSources;
+ Wait('start');
+ new CredentialType('get', credentialTypeId)
+ .then(model => {
+ model.mergeInputProperties('metadata');
+ vm.inputSources.metadata = model.get('inputs.metadata');
+ vm.inputSources.credentialTypeName = model.get('name');
+ const [metavals] = vm.inputSources.items
+ .filter(({ input_field_name }) => input_field_name === field)
+ .filter(({ source_credential }) => source_credential === credentialId)
+ .map(({ metadata }) => metadata);
+ Object.keys(metavals || {}).forEach(key => {
+ const obj = vm.inputSources.metadata.find(o => o.id === key);
+ if (obj) obj._value = metavals[key];
+ });
+ vm.setTab('metadata');
+ })
+ .finally(() => Wait('stop'));
+ };
+
+ vm.onInputSourceSelect = () => {
+ const { field, credentialId } = vm.inputSources;
+ vm.inputSources.items = vm.inputSources.items
+ .filter(({ input_field_name }) => input_field_name !== field)
+ .concat([{
+ input_field_name: field,
+ source_credential: credentialId,
+ target_credential: credential.get('id'),
+ }]);
+ vm.inputSources.field = null;
+ vm.inputSources.metadata = null;
+ vm.unsetTabs();
+ };
+
+ vm.onInputSourceTabSelect = (name) => {
+ if (name === 'metadata') {
+ vm.onInputSourceNext();
+ } else {
+ vm.setTab('credential');
+ }
+ };
+
+ vm.onInputSourceRowClick = ({ id, credential_type }) => {
+ vm.inputSources.credentialId = id;
+ vm.inputSources.credentialTypeId = credential_type;
+ vm.inputSources._value = credential_type;
+ };
+
+ vm.onInputSourceTest = () => {
+ const metadata = Object.assign({}, ...vm.inputSources.form.inputs._group
+ .filter(({ _value }) => _value !== undefined)
+ .map(({ id, _value }) => ({ [id]: _value })));
+ const name = $filter('sanitize')(vm.inputSources.credentialTypeName);
+ const endpoint = `${vm.inputSources.credentialId}/test/`;
+
+ return vm.runTest({ name, model: credential, endpoint, data: { metadata } });
+ };
+
+ vm.onExternalTestClick = () => {
+ credentialType.mergeInputProperties('metadata');
+ vm.externalTest.metadata = credentialType.get('inputs.metadata');
+ };
+
+ vm.onExternalTestClose = () => {
+ vm.externalTest.metadata = null;
+ };
+
+ vm.onExternalTest = () => {
+ const name = $filter('sanitize')(credentialType.get('name'));
+ const { inputs } = vm.getSubmitData();
+ const metadata = Object.assign({}, ...vm.externalTest.form.inputs._group
+ .filter(({ _value }) => _value !== undefined)
+ .map(({ id, _value }) => ({ [id]: _value })));
+
+ let model;
+ if (credential.get('credential_type') !== credentialType.get('id')) {
+ model = credentialType;
+ } else {
+ model = credential;
+ }
+
+ const endpoint = `${model.get('id')}/test/`;
+ return vm.runTest({ name, model, endpoint, data: { inputs, metadata } });
+ };
+ vm.form.secondary = vm.onExternalTestClick;
+
+ vm.runTest = ({ name, model, endpoint, data: { inputs, metadata } }) => {
+ return model.http.post({ url: endpoint, data: { inputs, metadata }, replace: false })
.then(() => {
ngToast.success({
- content: `
-
-
-
-
-
- ${name}: ${strings.get('edit.TEST_PASSED')}
-
-
`,
+ content: vm.buildTestNotificationContent({
+ name,
+ icon: 'fa-check-circle',
+ msg: strings.get('edit.TEST_PASSED'),
+ }),
dismissButton: false,
dismissOnTimeout: true
});
})
.catch(({ data }) => {
- const msg = data.inputs ? `${$filter('sanitize')(data.inputs)}` : strings.get('edit.TEST_FAILED');
-
+ const msg = data.inputs
+ ? `${$filter('sanitize')(data.inputs)}`
+ : strings.get('edit.TEST_FAILED');
ngToast.danger({
- content: `
-
-
-
-
-
- ${name}: ${msg}
-
-
`,
+ content: vm.buildTestNotificationContent({
+ name,
+ msg,
+ icon: 'fa-exclamation-triangle'
+ }),
dismissButton: false,
dismissOnTimeout: true
});
});
};
+ vm.buildTestNotificationContent = ({ name, msg, icon }) => (
+ `
+
+
+
+
+ ${name}: ${msg}
+
+
`
+ );
+
/**
* If a credential's `credential_type` is changed while editing, the inputs associated with
* the old type need to be cleared before saving the inputs associated with the new type.
@@ -258,6 +449,7 @@ EditCredentialsController.$inject = [
'ngToast',
'Wait',
'$filter',
+ 'CredentialTypeModel',
];
export default EditCredentialsController;
diff --git a/awx/ui/client/features/credentials/external-test.component.js b/awx/ui/client/features/credentials/external-test.component.js
new file mode 100644
index 0000000000..0c4fda3659
--- /dev/null
+++ b/awx/ui/client/features/credentials/external-test.component.js
@@ -0,0 +1,37 @@
+const templateUrl = require('~features/credentials/external-test.partial.html');
+
+function ExternalTestModalController ($scope, $element, strings) {
+ const vm = this || {};
+ let overlay;
+
+ vm.strings = strings;
+ vm.title = 'Test External Credential';
+
+ vm.$onInit = () => {
+ const [el] = $element;
+ overlay = el.querySelector('#external-test-modal');
+ vm.show();
+ };
+
+ vm.show = () => {
+ overlay.style.display = 'block';
+ overlay.style.opacity = 1;
+ };
+}
+
+ExternalTestModalController.$inject = [
+ '$scope',
+ '$element',
+ 'CredentialsStrings',
+];
+
+export default {
+ templateUrl,
+ controller: ExternalTestModalController,
+ controllerAs: 'vm',
+ bindings: {
+ onClose: '=',
+ onSubmit: '=',
+ form: '=',
+ },
+};
diff --git a/awx/ui/client/features/credentials/external-test.partial.html b/awx/ui/client/features/credentials/external-test.partial.html
new file mode 100644
index 0000000000..3d866c42f1
--- /dev/null
+++ b/awx/ui/client/features/credentials/external-test.partial.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ TITLE
+
+
+
+
+
+
+
+
diff --git a/awx/ui/client/features/credentials/index.js b/awx/ui/client/features/credentials/index.js
index 38e291ef8e..2c13f645ed 100644
--- a/awx/ui/client/features/credentials/index.js
+++ b/awx/ui/client/features/credentials/index.js
@@ -2,6 +2,8 @@ import LegacyCredentials from './legacy.credentials';
import AddController from './add-credentials.controller';
import EditController from './edit-credentials.controller';
import CredentialsStrings from './credentials.strings';
+import InputSourceLookupComponent from './input-source-lookup.component';
+import ExternalTestComponent from './external-test.component';
const MODULE_NAME = 'at.features.credentials';
@@ -40,7 +42,8 @@ function CredentialsResolve (
const dependents = {
credentialType: new CredentialType('get', typeId),
- organization: new Organization('get', orgId)
+ organization: new Organization('get', orgId),
+ credentialInputSources: models.credential.extend('GET', 'input_sources')
};
dependents.isOrgCredAdmin = dependents.organization.then((org) => org.search({ role_level: 'credential_admin_role' }));
@@ -139,6 +142,8 @@ angular
.controller('EditController', EditController)
.service('LegacyCredentialsService', LegacyCredentials)
.service('CredentialsStrings', CredentialsStrings)
+ .component('atInputSourceLookup', InputSourceLookupComponent)
+ .component('atExternalCredentialTest', ExternalTestComponent)
.run(CredentialsRun);
export default MODULE_NAME;
diff --git a/awx/ui/client/features/credentials/input-source-lookup.component.js b/awx/ui/client/features/credentials/input-source-lookup.component.js
new file mode 100644
index 0000000000..1ac781734c
--- /dev/null
+++ b/awx/ui/client/features/credentials/input-source-lookup.component.js
@@ -0,0 +1,92 @@
+const templateUrl = require('~features/credentials/input-source-lookup.partial.html');
+
+function InputSourceLookupController ($scope, $element, $http, GetBasePath, qs, strings) {
+ const vm = this || {};
+ let overlay;
+
+ vm.strings = strings;
+ vm.name = 'credential';
+ vm.title = 'Set Input Source';
+
+ vm.$onInit = () => {
+ const [el] = $element;
+ overlay = el.querySelector('#input-source-lookup');
+
+ const defaultParams = {
+ order_by: 'name',
+ credential_type__kind: 'external',
+ page_size: 5
+ };
+ vm.setDefaultParams(defaultParams);
+ vm.setData({ results: [], count: 0 });
+ $http({ method: 'GET', url: GetBasePath(`${vm.name}s`), params: defaultParams })
+ .then(({ data }) => {
+ vm.setData(data);
+ vm.show();
+ });
+ };
+
+ vm.show = () => {
+ overlay.style.display = 'block';
+ overlay.style.opacity = 1;
+ };
+
+ vm.close = () => {
+ vm.onClose();
+ };
+
+ vm.next = () => {
+ vm.onNext();
+ };
+
+ vm.select = () => {
+ vm.onSelect();
+ };
+
+ vm.test = () => {
+ vm.onTest();
+ };
+
+ vm.setData = ({ results, count }) => {
+ vm.dataset = { results, count };
+ vm.collection = vm.dataset.results;
+ };
+
+ vm.setDefaultParams = (params) => {
+ vm.list = { name: vm.name, iterator: vm.name };
+ vm.defaultParams = params;
+ vm.queryset = params;
+ };
+
+ vm.toggle_row = (obj) => {
+ vm.onRowClick(obj);
+ };
+
+ vm.onCredentialTabClick = () => vm.onTabSelect('credential');
+}
+
+InputSourceLookupController.$inject = [
+ '$scope',
+ '$element',
+ '$http',
+ 'GetBasePath',
+ 'QuerySet',
+ 'CredentialsStrings',
+];
+
+export default {
+ templateUrl,
+ controller: InputSourceLookupController,
+ controllerAs: 'vm',
+ bindings: {
+ tabs: '=',
+ onClose: '=',
+ onNext: '=',
+ onSelect: '=',
+ onTabSelect: '=',
+ onRowClick: '=',
+ onTest: '=',
+ selectedId: '=',
+ form: '=',
+ },
+};
diff --git a/awx/ui/client/features/credentials/input-source-lookup.partial.html b/awx/ui/client/features/credentials/input-source-lookup.partial.html
new file mode 100644
index 0000000000..4998201715
--- /dev/null
+++ b/awx/ui/client/features/credentials/input-source-lookup.partial.html
@@ -0,0 +1,174 @@
+
diff --git a/awx/ui/client/lib/components/form/form.directive.js b/awx/ui/client/lib/components/form/form.directive.js
index 9c008b19e6..7aaa90aa1a 100644
--- a/awx/ui/client/lib/components/form/form.directive.js
+++ b/awx/ui/client/lib/components/form/form.directive.js
@@ -87,13 +87,8 @@ function AtFormController (eventService, strings) {
if (!vm.state.isValid) {
return;
}
-
- vm.state.disabled = true;
-
const data = vm.getSubmitData();
-
- scope.state.secondary(data)
- .finally(() => { vm.state.disabled = false; });
+ scope.state.secondary(data);
};
vm.submit = () => {
diff --git a/awx/ui/client/lib/components/input/group.directive.js b/awx/ui/client/lib/components/input/group.directive.js
index 291b534ac9..3e62023255 100644
--- a/awx/ui/client/lib/components/input/group.directive.js
+++ b/awx/ui/client/lib/components/input/group.directive.js
@@ -48,7 +48,7 @@ function AtInputGroupController ($scope, $compile) {
state._value = source._value;
- const inputs = state._get(source._value);
+ const inputs = state._get(form);
const group = vm.createComponentConfigs(inputs);
vm.insert(group);
@@ -66,7 +66,9 @@ function AtInputGroupController ($scope, $compile) {
_element: vm.createComponent(input, i),
_key: 'inputs',
_group: true,
- _groupIndex: i
+ _groupIndex: i,
+ _onInputLookup: state._onInputLookup,
+ _onRemoveTag: state._onRemoveTag,
}, input));
});
}
@@ -160,7 +162,6 @@ function AtInputGroupController ($scope, $compile) {
${input._component}>`);
$compile(component)(scope.$parent);
-
return component;
};
diff --git a/awx/ui/client/lib/components/input/group.partial.html b/awx/ui/client/lib/components/input/group.partial.html
index 45d4a845e0..c32d29bb1e 100644
--- a/awx/ui/client/lib/components/input/group.partial.html
+++ b/awx/ui/client/lib/components/input/group.partial.html
@@ -1,7 +1,7 @@