@@ -35,6 +35,7 @@ interface Props<B> { | |||
children: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode; | |||
help?: React.ReactNode; | |||
hideKeyField?: boolean; | |||
isSecondInstance?: boolean; | |||
loading?: boolean; | |||
onCancel?: () => void; | |||
onDelete?: (definitionKey: string) => void; | |||
@@ -122,6 +123,7 @@ export default class AlmBindingDefinitionForm< | |||
children, | |||
help, | |||
hideKeyField, | |||
isSecondInstance, | |||
showInModal, | |||
loading = false, | |||
readOnly = false, | |||
@@ -129,39 +131,46 @@ export default class AlmBindingDefinitionForm< | |||
} = this.props; | |||
const { formData, touched } = this.state; | |||
const showEdit = this.props.onEdit !== undefined; | |||
const showCancel = touched || !showEdit; | |||
const showDelete = showEdit && this.props.onDelete !== undefined; | |||
return showInModal ? ( | |||
<AlmBindingDefinitionFormModalRenderer | |||
action={bindingDefinition.key ? 'edit' : 'create'} | |||
canSubmit={this.canSubmit} | |||
help={help} | |||
onCancel={this.handleCancel} | |||
onSubmit={this.handleFormSubmit}> | |||
{children({ | |||
formData, | |||
onFieldChange: this.handleFieldChange | |||
})} | |||
</AlmBindingDefinitionFormModalRenderer> | |||
) : ( | |||
<AlmBindingDefinitionFormRenderer | |||
canSubmit={this.canSubmit} | |||
help={help} | |||
loading={loading} | |||
onCancel={showCancel ? this.handleCancel : undefined} | |||
onDelete={showDelete ? this.handleDelete : undefined} | |||
onEdit={showEdit ? this.handleEdit : undefined} | |||
onSubmit={this.handleFormSubmit} | |||
success={success}> | |||
{children({ | |||
formData, | |||
hideKeyField, | |||
onFieldChange: this.handleFieldChange, | |||
readOnly | |||
})} | |||
</AlmBindingDefinitionFormRenderer> | |||
); | |||
if (showInModal) { | |||
const action = bindingDefinition.key ? 'edit' : 'create'; | |||
return ( | |||
<AlmBindingDefinitionFormModalRenderer | |||
action={action} | |||
canSubmit={this.canSubmit} | |||
help={help} | |||
isSecondInstance={Boolean(isSecondInstance)} | |||
onCancel={this.handleCancel} | |||
onSubmit={this.handleFormSubmit}> | |||
{children({ | |||
formData, | |||
onFieldChange: this.handleFieldChange | |||
})} | |||
</AlmBindingDefinitionFormModalRenderer> | |||
); | |||
} else { | |||
const showEdit = this.props.onEdit !== undefined; | |||
const showCancel = touched || !showEdit; | |||
const showDelete = showEdit && this.props.onDelete !== undefined; | |||
return ( | |||
<AlmBindingDefinitionFormRenderer | |||
canSubmit={this.canSubmit} | |||
help={help} | |||
loading={loading} | |||
onCancel={showCancel ? this.handleCancel : undefined} | |||
onDelete={showDelete ? this.handleDelete : undefined} | |||
onEdit={showEdit ? this.handleEdit : undefined} | |||
onSubmit={this.handleFormSubmit} | |||
success={success}> | |||
{children({ | |||
formData, | |||
hideKeyField, | |||
onFieldChange: this.handleFieldChange, | |||
readOnly | |||
})} | |||
</AlmBindingDefinitionFormRenderer> | |||
); | |||
} | |||
} | |||
} |
@@ -29,6 +29,7 @@ export interface AlmBindingDefinitionFormModalProps { | |||
canSubmit: () => boolean; | |||
children: React.ReactNode; | |||
help?: React.ReactNode; | |||
isSecondInstance: boolean; | |||
onCancel: () => void; | |||
onSubmit: () => void; | |||
} | |||
@@ -36,7 +37,7 @@ export interface AlmBindingDefinitionFormModalProps { | |||
export default function AlmBindingDefinitionFormModalRenderer( | |||
props: AlmBindingDefinitionFormModalProps | |||
) { | |||
const { action, children, help } = props; | |||
const { action, children, help, isSecondInstance } = props; | |||
const header = translate('settings.almintegration.form.header', action); | |||
return ( | |||
@@ -48,6 +49,12 @@ export default function AlmBindingDefinitionFormModalRenderer( | |||
</div> | |||
<div className="modal-body modal-container"> | |||
{isSecondInstance && action === 'create' && ( | |||
<Alert className="big-spacer-bottom" variant="warning"> | |||
{translate('settings.almintegration.form.second_instance_warning')} | |||
</Alert> | |||
)} | |||
<div className="display-flex-start"> | |||
<div className="flex-1">{children}</div> | |||
@@ -175,6 +175,7 @@ export default function AlmTabRenderer<B extends AlmBindingDefinition>( | |||
<AlmBindingDefinitionForm | |||
bindingDefinition={editedDefinition} | |||
help={help} | |||
isSecondInstance={definitions.length === 1} | |||
onCancel={props.onCancel} | |||
onSubmit={props.onSubmit} | |||
optionalFields={optionalFields} |
@@ -25,7 +25,12 @@ import { GithubBindingDefinition } from '../../../../../types/alm-settings'; | |||
import AlmBindingDefinitionForm from '../AlmBindingDefinitionForm'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender()).toMatchSnapshot('default'); | |||
expect(shallowRender({ showInModal: true })).toMatchSnapshot('modal'); | |||
expect( | |||
shallowRender({ bindingDefinition: mockGithubBindingDefinition(), showInModal: true }) | |||
).toMatchSnapshot('modal edit'); | |||
}); | |||
it('should reset if the props change', () => { |
@@ -25,7 +25,8 @@ import AlmBindingDefinitionFormModalRenderer, { | |||
it('should render correctly', () => { | |||
expect(shallowRender().dive()).toMatchSnapshot(); | |||
expect(shallowRender({ help: <span>Help me</span> }).dive()).toMatchSnapshot(); | |||
expect(shallowRender({ help: <span>Help me</span> }).dive()).toMatchSnapshot('with help'); | |||
expect(shallowRender({ isSecondInstance: true }).dive()).toMatchSnapshot('second instance'); | |||
}); | |||
function shallowRender(props: Partial<AlmBindingDefinitionFormModalProps> = {}) { | |||
@@ -33,6 +34,7 @@ function shallowRender(props: Partial<AlmBindingDefinitionFormModalProps> = {}) | |||
<AlmBindingDefinitionFormModalRenderer | |||
action="create" | |||
canSubmit={jest.fn()} | |||
isSecondInstance={false} | |||
onCancel={jest.fn()} | |||
onSubmit={jest.fn()} | |||
{...props}> |
@@ -78,6 +78,21 @@ it('should render correctly with validation', () => { | |||
}; | |||
expect(shallowRender(githubProps)).toMatchSnapshot(); | |||
expect(shallowRender({ ...githubProps, definitions: [] })).toMatchSnapshot('empty'); | |||
expect( | |||
shallowRender({ | |||
...githubProps, | |||
editedDefinition: mockGithubBindingDefinition() | |||
}) | |||
).toMatchSnapshot('create a second'); | |||
expect( | |||
shallowRender({ | |||
...githubProps, | |||
definitions: [], | |||
editedDefinition: mockGithubBindingDefinition() | |||
}) | |||
).toMatchSnapshot('create a first'); | |||
}); | |||
function shallowRenderAzure(props: Partial<AlmTabRendererProps<AzureBindingDefinition>> = {}) { |
@@ -1,6 +1,6 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
exports[`should render correctly: default 1`] = ` | |||
<AlmBindingDefinitionFormRenderer | |||
canSubmit={[Function]} | |||
loading={false} | |||
@@ -9,3 +9,23 @@ exports[`should render correctly 1`] = ` | |||
success={false} | |||
/> | |||
`; | |||
exports[`should render correctly: modal 1`] = ` | |||
<AlmBindingDefinitionFormModalRenderer | |||
action="create" | |||
canSubmit={[Function]} | |||
isSecondInstance={false} | |||
onCancel={[Function]} | |||
onSubmit={[Function]} | |||
/> | |||
`; | |||
exports[`should render correctly: modal edit 1`] = ` | |||
<AlmBindingDefinitionFormModalRenderer | |||
action="edit" | |||
canSubmit={[Function]} | |||
isSecondInstance={false} | |||
onCancel={[Function]} | |||
onSubmit={[Function]} | |||
/> | |||
`; |
@@ -52,7 +52,65 @@ exports[`should render correctly 1`] = ` | |||
</Modal> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
exports[`should render correctly: second instance 1`] = ` | |||
<Modal | |||
contentLabel="settings.almintegration.form.header.create" | |||
onRequestClose={[MockFunction]} | |||
size="medium" | |||
> | |||
<form | |||
className="views-form" | |||
onSubmit={[Function]} | |||
> | |||
<div | |||
className="modal-head" | |||
> | |||
<h2> | |||
settings.almintegration.form.header.create | |||
</h2> | |||
</div> | |||
<div | |||
className="modal-body modal-container" | |||
> | |||
<Alert | |||
className="big-spacer-bottom" | |||
variant="warning" | |||
> | |||
settings.almintegration.form.second_instance_warning | |||
</Alert> | |||
<div | |||
className="display-flex-start" | |||
> | |||
<div | |||
className="flex-1" | |||
> | |||
<Component /> | |||
</div> | |||
</div> | |||
</div> | |||
<div | |||
className="modal-foot" | |||
> | |||
<DeferredSpinner | |||
className="spacer-right" | |||
loading={false} | |||
/> | |||
<SubmitButton | |||
disabled={true} | |||
> | |||
settings.almintegration.form.save | |||
</SubmitButton> | |||
<ResetButtonLink | |||
onClick={[Function]} | |||
> | |||
cancel | |||
</ResetButtonLink> | |||
</div> | |||
</form> | |||
</Modal> | |||
`; | |||
exports[`should render correctly: with help 1`] = ` | |||
<Modal | |||
contentLabel="settings.almintegration.form.header.create" | |||
onRequestClose={[MockFunction]} |
@@ -48,6 +48,7 @@ exports[`should render correctly for multi-ALM binding: editing a definition 1`] | |||
} | |||
/> | |||
} | |||
isSecondInstance={true} | |||
onCancel={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
showInModal={true} | |||
@@ -386,6 +387,139 @@ exports[`should render correctly with validation 1`] = ` | |||
</div> | |||
`; | |||
exports[`should render correctly with validation: create a first 1`] = ` | |||
<div | |||
className="big-padded" | |||
> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<div | |||
className="spacer-bottom text-right" | |||
> | |||
<Button | |||
data-test="settings__alm-create" | |||
disabled={false} | |||
onClick={[MockFunction]} | |||
> | |||
settings.almintegration.table.create | |||
</Button> | |||
</div> | |||
<AlmBindingDefinitionForm | |||
bindingDefinition={ | |||
Object { | |||
"appId": "123456", | |||
"clientId": "client1", | |||
"clientSecret": "**clientsecret**", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http://github.enterprise.com", | |||
} | |||
} | |||
help={ | |||
<FormattedMessage | |||
defaultMessage="settings.almintegration.github.info" | |||
id="settings.almintegration.github.info" | |||
values={ | |||
Object { | |||
"link": <Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
target="_blank" | |||
to="/documentation/analysis/pr-decoration/" | |||
> | |||
learn_more | |||
</Link>, | |||
} | |||
} | |||
/> | |||
} | |||
isSecondInstance={false} | |||
onCancel={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
showInModal={true} | |||
> | |||
<Component /> | |||
</AlmBindingDefinitionForm> | |||
</DeferredSpinner> | |||
</div> | |||
`; | |||
exports[`should render correctly with validation: create a second 1`] = ` | |||
<div | |||
className="big-padded" | |||
> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<div | |||
className="spacer-bottom text-right" | |||
> | |||
<Button | |||
data-test="settings__alm-create" | |||
disabled={false} | |||
onClick={[MockFunction]} | |||
> | |||
settings.almintegration.table.create | |||
</Button> | |||
</div> | |||
<AlmBindingDefinitionBox | |||
definition={ | |||
Object { | |||
"appId": "123456", | |||
"clientId": "client1", | |||
"clientSecret": "**clientsecret**", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http://github.enterprise.com", | |||
} | |||
} | |||
key="key" | |||
multipleDefinitions={false} | |||
onCheck={[MockFunction]} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
<AlmBindingDefinitionForm | |||
bindingDefinition={ | |||
Object { | |||
"appId": "123456", | |||
"clientId": "client1", | |||
"clientSecret": "**clientsecret**", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http://github.enterprise.com", | |||
} | |||
} | |||
help={ | |||
<FormattedMessage | |||
defaultMessage="settings.almintegration.github.info" | |||
id="settings.almintegration.github.info" | |||
values={ | |||
Object { | |||
"link": <Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
target="_blank" | |||
to="/documentation/analysis/pr-decoration/" | |||
> | |||
learn_more | |||
</Link>, | |||
} | |||
} | |||
/> | |||
} | |||
isSecondInstance={true} | |||
onCancel={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
showInModal={true} | |||
> | |||
<Component /> | |||
</AlmBindingDefinitionForm> | |||
</DeferredSpinner> | |||
</div> | |||
`; | |||
exports[`should render correctly with validation: empty 1`] = ` | |||
<div | |||
className="big-padded" |
@@ -1076,6 +1076,7 @@ settings.almintegration.delete.info={0} projects will no longer get Pull Request | |||
settings.almintegration.delete.no_info=An unknown number of projects will no longer get Pull Request Decorations. | |||
settings.almintegration.form.header.create=Create a configuration | |||
settings.almintegration.form.header.edit=Edit the configuration | |||
settings.almintegration.form.second_instance_warning=Binding more than one instance of an ALM will deactivate the import of repositories from that ALM. | |||
settings.almintegration.form.name.azure=Configuration name | |||
settings.almintegration.form.name.azure.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Azure instance for a project. | |||
settings.almintegration.form.name.bitbucket=Configuration name |