aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/settings
diff options
context:
space:
mode:
authorWouter Admiraal <wouter.admiraal@sonarsource.com>2019-12-10 08:01:25 +0100
committerSonarTech <sonartech@sonarsource.com>2019-12-19 20:46:11 +0100
commit4a6ca23e2f3e9ea5f6c86b6aea0b2740d4a99910 (patch)
tree1861972ebae1735cb72fc91bc2dd822e5fede70e /server/sonar-web/src/main/js/apps/settings
parent2613e49e68f81c81b4d23ae1e640873990ca6991 (diff)
downloadsonarqube-4a6ca23e2f3e9ea5f6c86b6aea0b2740d4a99910.tar.gz
sonarqube-4a6ca23e2f3e9ea5f6c86b6aea0b2740d4a99910.zip
SONAR-12793 Simplify PR Decoration administration
Diffstat (limited to 'server/sonar-web/src/main/js/apps/settings')
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmDefinitionFormField.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationForm.tsx166
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModal.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModalRenderer.tsx17
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormRenderer.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationTable.tsx104
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTab.tsx132
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTabRenderer.tsx136
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureForm.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureFormModal.tsx)28
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTab.tsx84
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTabRenderer.tsx73
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketForm.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketFormModal.tsx)31
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx89
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTabRenderer.tsx76
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubForm.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubFormModal.tsx)30
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTab.tsx92
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTabRenderer.tsx77
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabForm.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabFormModal.tsx)30
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTab.tsx84
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTabRenderer.tsx73
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PullRequestDecoration.tsx24
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/TabHeader.tsx77
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModal-test.tsx)68
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModalRenderer-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormRenderer-test.tsx68
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationTable-test.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTab-test.tsx109
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTabRenderer-test.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTabRenderer-test.tsx)34
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureFormModal-test.tsx)6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTab-test.tsx77
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTabRenderer-test.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketFormModal-test.tsx)6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTabRenderer-test.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubFormModal-test.tsx)6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTab-test.tsx82
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabFormModal-test.tsx)6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTab-test.tsx77
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTabRenderer-test.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PRDecorationTabs-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/TabHeader-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmDefinitionFormField-test.tsx.snap3
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModal-test.tsx.snap)8
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModalRenderer-test.tsx.snap53
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormRenderer-test.tsx.snap121
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationTable-test.tsx.snap384
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTab-test.tsx.snap32
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap254
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureFormModal-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTab-test.tsx.snap27
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTabRenderer-test.tsx.snap80
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketFormModal-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap39
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap93
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubFormModal-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTab-test.tsx.snap43
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTabRenderer-test.tsx.snap97
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabFormModal-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTab-test.tsx.snap27
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTabRenderer-test.tsx.snap80
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap5
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PullRequestDecoration-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/TabHeader-test.tsx.snap83
64 files changed, 1935 insertions, 1960 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmDefinitionFormField.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmDefinitionFormField.tsx
index 1e758a1671d..80310699452 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmDefinitionFormField.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmDefinitionFormField.tsx
@@ -30,13 +30,24 @@ export interface AlmDefinitionFormFieldProps<B extends AlmSettingsBinding> {
maxLength?: number;
onFieldChange: (id: keyof B, value: string) => void;
propKey: keyof B;
+ readOnly?: boolean;
value: string;
}
export function AlmDefinitionFormField<B extends AlmSettingsBinding>(
props: AlmDefinitionFormFieldProps<B>
) {
- const { autoFocus, help, id, isTextArea, maxLength, onFieldChange, propKey, value } = props;
+ const {
+ autoFocus,
+ help,
+ id,
+ isTextArea,
+ maxLength,
+ onFieldChange,
+ propKey,
+ readOnly = false,
+ value
+ } = props;
return (
<div className="modal-field">
@@ -48,6 +59,7 @@ export function AlmDefinitionFormField<B extends AlmSettingsBinding>(
{isTextArea ? (
<textarea
className="settings-large-input"
+ disabled={readOnly}
id={id}
maxLength={maxLength || 2000}
onChange={e => onFieldChange(propKey, e.currentTarget.value)}
@@ -59,6 +71,7 @@ export function AlmDefinitionFormField<B extends AlmSettingsBinding>(
<input
autoFocus={autoFocus}
className="input-super-large"
+ disabled={readOnly}
id={id}
maxLength={maxLength || 100}
name={id}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationForm.tsx
new file mode 100644
index 00000000000..47e928ce424
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationForm.tsx
@@ -0,0 +1,166 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { isEqual, omit } from 'lodash';
+import * as React from 'react';
+import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings';
+import AlmPRDecorationFormModalRenderer from './AlmPRDecorationFormModalRenderer';
+import AlmPRDecorationFormRenderer from './AlmPRDecorationFormRenderer';
+
+export interface AlmPRDecorationFormChildrenProps<B> {
+ formData: B;
+ hideKeyField?: boolean;
+ onFieldChange: (fieldId: keyof B, value: string) => void;
+ readOnly?: boolean;
+}
+
+interface Props<B> {
+ alm: ALM_KEYS;
+ bindingDefinition: B;
+ children: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode;
+ help?: React.ReactNode;
+ hideKeyField?: boolean;
+ loading?: boolean;
+ onCancel?: () => void;
+ onDelete?: (definitionKey: string) => void;
+ onEdit?: (definitionKey: string) => void;
+ onSubmit: (data: B, originalKey: string) => void;
+ readOnly?: boolean;
+ showInModal?: boolean;
+ success?: boolean;
+}
+
+interface State<B> {
+ formData: B;
+ touched: boolean;
+}
+
+export default class AlmPRDecorationForm<B extends AlmSettingsBinding> extends React.PureComponent<
+ Props<B>,
+ State<B>
+> {
+ constructor(props: Props<B>) {
+ super(props);
+ this.state = { formData: props.bindingDefinition, touched: false };
+ }
+
+ componentDidUpdate(prevProps: Props<B>) {
+ if (!isEqual(prevProps.bindingDefinition, this.props.bindingDefinition)) {
+ this.setState({ formData: this.props.bindingDefinition, touched: false });
+ }
+ }
+
+ handleCancel = () => {
+ this.setState({ formData: this.props.bindingDefinition, touched: false });
+ if (this.props.onCancel) {
+ this.props.onCancel();
+ }
+ };
+
+ handleDelete = () => {
+ if (this.props.onDelete) {
+ this.props.onDelete(this.props.bindingDefinition.key);
+ }
+ };
+
+ handleEdit = () => {
+ if (this.props.onEdit) {
+ this.props.onEdit(this.props.bindingDefinition.key);
+ }
+ };
+
+ handleFieldChange = (fieldId: keyof B, value: string) => {
+ this.setState(({ formData }) => ({
+ formData: {
+ ...formData,
+ [fieldId]: value
+ },
+ touched: true
+ }));
+ };
+
+ handleFormSubmit = () => {
+ this.props.onSubmit(this.state.formData, this.props.bindingDefinition.key);
+ };
+
+ canSubmit = () => {
+ const { hideKeyField } = this.props;
+ const { formData, touched } = this.state;
+
+ let values;
+ if (hideKeyField) {
+ values = omit(formData, 'key');
+ } else {
+ values = { ...formData };
+ }
+
+ return touched && !Object.values(values).some(v => !v);
+ };
+
+ render() {
+ const {
+ alm,
+ bindingDefinition,
+ children,
+ help,
+ hideKeyField,
+ showInModal,
+ loading = false,
+ readOnly = false,
+ success = false
+ } = 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 ? (
+ <AlmPRDecorationFormModalRenderer
+ action={bindingDefinition.key ? 'edit' : 'create'}
+ alm={alm}
+ canSubmit={this.canSubmit}
+ help={help}
+ onCancel={this.handleCancel}
+ onSubmit={this.handleFormSubmit}>
+ {children({
+ formData,
+ onFieldChange: this.handleFieldChange
+ })}
+ </AlmPRDecorationFormModalRenderer>
+ ) : (
+ <AlmPRDecorationFormRenderer
+ 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
+ })}
+ </AlmPRDecorationFormRenderer>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModal.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModal.tsx
deleted file mode 100644
index aa5c5f3a33f..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModal.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings';
-import AlmPRDecorationFormModalRenderer from './AlmPRDecorationFormModalRenderer';
-
-interface ChildrenProps<AlmBindingDefinitionType> {
- formData: AlmBindingDefinitionType;
- onFieldChange: (fieldId: keyof AlmBindingDefinitionType, value: string) => void;
-}
-
-interface Props<B> {
- alm: ALM_KEYS;
- children: (props: ChildrenProps<B>) => React.ReactNode;
- bindingDefinition: B;
- onCancel: () => void;
- onSubmit: (data: B, originalKey: string) => void;
-}
-
-interface State<AlmBindingDefinitionType> {
- formData: AlmBindingDefinitionType;
-}
-
-export default class AlmPRDecorationFormModal<
- B extends AlmSettingsBinding
-> extends React.PureComponent<Props<B>, State<B>> {
- constructor(props: Props<B>) {
- super(props);
-
- this.state = { formData: props.bindingDefinition };
- }
-
- handleFieldChange = (fieldId: keyof B, value: string) => {
- this.setState(({ formData }) => ({
- formData: {
- ...formData,
- [fieldId]: value
- }
- }));
- };
-
- handleFormSubmit = () => {
- this.props.onSubmit(this.state.formData, this.props.bindingDefinition.key);
- };
-
- canSubmit = () => {
- return Object.values(this.state.formData).reduce(
- (result, value) => result && value.length > 0,
- true
- );
- };
-
- render() {
- const { alm, children, bindingDefinition } = this.props;
- const { formData } = this.state;
-
- return (
- <AlmPRDecorationFormModalRenderer
- alm={alm}
- canSubmit={this.canSubmit}
- onCancel={this.props.onCancel}
- onSubmit={this.handleFormSubmit}
- originalKey={bindingDefinition.key}>
- {children({
- formData,
- onFieldChange: this.handleFieldChange
- })}
- </AlmPRDecorationFormModalRenderer>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModalRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModalRenderer.tsx
index cbb4576ecdd..8773f06ad1a 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModalRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormModalRenderer.tsx
@@ -20,26 +20,28 @@
import * as React from 'react';
import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal';
+import { Alert } from 'sonar-ui-common/components/ui/Alert';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { ALM_KEYS } from '../../../../types/alm-settings';
export interface AlmPRDecorationFormModalProps {
+ action: 'edit' | 'create';
alm: ALM_KEYS;
canSubmit: () => boolean;
children: React.ReactNode;
+ help?: React.ReactNode;
onCancel: () => void;
onSubmit: () => void;
- originalKey: string;
}
export default function AlmPRDecorationFormModalRenderer(props: AlmPRDecorationFormModalProps) {
- const { alm, children, originalKey } = props;
+ const { alm, action, children, help } = props;
const header = translate(
'settings',
alm === ALM_KEYS.GITLAB ? 'mr_decoration' : 'pr_decoration',
'form.header',
- originalKey ? 'edit' : 'create'
+ action
);
return (
@@ -50,7 +52,14 @@ export default function AlmPRDecorationFormModalRenderer(props: AlmPRDecorationF
<h2>{header}</h2>
</div>
- <div className="modal-body modal-container">{children}</div>
+ <div className="modal-body modal-container">
+ {help && (
+ <Alert className="big-spacer-bottom" variant="info">
+ {help}
+ </Alert>
+ )}
+ {children}
+ </div>
<div className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormRenderer.tsx
new file mode 100644
index 00000000000..233eed7daa8
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationFormRenderer.tsx
@@ -0,0 +1,88 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { Button, ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
+import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon';
+import { Alert } from 'sonar-ui-common/components/ui/Alert';
+import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+
+export interface AlmPRDecorationFormRendererProps {
+ canSubmit: () => boolean;
+ children: React.ReactNode;
+ help?: React.ReactNode;
+ onCancel?: () => void;
+ onDelete?: () => void;
+ onEdit?: () => void;
+ onSubmit: () => void;
+ loading: boolean;
+ success: boolean;
+}
+
+export default function AlmPRDecorationFormRenderer(props: AlmPRDecorationFormRendererProps) {
+ const { children, help, loading, success } = props;
+
+ return (
+ <form
+ className="views-form"
+ data-test="settings__alm-form"
+ onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
+ e.preventDefault();
+ props.onSubmit();
+ }}>
+ {help && (
+ <Alert className="big-spacer-bottom" variant="info">
+ {help}
+ </Alert>
+ )}
+
+ {children}
+
+ <div className="display-flex-center">
+ {props.onEdit === undefined ? (
+ <SubmitButton disabled={loading || !props.canSubmit()}>
+ {translate('settings.pr_decoration.form.save')}
+ </SubmitButton>
+ ) : (
+ <Button disabled={loading} onClick={props.onEdit}>
+ {translate('edit')}
+ </Button>
+ )}
+ {props.onDelete && (
+ <Button className="button-red spacer-left" disabled={loading} onClick={props.onDelete}>
+ {translate('delete')}
+ </Button>
+ )}
+ {props.onCancel && (
+ <ResetButtonLink className="spacer-left" onClick={props.onCancel}>
+ {translate('cancel')}
+ </ResetButtonLink>
+ )}
+ {loading && <DeferredSpinner className="spacer-left" />}
+ {!loading && success && (
+ <span className="text-success spacer-left">
+ <AlertSuccessIcon className="spacer-right" />
+ {translate('settings.state.saved')}
+ </span>
+ )}
+ </div>
+ </form>
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationTable.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationTable.tsx
index 251cf7b3e1a..17f8920c730 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationTable.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmPRDecorationTable.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons';
+import { Button, ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons';
import EditIcon from 'sonar-ui-common/components/icons/EditIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { ALM_KEYS } from '../../../../types/alm-settings';
@@ -30,6 +30,7 @@ export interface AlmPRDecorationTableProps {
key: string;
additionalColumns: Array<string>;
}>;
+ onCreate: () => void;
onDelete: (definitionKey: string) => void;
onEdit: (definitionKey: string) => void;
}
@@ -38,51 +39,66 @@ export default function AlmPRDecorationTable(props: AlmPRDecorationTableProps) {
const { additionalColumnsHeaders, alm, definitions } = props;
return (
- <table className="data zebra fixed spacer-bottom">
- <thead>
- <tr>
- <th>{translate('settings.pr_decoration.table.column.name')}</th>
- {additionalColumnsHeaders.map(h => (
- <th key={h}>{h}</th>
- ))}
- <th className="action-small text-center">
- {translate('settings.pr_decoration.table.column.edit')}
- </th>
- <th className="action text-center">
- {translate('settings.pr_decoration.table.column.delete')}
- </th>
- </tr>
- </thead>
- <tbody>
- {definitions.length === 0 ? (
- <tr data-test="settings__alm-empty-table">
- <td colSpan={3 + additionalColumnsHeaders.length}>
- {translate('settings.pr_decoration.table.empty', alm)}
- </td>
+ <>
+ <div className="spacer-top big-spacer-bottom display-flex-space-between">
+ <h4 className="display-inline">
+ {translate(
+ 'settings',
+ alm === ALM_KEYS.GITLAB ? 'mr_decoration' : 'pr_decoration',
+ 'table.title'
+ )}
+ </h4>
+ <Button data-test="settings__alm-create" onClick={props.onCreate}>
+ {translate('settings.pr_decoration.table.create')}
+ </Button>
+ </div>
+
+ <table className="data zebra fixed spacer-bottom">
+ <thead>
+ <tr>
+ <th>{translate('settings.pr_decoration.table.column.name')}</th>
+ {additionalColumnsHeaders.map(h => (
+ <th key={h}>{h}</th>
+ ))}
+ <th className="action-small text-center">
+ {translate('settings.pr_decoration.table.column.edit')}
+ </th>
+ <th className="action text-center">
+ {translate('settings.pr_decoration.table.column.delete')}
+ </th>
</tr>
- ) : (
- definitions.map(({ key, additionalColumns }) => (
- <tr data-test="settings__alm-table-row" key={key}>
- <td className="nowrap hide-overflow" title={key}>
- {key}
- </td>
- {additionalColumns.map(value => (
- <td className="nowrap hide-overflow" key={value} title={value}>
- {value}
- </td>
- ))}
- <td className="text-center" data-test="settings__alm-table-row-edit">
- <ButtonIcon onClick={() => props.onEdit(key)}>
- <EditIcon />
- </ButtonIcon>
- </td>
- <td className="text-center" data-test="settings__alm-table-row-delete">
- <DeleteButton onClick={() => props.onDelete(key)} />
+ </thead>
+ <tbody>
+ {definitions.length === 0 ? (
+ <tr data-test="settings__alm-empty-table">
+ <td colSpan={3 + additionalColumnsHeaders.length}>
+ {translate('settings.pr_decoration.table.empty', alm)}
</td>
</tr>
- ))
- )}
- </tbody>
- </table>
+ ) : (
+ definitions.map(({ key, additionalColumns }) => (
+ <tr data-test="settings__alm-table-row" key={key}>
+ <td className="nowrap hide-overflow" title={key}>
+ {key}
+ </td>
+ {additionalColumns.map(value => (
+ <td className="nowrap hide-overflow" key={value} title={value}>
+ {value}
+ </td>
+ ))}
+ <td className="text-center" data-test="settings__alm-table-row-edit">
+ <ButtonIcon onClick={() => props.onEdit(key)}>
+ <EditIcon />
+ </ButtonIcon>
+ </td>
+ <td className="text-center" data-test="settings__alm-table-row-delete">
+ <DeleteButton onClick={() => props.onDelete(key)} />
+ </td>
+ </tr>
+ ))
+ )}
+ </tbody>
+ </table>
+ </>
);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTab.tsx
new file mode 100644
index 00000000000..5aba3ae0e9a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTab.tsx
@@ -0,0 +1,132 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings';
+import { AlmPRDecorationFormChildrenProps } from './AlmPRDecorationForm';
+import AlmTabRenderer from './AlmTabRenderer';
+
+interface Props<B> {
+ alm: ALM_KEYS;
+ additionalColumnsHeaders?: string[];
+ additionalColumnsKeys?: Array<keyof B>;
+ createConfiguration: (data: B) => Promise<void>;
+ defaultBinding: B;
+ definitions: B[];
+ form: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode;
+ loading: boolean;
+ multipleAlmEnabled: boolean;
+ onDelete: (definitionKey: string) => void;
+ onUpdateDefinitions: () => void;
+ updateConfiguration: (data: B & { newKey?: string }) => Promise<void>;
+}
+
+interface State<B> {
+ editedDefinition?: B;
+ submitting: boolean;
+ success: boolean;
+}
+
+export default class AlmTab<B extends AlmSettingsBinding> extends React.PureComponent<
+ Props<B>,
+ State<B>
+> {
+ mounted = false;
+ state: State<B> = { submitting: false, success: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleCancel = () => {
+ this.setState({
+ editedDefinition: undefined,
+ success: false
+ });
+ };
+
+ handleCreate = () => {
+ this.setState({ editedDefinition: this.props.defaultBinding, success: false });
+ };
+
+ handleEdit = (definitionKey: string) => {
+ const editedDefinition = this.props.definitions.find(d => d.key === definitionKey);
+ this.setState({ editedDefinition, success: false });
+ };
+
+ handleSubmit = (config: B, originalKey: string) => {
+ const call = originalKey
+ ? this.props.updateConfiguration({ newKey: config.key, ...config, key: originalKey })
+ : // If there's no support for multi-ALM binding, the key will be an empty string.
+ // Set a default.
+ this.props.createConfiguration(config.key ? config : { ...config, key: this.props.alm });
+
+ this.setState({ submitting: true });
+ return call
+ .then(() => {
+ if (this.mounted) {
+ this.setState({ editedDefinition: undefined, submitting: false, success: true });
+ }
+ })
+ .then(this.props.onUpdateDefinitions)
+ .catch(() => {
+ if (this.mounted) {
+ this.setState({ submitting: false, success: false });
+ }
+ });
+ };
+
+ render() {
+ const {
+ additionalColumnsHeaders = [],
+ additionalColumnsKeys = [],
+ alm,
+ defaultBinding,
+ definitions,
+ form,
+ loading,
+ multipleAlmEnabled
+ } = this.props;
+ const { editedDefinition, submitting, success } = this.state;
+
+ return (
+ <AlmTabRenderer
+ additionalColumnsHeaders={additionalColumnsHeaders}
+ additionalColumnsKeys={additionalColumnsKeys}
+ alm={alm}
+ defaultBinding={defaultBinding}
+ definitions={definitions}
+ editedDefinition={editedDefinition}
+ form={form}
+ loading={loading || submitting}
+ multipleAlmEnabled={multipleAlmEnabled}
+ onCancel={this.handleCancel}
+ onCreate={this.handleCreate}
+ onDelete={this.props.onDelete}
+ onEdit={this.handleEdit}
+ onSubmit={this.handleSubmit}
+ success={success}
+ />
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTabRenderer.tsx
new file mode 100644
index 00000000000..11e27dfc28c
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AlmTabRenderer.tsx
@@ -0,0 +1,136 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { Link } from 'react-router';
+import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings';
+import AlmPRDecorationForm, { AlmPRDecorationFormChildrenProps } from './AlmPRDecorationForm';
+import AlmPRDecorationTable from './AlmPRDecorationTable';
+
+export interface AlmTabRendererProps<B> {
+ additionalColumnsHeaders: string[];
+ additionalColumnsKeys: Array<keyof B>;
+ alm: ALM_KEYS;
+ editedDefinition?: B;
+ defaultBinding: B;
+ definitions: B[];
+ form: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode;
+ loading: boolean;
+ multipleAlmEnabled: boolean;
+ onCancel: () => void;
+ onCreate: () => void;
+ onDelete: (definitionKey: string) => void;
+ onEdit: (definitionKey: string) => void;
+ onSubmit: (config: B, originalKey: string) => void;
+ success: boolean;
+}
+
+export default function AlmTabRenderer<B extends AlmSettingsBinding>(
+ props: AlmTabRendererProps<B>
+) {
+ const {
+ additionalColumnsHeaders,
+ additionalColumnsKeys,
+ alm,
+ defaultBinding,
+ definitions,
+ editedDefinition,
+ form,
+ loading,
+ multipleAlmEnabled,
+ success
+ } = props;
+
+ let definition: B | undefined;
+ let mappedDefinitions: Array<{ key: string; additionalColumns: string[] }> = [];
+ let showEdit: boolean | undefined;
+
+ if (!multipleAlmEnabled) {
+ definition = editedDefinition;
+ if (definition === undefined && definitions.length > 0) {
+ definition = definitions[0];
+ }
+ showEdit = definition && editedDefinition === undefined;
+ } else {
+ mappedDefinitions = definitions.map(({ key, ...properties }) => {
+ const additionalColumns = additionalColumnsKeys.map(k => (properties as any)[k]);
+ return {
+ key,
+ additionalColumns
+ };
+ });
+ }
+
+ const help = (
+ <FormattedMessage
+ defaultMessage={translate(`settings.pr_decoration.${alm}.info`)}
+ id={`settings.pr_decoration.${alm}.info`}
+ values={{
+ link: (
+ <Link target="_blank" to="/documentation/analysis/pr-decoration/">
+ {translate('learn_more')}
+ </Link>
+ )
+ }}
+ />
+ );
+
+ return multipleAlmEnabled ? (
+ <DeferredSpinner loading={loading}>
+ <AlmPRDecorationTable
+ additionalColumnsHeaders={additionalColumnsHeaders}
+ alm={alm}
+ definitions={mappedDefinitions}
+ onCreate={props.onCreate}
+ onDelete={props.onDelete}
+ onEdit={props.onEdit}
+ />
+
+ {editedDefinition && (
+ <AlmPRDecorationForm
+ alm={alm}
+ bindingDefinition={editedDefinition}
+ help={help}
+ onCancel={props.onCancel}
+ onSubmit={props.onSubmit}
+ showInModal={true}>
+ {form}
+ </AlmPRDecorationForm>
+ )}
+ </DeferredSpinner>
+ ) : (
+ <AlmPRDecorationForm
+ alm={alm}
+ bindingDefinition={definition || defaultBinding}
+ help={help}
+ hideKeyField={true}
+ loading={loading}
+ onCancel={props.onCancel}
+ onDelete={definition ? props.onDelete : undefined}
+ onEdit={showEdit ? props.onEdit : undefined}
+ onSubmit={props.onSubmit}
+ readOnly={showEdit}
+ success={success}>
+ {form}
+ </AlmPRDecorationForm>
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureFormModal.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureForm.tsx
index 97eb5f44793..e3666792ba2 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureFormModal.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureForm.tsx
@@ -22,30 +22,36 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { AzureBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
-export interface AzureFormModalProps {
+export interface AzureFormProps {
formData: AzureBindingDefinition;
+ hideKeyField?: boolean;
onFieldChange: (fieldId: keyof AzureBindingDefinition, value: string) => void;
+ readOnly?: boolean;
}
-export default function AzureFormModal(props: AzureFormModalProps) {
- const { formData, onFieldChange } = props;
+export default function AzureForm(props: AzureFormProps) {
+ const { formData, hideKeyField, onFieldChange, readOnly } = props;
return (
<>
- <AlmDefinitionFormField
- autoFocus={true}
- help={translate('settings.pr_decoration.form.name.azure.help')}
- id="name.azure"
- onFieldChange={onFieldChange}
- propKey="key"
- value={formData.key}
- />
+ {!hideKeyField && (
+ <AlmDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.pr_decoration.form.name.azure.help')}
+ id="name.azure"
+ onFieldChange={onFieldChange}
+ propKey="key"
+ readOnly={readOnly}
+ value={formData.key}
+ />
+ )}
<AlmDefinitionFormField
help={translate('settings.pr_decoration.form.personal_access_token.azure.help')}
id="personal_access_token"
isTextArea={true}
onFieldChange={onFieldChange}
propKey="personalAccessToken"
+ readOnly={readOnly}
value={formData.personalAccessToken}
/>
</>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTab.tsx
index 22e7f0c2664..61c1869baff 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTab.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTab.tsx
@@ -19,73 +19,33 @@
*/
import * as React from 'react';
import { createAzureConfiguration, updateAzureConfiguration } from '../../../../api/almSettings';
-import { AzureBindingDefinition } from '../../../../types/alm-settings';
-import AzureTabRenderer from './AzureTabRenderer';
+import { ALM_KEYS, AzureBindingDefinition } from '../../../../types/alm-settings';
+import AlmTab from './AlmTab';
+import AzureForm from './AzureForm';
-interface Props {
+export interface AzureTabProps {
definitions: AzureBindingDefinition[];
loading: boolean;
+ multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}
-interface State {
- editedDefinition?: AzureBindingDefinition;
- projectCount?: number;
-}
-
-export default class AzureTab extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleCancel = () => {
- this.setState({
- editedDefinition: undefined
- });
- };
-
- handleCreate = () => {
- this.setState({ editedDefinition: { key: '', personalAccessToken: '' } });
- };
-
- handleEdit = (definitionKey: string) => {
- const editedDefinition = this.props.definitions.find(d => d.key === definitionKey);
- this.setState({ editedDefinition });
- };
-
- handleSubmit = (config: AzureBindingDefinition, originalKey: string) => {
- const call = originalKey
- ? updateAzureConfiguration({ newKey: config.key, ...config, key: originalKey })
- : createAzureConfiguration(config);
- return call.then(this.props.onUpdateDefinitions).then(() => {
- if (this.mounted) {
- this.setState({ editedDefinition: undefined });
- }
- });
- };
-
- render() {
- const { definitions, loading } = this.props;
- const { editedDefinition } = this.state;
- return (
- <AzureTabRenderer
- definitions={definitions}
- editedDefinition={editedDefinition}
- loading={loading}
- onCancel={this.handleCancel}
- onCreate={this.handleCreate}
- onDelete={this.props.onDelete}
- onEdit={this.handleEdit}
- onSubmit={this.handleSubmit}
- />
- );
- }
+export default function AzureTab(props: AzureTabProps) {
+ const { multipleAlmEnabled, definitions, loading } = props;
+
+ return (
+ <AlmTab
+ alm={ALM_KEYS.AZURE}
+ createConfiguration={createAzureConfiguration}
+ defaultBinding={{ key: '', personalAccessToken: '' }}
+ definitions={definitions}
+ form={childProps => <AzureForm {...childProps} />}
+ loading={loading}
+ multipleAlmEnabled={multipleAlmEnabled}
+ onDelete={props.onDelete}
+ onUpdateDefinitions={props.onUpdateDefinitions}
+ updateConfiguration={updateAzureConfiguration}
+ />
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTabRenderer.tsx
deleted file mode 100644
index 5efc4f2ff4c..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/AzureTabRenderer.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { ALM_KEYS, AzureBindingDefinition } from '../../../../types/alm-settings';
-import AlmPRDecorationFormModal from './AlmPRDecorationFormModal';
-import AlmPRDecorationTable from './AlmPRDecorationTable';
-import AzureFormModal from './AzureFormModal';
-import TabHeader from './TabHeader';
-
-export interface AzureTabRendererProps {
- editedDefinition?: AzureBindingDefinition;
- definitions: AzureBindingDefinition[];
- loading: boolean;
- onCancel: () => void;
- onCreate: () => void;
- onDelete: (definitionKey: string) => void;
- onEdit: (definitionKey: string) => void;
- onSubmit: (config: AzureBindingDefinition, originalKey: string) => void;
-}
-
-export default function AzureTabRenderer(props: AzureTabRendererProps) {
- const { definitions, editedDefinition, loading } = props;
- return (
- <>
- <TabHeader
- alm={ALM_KEYS.AZURE}
- definitionCount={definitions.length}
- onCreate={props.onCreate}
- />
-
- <DeferredSpinner loading={loading}>
- <AlmPRDecorationTable
- additionalColumnsHeaders={[]}
- alm={ALM_KEYS.AZURE}
- definitions={definitions.map(({ key }) => ({
- key,
- additionalColumns: []
- }))}
- onDelete={props.onDelete}
- onEdit={props.onEdit}
- />
- </DeferredSpinner>
-
- {editedDefinition && (
- <AlmPRDecorationFormModal
- alm={ALM_KEYS.AZURE}
- bindingDefinition={editedDefinition}
- onCancel={props.onCancel}
- onSubmit={props.onSubmit}>
- {childProps => <AzureFormModal {...childProps} />}
- </AlmPRDecorationFormModal>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketFormModal.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketForm.tsx
index 9228b4a8c04..957edf69806 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketFormModal.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketForm.tsx
@@ -23,25 +23,30 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { BitbucketBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
-export interface BitbucketFormModalProps {
+export interface BitbucketFormProps {
formData: BitbucketBindingDefinition;
+ hideKeyField?: boolean;
onFieldChange: (fieldId: keyof BitbucketBindingDefinition, value: string) => void;
+ readOnly?: boolean;
}
-export default function BitbucketFormModal(props: BitbucketFormModalProps) {
- const { formData, onFieldChange } = props;
+export default function BitbucketForm(props: BitbucketFormProps) {
+ const { formData, hideKeyField, onFieldChange, readOnly } = props;
return (
<>
- <AlmDefinitionFormField
- autoFocus={true}
- help={translate('settings.pr_decoration.form.name.bitbucket.help')}
- id="name.bitbucket"
- maxLength={100}
- onFieldChange={onFieldChange}
- propKey="key"
- value={formData.key}
- />
+ {!hideKeyField && (
+ <AlmDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.pr_decoration.form.name.bitbucket.help')}
+ id="name.bitbucket"
+ maxLength={100}
+ onFieldChange={onFieldChange}
+ propKey="key"
+ readOnly={readOnly}
+ value={formData.key}
+ />
+ )}
<AlmDefinitionFormField
help={
<FormattedMessage
@@ -54,6 +59,7 @@ export default function BitbucketFormModal(props: BitbucketFormModalProps) {
maxLength={2000}
onFieldChange={onFieldChange}
propKey="url"
+ readOnly={readOnly}
value={formData.url}
/>
<AlmDefinitionFormField
@@ -61,6 +67,7 @@ export default function BitbucketFormModal(props: BitbucketFormModalProps) {
isTextArea={true}
onFieldChange={onFieldChange}
propKey="personalAccessToken"
+ readOnly={readOnly}
value={formData.personalAccessToken}
/>
</>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx
index 13a37742c8e..ccfb8120044 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTab.tsx
@@ -18,79 +18,40 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { translate } from 'sonar-ui-common/helpers/l10n';
import {
createBitbucketConfiguration,
updateBitbucketConfiguration
} from '../../../../api/almSettings';
-import { BitbucketBindingDefinition } from '../../../../types/alm-settings';
-import BitbucketTabRenderer from './BitbucketTabRenderer';
+import { ALM_KEYS, BitbucketBindingDefinition } from '../../../../types/alm-settings';
+import AlmTab from './AlmTab';
+import BitbucketForm from './BitbucketForm';
-interface Props {
+export interface BitbucketTabProps {
definitions: BitbucketBindingDefinition[];
loading: boolean;
+ multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}
-interface State {
- editedDefinition?: BitbucketBindingDefinition;
- projectCount?: number;
-}
-
-export default class BitbucketTab extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleCancel = () => {
- this.setState({
- editedDefinition: undefined
- });
- };
-
- handleCreate = () => {
- this.setState({ editedDefinition: { key: '', url: '', personalAccessToken: '' } });
- };
-
- handleEdit = (definitionKey: string) => {
- const editedDefinition = this.props.definitions.find(d => d.key === definitionKey);
- this.setState({ editedDefinition });
- };
-
- handleSubmit = (config: BitbucketBindingDefinition, originalKey: string) => {
- const call = originalKey
- ? updateBitbucketConfiguration({ newKey: config.key, ...config, key: originalKey })
- : createBitbucketConfiguration(config);
- return call
- .then(() => {
- if (this.mounted) {
- this.setState({ editedDefinition: undefined });
- }
- })
- .then(this.props.onUpdateDefinitions);
- };
-
- render() {
- const { definitions, loading } = this.props;
- const { editedDefinition } = this.state;
- return (
- <BitbucketTabRenderer
- definitions={definitions}
- editedDefinition={editedDefinition}
- loading={loading}
- onCancel={this.handleCancel}
- onCreate={this.handleCreate}
- onDelete={this.props.onDelete}
- onEdit={this.handleEdit}
- onSubmit={this.handleSubmit}
- />
- );
- }
+export default function BitbucketTab(props: BitbucketTabProps) {
+ const { multipleAlmEnabled, definitions, loading } = props;
+
+ return (
+ <AlmTab
+ additionalColumnsHeaders={[translate('settings.pr_decoration.table.column.bitbucket.url')]}
+ additionalColumnsKeys={['url']}
+ alm={ALM_KEYS.BITBUCKET}
+ createConfiguration={createBitbucketConfiguration}
+ defaultBinding={{ key: '', url: '', personalAccessToken: '' }}
+ definitions={definitions}
+ form={childProps => <BitbucketForm {...childProps} />}
+ loading={loading}
+ multipleAlmEnabled={multipleAlmEnabled}
+ onDelete={props.onDelete}
+ onUpdateDefinitions={props.onUpdateDefinitions}
+ updateConfiguration={updateBitbucketConfiguration}
+ />
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTabRenderer.tsx
deleted file mode 100644
index b156f433713..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/BitbucketTabRenderer.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { ALM_KEYS, BitbucketBindingDefinition } from '../../../../types/alm-settings';
-import AlmPRDecorationFormModal from './AlmPRDecorationFormModal';
-import AlmPRDecorationTable from './AlmPRDecorationTable';
-import BitbucketFormModal from './BitbucketFormModal';
-import TabHeader from './TabHeader';
-
-export interface BitbucketTabRendererProps {
- editedDefinition?: BitbucketBindingDefinition;
- definitions: BitbucketBindingDefinition[];
- loading: boolean;
- onCancel: () => void;
- onCreate: () => void;
- onDelete: (definitionKey: string) => void;
- onEdit: (definitionKey: string) => void;
- onSubmit: (config: BitbucketBindingDefinition, originalKey: string) => void;
-}
-
-export default function BitbucketTabRenderer(props: BitbucketTabRendererProps) {
- const { definitions, editedDefinition, loading } = props;
- return (
- <>
- <TabHeader
- alm={ALM_KEYS.BITBUCKET}
- definitionCount={definitions.length}
- onCreate={props.onCreate}
- />
-
- <DeferredSpinner loading={loading}>
- <AlmPRDecorationTable
- additionalColumnsHeaders={[
- translate(`settings.pr_decoration.table.column.bitbucket.url`)
- ]}
- alm={ALM_KEYS.BITBUCKET}
- definitions={definitions.map(({ key, url }) => ({
- key,
- additionalColumns: [url]
- }))}
- onDelete={props.onDelete}
- onEdit={props.onEdit}
- />
- </DeferredSpinner>
-
- {editedDefinition && (
- <AlmPRDecorationFormModal
- alm={ALM_KEYS.BITBUCKET}
- bindingDefinition={editedDefinition}
- onCancel={props.onCancel}
- onSubmit={props.onSubmit}>
- {childProps => <BitbucketFormModal {...childProps} />}
- </AlmPRDecorationFormModal>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubFormModal.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubForm.tsx
index a271ae5134b..aa7876191d7 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubFormModal.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubForm.tsx
@@ -22,24 +22,29 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { GithubBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
-export interface GithubFormModalProps {
+export interface GithubFormProps {
formData: GithubBindingDefinition;
+ hideKeyField?: boolean;
onFieldChange: (fieldId: keyof GithubBindingDefinition, value: string) => void;
+ readOnly?: boolean;
}
-export default function GithubFormModal(props: GithubFormModalProps) {
- const { formData, onFieldChange } = props;
+export default function GithubForm(props: GithubFormProps) {
+ const { formData, hideKeyField, onFieldChange, readOnly } = props;
return (
<>
- <AlmDefinitionFormField
- autoFocus={true}
- help={translate('settings.pr_decoration.form.name.github.help')}
- id="name.github"
- onFieldChange={onFieldChange}
- propKey="key"
- value={formData.key}
- />
+ {!hideKeyField && (
+ <AlmDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.pr_decoration.form.name.github.help')}
+ id="name.github"
+ onFieldChange={onFieldChange}
+ propKey="key"
+ readOnly={readOnly}
+ value={formData.key}
+ />
+ )}
<AlmDefinitionFormField
help={
<>
@@ -57,6 +62,7 @@ export default function GithubFormModal(props: GithubFormModalProps) {
maxLength={2000}
onFieldChange={onFieldChange}
propKey="url"
+ readOnly={readOnly}
value={formData.url}
/>
<AlmDefinitionFormField
@@ -64,6 +70,7 @@ export default function GithubFormModal(props: GithubFormModalProps) {
maxLength={80}
onFieldChange={onFieldChange}
propKey="appId"
+ readOnly={readOnly}
value={formData.appId}
/>
<AlmDefinitionFormField
@@ -71,6 +78,7 @@ export default function GithubFormModal(props: GithubFormModalProps) {
isTextArea={true}
onFieldChange={onFieldChange}
propKey="privateKey"
+ readOnly={readOnly}
value={formData.privateKey}
/>
</>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTab.tsx
index 9c35ad18b89..078c37289b3 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTab.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTab.tsx
@@ -18,76 +18,40 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { translate } from 'sonar-ui-common/helpers/l10n';
import { createGithubConfiguration, updateGithubConfiguration } from '../../../../api/almSettings';
-import { GithubBindingDefinition } from '../../../../types/alm-settings';
-import GithubTabRenderer from './GithubTabRenderer';
+import { ALM_KEYS, GithubBindingDefinition } from '../../../../types/alm-settings';
+import AlmTab from './AlmTab';
+import GithubForm from './GithubForm';
-interface Props {
+export interface GithubTabProps {
definitions: GithubBindingDefinition[];
loading: boolean;
+ multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}
-interface State {
- editedDefinition?: GithubBindingDefinition;
- projectCount?: number;
-}
-
-export default class GithubTab extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleCancel = () => {
- this.setState({
- editedDefinition: undefined
- });
- };
-
- handleCreate = () => {
- this.setState({ editedDefinition: { key: '', appId: '', url: '', privateKey: '' } });
- };
-
- handleEdit = (definitionKey: string) => {
- const editedDefinition = this.props.definitions.find(d => d.key === definitionKey);
- this.setState({ editedDefinition });
- };
-
- handleSubmit = (config: GithubBindingDefinition, originalKey: string) => {
- const call = originalKey
- ? updateGithubConfiguration({ newKey: config.key, ...config, key: originalKey })
- : createGithubConfiguration(config);
- return call
- .then(() => {
- if (this.mounted) {
- this.setState({ editedDefinition: undefined });
- }
- })
- .then(this.props.onUpdateDefinitions);
- };
-
- render() {
- const { definitions, loading } = this.props;
- const { editedDefinition } = this.state;
- return (
- <GithubTabRenderer
- definitions={definitions}
- editedDefinition={editedDefinition}
- loading={loading}
- onCancel={this.handleCancel}
- onCreate={this.handleCreate}
- onDelete={this.props.onDelete}
- onEdit={this.handleEdit}
- onSubmit={this.handleSubmit}
- />
- );
- }
+export default function GithubTab(props: GithubTabProps) {
+ const { multipleAlmEnabled, definitions, loading } = props;
+
+ return (
+ <AlmTab
+ additionalColumnsHeaders={[
+ translate('settings.pr_decoration.table.column.github.url'),
+ translate('settings.pr_decoration.table.column.app_id')
+ ]}
+ additionalColumnsKeys={['appId', 'url']}
+ alm={ALM_KEYS.GITHUB}
+ createConfiguration={createGithubConfiguration}
+ defaultBinding={{ key: '', appId: '', url: '', privateKey: '' }}
+ definitions={definitions}
+ form={childProps => <GithubForm {...childProps} />}
+ loading={loading}
+ multipleAlmEnabled={multipleAlmEnabled}
+ onDelete={props.onDelete}
+ onUpdateDefinitions={props.onUpdateDefinitions}
+ updateConfiguration={updateGithubConfiguration}
+ />
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTabRenderer.tsx
deleted file mode 100644
index ac4b0927d76..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GithubTabRenderer.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { ALM_KEYS, GithubBindingDefinition } from '../../../../types/alm-settings';
-import AlmPRDecorationFormModal from './AlmPRDecorationFormModal';
-import AlmPRDecorationTable from './AlmPRDecorationTable';
-import GithubFormModal from './GithubFormModal';
-import TabHeader from './TabHeader';
-
-export interface GithubTabRendererProps {
- editedDefinition?: GithubBindingDefinition;
- definitions: GithubBindingDefinition[];
- loading: boolean;
- onCancel: () => void;
- onCreate: () => void;
- onDelete: (definitionKey: string) => void;
- onEdit: (definitionKey: string) => void;
- onSubmit: (config: GithubBindingDefinition, originalKey: string) => void;
-}
-
-export default function GithubTabRenderer(props: GithubTabRendererProps) {
- const { definitions, editedDefinition, loading } = props;
- return (
- <>
- <TabHeader
- alm={ALM_KEYS.GITHUB}
- definitionCount={definitions.length}
- onCreate={props.onCreate}
- />
-
- <DeferredSpinner loading={loading}>
- <AlmPRDecorationTable
- additionalColumnsHeaders={[
- translate(`settings.pr_decoration.table.column.github.url`),
- translate('settings.pr_decoration.table.column.app_id')
- ]}
- alm={ALM_KEYS.GITHUB}
- definitions={definitions.map(({ key, appId, url }) => ({
- key,
- additionalColumns: [url, appId]
- }))}
- onDelete={props.onDelete}
- onEdit={props.onEdit}
- />
- </DeferredSpinner>
-
- {editedDefinition && (
- <AlmPRDecorationFormModal
- alm={ALM_KEYS.GITHUB}
- bindingDefinition={editedDefinition}
- onCancel={props.onCancel}
- onSubmit={props.onSubmit}>
- {childProps => <GithubFormModal {...childProps} />}
- </AlmPRDecorationFormModal>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabFormModal.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabForm.tsx
index bf259c2637a..7f0728b53fd 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabFormModal.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabForm.tsx
@@ -22,34 +22,38 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { GitlabBindingDefinition } from '../../../../types/alm-settings';
import { AlmDefinitionFormField } from './AlmDefinitionFormField';
-export interface GitlabFormModalProps {
+export interface GitlabFormProps {
formData: GitlabBindingDefinition;
+ hideKeyField?: boolean;
onFieldChange: (fieldId: keyof GitlabBindingDefinition, value: string) => void;
+ readOnly?: boolean;
}
-export function GitlabFormModal(props: GitlabFormModalProps) {
- const { formData, onFieldChange } = props;
+export default function GitlabForm(props: GitlabFormProps) {
+ const { formData, hideKeyField, onFieldChange, readOnly } = props;
return (
<>
- <AlmDefinitionFormField
- autoFocus={true}
- help={translate('settings.pr_decoration.form.name.gitlab.help')}
- id="name.gitlab"
- onFieldChange={onFieldChange}
- propKey="key"
- value={formData.key}
- />
+ {!hideKeyField && (
+ <AlmDefinitionFormField
+ autoFocus={true}
+ help={translate('settings.pr_decoration.form.name.gitlab.help')}
+ id="name.gitlab"
+ onFieldChange={onFieldChange}
+ propKey="key"
+ readOnly={readOnly}
+ value={formData.key}
+ />
+ )}
<AlmDefinitionFormField
help={translate('settings.pr_decoration.form.personal_access_token.gitlab.help')}
id="personal_access_token"
isTextArea={true}
onFieldChange={onFieldChange}
propKey="personalAccessToken"
+ readOnly={readOnly}
value={formData.personalAccessToken}
/>
</>
);
}
-
-export default React.memo(GitlabFormModal);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTab.tsx
index 86079934892..4e37f990ac9 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTab.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTab.tsx
@@ -19,73 +19,33 @@
*/
import * as React from 'react';
import { createGitlabConfiguration, updateGitlabConfiguration } from '../../../../api/almSettings';
-import { GitlabBindingDefinition } from '../../../../types/alm-settings';
-import GitlabTabRenderer from './GitlabTabRenderer';
+import { ALM_KEYS, GitlabBindingDefinition } from '../../../../types/alm-settings';
+import AlmTab from './AlmTab';
+import GitlabForm from './GitlabForm';
-interface Props {
+export interface GitlabTabProps {
definitions: GitlabBindingDefinition[];
loading: boolean;
+ multipleAlmEnabled: boolean;
onDelete: (definitionKey: string) => void;
onUpdateDefinitions: () => void;
}
-interface State {
- editedDefinition?: GitlabBindingDefinition;
- projectCount?: number;
-}
-
-export default class GitlabTab extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleEdit = (definitionKey: string) => {
- const editedDefinition = this.props.definitions.find(d => d.key === definitionKey);
- this.setState({ editedDefinition });
- };
-
- handleSubmit = (config: GitlabBindingDefinition, originalKey: string) => {
- const call = originalKey
- ? updateGitlabConfiguration({ newKey: config.key, ...config, key: originalKey })
- : createGitlabConfiguration(config);
- return call.then(this.props.onUpdateDefinitions).then(() => {
- if (this.mounted) {
- this.setState({ editedDefinition: undefined });
- }
- });
- };
-
- handleCancel = () => {
- this.setState({
- editedDefinition: undefined
- });
- };
-
- handleCreate = () => {
- this.setState({ editedDefinition: { key: '', personalAccessToken: '' } });
- };
-
- render() {
- const { definitions, loading } = this.props;
- const { editedDefinition } = this.state;
- return (
- <GitlabTabRenderer
- definitions={definitions}
- editedDefinition={editedDefinition}
- loading={loading}
- onCancel={this.handleCancel}
- onCreate={this.handleCreate}
- onDelete={this.props.onDelete}
- onEdit={this.handleEdit}
- onSubmit={this.handleSubmit}
- />
- );
- }
+export default function GitlabTab(props: GitlabTabProps) {
+ const { multipleAlmEnabled, definitions, loading } = props;
+
+ return (
+ <AlmTab
+ alm={ALM_KEYS.GITLAB}
+ createConfiguration={createGitlabConfiguration}
+ defaultBinding={{ key: '', personalAccessToken: '' }}
+ definitions={definitions}
+ form={childProps => <GitlabForm {...childProps} />}
+ loading={loading}
+ multipleAlmEnabled={multipleAlmEnabled}
+ onDelete={props.onDelete}
+ onUpdateDefinitions={props.onUpdateDefinitions}
+ updateConfiguration={updateGitlabConfiguration}
+ />
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTabRenderer.tsx
deleted file mode 100644
index 17a268b40f1..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/GitlabTabRenderer.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { ALM_KEYS, GitlabBindingDefinition } from '../../../../types/alm-settings';
-import AlmPRDecorationFormModal from './AlmPRDecorationFormModal';
-import AlmPRDecorationTable from './AlmPRDecorationTable';
-import GitlabFormModal from './GitlabFormModal';
-import TabHeader from './TabHeader';
-
-export interface GitlabTabRendererProps {
- editedDefinition?: GitlabBindingDefinition;
- definitions: GitlabBindingDefinition[];
- loading: boolean;
- onCancel: () => void;
- onCreate: () => void;
- onDelete: (definitionKey: string) => void;
- onEdit: (definitionKey: string) => void;
- onSubmit: (config: GitlabBindingDefinition, originalKey: string) => void;
-}
-
-export default function GitlabTabRenderer(props: GitlabTabRendererProps) {
- const { definitions, editedDefinition, loading } = props;
- return (
- <>
- <TabHeader
- alm={ALM_KEYS.GITLAB}
- definitionCount={definitions.length}
- onCreate={props.onCreate}
- />
-
- <DeferredSpinner loading={loading}>
- <AlmPRDecorationTable
- additionalColumnsHeaders={[]}
- alm={ALM_KEYS.GITLAB}
- definitions={definitions.map(({ key }) => ({
- key,
- additionalColumns: []
- }))}
- onDelete={props.onDelete}
- onEdit={props.onEdit}
- />
- </DeferredSpinner>
-
- {editedDefinition && (
- <AlmPRDecorationFormModal
- alm={ALM_KEYS.GITLAB}
- bindingDefinition={editedDefinition}
- onCancel={props.onCancel}
- onSubmit={props.onSubmit}>
- {childProps => <GitlabFormModal {...childProps} />}
- </AlmPRDecorationFormModal>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx
index 096d4fb1e98..4534ba313c2 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PRDecorationTabs.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
+import { withAppState } from '../../../../components/hoc/withAppState';
import { AlmSettingsBindingDefinitions, ALM_KEYS } from '../../../../types/alm-settings';
import AzureTab from './AzureTab';
import BitbucketTab from './BitbucketTab';
@@ -29,6 +30,7 @@ import GithubTab from './GithubTab';
import GitlabTab from './GitlabTab';
export interface PRDecorationTabsProps {
+ appState: Pick<T.AppState, 'multipleAlmEnabled'>;
currentAlm: ALM_KEYS;
definitionKeyForDeletion?: string;
definitions: AlmSettingsBindingDefinitions;
@@ -48,8 +50,15 @@ export const almName = {
[ALM_KEYS.GITLAB]: 'GitLab'
};
-export default function PRDecorationTabs(props: PRDecorationTabsProps) {
- const { definitionKeyForDeletion, definitions, currentAlm, loading, projectCount } = props;
+export function PRDecorationTabs(props: PRDecorationTabsProps) {
+ const {
+ appState: { multipleAlmEnabled },
+ definitionKeyForDeletion,
+ definitions,
+ currentAlm,
+ loading,
+ projectCount
+ } = props;
return (
<>
@@ -128,6 +137,7 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) {
<AzureTab
definitions={definitions.azure}
loading={loading}
+ multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
@@ -136,6 +146,7 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) {
<BitbucketTab
definitions={definitions.bitbucket}
loading={loading}
+ multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
@@ -144,6 +155,7 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) {
<GithubTab
definitions={definitions.github}
loading={loading}
+ multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
@@ -152,6 +164,7 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) {
<GitlabTab
definitions={definitions.gitlab}
loading={loading}
+ multipleAlmEnabled={Boolean(multipleAlmEnabled)}
onDelete={props.onDelete}
onUpdateDefinitions={props.onUpdateDefinitions}
/>
@@ -169,3 +182,5 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) {
</>
);
}
+
+export default withAppState(PRDecorationTabs);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PullRequestDecoration.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PullRequestDecoration.tsx
index fcc47030045..0aaf240956d 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PullRequestDecoration.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/PullRequestDecoration.tsx
@@ -93,14 +93,22 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State
};
handleDelete = (definitionKey: string) => {
- return countBindedProjects(definitionKey).then(projectCount => {
- if (this.mounted) {
- this.setState({
- definitionKeyForDeletion: definitionKey,
- projectCount
- });
- }
- });
+ this.setState({ loading: true });
+ return countBindedProjects(definitionKey)
+ .then(projectCount => {
+ if (this.mounted) {
+ this.setState({
+ definitionKeyForDeletion: definitionKey,
+ loading: false,
+ projectCount
+ });
+ }
+ })
+ .catch(() => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ });
};
render() {
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/TabHeader.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/TabHeader.tsx
deleted file mode 100644
index 27e1d749a64..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/TabHeader.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { Link } from 'react-router';
-import { Button } from 'sonar-ui-common/components/controls/buttons';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { withAppState } from '../../../../components/hoc/withAppState';
-import { ALM_KEYS } from '../../../../types/alm-settings';
-
-export interface TabHeaderProps {
- alm: ALM_KEYS;
- appState: Pick<T.AppState, 'multipleAlmEnabled'>;
- definitionCount: number;
- onCreate: () => void;
-}
-
-export function TabHeader(props: TabHeaderProps) {
- const {
- alm,
- appState: { multipleAlmEnabled },
- definitionCount
- } = props;
- const showButton = multipleAlmEnabled || definitionCount === 0;
- return (
- <>
- <Alert className="spacer-top huge-spacer-bottom" variant="info">
- <FormattedMessage
- defaultMessage={translate(`settings.pr_decoration.${alm}.info`)}
- id={`settings.pr_decoration.${alm}.info`}
- values={{
- link: (
- <Link target="_blank" to="/documentation/analysis/pr-decoration/">
- {translate('learn_more')}
- </Link>
- )
- }}
- />
- </Alert>
-
- <div className="big-spacer-bottom display-flex-space-between">
- <h4 className="display-inline">
- {translate(
- 'settings',
- alm === ALM_KEYS.GITLAB ? 'mr_decoration' : 'pr_decoration',
- 'table.title'
- )}
- </h4>
- {showButton && (
- <Button data-test="settings__alm-create" onClick={props.onCreate}>
- {translate('settings.pr_decoration.table.create')}
- </Button>
- )}
- </div>
- </>
- );
-}
-
-export default withAppState(TabHeader);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModal-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationForm-test.tsx
index c50624e99a6..0f23da700ca 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationForm-test.tsx
@@ -22,12 +22,24 @@ import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings';
import { ALM_KEYS, GithubBindingDefinition } from '../../../../../types/alm-settings';
-import AlmPRDecorationFormModal from '../AlmPRDecorationFormModal';
+import AlmPRDecorationForm from '../AlmPRDecorationForm';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});
+it('should reset if the props change', () => {
+ const bindingDefinition = mockGithubDefinition();
+ const wrapper = shallowRender({ bindingDefinition });
+
+ wrapper.setState({ formData: { ...bindingDefinition, appId: 'newAppId' }, touched: true });
+ wrapper.setProps({ bindingDefinition: { ...bindingDefinition } });
+ expect(wrapper.state('touched')).toBe(true);
+
+ wrapper.setProps({ bindingDefinition: mockGithubDefinition({ key: 'diffKey' }) });
+ expect(wrapper.state('touched')).toBe(false);
+});
+
it('should handle field changes', () => {
const wrapper = shallowRender();
@@ -42,7 +54,7 @@ it('should handle field changes', () => {
wrapper.instance().handleFieldChange('url', formData.url);
wrapper.instance().handleFieldChange('appId', formData.appId);
wrapper.instance().handleFieldChange('privateKey', formData.privateKey);
- expect(wrapper.state()).toEqual({ formData });
+ expect(wrapper.state().formData).toEqual(formData);
});
it('should handle form submit', async () => {
@@ -65,27 +77,59 @@ it('should handle form submit', async () => {
expect(onSubmit).toHaveBeenCalledWith(formData, 'originalKey');
});
-it('should (dis)allow submit by validating its state', async () => {
- const wrapper = shallowRender();
+it('should handle cancelling', () => {
+ const onCancel = jest.fn();
+ const bindingDefinition = {
+ appId: 'foo',
+ key: 'bar',
+ privateKey: 'baz',
+ url: 'http://github.enterprise.com'
+ };
+ const wrapper = shallowRender({
+ bindingDefinition,
+ onCancel
+ });
- expect(wrapper.instance().canSubmit()).toBe(false);
wrapper.setState({ formData: mockGithubDefinition() });
- await waitAndUpdate(wrapper);
+ wrapper.instance().handleCancel();
+
+ expect(wrapper.state().formData).toBe(bindingDefinition);
+ expect(onCancel).toHaveBeenCalled();
+});
+
+it('should handle deleting', () => {
+ const onDelete = jest.fn();
+ const bindingDefinition = mockGithubDefinition();
+ const wrapper = shallowRender({
+ bindingDefinition,
+ onDelete
+ });
+
+ wrapper.instance().handleDelete();
+ expect(onDelete).toHaveBeenCalledWith(bindingDefinition.key);
+});
+
+it('should (dis)allow submit by validating its state', () => {
+ const wrapper = shallowRender();
+ expect(wrapper.instance().canSubmit()).toBe(false);
+
+ wrapper.setState({ formData: mockGithubDefinition(), touched: true });
+ expect(wrapper.instance().canSubmit()).toBe(true);
+ wrapper.setState({ formData: mockGithubDefinition({ key: '' }), touched: true });
+ wrapper.setProps({ hideKeyField: true });
expect(wrapper.instance().canSubmit()).toBe(true);
});
-function shallowRender(
- props: Partial<AlmPRDecorationFormModal<GithubBindingDefinition>['props']> = {}
-) {
- return shallow<AlmPRDecorationFormModal<GithubBindingDefinition>>(
- <AlmPRDecorationFormModal
+function shallowRender(props: Partial<AlmPRDecorationForm<GithubBindingDefinition>['props']> = {}) {
+ return shallow<AlmPRDecorationForm<GithubBindingDefinition>>(
+ <AlmPRDecorationForm
alm={ALM_KEYS.GITHUB}
bindingDefinition={{ appId: '', key: '', privateKey: '', url: '' }}
onCancel={jest.fn()}
onSubmit={jest.fn()}
{...props}>
{() => null}
- </AlmPRDecorationFormModal>
+ </AlmPRDecorationForm>
);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModalRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModalRenderer-test.tsx
index 249f469a464..148d2b219e5 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModalRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormModalRenderer-test.tsx
@@ -26,16 +26,17 @@ import AlmPRDecorationFormModalRenderer, {
it('should render correctly', () => {
expect(shallowRender().dive()).toMatchSnapshot();
+ expect(shallowRender({ help: <span>Help me</span> }).dive()).toMatchSnapshot();
});
function shallowRender(props: Partial<AlmPRDecorationFormModalProps> = {}) {
return shallow(
<AlmPRDecorationFormModalRenderer
+ action="create"
alm={ALM_KEYS.GITHUB}
canSubmit={jest.fn()}
onCancel={jest.fn()}
onSubmit={jest.fn()}
- originalKey=""
{...props}>
{() => null}
</AlmPRDecorationFormModalRenderer>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormRenderer-test.tsx
new file mode 100644
index 00000000000..a3a8795e3c6
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationFormRenderer-test.tsx
@@ -0,0 +1,68 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
+import { submit } from 'sonar-ui-common/helpers/testUtils';
+import AlmPRDecorationFormRenderer, {
+ AlmPRDecorationFormRendererProps
+} from '../AlmPRDecorationFormRenderer';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ onCancel: jest.fn() })).toMatchSnapshot();
+ expect(shallowRender({ onDelete: jest.fn() })).toMatchSnapshot();
+ expect(shallowRender({ success: true })).toMatchSnapshot();
+ expect(shallowRender({ loading: true })).toMatchSnapshot();
+});
+
+it('should correctly block the form submission', () => {
+ const canSubmit = jest.fn(() => false);
+ const wrapper = shallowRender({ canSubmit, loading: false });
+
+ expect(canSubmit).toBeCalled();
+ expect(wrapper.find(SubmitButton).prop('disabled')).toBe(true);
+
+ wrapper.setProps({ canSubmit: jest.fn(), loading: true });
+ expect(wrapper.find(SubmitButton).prop('disabled')).toBe(true);
+
+ wrapper.setProps({ canSubmit: () => true, loading: false });
+ expect(wrapper.find(SubmitButton).prop('disabled')).toBe(false);
+});
+
+it('should correctly submit the form', () => {
+ const onSubmit = jest.fn();
+ const wrapper = shallowRender({ onSubmit });
+ submit(wrapper.find('form'));
+ expect(onSubmit).toBeCalled();
+});
+
+function shallowRender(props: Partial<AlmPRDecorationFormRendererProps> = {}) {
+ return shallow(
+ <AlmPRDecorationFormRenderer
+ canSubmit={jest.fn()}
+ loading={false}
+ onSubmit={jest.fn()}
+ success={false}
+ {...props}>
+ {() => null}
+ </AlmPRDecorationFormRenderer>
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationTable-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationTable-test.tsx
index 758d1964804..74c18ce675c 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationTable-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmPRDecorationTable-test.tsx
@@ -33,10 +33,12 @@ it('should render correctly', () => {
{ key: 'definition2', additionalColumns: ['def2-v1', 'def2-v2'] }
]
})
- ).toMatchSnapshot();
+ ).toMatchSnapshot('additional columns');
+ expect(shallowRender({ alm: ALM_KEYS.GITHUB })).toMatchSnapshot('title adjusts for GitLab');
});
-it('should callback', () => {
+it('should correctly trigger create, delete, and edit', () => {
+ const onCreate = jest.fn();
const onDelete = jest.fn();
const onEdit = jest.fn();
@@ -44,10 +46,14 @@ it('should callback', () => {
additionalColumnsHeaders: [],
alm: ALM_KEYS.BITBUCKET,
definitions: [{ key: 'defKey', additionalColumns: [] }],
+ onCreate,
onDelete,
onEdit
});
+ wrapper.find('Button').simulate('click');
+ expect(onCreate).toBeCalled();
+
wrapper.find('DeleteButton').simulate('click');
expect(onDelete).toBeCalledWith('defKey');
@@ -61,6 +67,7 @@ function shallowRender(props: Partial<AlmPRDecorationTableProps> = {}) {
additionalColumnsHeaders={[]}
alm={ALM_KEYS.AZURE}
definitions={[]}
+ onCreate={jest.fn()}
onDelete={jest.fn()}
onEdit={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTab-test.tsx
new file mode 100644
index 00000000000..ed81dba98c5
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTab-test.tsx
@@ -0,0 +1,109 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
+import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings';
+import { ALM_KEYS, AzureBindingDefinition } from '../../../../../types/alm-settings';
+import AlmTab from '../AlmTab';
+
+const DEFAULT_BINDING = {
+ key: '',
+ personalAccessToken: ''
+};
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should handle cancel', async () => {
+ const wrapper = shallowRender();
+
+ wrapper.setState({
+ editedDefinition: mockAzureDefinition()
+ });
+
+ wrapper.instance().handleCancel();
+
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should handle edit', async () => {
+ const config = mockAzureDefinition();
+ const wrapper = shallowRender({ definitions: [config] });
+ wrapper.instance().handleEdit(config.key);
+ await waitAndUpdate(wrapper);
+ expect(wrapper.state().editedDefinition).toEqual(config);
+});
+
+it('should create config', async () => {
+ const onUpdateDefinitions = jest.fn();
+ const createConfiguration = jest.fn(() => Promise.resolve());
+ const config = mockAzureDefinition();
+ const wrapper = shallowRender({ createConfiguration, onUpdateDefinitions });
+
+ wrapper.instance().handleCreate();
+ expect(wrapper.state().editedDefinition).toBe(DEFAULT_BINDING);
+
+ wrapper.setState({ editedDefinition: config });
+ await wrapper.instance().handleSubmit(config, '');
+
+ expect(createConfiguration).toBeCalledWith(config);
+ expect(onUpdateDefinitions).toBeCalled();
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+it('should update config', async () => {
+ const onUpdateDefinitions = jest.fn();
+ const updateConfiguration = jest.fn(() => Promise.resolve());
+ const config = mockAzureDefinition();
+ const wrapper = shallowRender({ onUpdateDefinitions, updateConfiguration });
+ wrapper.setState({ editedDefinition: config });
+
+ await wrapper.instance().handleSubmit(config, 'originalKey');
+
+ expect(updateConfiguration).toBeCalledWith({
+ newKey: 'key',
+ ...config,
+ key: 'originalKey'
+ });
+ expect(onUpdateDefinitions).toBeCalled();
+ expect(wrapper.state().editedDefinition).toBeUndefined();
+});
+
+function shallowRender(props: Partial<AlmTab<AzureBindingDefinition>['props']> = {}) {
+ return shallow<AlmTab<AzureBindingDefinition>>(
+ <AlmTab
+ alm={ALM_KEYS.AZURE}
+ createConfiguration={jest.fn()}
+ defaultBinding={DEFAULT_BINDING}
+ definitions={[mockAzureDefinition()]}
+ form={jest.fn()}
+ loading={false}
+ multipleAlmEnabled={true}
+ onDelete={jest.fn()}
+ onUpdateDefinitions={jest.fn()}
+ updateConfiguration={jest.fn()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTabRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTabRenderer-test.tsx
index b81f8b6628f..a727cd1e807 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTabRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AlmTabRenderer-test.tsx
@@ -20,24 +20,42 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings';
-import GithubTabRenderer, { GithubTabRendererProps } from '../GithubTabRenderer';
+import { ALM_KEYS, GithubBindingDefinition } from '../../../../../types/alm-settings';
+import AlmTabRenderer, { AlmTabRendererProps } from '../AlmTabRenderer';
-it('should render correctly', () => {
- expect(shallowRender({ loading: true })).toMatchSnapshot();
- expect(shallowRender()).toMatchSnapshot();
- expect(shallowRender({ editedDefinition: mockGithubDefinition() })).toMatchSnapshot();
+it('should render correctly for multi-ALM binding', () => {
+ expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
+ expect(shallowRender()).toMatchSnapshot('loaded');
+ expect(shallowRender({ editedDefinition: mockGithubDefinition() })).toMatchSnapshot(
+ 'editing a definition'
+ );
+});
+
+it('should render correctly for single-ALM binding', () => {
+ expect(shallowRender({ loading: true, multipleAlmEnabled: false })).toMatchSnapshot();
+ expect(shallowRender({ multipleAlmEnabled: false })).toMatchSnapshot();
+ expect(
+ shallowRender({ definitions: [mockGithubDefinition()], multipleAlmEnabled: false })
+ ).toMatchSnapshot();
});
-function shallowRender(props: Partial<GithubTabRendererProps> = {}) {
+function shallowRender(props: Partial<AlmTabRendererProps<GithubBindingDefinition>> = {}) {
return shallow(
- <GithubTabRenderer
- definitions={[]}
+ <AlmTabRenderer
+ additionalColumnsHeaders={['url', 'app_id']}
+ additionalColumnsKeys={['url', 'appId']}
+ alm={ALM_KEYS.GITHUB}
+ defaultBinding={mockGithubDefinition()}
+ definitions={[mockGithubDefinition()]}
+ form={jest.fn()}
loading={false}
+ multipleAlmEnabled={true}
onCancel={jest.fn()}
onCreate={jest.fn()}
onDelete={jest.fn()}
onEdit={jest.fn()}
onSubmit={jest.fn()}
+ success={false}
{...props}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureFormModal-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureForm-test.tsx
index 487caa2beea..27c622a0e10 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureFormModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureForm-test.tsx
@@ -20,16 +20,16 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings';
-import AzureFormModal, { AzureFormModalProps } from '../AzureFormModal';
+import AzureForm, { AzureFormProps } from '../AzureForm';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ formData: mockAzureDefinition() })).toMatchSnapshot();
});
-function shallowRender(props: Partial<AzureFormModalProps> = {}) {
+function shallowRender(props: Partial<AzureFormProps> = {}) {
return shallow(
- <AzureFormModal
+ <AzureForm
formData={{ key: '', personalAccessToken: '' }}
onFieldChange={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTab-test.tsx
index 17ef4dd7ea5..1219b421c2d 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTab-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTab-test.tsx
@@ -19,86 +19,19 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { createAzureConfiguration, updateAzureConfiguration } from '../../../../../api/almSettings';
import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings';
-import AzureTab from '../AzureTab';
-
-jest.mock('../../../../../api/almSettings', () => ({
- countBindedProjects: jest.fn().mockResolvedValue(2),
- createAzureConfiguration: jest.fn().mockResolvedValue({}),
- deleteConfiguration: jest.fn().mockResolvedValue({}),
- updateAzureConfiguration: jest.fn().mockResolvedValue({})
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
+import AzureTab, { AzureTabProps } from '../AzureTab';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});
-it('should handle cancel', async () => {
- const wrapper = shallowRender();
-
- wrapper.setState({
- editedDefinition: mockAzureDefinition()
- });
-
- wrapper.instance().handleCancel();
-
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should handle edit', async () => {
- const config = {
- key: 'key',
- personalAccessToken: 'asdf14'
- };
- const wrapper = shallowRender({ definitions: [config] });
- wrapper.instance().handleEdit(config.key);
- await waitAndUpdate(wrapper);
- expect(wrapper.state().editedDefinition).toEqual(config);
-});
-
-it('should create config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockAzureDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, '');
-
- expect(createAzureConfiguration).toBeCalledWith(config);
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should update config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockAzureDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, 'originalKey');
-
- expect(updateAzureConfiguration).toBeCalledWith({
- newKey: 'key',
- ...config,
- key: 'originalKey'
- });
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-function shallowRender(props: Partial<AzureTab['props']> = {}) {
- return shallow<AzureTab>(
+function shallowRender(props: Partial<AzureTabProps> = {}) {
+ return shallow(
<AzureTab
- definitions={[]}
+ definitions={[mockAzureDefinition()]}
loading={false}
+ multipleAlmEnabled={true}
onDelete={jest.fn()}
onUpdateDefinitions={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTabRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTabRenderer-test.tsx
deleted file mode 100644
index f8b6c713b00..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/AzureTabRenderer-test.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings';
-import AzureTabRenderer, { AzureTabRendererProps } from '../AzureTabRenderer';
-
-it('should render correctly', () => {
- expect(shallowRender({ loading: true })).toMatchSnapshot();
- expect(shallowRender()).toMatchSnapshot();
- expect(shallowRender({ editedDefinition: mockAzureDefinition() })).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<AzureTabRendererProps> = {}) {
- return shallow(
- <AzureTabRenderer
- definitions={[]}
- loading={false}
- onCancel={jest.fn()}
- onCreate={jest.fn()}
- onDelete={jest.fn()}
- onEdit={jest.fn()}
- onSubmit={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketFormModal-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketForm-test.tsx
index a05f9c9fd4b..ae1f88fa4e2 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketFormModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketForm-test.tsx
@@ -20,16 +20,16 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockBitbucketDefinition } from '../../../../../helpers/mocks/alm-settings';
-import BitbucketFormModal, { BitbucketFormModalProps } from '../BitbucketFormModal';
+import BitbucketForm, { BitbucketFormProps } from '../BitbucketForm';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ formData: mockBitbucketDefinition() })).toMatchSnapshot();
});
-function shallowRender(props: Partial<BitbucketFormModalProps> = {}) {
+function shallowRender(props: Partial<BitbucketFormProps> = {}) {
return shallow(
- <BitbucketFormModal
+ <BitbucketForm
formData={{ key: '', personalAccessToken: '', url: '' }}
onFieldChange={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx
index 836bd1d3f2a..14304140565 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTab-test.tsx
@@ -19,97 +19,19 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import {
- createBitbucketConfiguration,
- updateBitbucketConfiguration
-} from '../../../../../api/almSettings';
import { mockBitbucketDefinition } from '../../../../../helpers/mocks/alm-settings';
-import BitbucketTab from '../BitbucketTab';
-
-jest.mock('../../../../../api/almSettings', () => ({
- countBindedProjects: jest.fn().mockResolvedValue(2),
- createBitbucketConfiguration: jest.fn().mockResolvedValue({}),
- deleteConfiguration: jest.fn().mockResolvedValue({}),
- updateBitbucketConfiguration: jest.fn().mockResolvedValue({})
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
+import BitbucketTab, { BitbucketTabProps } from '../BitbucketTab';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});
-it('should handle cancel', async () => {
- const wrapper = shallowRender();
-
- wrapper.setState({
- editedDefinition: mockBitbucketDefinition()
- });
-
- wrapper.instance().handleCancel();
-
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should create config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockBitbucketDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, '');
-
- expect(createBitbucketConfiguration).toBeCalledWith(config);
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should update config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockBitbucketDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, 'originalKey');
-
- expect(updateBitbucketConfiguration).toBeCalledWith({
- newKey: 'key',
- ...config,
- key: 'originalKey'
- });
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should handle create', async () => {
- const wrapper = shallowRender();
- wrapper.instance().handleCreate();
- await waitAndUpdate(wrapper);
- expect(wrapper.state().editedDefinition).toEqual({ key: '', url: '', personalAccessToken: '' });
-});
-
-it('should handle edit', async () => {
- const config = {
- key: 'key',
- url: 'url',
- personalAccessToken: 'PAT'
- };
- const wrapper = shallowRender({ definitions: [config] });
- wrapper.instance().handleEdit(config.key);
- await waitAndUpdate(wrapper);
- expect(wrapper.state().editedDefinition).toEqual(config);
-});
-
-function shallowRender(props: Partial<BitbucketTab['props']> = {}) {
- return shallow<BitbucketTab>(
+function shallowRender(props: Partial<BitbucketTabProps> = {}) {
+ return shallow(
<BitbucketTab
- definitions={[]}
+ definitions={[mockBitbucketDefinition()]}
loading={false}
+ multipleAlmEnabled={true}
onDelete={jest.fn()}
onUpdateDefinitions={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTabRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTabRenderer-test.tsx
deleted file mode 100644
index f2daaa98fa5..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/BitbucketTabRenderer-test.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockBitbucketDefinition } from '../../../../../helpers/mocks/alm-settings';
-import BitbucketTabRenderer, { BitbucketTabRendererProps } from '../BitbucketTabRenderer';
-
-it('should render correctly', () => {
- expect(shallowRender({ loading: true })).toMatchSnapshot();
- expect(shallowRender()).toMatchSnapshot();
- expect(shallowRender({ editedDefinition: mockBitbucketDefinition() })).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<BitbucketTabRendererProps> = {}) {
- return shallow(
- <BitbucketTabRenderer
- definitions={[]}
- loading={false}
- onCancel={jest.fn()}
- onCreate={jest.fn()}
- onDelete={jest.fn()}
- onEdit={jest.fn()}
- onSubmit={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubFormModal-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubForm-test.tsx
index 44f595894a5..860f8045a27 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubFormModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubForm-test.tsx
@@ -20,16 +20,16 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings';
-import GithubFormModal, { GithubFormModalProps } from '../GithubFormModal';
+import GithubForm, { GithubFormProps } from '../GithubForm';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ formData: mockGithubDefinition() })).toMatchSnapshot();
});
-function shallowRender(props: Partial<GithubFormModalProps> = {}) {
+function shallowRender(props: Partial<GithubFormProps> = {}) {
return shallow(
- <GithubFormModal
+ <GithubForm
formData={{ key: '', appId: '', privateKey: '', url: '' }}
onFieldChange={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTab-test.tsx
index b1209124f02..2dce1d43c16 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTab-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GithubTab-test.tsx
@@ -19,91 +19,19 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import {
- createGithubConfiguration,
- updateGithubConfiguration
-} from '../../../../../api/almSettings';
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings';
-import GithubTab from '../GithubTab';
-
-jest.mock('../../../../../api/almSettings', () => ({
- countBindedProjects: jest.fn().mockResolvedValue(2),
- createGithubConfiguration: jest.fn().mockResolvedValue({}),
- deleteConfiguration: jest.fn().mockResolvedValue({}),
- updateGithubConfiguration: jest.fn().mockResolvedValue({})
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
+import GithubTab, { GithubTabProps } from '../GithubTab';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});
-it('should handle cancel', async () => {
- const wrapper = shallowRender();
-
- wrapper.setState({
- editedDefinition: mockGithubDefinition()
- });
-
- wrapper.instance().handleCancel();
-
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should handle edit', async () => {
- const config = {
- key: 'key',
- url: 'url',
- appId: 'appid',
- privateKey: 'PAT'
- };
- const wrapper = shallowRender({ definitions: [config] });
- wrapper.instance().handleEdit(config.key);
- await waitAndUpdate(wrapper);
- expect(wrapper.state().editedDefinition).toEqual(config);
-});
-
-it('should create config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockGithubDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, '');
-
- expect(createGithubConfiguration).toBeCalledWith(config);
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should update config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockGithubDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, 'originalKey');
-
- expect(updateGithubConfiguration).toBeCalledWith({
- newKey: 'key',
- ...config,
- key: 'originalKey'
- });
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-function shallowRender(props: Partial<GithubTab['props']> = {}) {
- return shallow<GithubTab>(
+function shallowRender(props: Partial<GithubTabProps> = {}) {
+ return shallow(
<GithubTab
- definitions={[]}
+ definitions={[mockGithubDefinition()]}
loading={false}
+ multipleAlmEnabled={true}
onDelete={jest.fn()}
onUpdateDefinitions={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabFormModal-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabForm-test.tsx
index 54886e50f79..66b501154e6 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabFormModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabForm-test.tsx
@@ -20,16 +20,16 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockGitlabDefinition } from '../../../../../helpers/mocks/alm-settings';
-import { GitlabFormModal, GitlabFormModalProps } from '../GitlabFormModal';
+import GitlabForm, { GitlabFormProps } from '../GitlabForm';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
expect(shallowRender({ formData: mockGitlabDefinition() })).toMatchSnapshot();
});
-function shallowRender(props: Partial<GitlabFormModalProps> = {}) {
+function shallowRender(props: Partial<GitlabFormProps> = {}) {
return shallow(
- <GitlabFormModal
+ <GitlabForm
formData={{ key: '', personalAccessToken: '' }}
onFieldChange={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTab-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTab-test.tsx
index abe042b7fbd..eff98495ce3 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTab-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTab-test.tsx
@@ -19,86 +19,19 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import {
- createGitlabConfiguration,
- updateGitlabConfiguration
-} from '../../../../../api/almSettings';
import { mockGitlabDefinition } from '../../../../../helpers/mocks/alm-settings';
-import GitlabTab from '../GitlabTab';
-
-jest.mock('../../../../../api/almSettings', () => ({
- countBindedProjects: jest.fn().mockResolvedValue(2),
- createGitlabConfiguration: jest.fn().mockResolvedValue({}),
- deleteConfiguration: jest.fn().mockResolvedValue({}),
- updateGitlabConfiguration: jest.fn().mockResolvedValue({})
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
+import GitlabTab, { GitlabTabProps } from '../GitlabTab';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});
-it('should handle cancel', async () => {
- const wrapper = shallowRender();
-
- wrapper.setState({
- editedDefinition: mockGitlabDefinition()
- });
-
- wrapper.instance().handleCancel();
-
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should handle edit', async () => {
- const config = mockGitlabDefinition();
- const wrapper = shallowRender({ definitions: [config] });
- wrapper.instance().handleEdit(config.key);
- await waitAndUpdate(wrapper);
- expect(wrapper.state().editedDefinition).toEqual(config);
-});
-
-it('should create config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockGitlabDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, '');
-
- expect(createGitlabConfiguration).toBeCalledWith(config);
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-it('should update config', async () => {
- const onUpdateDefinitions = jest.fn();
- const config = mockGitlabDefinition();
- const wrapper = shallowRender({ onUpdateDefinitions });
- wrapper.setState({ editedDefinition: config });
-
- await wrapper.instance().handleSubmit(config, 'originalKey');
-
- expect(updateGitlabConfiguration).toBeCalledWith({
- newKey: 'foo',
- ...config,
- key: 'originalKey'
- });
- expect(onUpdateDefinitions).toBeCalled();
- expect(wrapper.state().editedDefinition).toBeUndefined();
-});
-
-function shallowRender(props: Partial<GitlabTab['props']> = {}) {
- return shallow<GitlabTab>(
+function shallowRender(props: Partial<GitlabTabProps> = {}) {
+ return shallow(
<GitlabTab
- definitions={[]}
+ definitions={[mockGitlabDefinition()]}
loading={false}
+ multipleAlmEnabled={true}
onDelete={jest.fn()}
onUpdateDefinitions={jest.fn()}
{...props}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTabRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTabRenderer-test.tsx
deleted file mode 100644
index 5fe001eadeb..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/GitlabTabRenderer-test.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockGitlabDefinition } from '../../../../../helpers/mocks/alm-settings';
-import GitlabTabRenderer, { GitlabTabRendererProps } from '../GitlabTabRenderer';
-
-it('should render correctly', () => {
- expect(shallowRender({ loading: true })).toMatchSnapshot();
- expect(shallowRender()).toMatchSnapshot();
- expect(shallowRender({ editedDefinition: mockGitlabDefinition() })).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<GitlabTabRendererProps> = {}) {
- return shallow(
- <GitlabTabRenderer
- definitions={[]}
- loading={false}
- onCancel={jest.fn()}
- onCreate={jest.fn()}
- onDelete={jest.fn()}
- onEdit={jest.fn()}
- onSubmit={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PRDecorationTabs-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PRDecorationTabs-test.tsx
index 9a84060a2ad..313ad6eb8ea 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PRDecorationTabs-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/PRDecorationTabs-test.tsx
@@ -20,7 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { ALM_KEYS } from '../../../../../types/alm-settings';
-import PRDecorationTabs, { PRDecorationTabsProps } from '../PRDecorationTabs';
+import { PRDecorationTabs, PRDecorationTabsProps } from '../PRDecorationTabs';
it('should render correctly', () => {
expect(shallowRender({ loading: true })).toMatchSnapshot();
@@ -33,6 +33,7 @@ it('should render correctly', () => {
function shallowRender(props: Partial<PRDecorationTabsProps> = {}) {
return shallow(
<PRDecorationTabs
+ appState={{ multipleAlmEnabled: false }}
currentAlm={ALM_KEYS.GITHUB}
definitions={{ azure: [], bitbucket: [], github: [], gitlab: [] }}
loading={false}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/TabHeader-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/TabHeader-test.tsx
deleted file mode 100644
index d97e88eee6c..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/TabHeader-test.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { Button } from 'sonar-ui-common/components/controls/buttons';
-import { ALM_KEYS } from '../../../../../types/alm-settings';
-import { TabHeader, TabHeaderProps } from '../TabHeader';
-
-it('should render correctly', () => {
- expect(shallowRender(ALM_KEYS.AZURE)).toMatchSnapshot();
- expect(shallowRender(ALM_KEYS.GITHUB)).toMatchSnapshot();
-});
-
-it('should only show the create button if certain conditions are met', () => {
- expect(
- shallowRender(ALM_KEYS.GITHUB, { appState: { multipleAlmEnabled: false }, definitionCount: 1 })
- .find(Button)
- .exists()
- ).toBe(false);
-
- expect(
- shallowRender(ALM_KEYS.GITHUB, { appState: { multipleAlmEnabled: false }, definitionCount: 0 })
- .find(Button)
- .exists()
- ).toBe(true);
-
- expect(
- shallowRender(ALM_KEYS.GITHUB, { appState: { multipleAlmEnabled: true }, definitionCount: 5 })
- .find(Button)
- .exists()
- ).toBe(true);
-});
-
-function shallowRender(alm: ALM_KEYS, props: Partial<TabHeaderProps> = {}) {
- return shallow(
- <TabHeader alm={alm} appState={{}} definitionCount={0} onCreate={jest.fn()} {...props} />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmDefinitionFormField-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmDefinitionFormField-test.tsx.snap
index 0d975f13e19..57a15af1578 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmDefinitionFormField-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmDefinitionFormField-test.tsx.snap
@@ -17,6 +17,7 @@ exports[`should render correctly 1`] = `
</label>
<input
className="input-super-large"
+ disabled={false}
id="key"
maxLength={40}
name="key"
@@ -49,6 +50,7 @@ exports[`should render correctly 2`] = `
</label>
<input
className="input-super-large"
+ disabled={false}
id="key"
maxLength={40}
name="key"
@@ -77,6 +79,7 @@ exports[`should render correctly 3`] = `
</label>
<textarea
className="settings-large-input"
+ disabled={false}
id="key"
maxLength={40}
onChange={[Function]}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationForm-test.tsx.snap
index 20c47fea39b..98dbf7f493c 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationForm-test.tsx.snap
@@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<AlmPRDecorationFormModalRenderer
- alm="github"
+<AlmPRDecorationFormRenderer
canSubmit={[Function]}
- onCancel={[MockFunction]}
+ loading={false}
+ onCancel={[Function]}
onSubmit={[Function]}
- originalKey=""
+ success={false}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModalRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModalRenderer-test.tsx.snap
index baaeb049227..8c73cbf6880 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModalRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormModalRenderer-test.tsx.snap
@@ -44,3 +44,56 @@ exports[`should render correctly 1`] = `
</form>
</Modal>
`;
+
+exports[`should render correctly 2`] = `
+<Modal
+ contentLabel="settings.pr_decoration.form.header.create"
+ onRequestClose={[MockFunction]}
+ size="medium"
+>
+ <form
+ className="views-form"
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-head"
+ >
+ <h2>
+ settings.pr_decoration.form.header.create
+ </h2>
+ </div>
+ <div
+ className="modal-body modal-container"
+ >
+ <Alert
+ className="big-spacer-bottom"
+ variant="info"
+ >
+ <span>
+ Help me
+ </span>
+ </Alert>
+ <Component />
+ </div>
+ <div
+ className="modal-foot"
+ >
+ <DeferredSpinner
+ className="spacer-right"
+ loading={false}
+ timeout={100}
+ />
+ <SubmitButton
+ disabled={true}
+ >
+ settings.pr_decoration.form.save
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[Function]}
+ >
+ cancel
+ </ResetButtonLink>
+ </div>
+ </form>
+</Modal>
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormRenderer-test.tsx.snap
new file mode 100644
index 00000000000..fddedfb39c2
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationFormRenderer-test.tsx.snap
@@ -0,0 +1,121 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<form
+ className="views-form"
+ data-test="settings__alm-form"
+ onSubmit={[Function]}
+>
+ <Component />
+ <div
+ className="display-flex-center"
+ >
+ <SubmitButton
+ disabled={true}
+ >
+ settings.pr_decoration.form.save
+ </SubmitButton>
+ </div>
+</form>
+`;
+
+exports[`should render correctly 2`] = `
+<form
+ className="views-form"
+ data-test="settings__alm-form"
+ onSubmit={[Function]}
+>
+ <Component />
+ <div
+ className="display-flex-center"
+ >
+ <SubmitButton
+ disabled={true}
+ >
+ settings.pr_decoration.form.save
+ </SubmitButton>
+ <ResetButtonLink
+ className="spacer-left"
+ onClick={[MockFunction]}
+ >
+ cancel
+ </ResetButtonLink>
+ </div>
+</form>
+`;
+
+exports[`should render correctly 3`] = `
+<form
+ className="views-form"
+ data-test="settings__alm-form"
+ onSubmit={[Function]}
+>
+ <Component />
+ <div
+ className="display-flex-center"
+ >
+ <SubmitButton
+ disabled={true}
+ >
+ settings.pr_decoration.form.save
+ </SubmitButton>
+ <Button
+ className="button-red spacer-left"
+ disabled={false}
+ onClick={[MockFunction]}
+ >
+ delete
+ </Button>
+ </div>
+</form>
+`;
+
+exports[`should render correctly 4`] = `
+<form
+ className="views-form"
+ data-test="settings__alm-form"
+ onSubmit={[Function]}
+>
+ <Component />
+ <div
+ className="display-flex-center"
+ >
+ <SubmitButton
+ disabled={true}
+ >
+ settings.pr_decoration.form.save
+ </SubmitButton>
+ <span
+ className="text-success spacer-left"
+ >
+ <AlertSuccessIcon
+ className="spacer-right"
+ />
+ settings.state.saved
+ </span>
+ </div>
+</form>
+`;
+
+exports[`should render correctly 5`] = `
+<form
+ className="views-form"
+ data-test="settings__alm-form"
+ onSubmit={[Function]}
+>
+ <Component />
+ <div
+ className="display-flex-center"
+ >
+ <SubmitButton
+ disabled={true}
+ >
+ settings.pr_decoration.form.save
+ </SubmitButton>
+ <DeferredSpinner
+ className="spacer-left"
+ timeout={100}
+ />
+ </div>
+</form>
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationTable-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationTable-test.tsx.snap
index 1334b79e8bf..bc850412321 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationTable-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmPRDecorationTable-test.tsx.snap
@@ -1,158 +1,244 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<table
- className="data zebra fixed spacer-bottom"
->
- <thead>
- <tr>
- <th>
- settings.pr_decoration.table.column.name
- </th>
- <th
- className="action-small text-center"
- >
- settings.pr_decoration.table.column.edit
- </th>
- <th
- className="action text-center"
- >
- settings.pr_decoration.table.column.delete
- </th>
- </tr>
- </thead>
- <tbody>
- <tr
- data-test="settings__alm-empty-table"
+<Fragment>
+ <div
+ className="spacer-top big-spacer-bottom display-flex-space-between"
+ >
+ <h4
+ className="display-inline"
>
- <td
- colSpan={3}
- >
- settings.pr_decoration.table.empty.azure
- </td>
- </tr>
- </tbody>
-</table>
+ settings.pr_decoration.table.title
+ </h4>
+ <Button
+ data-test="settings__alm-create"
+ onClick={[MockFunction]}
+ >
+ settings.pr_decoration.table.create
+ </Button>
+ </div>
+ <table
+ className="data zebra fixed spacer-bottom"
+ >
+ <thead>
+ <tr>
+ <th>
+ settings.pr_decoration.table.column.name
+ </th>
+ <th
+ className="action-small text-center"
+ >
+ settings.pr_decoration.table.column.edit
+ </th>
+ <th
+ className="action text-center"
+ >
+ settings.pr_decoration.table.column.delete
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr
+ data-test="settings__alm-empty-table"
+ >
+ <td
+ colSpan={3}
+ >
+ settings.pr_decoration.table.empty.azure
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</Fragment>
`;
-exports[`should render correctly 2`] = `
-<table
- className="data zebra fixed spacer-bottom"
->
- <thead>
- <tr>
- <th>
- settings.pr_decoration.table.column.name
- </th>
- <th
- key="additional1"
- >
- additional1
- </th>
- <th
- key="additional2"
- >
- additional2
- </th>
- <th
- className="action-small text-center"
- >
- settings.pr_decoration.table.column.edit
- </th>
- <th
- className="action text-center"
- >
- settings.pr_decoration.table.column.delete
- </th>
- </tr>
- </thead>
- <tbody>
- <tr
- data-test="settings__alm-table-row"
- key="definition1"
+exports[`should render correctly: additional columns 1`] = `
+<Fragment>
+ <div
+ className="spacer-top big-spacer-bottom display-flex-space-between"
+ >
+ <h4
+ className="display-inline"
>
- <td
- className="nowrap hide-overflow"
- title="definition1"
- >
- definition1
- </td>
- <td
- className="nowrap hide-overflow"
- key="def1-v1"
- title="def1-v1"
- >
- def1-v1
- </td>
- <td
- className="nowrap hide-overflow"
- key="def1-v2"
- title="def1-v2"
- >
- def1-v2
- </td>
- <td
- className="text-center"
- data-test="settings__alm-table-row-edit"
- >
- <ButtonIcon
- onClick={[Function]}
- >
- <EditIcon />
- </ButtonIcon>
- </td>
- <td
- className="text-center"
- data-test="settings__alm-table-row-delete"
- >
- <DeleteButton
- onClick={[Function]}
- />
- </td>
- </tr>
- <tr
- data-test="settings__alm-table-row"
- key="definition2"
+ settings.pr_decoration.table.title
+ </h4>
+ <Button
+ data-test="settings__alm-create"
+ onClick={[MockFunction]}
>
- <td
- className="nowrap hide-overflow"
- title="definition2"
- >
- definition2
- </td>
- <td
- className="nowrap hide-overflow"
- key="def2-v1"
- title="def2-v1"
- >
- def2-v1
- </td>
- <td
- className="nowrap hide-overflow"
- key="def2-v2"
- title="def2-v2"
- >
- def2-v2
- </td>
- <td
- className="text-center"
- data-test="settings__alm-table-row-edit"
- >
- <ButtonIcon
- onClick={[Function]}
- >
- <EditIcon />
- </ButtonIcon>
- </td>
- <td
- className="text-center"
- data-test="settings__alm-table-row-delete"
- >
- <DeleteButton
- onClick={[Function]}
- />
- </td>
- </tr>
- </tbody>
-</table>
+ settings.pr_decoration.table.create
+ </Button>
+ </div>
+ <table
+ className="data zebra fixed spacer-bottom"
+ >
+ <thead>
+ <tr>
+ <th>
+ settings.pr_decoration.table.column.name
+ </th>
+ <th
+ key="additional1"
+ >
+ additional1
+ </th>
+ <th
+ key="additional2"
+ >
+ additional2
+ </th>
+ <th
+ className="action-small text-center"
+ >
+ settings.pr_decoration.table.column.edit
+ </th>
+ <th
+ className="action text-center"
+ >
+ settings.pr_decoration.table.column.delete
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr
+ data-test="settings__alm-table-row"
+ key="definition1"
+ >
+ <td
+ className="nowrap hide-overflow"
+ title="definition1"
+ >
+ definition1
+ </td>
+ <td
+ className="nowrap hide-overflow"
+ key="def1-v1"
+ title="def1-v1"
+ >
+ def1-v1
+ </td>
+ <td
+ className="nowrap hide-overflow"
+ key="def1-v2"
+ title="def1-v2"
+ >
+ def1-v2
+ </td>
+ <td
+ className="text-center"
+ data-test="settings__alm-table-row-edit"
+ >
+ <ButtonIcon
+ onClick={[Function]}
+ >
+ <EditIcon />
+ </ButtonIcon>
+ </td>
+ <td
+ className="text-center"
+ data-test="settings__alm-table-row-delete"
+ >
+ <DeleteButton
+ onClick={[Function]}
+ />
+ </td>
+ </tr>
+ <tr
+ data-test="settings__alm-table-row"
+ key="definition2"
+ >
+ <td
+ className="nowrap hide-overflow"
+ title="definition2"
+ >
+ definition2
+ </td>
+ <td
+ className="nowrap hide-overflow"
+ key="def2-v1"
+ title="def2-v1"
+ >
+ def2-v1
+ </td>
+ <td
+ className="nowrap hide-overflow"
+ key="def2-v2"
+ title="def2-v2"
+ >
+ def2-v2
+ </td>
+ <td
+ className="text-center"
+ data-test="settings__alm-table-row-edit"
+ >
+ <ButtonIcon
+ onClick={[Function]}
+ >
+ <EditIcon />
+ </ButtonIcon>
+ </td>
+ <td
+ className="text-center"
+ data-test="settings__alm-table-row-delete"
+ >
+ <DeleteButton
+ onClick={[Function]}
+ />
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</Fragment>
+`;
+
+exports[`should render correctly: title adjusts for GitLab 1`] = `
+<Fragment>
+ <div
+ className="spacer-top big-spacer-bottom display-flex-space-between"
+ >
+ <h4
+ className="display-inline"
+ >
+ settings.pr_decoration.table.title
+ </h4>
+ <Button
+ data-test="settings__alm-create"
+ onClick={[MockFunction]}
+ >
+ settings.pr_decoration.table.create
+ </Button>
+ </div>
+ <table
+ className="data zebra fixed spacer-bottom"
+ >
+ <thead>
+ <tr>
+ <th>
+ settings.pr_decoration.table.column.name
+ </th>
+ <th
+ className="action-small text-center"
+ >
+ settings.pr_decoration.table.column.edit
+ </th>
+ <th
+ className="action text-center"
+ >
+ settings.pr_decoration.table.column.delete
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr
+ data-test="settings__alm-empty-table"
+ >
+ <td
+ colSpan={3}
+ >
+ settings.pr_decoration.table.empty.github
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</Fragment>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTab-test.tsx.snap
new file mode 100644
index 00000000000..5d3f8507f61
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTab-test.tsx.snap
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<AlmTabRenderer
+ additionalColumnsHeaders={Array []}
+ additionalColumnsKeys={Array []}
+ alm="azure"
+ defaultBinding={
+ Object {
+ "key": "",
+ "personalAccessToken": "",
+ }
+ }
+ definitions={
+ Array [
+ Object {
+ "key": "key",
+ "personalAccessToken": "asdf1234",
+ },
+ ]
+ }
+ form={[MockFunction]}
+ loading={false}
+ multipleAlmEnabled={true}
+ onCancel={[Function]}
+ onCreate={[Function]}
+ onDelete={[MockFunction]}
+ onEdit={[Function]}
+ onSubmit={[Function]}
+ success={false}
+/>
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
new file mode 100644
index 00000000000..620640396af
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
@@ -0,0 +1,254 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly for multi-ALM binding: editing a definition 1`] = `
+<DeferredSpinner
+ loading={false}
+ timeout={100}
+>
+ <AlmPRDecorationTable
+ additionalColumnsHeaders={
+ Array [
+ "url",
+ "app_id",
+ ]
+ }
+ alm="github"
+ definitions={
+ Array [
+ Object {
+ "additionalColumns": Array [
+ "http://github.enterprise.com",
+ "123456",
+ ],
+ "key": "key",
+ },
+ ]
+ }
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ />
+ <AlmPRDecorationForm
+ alm="github"
+ bindingDefinition={
+ Object {
+ "appId": "123456",
+ "key": "key",
+ "privateKey": "asdf1234",
+ "url": "http://github.enterprise.com",
+ }
+ }
+ help={
+ <FormattedMessage
+ defaultMessage="settings.pr_decoration.github.info"
+ id="settings.pr_decoration.github.info"
+ values={
+ Object {
+ "link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/analysis/pr-decoration/"
+ >
+ learn_more
+ </Link>,
+ }
+ }
+ />
+ }
+ onCancel={[MockFunction]}
+ onSubmit={[MockFunction]}
+ showInModal={true}
+ >
+ <Component />
+ </AlmPRDecorationForm>
+</DeferredSpinner>
+`;
+
+exports[`should render correctly for multi-ALM binding: loaded 1`] = `
+<DeferredSpinner
+ loading={false}
+ timeout={100}
+>
+ <AlmPRDecorationTable
+ additionalColumnsHeaders={
+ Array [
+ "url",
+ "app_id",
+ ]
+ }
+ alm="github"
+ definitions={
+ Array [
+ Object {
+ "additionalColumns": Array [
+ "http://github.enterprise.com",
+ "123456",
+ ],
+ "key": "key",
+ },
+ ]
+ }
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ />
+</DeferredSpinner>
+`;
+
+exports[`should render correctly for multi-ALM binding: loading 1`] = `
+<DeferredSpinner
+ loading={true}
+ timeout={100}
+>
+ <AlmPRDecorationTable
+ additionalColumnsHeaders={
+ Array [
+ "url",
+ "app_id",
+ ]
+ }
+ alm="github"
+ definitions={
+ Array [
+ Object {
+ "additionalColumns": Array [
+ "http://github.enterprise.com",
+ "123456",
+ ],
+ "key": "key",
+ },
+ ]
+ }
+ onCreate={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ />
+</DeferredSpinner>
+`;
+
+exports[`should render correctly for single-ALM binding 1`] = `
+<AlmPRDecorationForm
+ alm="github"
+ bindingDefinition={
+ Object {
+ "appId": "123456",
+ "key": "key",
+ "privateKey": "asdf1234",
+ "url": "http://github.enterprise.com",
+ }
+ }
+ help={
+ <FormattedMessage
+ defaultMessage="settings.pr_decoration.github.info"
+ id="settings.pr_decoration.github.info"
+ values={
+ Object {
+ "link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/analysis/pr-decoration/"
+ >
+ learn_more
+ </Link>,
+ }
+ }
+ />
+ }
+ hideKeyField={true}
+ loading={true}
+ onCancel={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ readOnly={true}
+ success={false}
+>
+ <Component />
+</AlmPRDecorationForm>
+`;
+
+exports[`should render correctly for single-ALM binding 2`] = `
+<AlmPRDecorationForm
+ alm="github"
+ bindingDefinition={
+ Object {
+ "appId": "123456",
+ "key": "key",
+ "privateKey": "asdf1234",
+ "url": "http://github.enterprise.com",
+ }
+ }
+ help={
+ <FormattedMessage
+ defaultMessage="settings.pr_decoration.github.info"
+ id="settings.pr_decoration.github.info"
+ values={
+ Object {
+ "link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/analysis/pr-decoration/"
+ >
+ learn_more
+ </Link>,
+ }
+ }
+ />
+ }
+ hideKeyField={true}
+ loading={false}
+ onCancel={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ readOnly={true}
+ success={false}
+>
+ <Component />
+</AlmPRDecorationForm>
+`;
+
+exports[`should render correctly for single-ALM binding 3`] = `
+<AlmPRDecorationForm
+ alm="github"
+ bindingDefinition={
+ Object {
+ "appId": "123456",
+ "key": "key",
+ "privateKey": "asdf1234",
+ "url": "http://github.enterprise.com",
+ }
+ }
+ help={
+ <FormattedMessage
+ defaultMessage="settings.pr_decoration.github.info"
+ id="settings.pr_decoration.github.info"
+ values={
+ Object {
+ "link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/analysis/pr-decoration/"
+ >
+ learn_more
+ </Link>,
+ }
+ }
+ />
+ }
+ hideKeyField={true}
+ loading={false}
+ onCancel={[MockFunction]}
+ onDelete={[MockFunction]}
+ onEdit={[MockFunction]}
+ onSubmit={[MockFunction]}
+ readOnly={true}
+ success={false}
+>
+ <Component />
+</AlmPRDecorationForm>
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureFormModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureForm-test.tsx.snap
index b980d1d72cd..b980d1d72cd 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureFormModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureForm-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTab-test.tsx.snap
index b80dec07064..f73bb4670fe 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTab-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTab-test.tsx.snap
@@ -1,13 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<AzureTabRenderer
- definitions={Array []}
+<AlmTab
+ alm="azure"
+ createConfiguration={[Function]}
+ defaultBinding={
+ Object {
+ "key": "",
+ "personalAccessToken": "",
+ }
+ }
+ definitions={
+ Array [
+ Object {
+ "key": "key",
+ "personalAccessToken": "asdf1234",
+ },
+ ]
+ }
+ form={[Function]}
loading={false}
- onCancel={[Function]}
- onCreate={[Function]}
+ multipleAlmEnabled={true}
onDelete={[MockFunction]}
- onEdit={[Function]}
- onSubmit={[Function]}
+ onUpdateDefinitions={[MockFunction]}
+ updateConfiguration={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTabRenderer-test.tsx.snap
deleted file mode 100644
index 8e82621775a..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/AzureTabRenderer-test.tsx.snap
+++ /dev/null
@@ -1,80 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="azure"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={Array []}
- alm="azure"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 2`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="azure"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={Array []}
- alm="azure"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 3`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="azure"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={Array []}
- alm="azure"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
- <AlmPRDecorationFormModal
- alm="azure"
- bindingDefinition={
- Object {
- "key": "key",
- "personalAccessToken": "asdf1234",
- }
- }
- onCancel={[MockFunction]}
- onSubmit={[MockFunction]}
- >
- <Component />
- </AlmPRDecorationFormModal>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketFormModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap
index 831e13ea2e5..831e13ea2e5 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketFormModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
index 68fb3da0537..9d519a62456 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTab-test.tsx.snap
@@ -1,13 +1,40 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<BitbucketTabRenderer
- definitions={Array []}
+<AlmTab
+ additionalColumnsHeaders={
+ Array [
+ "settings.pr_decoration.table.column.bitbucket.url",
+ ]
+ }
+ additionalColumnsKeys={
+ Array [
+ "url",
+ ]
+ }
+ alm="bitbucket"
+ createConfiguration={[Function]}
+ defaultBinding={
+ Object {
+ "key": "",
+ "personalAccessToken": "",
+ "url": "",
+ }
+ }
+ definitions={
+ Array [
+ Object {
+ "key": "key",
+ "personalAccessToken": "asdf1234",
+ "url": "http://bbs.enterprise.com",
+ },
+ ]
+ }
+ form={[Function]}
loading={false}
- onCancel={[Function]}
- onCreate={[Function]}
+ multipleAlmEnabled={true}
onDelete={[MockFunction]}
- onEdit={[Function]}
- onSubmit={[Function]}
+ onUpdateDefinitions={[MockFunction]}
+ updateConfiguration={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap
deleted file mode 100644
index 5c58a795784..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/BitbucketTabRenderer-test.tsx.snap
+++ /dev/null
@@ -1,93 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="bitbucket"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={
- Array [
- "settings.pr_decoration.table.column.bitbucket.url",
- ]
- }
- alm="bitbucket"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 2`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="bitbucket"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={
- Array [
- "settings.pr_decoration.table.column.bitbucket.url",
- ]
- }
- alm="bitbucket"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 3`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="bitbucket"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={
- Array [
- "settings.pr_decoration.table.column.bitbucket.url",
- ]
- }
- alm="bitbucket"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
- <AlmPRDecorationFormModal
- alm="bitbucket"
- bindingDefinition={
- Object {
- "key": "key",
- "personalAccessToken": "asdf1234",
- "url": "http://bbs.enterprise.com",
- }
- }
- onCancel={[MockFunction]}
- onSubmit={[MockFunction]}
- >
- <Component />
- </AlmPRDecorationFormModal>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubFormModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubForm-test.tsx.snap
index 3f4492a255d..3f4492a255d 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubFormModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubForm-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTab-test.tsx.snap
index 95b9c9ebfb5..2fc099dd893 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTab-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTab-test.tsx.snap
@@ -1,13 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<GithubTabRenderer
- definitions={Array []}
+<AlmTab
+ additionalColumnsHeaders={
+ Array [
+ "settings.pr_decoration.table.column.github.url",
+ "settings.pr_decoration.table.column.app_id",
+ ]
+ }
+ additionalColumnsKeys={
+ Array [
+ "appId",
+ "url",
+ ]
+ }
+ alm="github"
+ createConfiguration={[Function]}
+ defaultBinding={
+ Object {
+ "appId": "",
+ "key": "",
+ "privateKey": "",
+ "url": "",
+ }
+ }
+ definitions={
+ Array [
+ Object {
+ "appId": "123456",
+ "key": "key",
+ "privateKey": "asdf1234",
+ "url": "http://github.enterprise.com",
+ },
+ ]
+ }
+ form={[Function]}
loading={false}
- onCancel={[Function]}
- onCreate={[Function]}
+ multipleAlmEnabled={true}
onDelete={[MockFunction]}
- onEdit={[Function]}
- onSubmit={[Function]}
+ onUpdateDefinitions={[MockFunction]}
+ updateConfiguration={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTabRenderer-test.tsx.snap
deleted file mode 100644
index aa48a283a56..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GithubTabRenderer-test.tsx.snap
+++ /dev/null
@@ -1,97 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="github"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={
- Array [
- "settings.pr_decoration.table.column.github.url",
- "settings.pr_decoration.table.column.app_id",
- ]
- }
- alm="github"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 2`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="github"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={
- Array [
- "settings.pr_decoration.table.column.github.url",
- "settings.pr_decoration.table.column.app_id",
- ]
- }
- alm="github"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 3`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="github"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={
- Array [
- "settings.pr_decoration.table.column.github.url",
- "settings.pr_decoration.table.column.app_id",
- ]
- }
- alm="github"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
- <AlmPRDecorationFormModal
- alm="github"
- bindingDefinition={
- Object {
- "appId": "123456",
- "key": "key",
- "privateKey": "asdf1234",
- "url": "http://github.enterprise.com",
- }
- }
- onCancel={[MockFunction]}
- onSubmit={[MockFunction]}
- >
- <Component />
- </AlmPRDecorationFormModal>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabFormModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabForm-test.tsx.snap
index 8c2b54c3887..8c2b54c3887 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabFormModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabForm-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTab-test.tsx.snap
index 95bb1ac5bef..fdee120ed9f 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTab-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTab-test.tsx.snap
@@ -1,13 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<GitlabTabRenderer
- definitions={Array []}
+<AlmTab
+ alm="gitlab"
+ createConfiguration={[Function]}
+ defaultBinding={
+ Object {
+ "key": "",
+ "personalAccessToken": "",
+ }
+ }
+ definitions={
+ Array [
+ Object {
+ "key": "foo",
+ "personalAccessToken": "foobar",
+ },
+ ]
+ }
+ form={[Function]}
loading={false}
- onCancel={[Function]}
- onCreate={[Function]}
+ multipleAlmEnabled={true}
onDelete={[MockFunction]}
- onEdit={[Function]}
- onSubmit={[Function]}
+ onUpdateDefinitions={[MockFunction]}
+ updateConfiguration={[Function]}
/>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTabRenderer-test.tsx.snap
deleted file mode 100644
index 3b572677eb3..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/GitlabTabRenderer-test.tsx.snap
+++ /dev/null
@@ -1,80 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="gitlab"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={true}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={Array []}
- alm="gitlab"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 2`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="gitlab"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={Array []}
- alm="gitlab"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
-</Fragment>
-`;
-
-exports[`should render correctly 3`] = `
-<Fragment>
- <Connect(withAppState(TabHeader))
- alm="gitlab"
- definitionCount={0}
- onCreate={[MockFunction]}
- />
- <DeferredSpinner
- loading={false}
- timeout={100}
- >
- <AlmPRDecorationTable
- additionalColumnsHeaders={Array []}
- alm="gitlab"
- definitions={Array []}
- onDelete={[MockFunction]}
- onEdit={[MockFunction]}
- />
- </DeferredSpinner>
- <AlmPRDecorationFormModal
- alm="gitlab"
- bindingDefinition={
- Object {
- "key": "foo",
- "personalAccessToken": "foobar",
- }
- }
- onCancel={[MockFunction]}
- onSubmit={[MockFunction]}
- >
- <Component />
- </AlmPRDecorationFormModal>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap
index fa3df3d8b61..5590bf87bcb 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PRDecorationTabs-test.tsx.snap
@@ -78,6 +78,7 @@ exports[`should render correctly 1`] = `
<GithubTab
definitions={Array []}
loading={true}
+ multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
@@ -163,6 +164,7 @@ exports[`should render correctly 2`] = `
<GithubTab
definitions={Array []}
loading={false}
+ multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
@@ -253,6 +255,7 @@ exports[`should render correctly 3`] = `
<AzureTab
definitions={Array []}
loading={false}
+ multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
@@ -338,6 +341,7 @@ exports[`should render correctly 4`] = `
<BitbucketTab
definitions={Array []}
loading={false}
+ multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
@@ -423,6 +427,7 @@ exports[`should render correctly 5`] = `
<GitlabTab
definitions={Array []}
loading={false}
+ multipleAlmEnabled={false}
onDelete={[MockFunction]}
onUpdateDefinitions={[MockFunction]}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PullRequestDecoration-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PullRequestDecoration-test.tsx.snap
index fc902c9c1e3..d41b9e0d342 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PullRequestDecoration-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/PullRequestDecoration-test.tsx.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<PRDecorationTabs
+<Connect(withAppState(PRDecorationTabs))
currentAlm="github"
definitions={
Object {
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/TabHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/TabHeader-test.tsx.snap
deleted file mode 100644
index f2398aecdd7..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecoration/__tests__/__snapshots__/TabHeader-test.tsx.snap
+++ /dev/null
@@ -1,83 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <Alert
- className="spacer-top huge-spacer-bottom"
- variant="info"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.azure.info"
- id="settings.pr_decoration.azure.info"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/analysis/pr-decoration/"
- >
- learn_more
- </Link>,
- }
- }
- />
- </Alert>
- <div
- className="big-spacer-bottom display-flex-space-between"
- >
- <h4
- className="display-inline"
- >
- settings.pr_decoration.table.title
- </h4>
- <Button
- data-test="settings__alm-create"
- onClick={[MockFunction]}
- >
- settings.pr_decoration.table.create
- </Button>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly 2`] = `
-<Fragment>
- <Alert
- className="spacer-top huge-spacer-bottom"
- variant="info"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.github.info"
- id="settings.pr_decoration.github.info"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/analysis/pr-decoration/"
- >
- learn_more
- </Link>,
- }
- }
- />
- </Alert>
- <div
- className="big-spacer-bottom display-flex-space-between"
- >
- <h4
- className="display-inline"
- >
- settings.pr_decoration.table.title
- </h4>
- <Button
- data-test="settings__alm-create"
- onClick={[MockFunction]}
- >
- settings.pr_decoration.table.create
- </Button>
- </div>
-</Fragment>
-`;