diff options
Diffstat (limited to 'server/sonar-web/src/main/js/apps/settings')
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> -`; |