From e80e3f7410409adee64957442eae9e8b2bf4874d Mon Sep 17 00:00:00 2001 From: mabashian Date: Wed, 26 Feb 2020 16:59:45 -0500 Subject: [PATCH] Reapply prompt on launch for job template fields after rebasing. --- .../CodeMirrorInput/VariablesField.jsx | 131 +- .../Lookup/MultiCredentialsLookup.jsx | 206 +-- .../src/screens/Host/shared/HostForm.jsx | 186 +-- .../Template/shared/JobTemplateForm.jsx | 1218 ++++------------- 4 files changed, 341 insertions(+), 1400 deletions(-) diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx index 46a502df8c..336a3fa996 100644 --- a/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx @@ -1,82 +1,12 @@ import React, { useState } from 'react'; import { string, bool } from 'prop-types'; -import { useField } from 'formik'; -import { Split, SplitItem } from '@patternfly/react-core'; -import { yamlToJson, jsonToYaml, isJson } from '@util/yaml'; -import CodeMirrorInput from './CodeMirrorInput'; -import YamlJsonToggle from './YamlJsonToggle'; -import { JSON_MODE, YAML_MODE } from './constants'; - -function VariablesField({ id, name, label, readOnly }) { - const [field, meta, helpers] = useField(name); - const [mode, setMode] = useState(isJson(field.value) ? JSON_MODE : YAML_MODE); - - return ( - <> - - - - - - { - try { - const newVal = - newMode === YAML_MODE - ? jsonToYaml(field.value) - : yamlToJson(field.value); - helpers.setValue(newVal); - setMode(newMode); - } catch (err) { - helpers.setError(err.message); - } - }} - /> - - - { - helpers.setValue(newVal); - }} - hasErrors={!!meta.error} - /> - {meta.error ? ( -
- {meta.error} -
- ) : null} - - ); -} -VariablesField.propTypes = { - id: string.isRequired, - name: string.isRequired, - label: string.isRequired, - readOnly: bool, -}; -VariablesField.defaultProps = { - readOnly: false, -}; - -export default VariablesField; - - -/* -import React, { useState } from 'react'; -import { string, bool } from 'prop-types'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { Field, useFormikContext } from 'formik'; -import { Split, SplitItem } from '@patternfly/react-core'; -import { yamlToJson, jsonToYaml, isJson } from '@util/yaml'; -import { CheckboxField } from '@components/FormField'; +import { useField } from 'formik'; import styled from 'styled-components'; +import { Split, SplitItem } from '@patternfly/react-core'; +import { CheckboxField } from '@components/FormField'; +import { yamlToJson, jsonToYaml, isJson } from '@util/yaml'; import CodeMirrorInput from './CodeMirrorInput'; import YamlJsonToggle from './YamlJsonToggle'; import { JSON_MODE, YAML_MODE } from './constants'; @@ -91,9 +21,8 @@ const StyledCheckboxField = styled(CheckboxField)` `; function VariablesField({ i18n, id, name, label, readOnly, promptId }) { - const { values, setFieldError, setFieldValue } = useFormikContext(); - const value = values[name]; - const [mode, setMode] = useState(isJson(value) ? JSON_MODE : YAML_MODE); + const [field, meta, helpers] = useField(name); + const [mode, setMode] = useState(isJson(field.value) ? JSON_MODE : YAML_MODE); return (
@@ -111,12 +40,12 @@ function VariablesField({ i18n, id, name, label, readOnly, promptId }) { try { const newVal = newMode === YAML_MODE - ? jsonToYaml(value) - : yamlToJson(value); - setFieldValue(name, newVal); + ? jsonToYaml(field.value) + : yamlToJson(field.value); + helpers.setValue(newVal); setMode(newMode); } catch (err) { - setFieldError(name, err.message); + helpers.setError(err.message); } }} /> @@ -130,29 +59,20 @@ function VariablesField({ i18n, id, name, label, readOnly, promptId }) { /> )} - - {({ field, form }) => ( - <> - { - form.setFieldValue(name, newVal); - }} - hasErrors={!!form.errors[field.name]} - /> - {form.errors[field.name] ? ( -
- {form.errors[field.name]} -
- ) : null} - - )} -
+ { + helpers.setValue(newVal); + }} + hasErrors={!!meta.error} + /> + {meta.error ? ( +
+ {meta.error} +
+ ) : null}
); } @@ -161,10 +81,11 @@ VariablesField.propTypes = { name: string.isRequired, label: string.isRequired, readOnly: bool, + promptId: string, }; VariablesField.defaultProps = { readOnly: false, + promptId: null, }; export default withI18n()(VariablesField); -*/ diff --git a/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx b/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx index 12d660ffef..9a24316c74 100644 --- a/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx +++ b/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx @@ -3,210 +3,10 @@ import { withRouter } from 'react-router-dom'; import PropTypes from 'prop-types'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { FormGroup, ToolbarItem } from '@patternfly/react-core'; -import { CredentialsAPI, CredentialTypesAPI } from '@api'; -import AnsibleSelect from '@components/AnsibleSelect'; -import { FieldTooltip } from '@components/FormField'; -import CredentialChip from '@components/CredentialChip'; -import { getQSConfig, parseQueryString } from '@util/qs'; -import Lookup from './Lookup'; -import OptionsList from './shared/OptionsList'; - -const QS_CONFIG = getQSConfig('credentials', { - page: 1, - page_size: 5, - order_by: 'name', -}); - -async function loadCredentialTypes() { - const { data } = await CredentialTypesAPI.read(); - const acceptableTypes = ['machine', 'cloud', 'net', 'ssh', 'vault']; - return data.results.filter(type => acceptableTypes.includes(type.kind)); -} - -async function loadCredentials(params, selectedCredentialTypeId) { - params.credential_type = selectedCredentialTypeId || 1; - const { data } = await CredentialsAPI.read(params); - return data; -} - -function MultiCredentialsLookup(props) { - const { tooltip, value, onChange, onError, history, i18n } = props; - const [credentialTypes, setCredentialTypes] = useState([]); - const [selectedType, setSelectedType] = useState(null); - const [credentials, setCredentials] = useState([]); - const [credentialsCount, setCredentialsCount] = useState(0); - - useEffect(() => { - (async () => { - try { - const types = await loadCredentialTypes(); - setCredentialTypes(types); - const match = types.find(type => type.kind === 'ssh') || types[0]; - setSelectedType(match); - } catch (err) { - onError(err); - } - })(); - }, [onError]); - - useEffect(() => { - (async () => { - if (!selectedType) { - return; - } - try { - const params = parseQueryString(QS_CONFIG, history.location.search); - const { results, count } = await loadCredentials( - params, - selectedType.id - ); - setCredentials(results); - setCredentialsCount(count); - } catch (err) { - onError(err); - } - })(); - }, [selectedType, history.location.search, onError]); - - const renderChip = ({ item, removeItem, canDelete }) => ( - removeItem(item)} - isReadOnly={!canDelete} - credential={item} - /> - ); - - const isMultiple = selectedType && selectedType.kind === 'vault'; - - return ( - - {tooltip && } - { - return ( - - {credentialTypes && credentialTypes.length > 0 && ( - -
- {i18n._(t`Selected Category`)} -
- ({ - key: type.id, - value: type.id, - label: type.name, - isDisabled: false, - }))} - value={selectedType && selectedType.id} - onChange={(e, id) => { - setSelectedType( - credentialTypes.find(o => o.id === parseInt(id, 10)) - ); - }} - /> -
- )} - { - if (isMultiple) { - return dispatch({ type: 'SELECT_ITEM', item }); - } - const selectedItems = state.selectedItems.filter( - i => i.kind !== item.kind - ); - selectedItems.push(item); - return dispatch({ - type: 'SET_SELECTED_ITEMS', - selectedItems, - }); - }} - deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })} - renderItemChip={renderChip} - /> -
- ); - }} - /> -
- ); -} - -MultiCredentialsLookup.propTypes = { - tooltip: PropTypes.string, - value: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.number, - name: PropTypes.string, - description: PropTypes.string, - kind: PropTypes.string, - clound: PropTypes.bool, - }) - ), - onChange: PropTypes.func.isRequired, - onError: PropTypes.func.isRequired, -}; - -MultiCredentialsLookup.defaultProps = { - tooltip: '', - value: [], -}; - -export { MultiCredentialsLookup as _MultiCredentialsLookup }; -export default withI18n()(withRouter(MultiCredentialsLookup)); - - -/* -import React, { Fragment, useState, useEffect } from 'react'; -import { withRouter } from 'react-router-dom'; -import PropTypes from 'prop-types'; -import { withI18n } from '@lingui/react'; -import { t } from '@lingui/macro'; import { ToolbarItem } from '@patternfly/react-core'; import { CredentialsAPI, CredentialTypesAPI } from '@api'; import AnsibleSelect from '@components/AnsibleSelect'; import CredentialChip from '@components/CredentialChip'; -import VerticalSeperator from '@components/VerticalSeparator'; import { getQSConfig, parseQueryString } from '@util/qs'; import Lookup from './Lookup'; import OptionsList from './shared/OptionsList'; @@ -293,8 +93,9 @@ function MultiCredentialsLookup(props) { {credentialTypes && credentialTypes.length > 0 && ( -
{i18n._(t`Selected Category`)}
- +
+ {i18n._(t`Selected Category`)} +
{hostAddMatch && ( - inventoryHelpers.setTouched()} - tooltip={i18n._( - t`Select the inventory that this host will belong to.` - )} + { - inventoryHelpers.setValuealue(value.id); - setInventory(value); - }} - required - touched={inventoryMeta.touched} - error={inventoryMeta.error} - /> + > + + inventoryHelpers.setTouched()} + tooltip={i18n._( + t`Select the inventory that this host will belong to.` + )} + isValid={!inventoryMeta.touched || !inventoryMeta.error} + helperTextInvalid={inventoryMeta.error} + onChange={value => { + inventoryHelpers.setValue(value.id); + setInventory(value); + }} + required + touched={inventoryMeta.touched} + error={inventoryMeta.error} + /> + )} - {formik => ( -
- - - - {hostAddMatch && ( - - {({ form }) => ( - - - form.setFieldTouched('inventory')} - onChange={value => { - form.setFieldValue('inventory', value.id); - setInventory(value); - }} - required - touched={form.touched.inventory} - error={form.errors.inventory} - /> - - )} - - )} - - - - - - - - )} - - ); -} - -HostForm.propTypes = { - handleSubmit: func.isRequired, - handleCancel: func.isRequired, - host: shape({}), - submitError: shape({}), -}; - -HostForm.defaultProps = { - host: { - name: '', - description: '', - inventory: undefined, - variables: '---\n', - summary_fields: { - inventory: null, - }, - }, - submitError: null, -}; - -export { HostForm as _HostForm }; -export default withI18n()(HostForm); -*/ diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx index c6a2c3b594..f9f68507cb 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx @@ -27,7 +27,7 @@ import { FormFullWidthLayout, FormCheckboxLayout, } from '@components/FormLayout'; -import CollapsibleSection from '@components/CollapsibleSection'; +import { VariablesField } from '@components/CodeMirrorInput'; import { required } from '@util/validators'; import { JobTemplate } from '@types'; import { @@ -202,667 +202,9 @@ class JobTemplateForm extends Component { return ; } - const AdvancedFieldsWrapper = template.isNew ? CollapsibleSection : 'div'; - return (
- - - - - {({ form, field }) => { - const isValid = !form.touched.job_type || !form.errors.job_type; - return ( - - ); - }} - - - - {({ form }) => ( - form.setFieldTouched('inventory')} - tooltip={i18n._(t`Select the inventory containing the hosts - you want this job to manage.`)} - isValid={!form.touched.inventory || !form.errors.inventory} - helperTextInvalid={form.errors.inventory} - onChange={value => { - form.setFieldValue('inventory', value.id); - form.setFieldValue('organizationId', value.organization); - this.setState({ inventory: value }); - }} - required - touched={form.touched.inventory} - error={form.errors.inventory} - /> - )} - - - {({ form }) => ( - form.setFieldTouched('project')} - tooltip={i18n._(t`Select the project containing the playbook - you want this job to execute.`)} - isValid={!form.touched.project || !form.errors.project} - helperTextInvalid={form.errors.project} - onChange={this.handleProjectUpdate} - required - /> - )} - - {project && project.allow_override && ( - - )} - - {({ field, form }) => { - const isValid = !form.touched.playbook || !form.errors.playbook; - return ( - - - form.setFieldTouched('playbook')} - onError={this.setContentError} - /> - - ); - }} - - - - {({ field }) => ( - - - setFieldValue('labels', labels)} - onError={this.setContentError} - /> - - )} - - - {({ field }) => ( - - setFieldValue('credentials', newCredentials) - } - onError={this.setContentError} - tooltip={i18n._( - t`Select credentials that allow Tower to access the nodes this job will be ran against. You can only select one credential of each type. For machine credentials (SSH), checking "Prompt on launch" without selecting credentials will require you to select a machine credential at run time. If you select credentials and check "Prompt on launch", the selected credential(s) become the defaults that can be updated at run time.` - )} - /> - )} - - - - - {i18n._(t`The number of parallel or simultaneous - processes to use while executing the playbook. An empty value, - or a value less than 1 will use the Ansible default which is - usually 5. The default number of forks can be overwritten - with a change to`)}{' '} - ansible.cfg.{' '} - {i18n._(t`Refer to the Ansible documentation for details - about the configuration file.`)} - - } - /> - - - {({ field }) => ( - - - - - )} - - - - - {({ field, form }) => ( - - -
- - form.setFieldValue(field.name, checked) - } - /> -
-
- )} -
- - - {({ field, form }) => ( - - form.setFieldValue(field.name, value) - } - tooltip={i18n._(t`Select the Instance Groups for this Organization - to run on.`)} - /> - )} - - - {({ field, form }) => ( - - - - form.setFieldValue(field.name, value) - } - /> - - )} - - - {({ field, form }) => ( - - - - form.setFieldValue(field.name, value) - } - /> - - )} - - - - - - {i18n._(t`Provisioning Callbacks`)} -   - - - } - id="option-callbacks" - isChecked={allowCallbacks} - onChange={checked => { - this.setState({ allowCallbacks: checked }); - }} - /> - - - - - - {allowCallbacks && ( - <> - {callbackUrl && ( - - - - )} - - - )} -
-
-
- - -
-
- ); - } -} - -const FormikApp = withFormik({ - mapPropsToValues(props) { - const { template = {} } = props; - const { - summary_fields = { - labels: { results: [] }, - inventory: { organization: null }, - }, - } = template; - const hasInventory = summary_fields.inventory - ? summary_fields.inventory.organization_id - : null; - return { - ask_job_type_on_launch: template.ask_job_type_on_launch || false, - name: template.name || '', - description: template.description || '', - job_type: template.job_type || 'run', - inventory: template.inventory || '', - project: template.project || '', - scm_branch: template.scm_branch || '', - playbook: template.playbook || '', - labels: summary_fields.labels.results || [], - forks: template.forks || 0, - limit: template.limit || '', - verbosity: template.verbosity || '0', - job_slice_count: template.job_slice_count || 1, - timeout: template.timeout || 0, - diff_mode: template.diff_mode || false, - job_tags: template.job_tags || '', - skip_tags: template.skip_tags || '', - become_enabled: template.become_enabled || false, - allow_callbacks: template.allow_callbacks || false, - allow_simultaneous: template.allow_simultaneous || false, - use_fact_cache: template.use_fact_cache || false, - host_config_key: template.host_config_key || '', - organizationId: hasInventory, - initialInstanceGroups: [], - instanceGroups: [], - credentials: summary_fields.credentials || [], - }; - }, - handleSubmit: async (values, { props, setErrors }) => { - try { - await props.handleSubmit(values); - } catch (errors) { - setErrors(errors); - } - }, -})(JobTemplateForm); - -export { JobTemplateForm as _JobTemplateForm }; -export default withI18n()(withRouter(FormikApp)); - - - - - -/* -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { withRouter } from 'react-router-dom'; -import { withI18n } from '@lingui/react'; -import { t } from '@lingui/macro'; -import { withFormik, Field } from 'formik'; -import { - Form, - FormGroup, - Switch, - Checkbox, - TextInput, -} from '@patternfly/react-core'; -import ContentError from '@components/ContentError'; -import ContentLoading from '@components/ContentLoading'; -import AnsibleSelect from '@components/AnsibleSelect'; -import { TagMultiSelect } from '@components/MultiSelect'; -import FormActionGroup from '@components/FormActionGroup'; -import FormField, { - CheckboxField, - FieldTooltip, - FormSubmitError, -} from '@components/FormField'; -import FieldWithPrompt from '@components/FieldWithPrompt'; -import FormRow from '@components/FormRow'; -import { required } from '@util/validators'; -import styled from 'styled-components'; -import { JobTemplate } from '@types'; -import { - InventoryLookup, - InstanceGroupsLookup, - ProjectLookup, - MultiCredentialsLookup, -} from '@components/Lookup'; -import { VariablesField } from '@components/CodeMirrorInput'; -import { JobTemplatesAPI, ProjectsAPI } from '@api'; -import LabelSelect from './LabelSelect'; -import PlaybookSelect from './PlaybookSelect'; - -const GridFormGroup = styled(FormGroup)` - & > label { - grid-column: 1 / -1; - } - - && { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - } -`; - -class JobTemplateForm extends Component { - static propTypes = { - template: JobTemplate, - handleCancel: PropTypes.func.isRequired, - handleSubmit: PropTypes.func.isRequired, - submitError: PropTypes.shape({}), - }; - - static defaultProps = { - template: { - name: '', - description: '', - job_type: 'run', - inventory: undefined, - project: undefined, - playbook: '', - summary_fields: { - inventory: null, - labels: { results: [] }, - project: null, - credentials: [], - }, - isNew: true, - }, - submitError: null, - }; - - constructor(props) { - super(props); - this.state = { - hasContentLoading: true, - contentError: false, - project: props.template.summary_fields.project, - inventory: props.template.summary_fields.inventory, - allowCallbacks: !!props.template.host_config_key, - }; - this.handleProjectValidation = this.handleProjectValidation.bind(this); - this.loadRelatedInstanceGroups = this.loadRelatedInstanceGroups.bind(this); - this.handleProjectUpdate = this.handleProjectUpdate.bind(this); - this.setContentError = this.setContentError.bind(this); - this.fetchProject = this.fetchProject.bind(this); - } - - componentDidMount() { - const { validateField } = this.props; - this.setState({ contentError: null, hasContentLoading: true }); - // TODO: determine when LabelSelect has finished loading labels - Promise.all([this.loadRelatedInstanceGroups(), this.fetchProject()]).then( - () => { - this.setState({ hasContentLoading: false }); - validateField('project'); - } - ); - } - - async fetchProject() { - const { project } = this.state; - if (project && project.id) { - try { - const { data: projectData } = await ProjectsAPI.readDetail(project.id); - this.setState({ project: projectData }); - } catch (err) { - this.setState({ contentError: err }); - } - } - } - - async loadRelatedInstanceGroups() { - const { setFieldValue, template } = this.props; - if (!template.id) { - return; - } - try { - const { data } = await JobTemplatesAPI.readInstanceGroups(template.id); - setFieldValue('initialInstanceGroups', data.results); - setFieldValue('instanceGroups', [...data.results]); - } catch (err) { - this.setState({ contentError: err }); - } - } - - handleProjectValidation() { - const { i18n, touched } = this.props; - const { project } = this.state; - return () => { - if (!project && touched.project) { - return i18n._(t`Select a value for this field`); - } - if (project && project.status === 'never updated') { - return i18n._(t`This project needs to be updated`); - } - return undefined; - }; - } - - handleProjectUpdate(project) { - const { setFieldValue } = this.props; - setFieldValue('project', project.id); - setFieldValue('playbook', 0); - setFieldValue('scm_branch', ''); - this.setState({ project }); - } - - setContentError(contentError) { - this.setState({ contentError }); - } - - render() { - const { - contentError, - hasContentLoading, - inventory, - project, - allowCallbacks, - } = this.state; - const { - handleCancel, - handleSubmit, - handleBlur, - setFieldValue, - template, - submitError, - i18n, - } = this.props; - - const jobTypeOptions = [ - { - value: '', - key: '', - label: i18n._(t`Choose a job type`), - isDisabled: true, - }, - { value: 'run', key: 'run', label: i18n._(t`Run`), isDisabled: false }, - { - value: 'check', - key: 'check', - label: i18n._(t`Check`), - isDisabled: false, - }, - ]; - const verbosityOptions = [ - { value: '0', key: '0', label: i18n._(t`0 (Normal)`) }, - { value: '1', key: '1', label: i18n._(t`1 (Verbose)`) }, - { value: '2', key: '2', label: i18n._(t`2 (More Verbose)`) }, - { value: '3', key: '3', label: i18n._(t`3 (Debug)`) }, - { value: '4', key: '4', label: i18n._(t`4 (Connection Debug)`) }, - ]; - let callbackUrl; - if (template && template.related) { - const { origin } = document.location; - const path = template.related.callback || `${template.url}callback`; - callbackUrl = `${origin}${path}`; - } - - if (hasContentLoading) { - return ; - } - - if (contentError) { - return ; - } - - return ( -
- - - - - {({ field }) => ( - - - setFieldValue('labels', labels)} - onError={this.setContentError} - /> - - )} - - - - - - {({ field }) => { - return ( - + + + {({ field }) => { + return ( + + setFieldValue('credentials', newCredentials) + } + onError={this.setContentError} + /> + ); + }} + + + + {({ field }) => ( + + + - setFieldValue('credentials', newCredentials) - } + onChange={labels => setFieldValue('labels', labels)} onError={this.setContentError} /> - ); - }} - - - - - - {i18n._(t`The number of parallel or simultaneous - processes to use while executing the playbook. An empty value, - or a value less than 1 will use the Ansible default which is - usually 5. The default number of forks can be overwritten - with a change to`)}{' '} - ansible.cfg.{' '} - {i18n._(t`Refer to the Ansible documentation for details - about the configuration file.`)} - - } - /> - - - {({ form, field }) => { - return ( - { - field.onChange(event); - }} - /> - ); - }} - - - - - {({ field }) => ( - + )} - - - - - - {({ form, field }) => { - return ( - - form.setFieldValue(field.name, checked) - } - /> - ); - }} - - - - - {({ field, form }) => ( - form.setFieldValue(field.name, value)} - tooltip={i18n._(t`Select the Instance Groups for this Organization - to run on.`)} + - )} - - - - {({ field, form }) => ( - form.setFieldValue(field.name, value)} + + + {i18n._(t`The number of parallel or simultaneous + processes to use while executing the playbook. An empty value, + or a value less than 1 will use the Ansible default which is + usually 5. The default number of forks can be overwritten + with a change to`)}{' '} + ansible.cfg.{' '} + {i18n._(t`Refer to the Ansible documentation for details + about the configuration file.`)} + + } /> - )} - - - - - {({ field, form }) => ( - form.setFieldValue(field.name, value)} - /> - )} - - - - - - {i18n._(t`Provisioning Callbacks`)} -   - - - } - id="option-callbacks" - isChecked={allowCallbacks} - onChange={checked => { - this.setState({ allowCallbacks: checked }); - }} - /> - - - -
- - {callbackUrl && ( - - - - )} - - -
- - - - - + + {({ form, field }) => { + return ( + { + field.onChange(event); + }} + /> + ); + }} + + + + + {({ field }) => ( + + )} + + + + + + + {({ form, field }) => { + return ( + + form.setFieldValue(field.name, checked) + } + /> + ); + }} + + + + + {({ field, form }) => ( + form.setFieldValue(field.name, value)} + tooltip={i18n._(t`Select the Instance Groups for this Organization + to run on.`)} + /> + )} + + + + {({ field, form }) => ( + + form.setFieldValue(field.name, value) + } + /> + )} + + + + + {({ field, form }) => ( + + form.setFieldValue(field.name, value) + } + /> + )} + + + + + + + {i18n._(t`Provisioning Callbacks`)} +   + + + } + id="option-callbacks" + isChecked={allowCallbacks} + onChange={checked => { + this.setState({ allowCallbacks: checked }); + }} + /> + + + + + + {allowCallbacks && ( + <> + {callbackUrl && ( + + + + )} + + + )} + + + + + ); } @@ -1388,4 +729,3 @@ const FormikApp = withFormik({ export { JobTemplateForm as _JobTemplateForm }; export default withI18n()(withRouter(FormikApp)); -*/