aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps
diff options
context:
space:
mode:
authorPhilippe Perrin <philippe.perrin@sonarsource.com>2021-06-24 14:15:06 +0200
committersonartech <sonartech@sonarsource.com>2021-06-28 20:03:21 +0000
commitf3180f874f095ffa1d26f876a6fd4acfb3cdf6c4 (patch)
tree4ed2db36d87cb988067f19a2af84d1fbf9db2648 /server/sonar-web/src/main/js/apps
parentafac7cec97a340daf10f8b61e132bc29ae4999f2 (diff)
downloadsonarqube-f3180f874f095ffa1d26f876a6fd4acfb3cdf6c4.tar.gz
sonarqube-f3180f874f095ffa1d26f876a6fd4acfb3cdf6c4.zip
SONAR-14932 Trigger alm settings validation before closing the modal
Diffstat (limited to 'server/sonar-web/src/main/js/apps')
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx76
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap101
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionForm.tsx76
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormRenderer.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionForm-test.tsx31
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormRenderer-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormRenderer-test.tsx.snap73
8 files changed, 329 insertions, 51 deletions
diff --git a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
index b4c8c35affb..43a9a8fb69c 100644
--- a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
@@ -257,6 +257,7 @@ export class CreateProjectPage extends React.PureComponent<Props, State> {
alreadyHaveInstanceConfigured={false}
onCancel={this.handleOnCancelCreation}
afterSubmit={this.handleAfterSubmit}
+ enforceValidation={true}
/>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
index da7ede592d4..2845ff4d050 100644
--- a/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
+++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectPage-test.tsx
@@ -19,9 +19,12 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { getAlmSettings } from '../../../../api/alm-settings';
import { mockLocation, mockLoggedInUser, mockRouter } from '../../../../helpers/testMocks';
import { AlmKeys } from '../../../../types/alm-settings';
+import AlmBindingDefinitionForm from '../../../settings/components/almIntegration/AlmBindingDefinitionForm';
+import CreateProjectModeSelection from '../CreateProjectModeSelection';
import { CreateProjectPage } from '../CreateProjectPage';
import { CreateProjectModes } from '../types';
@@ -36,42 +39,65 @@ it('should render correctly', () => {
expect(getAlmSettings).toBeCalled();
});
-it('should render correctly if the manual method is selected', () => {
+it.each([
+ [CreateProjectModes.Manual],
+ [CreateProjectModes.AzureDevOps],
+ [CreateProjectModes.BitbucketServer],
+ [CreateProjectModes.BitbucketCloud],
+ [CreateProjectModes.GitHub],
+ [CreateProjectModes.GitLab]
+])('should render correctly for %s mode', (mode: CreateProjectModes) => {
expect(
shallowRender({
- location: mockLocation({ query: { mode: CreateProjectModes.Manual } })
+ location: mockLocation({ query: { mode } })
})
).toMatchSnapshot();
});
-it('should render correctly if the Azure method is selected', () => {
- expect(
- shallowRender({
- location: mockLocation({ query: { mode: CreateProjectModes.AzureDevOps } })
- })
- ).toMatchSnapshot();
-});
+it('should render alm configuration creation correctly', () => {
+ const wrapper = shallowRender();
-it('should render correctly if the BBS method is selected', () => {
- expect(
- shallowRender({
- location: mockLocation({ query: { mode: CreateProjectModes.BitbucketServer } })
- })
- ).toMatchSnapshot();
+ wrapper
+ .find(CreateProjectModeSelection)
+ .props()
+ .onConfigMode(AlmKeys.Azure);
+ expect(wrapper).toMatchSnapshot();
});
-it('should render correctly if the GitHub method is selected', () => {
- const wrapper = shallowRender({
- location: mockLocation({ query: { mode: CreateProjectModes.GitHub } })
- });
- expect(wrapper).toMatchSnapshot();
+it('should cancel alm configuration creation properly', () => {
+ const wrapper = shallowRender();
+
+ wrapper
+ .find(CreateProjectModeSelection)
+ .props()
+ .onConfigMode(AlmKeys.Azure);
+ expect(wrapper.state().creatingAlmDefinition).toBe(AlmKeys.Azure);
+
+ wrapper
+ .find(AlmBindingDefinitionForm)
+ .props()
+ .onCancel();
+ expect(wrapper.state().creatingAlmDefinition).toBeUndefined();
});
-it('should render correctly if the GitLab method is selected', () => {
- const wrapper = shallowRender({
- location: mockLocation({ query: { mode: CreateProjectModes.GitLab } })
- });
- expect(wrapper).toMatchSnapshot();
+it('should submit alm configuration creation properly', async () => {
+ const push = jest.fn();
+ const wrapper = shallowRender({ router: mockRouter({ push }) });
+
+ wrapper
+ .find(CreateProjectModeSelection)
+ .props()
+ .onConfigMode(AlmKeys.Azure);
+ expect(wrapper.state().creatingAlmDefinition).toBe(AlmKeys.Azure);
+
+ wrapper
+ .find(AlmBindingDefinitionForm)
+ .props()
+ .afterSubmit({ key: 'test-key' });
+ await waitAndUpdate(wrapper);
+ expect(wrapper.state().creatingAlmDefinition).toBeUndefined();
+ expect(getAlmSettings).toHaveBeenCalled();
+ expect(push).toHaveBeenCalledWith({ pathname: '/path', query: { mode: AlmKeys.Azure } });
});
it('should submit alm configuration creation properly for BBC', async () => {
diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
index 58fa5abb10e..e23064c7a37 100644
--- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
@@ -1,5 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`should render alm configuration creation correctly 1`] = `
+<Fragment>
+ <Helmet
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="onboarding.create_project.select_method"
+ titleTemplate="%s"
+ />
+ <A11ySkipTarget
+ anchor="create_project_main"
+ />
+ <div
+ className="page page-limited huge-spacer-bottom position-relative"
+ id="create-project"
+ >
+ <Connect(withAppState(CreateProjectModeSelection))
+ almCounts={
+ Object {
+ "azure": 0,
+ "bitbucket": 0,
+ "bitbucketcloud": 0,
+ "github": 0,
+ "gitlab": 0,
+ }
+ }
+ loadingBindings={true}
+ onConfigMode={[Function]}
+ onSelectMode={[Function]}
+ />
+ <AlmBindingDefinitionForm
+ afterSubmit={[Function]}
+ alm="azure"
+ alreadyHaveInstanceConfigured={false}
+ enforceValidation={true}
+ onCancel={[Function]}
+ />
+ </div>
+</Fragment>
+`;
+
exports[`should render correctly 1`] = `
<Fragment>
<Helmet
@@ -33,7 +73,7 @@ exports[`should render correctly 1`] = `
</Fragment>
`;
-exports[`should render correctly if the Azure method is selected 1`] = `
+exports[`should render correctly for azure mode 1`] = `
<Fragment>
<Helmet
defer={true}
@@ -84,7 +124,7 @@ exports[`should render correctly if the Azure method is selected 1`] = `
</Fragment>
`;
-exports[`should render correctly if the BBS method is selected 1`] = `
+exports[`should render correctly for bitbucket mode 1`] = `
<Fragment>
<Helmet
defer={true}
@@ -135,7 +175,58 @@ exports[`should render correctly if the BBS method is selected 1`] = `
</Fragment>
`;
-exports[`should render correctly if the GitHub method is selected 1`] = `
+exports[`should render correctly for bitbucketcloud mode 1`] = `
+<Fragment>
+ <Helmet
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="onboarding.create_project.select_method"
+ titleTemplate="%s"
+ />
+ <A11ySkipTarget
+ anchor="create_project_main"
+ />
+ <div
+ className="page page-limited huge-spacer-bottom position-relative"
+ id="create-project"
+ >
+ <BitbucketCloudProjectCreate
+ canAdmin={false}
+ loadingBindings={true}
+ location={
+ Object {
+ "action": "PUSH",
+ "hash": "",
+ "key": "key",
+ "pathname": "/path",
+ "query": Object {
+ "mode": "bitbucketcloud",
+ },
+ "search": "",
+ "state": Object {},
+ }
+ }
+ onProjectCreate={[Function]}
+ router={
+ Object {
+ "createHref": [MockFunction],
+ "createPath": [MockFunction],
+ "go": [MockFunction],
+ "goBack": [MockFunction],
+ "goForward": [MockFunction],
+ "isActive": [MockFunction],
+ "push": [MockFunction],
+ "replace": [MockFunction],
+ "setRouteLeaveHook": [MockFunction],
+ }
+ }
+ settings={Array []}
+ />
+ </div>
+</Fragment>
+`;
+
+exports[`should render correctly for github mode 1`] = `
<Fragment>
<Helmet
defer={true}
@@ -186,7 +277,7 @@ exports[`should render correctly if the GitHub method is selected 1`] = `
</Fragment>
`;
-exports[`should render correctly if the GitLab method is selected 1`] = `
+exports[`should render correctly for gitlab mode 1`] = `
<Fragment>
<Helmet
defer={true}
@@ -237,7 +328,7 @@ exports[`should render correctly if the GitLab method is selected 1`] = `
</Fragment>
`;
-exports[`should render correctly if the manual method is selected 1`] = `
+exports[`should render correctly for manual mode 1`] = `
<Fragment>
<Helmet
defer={true}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionForm.tsx
index 739089ab2fd..090b22c04dd 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionForm.tsx
@@ -24,11 +24,13 @@ import {
createBitbucketServerConfiguration,
createGithubConfiguration,
createGitlabConfiguration,
+ deleteConfiguration,
updateAzureConfiguration,
updateBitbucketCloudConfiguration,
updateBitbucketServerConfiguration,
updateGithubConfiguration,
- updateGitlabConfiguration
+ updateGitlabConfiguration,
+ validateAlmSettings
} from '../../../../api/alm-settings';
import {
AlmBindingDefinition,
@@ -47,8 +49,9 @@ interface Props {
alm: AlmKeys;
bindingDefinition?: AlmBindingDefinition;
alreadyHaveInstanceConfigured: boolean;
- onCancel?: () => void;
- afterSubmit?: (data: AlmBindingDefinitionBase) => void;
+ onCancel: () => void;
+ afterSubmit: (data: AlmBindingDefinitionBase) => void;
+ enforceValidation?: boolean;
}
interface State {
@@ -56,6 +59,8 @@ interface State {
touched: boolean;
submitting: boolean;
bitbucketVariant?: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud;
+ alreadySavedFormData?: AlmBindingDefinition;
+ validationError?: string;
}
const BINDING_PER_ALM = {
@@ -144,33 +149,71 @@ export default class AlmBindingDefinitionForm extends React.PureComponent<Props,
};
handleFormSubmit = async () => {
- const { alm } = this.props;
- const { formData, bitbucketVariant } = this.state;
+ const { alm, enforceValidation } = this.props;
+ const { formData, bitbucketVariant, alreadySavedFormData, validationError } = this.state;
const apiAlm = bitbucketVariant ?? alm;
- const apiMethod = this.props.bindingDefinition?.key
- ? BINDING_PER_ALM[apiAlm].updateApi({
- newKey: formData.key,
- ...formData,
- key: this.props.bindingDefinition.key
- } as any)
- : BINDING_PER_ALM[apiAlm].createApi({ ...formData } as any);
+ let apiMethod;
+
+ if (alreadySavedFormData && validationError) {
+ apiMethod = BINDING_PER_ALM[apiAlm].updateApi({
+ newKey: formData.key,
+ ...formData,
+ key: alreadySavedFormData.key
+ } as any);
+ } else if (this.props.bindingDefinition?.key) {
+ apiMethod = BINDING_PER_ALM[apiAlm].updateApi({
+ newKey: formData.key,
+ ...formData,
+ key: this.props.bindingDefinition.key
+ } as any);
+ } else {
+ apiMethod = BINDING_PER_ALM[apiAlm].createApi({ ...formData } as any);
+ }
this.setState({ submitting: true });
try {
await apiMethod;
- if (this.props.afterSubmit) {
+ if (!this.mounted) {
+ return;
+ }
+
+ this.setState({ alreadySavedFormData: formData });
+
+ let error: string | undefined;
+
+ if (enforceValidation) {
+ error = await validateAlmSettings(formData.key);
+ }
+
+ if (!this.mounted) {
+ return;
+ }
+
+ if (error) {
+ this.setState({ validationError: error });
+ } else {
this.props.afterSubmit(formData);
}
} finally {
if (this.mounted) {
- this.setState({ submitting: false });
+ this.setState({ submitting: false, touched: false });
}
}
};
+ handleOnCancel = async () => {
+ const { alreadySavedFormData } = this.state;
+
+ if (alreadySavedFormData) {
+ await deleteConfiguration(alreadySavedFormData.key);
+ }
+
+ this.props.onCancel();
+ };
+
handleBitbucketVariantChange = (
bitbucketVariant: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud
) => {
@@ -188,7 +231,7 @@ export default class AlmBindingDefinitionForm extends React.PureComponent<Props,
render() {
const { alm, bindingDefinition, alreadyHaveInstanceConfigured } = this.props;
- const { formData, submitting, bitbucketVariant } = this.state;
+ const { formData, submitting, bitbucketVariant, validationError } = this.state;
const isUpdate = !!bindingDefinition;
@@ -198,13 +241,14 @@ export default class AlmBindingDefinitionForm extends React.PureComponent<Props,
isUpdate={isUpdate}
canSubmit={this.canSubmit()}
alreadyHaveInstanceConfigured={alreadyHaveInstanceConfigured}
- onCancel={() => this.props.onCancel && this.props.onCancel()}
+ onCancel={this.handleOnCancel}
onSubmit={this.handleFormSubmit}
onFieldChange={this.handleFieldChange}
formData={formData}
submitting={submitting}
bitbucketVariant={bitbucketVariant}
onBitbucketVariantChange={this.handleBitbucketVariantChange}
+ validationError={validationError}
/>
);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormRenderer.tsx
index c50f5d2ed4e..1aca5499b39 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormRenderer.tsx
@@ -51,6 +51,7 @@ export interface AlmBindingDefinitionFormProps {
onBitbucketVariantChange: (
bitbucketVariant: AlmKeys.BitbucketServer | AlmKeys.BitbucketCloud
) => void;
+ validationError?: string;
}
export default class AlmBindingDefinitionFormRenderer extends React.PureComponent<
@@ -99,7 +100,13 @@ export default class AlmBindingDefinitionFormRenderer extends React.PureComponen
};
render() {
- const { isUpdate, alreadyHaveInstanceConfigured, canSubmit, submitting } = this.props;
+ const {
+ isUpdate,
+ alreadyHaveInstanceConfigured,
+ canSubmit,
+ submitting,
+ validationError
+ } = this.props;
const header = translate('settings.almintegration.form.header', isUpdate ? 'edit' : 'create');
const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
@@ -125,6 +132,16 @@ export default class AlmBindingDefinitionFormRenderer extends React.PureComponen
</Alert>
)}
{this.renderForm()}
+ {validationError && !canSubmit && (
+ <Alert variant="error">
+ <p className="spacer-bottom">
+ {translate('settings.almintegration.configuration_invalid')}
+ </p>
+ <ul className="list-styled">
+ <li>{validationError}</li>
+ </ul>
+ </Alert>
+ )}
</div>
<div className="modal-foot">
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionForm-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionForm-test.tsx
index 09f5f58c8a3..b4ca5b1e7b4 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionForm-test.tsx
@@ -26,11 +26,13 @@ import {
createBitbucketServerConfiguration,
createGithubConfiguration,
createGitlabConfiguration,
+ deleteConfiguration,
updateAzureConfiguration,
updateBitbucketCloudConfiguration,
updateBitbucketServerConfiguration,
updateGithubConfiguration,
- updateGitlabConfiguration
+ updateGitlabConfiguration,
+ validateAlmSettings
} from '../../../../../api/alm-settings';
import {
mockAzureBindingDefinition,
@@ -53,7 +55,9 @@ jest.mock('../../../../../api/alm-settings', () => ({
updateBitbucketCloudConfiguration: jest.fn().mockResolvedValue({}),
updateBitbucketServerConfiguration: jest.fn().mockResolvedValue({}),
updateGithubConfiguration: jest.fn().mockResolvedValue({}),
- updateGitlabConfiguration: jest.fn().mockResolvedValue({})
+ updateGitlabConfiguration: jest.fn().mockResolvedValue({}),
+ validateAlmSettings: jest.fn().mockResolvedValue(undefined),
+ deleteConfiguration: jest.fn().mockResolvedValue(undefined)
}));
beforeEach(() => {
@@ -89,12 +93,31 @@ it('should handle form submit', async () => {
const wrapper = shallowRender({ afterSubmit });
wrapper.instance().setState({ formData });
- await waitAndUpdate(wrapper);
await wrapper.instance().handleFormSubmit();
- await waitAndUpdate(wrapper);
expect(afterSubmit).toHaveBeenCalledWith(formData);
});
+it('should handle validation error during submit, and cancellation', async () => {
+ const afterSubmit = jest.fn();
+ const formData = mockGithubBindingDefinition();
+ const error = 'This a test error message';
+ (validateAlmSettings as jest.Mock).mockResolvedValueOnce(error);
+
+ const wrapper = shallowRender({ afterSubmit, enforceValidation: true });
+
+ wrapper.instance().setState({ formData });
+ await wrapper.instance().handleFormSubmit();
+ expect(validateAlmSettings).toHaveBeenCalledWith(formData.key);
+ expect(wrapper.state().validationError).toBe(error);
+ expect(afterSubmit).not.toHaveBeenCalledWith();
+
+ wrapper
+ .find(AlmBindingDefinitionFormRenderer)
+ .props()
+ .onCancel();
+ expect(deleteConfiguration).toHaveBeenCalledWith(formData.key);
+});
+
it.each([
[AlmKeys.Azure, undefined, createAzureConfiguration],
[AlmKeys.Azure, mockAzureBindingDefinition(), updateAzureConfiguration],
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormRenderer-test.tsx
index a28503cd58c..e60c01849c8 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormRenderer-test.tsx
@@ -34,6 +34,9 @@ it('should render correctly', () => {
expect(shallowRender({ alreadyHaveInstanceConfigured: true })).toMatchSnapshot('second instance');
expect(shallowRender({ submitting: true })).toMatchSnapshot('submitting');
expect(shallowRender({ isUpdate: true })).toMatchSnapshot('editing');
+ expect(shallowRender({ validationError: 'this is a validation error' })).toMatchSnapshot(
+ 'with validation error'
+ );
});
it.each([[AlmKeys.Azure], [AlmKeys.GitHub], [AlmKeys.GitLab], [AlmKeys.BitbucketServer]])(
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormRenderer-test.tsx.snap
index ef718f37281..fceec04e547 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormRenderer-test.tsx.snap
@@ -464,3 +464,76 @@ exports[`should render correctly: submitting 1`] = `
</form>
</Modal>
`;
+
+exports[`should render correctly: with validation error 1`] = `
+<Modal
+ contentLabel="settings.almintegration.form.header.create"
+ onRequestClose={[MockFunction]}
+ shouldCloseOnOverlayClick={false}
+ 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"
+ >
+ <GithubForm
+ formData={
+ Object {
+ "appId": "123456",
+ "clientId": "client1",
+ "clientSecret": "**clientsecret**",
+ "key": "key",
+ "privateKey": "asdf1234",
+ "url": "http://github.enterprise.com",
+ }
+ }
+ onFieldChange={[MockFunction]}
+ />
+ <Alert
+ variant="error"
+ >
+ <p
+ className="spacer-bottom"
+ >
+ settings.almintegration.configuration_invalid
+ </p>
+ <ul
+ className="list-styled"
+ >
+ <li>
+ this is a validation error
+ </li>
+ </ul>
+ </Alert>
+ </div>
+ <div
+ className="modal-foot"
+ >
+ <SubmitButton
+ disabled={true}
+ >
+ settings.almintegration.form.save
+ <DeferredSpinner
+ className="spacer-left"
+ loading={false}
+ />
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
+ >
+ cancel
+ </ResetButtonLink>
+ </div>
+ </form>
+</Modal>
+`;