@@ -38,6 +38,14 @@ export function updateGithubConfiguration(data: T.GithubBindingDefinition & { ne | |||
return post('/api/alm_settings/update_github', data).catch(throwGlobalError); | |||
} | |||
export function createAzureConfiguration(data: T.AzureBindingDefinition) { | |||
return post('/api/alm_settings/create_azure', data).catch(throwGlobalError); | |||
} | |||
export function updateAzureConfiguration(data: T.AzureBindingDefinition & { newKey: string }) { | |||
return post('/api/alm_settings/update_azure', data).catch(throwGlobalError); | |||
} | |||
export function deleteConfiguration(key: string) { | |||
return post('/api/alm_settings/delete', { key }).catch(throwGlobalError); | |||
} |
@@ -0,0 +1,72 @@ | |||
/* | |||
* 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 HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
export interface AlmDefinitionFormFieldProps<B extends T.AlmSettingsBinding> { | |||
autoFocus?: boolean; | |||
formData: B; | |||
help: boolean; | |||
id: string; | |||
isTextArea: boolean; | |||
maxLength: number; | |||
onFieldChange: (id: keyof B, value: string) => void; | |||
propKey: keyof B; | |||
} | |||
export function AlmDefinitionFormField<B extends T.AlmSettingsBinding>( | |||
props: AlmDefinitionFormFieldProps<B> | |||
) { | |||
const { autoFocus, formData, help, id, isTextArea, maxLength, onFieldChange, propKey } = props; | |||
return ( | |||
<div className="modal-field"> | |||
<label className="display-flex-center" htmlFor={id}> | |||
{translate('settings.pr_decoration.form', id)} | |||
<em className="mandatory spacer-right">*</em> | |||
{help && <HelpTooltip overlay={translate('settings.pr_decoration.form', id, 'help')} />} | |||
</label> | |||
{isTextArea ? ( | |||
<textarea | |||
className="settings-large-input" | |||
id="privateKey" | |||
maxLength={maxLength} | |||
onChange={e => onFieldChange(propKey, e.currentTarget.value)} | |||
required={true} | |||
rows={5} | |||
value={String(formData[propKey])} | |||
/> | |||
) : ( | |||
<input | |||
autoFocus={autoFocus} | |||
className="input-super-large" | |||
id={id} | |||
maxLength={maxLength} | |||
name={id} | |||
onChange={e => onFieldChange(propKey, e.currentTarget.value)} | |||
size={50} | |||
type="text" | |||
value={String(formData[propKey])} | |||
/> | |||
)} | |||
</div> | |||
); | |||
} |
@@ -20,25 +20,32 @@ | |||
import * as React from 'react'; | |||
import AlmPRDecorationFormModalRenderer from './AlmPRDecorationFormModalRenderer'; | |||
interface Props { | |||
alm: string; | |||
bindingDefinition: T.GithubBindingDefinition; | |||
interface ChildrenProps<AlmBindingDefinitionType> { | |||
formData: AlmBindingDefinitionType; | |||
onFieldChange: (fieldId: keyof AlmBindingDefinitionType, value: string) => void; | |||
} | |||
interface Props<B> { | |||
children: (props: ChildrenProps<B>) => React.ReactNode; | |||
bindingDefinition: B; | |||
onCancel: () => void; | |||
onSubmit: (bindingDefinition: T.GithubBindingDefinition, originalKey: string) => void; | |||
onSubmit: (data: B, originalKey: string) => void; | |||
} | |||
interface State { | |||
formData: T.GithubBindingDefinition; | |||
interface State<AlmBindingDefinitionType> { | |||
formData: AlmBindingDefinitionType; | |||
} | |||
export default class AlmPRDecorationFormModal extends React.PureComponent<Props, State> { | |||
constructor(props: Props) { | |||
export default class AlmPRDecorationFormModal< | |||
B extends T.AlmSettingsBinding | |||
> extends React.PureComponent<Props<B>, State<B>> { | |||
constructor(props: Props<B>) { | |||
super(props); | |||
this.state = { formData: props.bindingDefinition }; | |||
} | |||
handleFieldChange = (fieldId: keyof T.GithubBindingDefinition, value: string) => { | |||
handleFieldChange = (fieldId: keyof B, value: string) => { | |||
this.setState(({ formData }) => ({ | |||
formData: { | |||
...formData, | |||
@@ -59,19 +66,20 @@ export default class AlmPRDecorationFormModal extends React.PureComponent<Props, | |||
}; | |||
render() { | |||
const { alm, bindingDefinition } = this.props; | |||
const { children, bindingDefinition } = this.props; | |||
const { formData } = this.state; | |||
return ( | |||
<AlmPRDecorationFormModalRenderer | |||
alm={alm} | |||
canSubmit={this.canSubmit} | |||
formData={formData} | |||
onCancel={this.props.onCancel} | |||
onFieldChange={this.handleFieldChange} | |||
onSubmit={this.handleFormSubmit} | |||
originalKey={bindingDefinition.key} | |||
/> | |||
originalKey={bindingDefinition.key}> | |||
{children({ | |||
formData, | |||
onFieldChange: this.handleFieldChange | |||
})} | |||
</AlmPRDecorationFormModalRenderer> | |||
); | |||
} | |||
} |
@@ -19,69 +19,20 @@ | |||
*/ | |||
import * as React from 'react'; | |||
import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | |||
import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip'; | |||
import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { ALM_KEYS } from '../../utils'; | |||
export interface AlmPRDecorationFormModalProps { | |||
alm: string; | |||
canSubmit: () => boolean; | |||
formData: T.GithubBindingDefinition; | |||
children: React.ReactNode; | |||
onCancel: () => void; | |||
onSubmit: () => void; | |||
onFieldChange: (id: string, value: string) => void; | |||
originalKey: string; | |||
} | |||
function renderField(params: { | |||
autoFocus?: boolean; | |||
formData: T.GithubBindingDefinition; | |||
help: boolean; | |||
id: string; | |||
isTextArea: boolean; | |||
maxLength: number; | |||
onFieldChange: (id: string, value: string) => void; | |||
propKey: keyof T.GithubBindingDefinition; | |||
}) { | |||
const { autoFocus, formData, help, id, isTextArea, maxLength, onFieldChange, propKey } = params; | |||
return ( | |||
<div className="modal-field"> | |||
<label className="display-flex-center" htmlFor={id}> | |||
{translate('settings.pr_decoration.form', id)} | |||
<em className="mandatory spacer-right">*</em> | |||
{help && <HelpTooltip overlay={translate('settings.pr_decoration.form', id, 'help')} />} | |||
</label> | |||
{isTextArea ? ( | |||
<textarea | |||
className="settings-large-input" | |||
id="privateKey" | |||
maxLength={maxLength} | |||
onChange={e => onFieldChange(propKey, e.currentTarget.value)} | |||
required={true} | |||
rows={5} | |||
value={formData[propKey]} | |||
/> | |||
) : ( | |||
<input | |||
autoFocus={autoFocus} | |||
className="input-super-large" | |||
id={id} | |||
maxLength={maxLength} | |||
name={id} | |||
onChange={e => onFieldChange(propKey, e.currentTarget.value)} | |||
size={50} | |||
type="text" | |||
value={formData[propKey]} | |||
/> | |||
)} | |||
</div> | |||
); | |||
} | |||
export default function AlmPRDecorationFormModalRenderer(props: AlmPRDecorationFormModalProps) { | |||
const { alm, formData, onFieldChange, originalKey } = props; | |||
const { children, originalKey } = props; | |||
const header = translate('settings.pr_decoration.form.header', originalKey ? 'edit' : 'create'); | |||
return ( | |||
@@ -92,46 +43,7 @@ export default function AlmPRDecorationFormModalRenderer(props: AlmPRDecorationF | |||
<h2>{header}</h2> | |||
</div> | |||
<div className="modal-body modal-container"> | |||
{renderField({ | |||
autoFocus: true, | |||
id: 'name', | |||
formData, | |||
propKey: 'key', | |||
maxLength: 40, | |||
onFieldChange, | |||
help: true, | |||
isTextArea: false | |||
})} | |||
{renderField({ | |||
id: `url.${alm}`, | |||
formData, | |||
propKey: 'url', | |||
maxLength: 2000, | |||
onFieldChange, | |||
help: false, | |||
isTextArea: false | |||
})} | |||
{alm === ALM_KEYS.GITHUB && | |||
renderField({ | |||
id: 'app_id', | |||
formData, | |||
propKey: 'appId', | |||
maxLength: 80, | |||
onFieldChange, | |||
help: false, | |||
isTextArea: false | |||
})} | |||
{renderField({ | |||
id: 'private_key', | |||
formData, | |||
propKey: 'privateKey', | |||
maxLength: 2000, | |||
onFieldChange, | |||
help: false, | |||
isTextArea: true | |||
})} | |||
</div> | |||
<div className="modal-body modal-container">{children}</div> | |||
<div className="modal-foot"> | |||
<DeferredSpinner className="spacer-right" loading={submitting} /> |
@@ -0,0 +1,54 @@ | |||
/* | |||
* 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 { AlmDefinitionFormField } from './AlmDefinitionFormField'; | |||
export interface AzureFormModalProps { | |||
formData: T.AzureBindingDefinition; | |||
onFieldChange: (fieldId: keyof T.AzureBindingDefinition, value: string) => void; | |||
} | |||
export default function AzureFormModal(props: AzureFormModalProps) { | |||
const { formData, onFieldChange } = props; | |||
return ( | |||
<> | |||
<AlmDefinitionFormField | |||
autoFocus={true} | |||
formData={formData} | |||
help={true} | |||
id="name" | |||
isTextArea={false} | |||
maxLength={40} | |||
onFieldChange={onFieldChange} | |||
propKey="key" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={formData} | |||
help={true} | |||
id="personal_access_token" | |||
isTextArea={true} | |||
maxLength={2000} | |||
onFieldChange={onFieldChange} | |||
propKey="personalAccessToken" | |||
/> | |||
</> | |||
); | |||
} |
@@ -0,0 +1,89 @@ | |||
/* | |||
* 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 { createAzureConfiguration, updateAzureConfiguration } from '../../../../api/almSettings'; | |||
import AzureTabRenderer from './AzureTabRenderer'; | |||
interface Props { | |||
definitions: T.AzureBindingDefinition[]; | |||
loading: boolean; | |||
onDelete: (definitionKey: string) => void; | |||
onUpdateDefinitions: () => void; | |||
} | |||
interface State { | |||
editedDefinition?: T.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 = (config: T.AzureBindingDefinition) => { | |||
this.setState({ editedDefinition: config }); | |||
}; | |||
handleSubmit = (config: T.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} | |||
/> | |||
); | |||
} | |||
} |
@@ -0,0 +1,61 @@ | |||
/* | |||
* 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 { ALM_KEYS } from '../../utils'; | |||
import AlmPRDecorationFormModal from './AlmPRDecorationFormModal'; | |||
import AzureFormModal from './AzureFormModal'; | |||
import AzureTable from './AzureTable'; | |||
import TabHeader from './TabHeader'; | |||
export interface AzureTabRendererProps { | |||
editedDefinition?: T.AzureBindingDefinition; | |||
definitions: T.AzureBindingDefinition[]; | |||
loading: boolean; | |||
onCancel: () => void; | |||
onCreate: () => void; | |||
onDelete: (definitionKey: string) => void; | |||
onEdit: (config: T.AzureBindingDefinition) => void; | |||
onSubmit: (config: T.AzureBindingDefinition, originalKey: string) => void; | |||
} | |||
export default function AzureTabRenderer(props: AzureTabRendererProps) { | |||
const { definitions, editedDefinition, loading } = props; | |||
return ( | |||
<> | |||
<TabHeader alm={ALM_KEYS.AZURE} onCreate={props.onCreate} /> | |||
<AzureTable | |||
definitions={definitions} | |||
loading={loading} | |||
onDelete={props.onDelete} | |||
onEdit={props.onEdit} | |||
/> | |||
{editedDefinition && ( | |||
<AlmPRDecorationFormModal | |||
bindingDefinition={editedDefinition} | |||
onCancel={props.onCancel} | |||
onSubmit={props.onSubmit}> | |||
{childProps => <AzureFormModal {...childProps} />} | |||
</AlmPRDecorationFormModal> | |||
)} | |||
</> | |||
); | |||
} |
@@ -0,0 +1,72 @@ | |||
/* | |||
* 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 { ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons'; | |||
import EditIcon from 'sonar-ui-common/components/icons/EditIcon'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
export interface AzureTableProps { | |||
definitions: T.AzureBindingDefinition[]; | |||
loading: boolean; | |||
onDelete: (definitionKey: string) => void; | |||
onEdit: (config: T.AzureBindingDefinition) => void; | |||
} | |||
export default function AzureTable(props: AzureTableProps) { | |||
const { definitions, loading } = props; | |||
if (loading) { | |||
return <DeferredSpinner />; | |||
} | |||
return ( | |||
<table className="data zebra spacer-bottom"> | |||
<thead> | |||
<tr> | |||
<th>{translate('settings.pr_decoration.table.column.name')}</th> | |||
<th className="thin">{translate('settings.pr_decoration.table.column.edit')}</th> | |||
<th className="thin">{translate('settings.pr_decoration.table.column.delete')}</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{definitions.length < 1 ? ( | |||
<tr> | |||
<td colSpan={3}>{translate('settings.pr_decoration.table.empty.azure')}</td> | |||
</tr> | |||
) : ( | |||
definitions.map(definition => ( | |||
<tr key={definition.key}> | |||
<td>{definition.key}</td> | |||
<td> | |||
<ButtonIcon onClick={() => props.onEdit(definition)}> | |||
<EditIcon /> | |||
</ButtonIcon> | |||
</td> | |||
<td> | |||
<DeleteButton onClick={() => props.onDelete(definition.key)} /> | |||
</td> | |||
</tr> | |||
)) | |||
)} | |||
</tbody> | |||
</table> | |||
); | |||
} |
@@ -45,6 +45,7 @@ export default function DeleteModal({ id, onDelete, onCancel, projectCount }: De | |||
confirmButtonText={translate('delete')} | |||
confirmData={id} | |||
header={translate('settings.pr_decoration.delete.header')} | |||
isDestructive={true} | |||
onClose={onCancel} | |||
onConfirm={onDelete}> | |||
<> |
@@ -0,0 +1,72 @@ | |||
/* | |||
* 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 { AlmDefinitionFormField } from './AlmDefinitionFormField'; | |||
export interface GithubFormModalProps { | |||
formData: T.GithubBindingDefinition; | |||
onFieldChange: (fieldId: keyof T.GithubBindingDefinition, value: string) => void; | |||
} | |||
export default function GithubFormModal(props: GithubFormModalProps) { | |||
const { formData, onFieldChange } = props; | |||
return ( | |||
<> | |||
<AlmDefinitionFormField | |||
autoFocus={true} | |||
formData={formData} | |||
help={true} | |||
id="name" | |||
isTextArea={false} | |||
maxLength={40} | |||
onFieldChange={onFieldChange} | |||
propKey="key" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={formData} | |||
help={false} | |||
id="url.github" | |||
isTextArea={false} | |||
maxLength={2000} | |||
onFieldChange={onFieldChange} | |||
propKey="url" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={formData} | |||
help={false} | |||
id="app_id" | |||
isTextArea={false} | |||
maxLength={80} | |||
onFieldChange={onFieldChange} | |||
propKey="appId" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={formData} | |||
help={false} | |||
id="private_key" | |||
isTextArea={true} | |||
maxLength={2000} | |||
onFieldChange={onFieldChange} | |||
propKey="privateKey" | |||
/> | |||
</> | |||
); | |||
} |
@@ -18,23 +18,18 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { | |||
countBindedProjects, | |||
createGithubConfiguration, | |||
deleteConfiguration, | |||
updateGithubConfiguration | |||
} from '../../../../api/almSettings'; | |||
import { ALM_KEYS } from '../../utils'; | |||
import TabRenderer from './TabRenderer'; | |||
import { createGithubConfiguration, updateGithubConfiguration } from '../../../../api/almSettings'; | |||
import GithubTabRenderer from './GithubTabRenderer'; | |||
interface Props { | |||
definitions: T.GithubBindingDefinition[]; | |||
loading: boolean; | |||
onDelete: (definitionKey: string) => void; | |||
onUpdateDefinitions: () => void; | |||
} | |||
interface State { | |||
definitionInEdition?: T.GithubBindingDefinition; | |||
definitionKeyForDeletion?: string; | |||
editedDefinition?: T.GithubBindingDefinition; | |||
projectCount?: number; | |||
} | |||
@@ -52,67 +47,44 @@ export default class GithubTab extends React.PureComponent<Props, State> { | |||
handleCancel = () => { | |||
this.setState({ | |||
definitionKeyForDeletion: undefined, | |||
definitionInEdition: undefined, | |||
projectCount: undefined | |||
editedDefinition: undefined | |||
}); | |||
}; | |||
deleteConfiguration = (id: string) => { | |||
return deleteConfiguration(id) | |||
.then(this.props.onUpdateDefinitions) | |||
.then(() => { | |||
if (this.mounted) { | |||
this.setState({ definitionKeyForDeletion: undefined }); | |||
} | |||
}); | |||
}; | |||
handleCreate = () => { | |||
this.setState({ definitionInEdition: { key: '', appId: '', url: '', privateKey: '' } }); | |||
}; | |||
handleDelete = (config: T.GithubBindingDefinition) => { | |||
this.setState({ definitionKeyForDeletion: config.key }); | |||
return countBindedProjects(config.key).then(projectCount => { | |||
if (this.mounted) { | |||
this.setState({ projectCount }); | |||
} | |||
}); | |||
this.setState({ editedDefinition: { key: '', appId: '', url: '', privateKey: '' } }); | |||
}; | |||
handleEdit = (config: T.GithubBindingDefinition) => { | |||
this.setState({ definitionInEdition: config }); | |||
this.setState({ editedDefinition: config }); | |||
}; | |||
handleSubmit = (config: T.GithubBindingDefinition, originalKey: string) => { | |||
const call = originalKey | |||
? updateGithubConfiguration({ newKey: config.key, ...config, key: originalKey }) | |||
: createGithubConfiguration(config); | |||
return call.then(this.props.onUpdateDefinitions).then(() => { | |||
if (this.mounted) { | |||
this.setState({ definitionInEdition: undefined }); | |||
} | |||
}); | |||
return call | |||
.then(() => { | |||
if (this.mounted) { | |||
this.setState({ editedDefinition: undefined }); | |||
} | |||
}) | |||
.then(this.props.onUpdateDefinitions); | |||
}; | |||
render() { | |||
const { definitions } = this.props; | |||
const { definitionKeyForDeletion, definitionInEdition, projectCount } = this.state; | |||
const { definitions, loading } = this.props; | |||
const { editedDefinition } = this.state; | |||
return ( | |||
<TabRenderer | |||
alm={ALM_KEYS.GITHUB} | |||
definitionInEdition={definitionInEdition} | |||
definitionKeyForDeletion={definitionKeyForDeletion} | |||
<GithubTabRenderer | |||
definitions={definitions} | |||
editedDefinition={editedDefinition} | |||
loading={loading} | |||
onCancel={this.handleCancel} | |||
onConfirmDelete={this.deleteConfiguration} | |||
onCreate={this.handleCreate} | |||
onDelete={this.handleDelete} | |||
onDelete={this.props.onDelete} | |||
onEdit={this.handleEdit} | |||
onSubmit={this.handleSubmit} | |||
projectCount={projectCount} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,61 @@ | |||
/* | |||
* 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 { ALM_KEYS } from '../../utils'; | |||
import AlmPRDecorationFormModal from './AlmPRDecorationFormModal'; | |||
import GithubFormModal from './GithubFormModal'; | |||
import GithubTable from './GithubTable'; | |||
import TabHeader from './TabHeader'; | |||
export interface GithubTabRendererProps { | |||
editedDefinition?: T.GithubBindingDefinition; | |||
definitions: T.GithubBindingDefinition[]; | |||
loading: boolean; | |||
onCancel: () => void; | |||
onCreate: () => void; | |||
onDelete: (definitionKey: string) => void; | |||
onEdit: (config: T.GithubBindingDefinition) => void; | |||
onSubmit: (config: T.GithubBindingDefinition, originalKey: string) => void; | |||
} | |||
export default function GithubTabRenderer(props: GithubTabRendererProps) { | |||
const { definitions, editedDefinition, loading } = props; | |||
return ( | |||
<> | |||
<TabHeader alm={ALM_KEYS.GITHUB} onCreate={props.onCreate} /> | |||
<GithubTable | |||
definitions={definitions} | |||
loading={loading} | |||
onDelete={props.onDelete} | |||
onEdit={props.onEdit} | |||
/> | |||
{editedDefinition && ( | |||
<AlmPRDecorationFormModal | |||
bindingDefinition={editedDefinition} | |||
onCancel={props.onCancel} | |||
onSubmit={props.onSubmit}> | |||
{childProps => <GithubFormModal {...childProps} />} | |||
</AlmPRDecorationFormModal> | |||
)} | |||
</> | |||
); | |||
} |
@@ -0,0 +1,70 @@ | |||
/* | |||
* 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 { ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons'; | |||
import EditIcon from 'sonar-ui-common/components/icons/EditIcon'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
export interface GithubTableProps { | |||
definitions: T.GithubBindingDefinition[]; | |||
loading: boolean; | |||
onDelete: (definitionKey: string) => void; | |||
onEdit: (config: T.GithubBindingDefinition) => void; | |||
} | |||
export default function GithubTable(props: GithubTableProps) { | |||
const { definitions, loading } = props; | |||
if (loading) { | |||
return <DeferredSpinner />; | |||
} | |||
return ( | |||
<table className="data zebra spacer-bottom"> | |||
<thead> | |||
<tr> | |||
<th>{translate('settings.pr_decoration.table.column.name')}</th> | |||
<th>{translate(`settings.pr_decoration.table.column.github.url`)}</th> | |||
<th>{translate('settings.pr_decoration.table.column.app_id')}</th> | |||
<th className="thin">{translate('settings.pr_decoration.table.column.edit')}</th> | |||
<th className="thin">{translate('settings.pr_decoration.table.column.delete')}</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{definitions.map(definition => ( | |||
<tr key={definition.key}> | |||
<td>{definition.key}</td> | |||
<td>{definition.url}</td> | |||
<td>{definition.appId}</td> | |||
<td> | |||
<ButtonIcon onClick={() => props.onEdit(definition)}> | |||
<EditIcon /> | |||
</ButtonIcon> | |||
</td> | |||
<td> | |||
<DeleteButton onClick={() => props.onDelete(definition.key)} /> | |||
</td> | |||
</tr> | |||
))} | |||
</tbody> | |||
</table> | |||
); | |||
} |
@@ -1,71 +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 { ButtonIcon } from 'sonar-ui-common/components/controls/buttons'; | |||
import DeleteIcon from 'sonar-ui-common/components/icons/DeleteIcon'; | |||
import EditIcon from 'sonar-ui-common/components/icons/EditIcon'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { ALM_KEYS } from '../../utils'; | |||
export interface PRDecorationTableProps { | |||
alm: ALM_KEYS; | |||
definitions: T.GithubBindingDefinition[]; | |||
onDelete: (config: T.GithubBindingDefinition) => void; | |||
onEdit: (config: T.GithubBindingDefinition) => void; | |||
} | |||
export default function PRDecorationTable(props: PRDecorationTableProps) { | |||
const { alm, definitions } = props; | |||
return ( | |||
<> | |||
<table className="data zebra spacer-bottom"> | |||
<thead> | |||
<tr> | |||
<th>{translate('settings.pr_decoration.table.column.name')}</th> | |||
<th>{translate(`settings.pr_decoration.table.column.${alm}.url`)}</th> | |||
<th>{translate('settings.pr_decoration.table.column.app_id')}</th> | |||
<th className="thin">{translate('settings.pr_decoration.table.column.edit')}</th> | |||
<th className="thin">{translate('settings.pr_decoration.table.column.delete')}</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{definitions.map(definition => ( | |||
<tr key={definition.key}> | |||
<td>{definition.key}</td> | |||
<td>{definition.url}</td> | |||
<td>{definition.appId}</td> | |||
<td> | |||
<ButtonIcon onClick={() => props.onEdit(definition)}> | |||
<EditIcon /> | |||
</ButtonIcon> | |||
</td> | |||
<td> | |||
<ButtonIcon onClick={() => props.onDelete(definition)}> | |||
<DeleteIcon /> | |||
</ButtonIcon> | |||
</td> | |||
</tr> | |||
))} | |||
</tbody> | |||
</table> | |||
</> | |||
); | |||
} |
@@ -19,25 +19,27 @@ | |||
*/ | |||
import * as React from 'react'; | |||
import BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { almName, ALM_KEYS } from '../../utils'; | |||
import AzureTab from './AzureTab'; | |||
import DeleteModal from './DeleteModal'; | |||
import GithubTab from './GithubTab'; | |||
export interface PRDecorationTabsProps { | |||
currentAlm: ALM_KEYS; | |||
definitionKeyForDeletion?: string; | |||
definitions: T.AlmSettingsBindingDefinitions; | |||
loading: boolean; | |||
onCancel: () => void; | |||
onConfirmDelete: (definitionKey: string) => void; | |||
onDelete: (definitionKey: string) => void; | |||
onSelectAlm: (alm: ALM_KEYS) => void; | |||
onUpdateDefinitions: () => void; | |||
projectCount?: number; | |||
} | |||
export default function PRDecorationTabs(props: PRDecorationTabsProps) { | |||
const { definitions, currentAlm, loading } = props; | |||
if (loading) { | |||
return <DeferredSpinner />; | |||
} | |||
const { definitionKeyForDeletion, definitions, currentAlm, loading, projectCount } = props; | |||
return ( | |||
<> | |||
@@ -55,16 +57,41 @@ export default function PRDecorationTabs(props: PRDecorationTabsProps) { | |||
{ | |||
key: ALM_KEYS.GITHUB, | |||
label: almName[ALM_KEYS.GITHUB] | |||
}, | |||
{ | |||
key: ALM_KEYS.AZURE, | |||
label: almName[ALM_KEYS.AZURE] | |||
} | |||
]} | |||
/> | |||
<div className="boxed-group boxed-group-inner"> | |||
<GithubTab | |||
definitions={definitions.github} | |||
onUpdateDefinitions={props.onUpdateDefinitions} | |||
/> | |||
{currentAlm === ALM_KEYS.AZURE && ( | |||
<AzureTab | |||
definitions={definitions.azure} | |||
loading={loading} | |||
onDelete={props.onDelete} | |||
onUpdateDefinitions={props.onUpdateDefinitions} | |||
/> | |||
)} | |||
{currentAlm === ALM_KEYS.GITHUB && ( | |||
<GithubTab | |||
definitions={definitions.github} | |||
loading={loading} | |||
onDelete={props.onDelete} | |||
onUpdateDefinitions={props.onUpdateDefinitions} | |||
/> | |||
)} | |||
</div> | |||
{definitionKeyForDeletion && ( | |||
<DeleteModal | |||
id={definitionKeyForDeletion} | |||
onCancel={props.onCancel} | |||
onDelete={props.onConfirmDelete} | |||
projectCount={projectCount} | |||
/> | |||
)} | |||
</> | |||
); | |||
} |
@@ -18,14 +18,20 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { getAlmDefinitions } from '../../../../api/almSettings'; | |||
import { | |||
countBindedProjects, | |||
deleteConfiguration, | |||
getAlmDefinitions | |||
} from '../../../../api/almSettings'; | |||
import { ALM_KEYS } from '../../utils'; | |||
import PRDecorationTabs from './PRDecorationTabs'; | |||
interface State { | |||
currentAlm: ALM_KEYS; | |||
definitionKeyForDeletion?: string; | |||
definitions: T.AlmSettingsBindingDefinitions; | |||
loading: boolean; | |||
projectCount?: number; | |||
} | |||
export default class PullRequestDecoration extends React.PureComponent<{}, State> { | |||
@@ -33,6 +39,7 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State | |||
state: State = { | |||
currentAlm: ALM_KEYS.GITHUB, | |||
definitions: { | |||
[ALM_KEYS.AZURE]: [], | |||
[ALM_KEYS.GITHUB]: [] | |||
}, | |||
loading: true | |||
@@ -47,7 +54,18 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State | |||
this.mounted = false; | |||
} | |||
deleteConfiguration = (definitionKey: string) => { | |||
return deleteConfiguration(definitionKey) | |||
.then(() => { | |||
if (this.mounted) { | |||
this.setState({ definitionKeyForDeletion: undefined, projectCount: undefined }); | |||
} | |||
}) | |||
.then(this.fetchPullRequestDecorationSetting); | |||
}; | |||
fetchPullRequestDecorationSetting = () => { | |||
this.setState({ loading: true }); | |||
return getAlmDefinitions() | |||
.then(definitions => { | |||
if (this.mounted) { | |||
@@ -68,9 +86,27 @@ export default class PullRequestDecoration extends React.PureComponent<{}, State | |||
this.setState({ currentAlm }); | |||
}; | |||
handleCancel = () => { | |||
this.setState({ definitionKeyForDeletion: undefined, projectCount: undefined }); | |||
}; | |||
handleDelete = (definitionKey: string) => { | |||
return countBindedProjects(definitionKey).then(projectCount => { | |||
if (this.mounted) { | |||
this.setState({ | |||
definitionKeyForDeletion: definitionKey, | |||
projectCount | |||
}); | |||
} | |||
}); | |||
}; | |||
render() { | |||
return ( | |||
<PRDecorationTabs | |||
onCancel={this.handleCancel} | |||
onConfirmDelete={this.deleteConfiguration} | |||
onDelete={this.handleDelete} | |||
onSelectAlm={this.handleSelectAlm} | |||
onUpdateDefinitions={this.fetchPullRequestDecorationSetting} | |||
{...this.state} |
@@ -24,26 +24,14 @@ 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 { ALM_KEYS } from '../../utils'; | |||
import AlmPRDecorationFormModal from './AlmPRDecorationFormModal'; | |||
import DeleteModal from './DeleteModal'; | |||
import PRDecorationTable from './PRDecorationTable'; | |||
export interface TabRendererProps { | |||
export interface TabHeaderProps { | |||
alm: ALM_KEYS; | |||
definitionInEdition?: T.GithubBindingDefinition; | |||
definitionKeyForDeletion?: string; | |||
definitions: T.GithubBindingDefinition[]; | |||
onCancel: () => void; | |||
onConfirmDelete: (id: string) => void; | |||
onCreate: () => void; | |||
onDelete: (config: T.GithubBindingDefinition) => void; | |||
onEdit: (config: T.GithubBindingDefinition) => void; | |||
onSubmit: (config: T.GithubBindingDefinition, originalKey: string) => void; | |||
projectCount?: number; | |||
} | |||
export default function TabRenderer(props: TabRendererProps) { | |||
const { alm, definitions, definitionKeyForDeletion, definitionInEdition, projectCount } = props; | |||
export default function TabHeader(props: TabHeaderProps) { | |||
const { alm } = props; | |||
return ( | |||
<> | |||
<Alert className="spacer-top huge-spacer-bottom" variant="info"> | |||
@@ -64,30 +52,6 @@ export default function TabRenderer(props: TabRendererProps) { | |||
<h4 className="display-inline">{translate('settings.pr_decoration.table.title')}</h4> | |||
<Button onClick={props.onCreate}>{translate('settings.pr_decoration.table.create')}</Button> | |||
</div> | |||
<PRDecorationTable | |||
alm={alm} | |||
definitions={definitions} | |||
onDelete={props.onDelete} | |||
onEdit={props.onEdit} | |||
/> | |||
{definitionKeyForDeletion && ( | |||
<DeleteModal | |||
id={definitionKeyForDeletion} | |||
onCancel={props.onCancel} | |||
onDelete={props.onConfirmDelete} | |||
projectCount={projectCount} | |||
/> | |||
)} | |||
{definitionInEdition && ( | |||
<AlmPRDecorationFormModal | |||
alm={ALM_KEYS.GITHUB} | |||
bindingDefinition={definitionInEdition} | |||
onCancel={props.onCancel} | |||
onSubmit={props.onSubmit} | |||
/> | |||
)} | |||
</> | |||
); | |||
} |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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 { AlmDefinitionFormField, AlmDefinitionFormFieldProps } from '../AlmDefinitionFormField'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ help: true })).toMatchSnapshot(); | |||
expect(shallowRender({ isTextArea: true })).toMatchSnapshot(); | |||
}); | |||
it('should call onFieldChange', () => { | |||
const onInputChange = jest.fn(); | |||
shallowRender({ onFieldChange: onInputChange }) | |||
.find('input') | |||
.simulate('change', { currentTarget: { value: '' } }); | |||
expect(onInputChange).toBeCalled(); | |||
const onTextAreaChange = jest.fn(); | |||
shallowRender({ isTextArea: true, onFieldChange: onTextAreaChange }) | |||
.find('textarea') | |||
.simulate('change', { currentTarget: { value: '' } }); | |||
expect(onTextAreaChange).toBeCalled(); | |||
}); | |||
function shallowRender(props: Partial<AlmDefinitionFormFieldProps<T.AlmSettingsBinding>> = {}) { | |||
return shallow( | |||
<AlmDefinitionFormField | |||
formData={{ key: 'key' }} | |||
help={false} | |||
id="key" | |||
isTextArea={false} | |||
maxLength={40} | |||
onFieldChange={jest.fn()} | |||
propKey="key" | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -21,7 +21,6 @@ import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import { mockGithubDefinition } from '../../../../../helpers/testMocks'; | |||
import { ALM_KEYS } from '../../../utils'; | |||
import AlmPRDecorationFormModal from '../AlmPRDecorationFormModal'; | |||
it('should render correctly', () => { | |||
@@ -75,14 +74,16 @@ it('should (dis)allow submit by validating its state', async () => { | |||
expect(wrapper.instance().canSubmit()).toBe(true); | |||
}); | |||
function shallowRender(props: Partial<AlmPRDecorationFormModal['props']> = {}) { | |||
return shallow<AlmPRDecorationFormModal>( | |||
function shallowRender( | |||
props: Partial<AlmPRDecorationFormModal<T.GithubBindingDefinition>['props']> = {} | |||
) { | |||
return shallow<AlmPRDecorationFormModal<T.GithubBindingDefinition>>( | |||
<AlmPRDecorationFormModal | |||
alm={ALM_KEYS.GITHUB} | |||
bindingDefinition={{ appId: '', key: '', privateKey: '', url: '' }} | |||
onCancel={jest.fn()} | |||
onSubmit={jest.fn()} | |||
{...props} | |||
/> | |||
{...props}> | |||
{() => null} | |||
</AlmPRDecorationFormModal> | |||
); | |||
} |
@@ -19,8 +19,6 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGithubDefinition } from '../../../../../helpers/testMocks'; | |||
import { ALM_KEYS } from '../../../utils'; | |||
import AlmPRDecorationFormModalRenderer, { | |||
AlmPRDecorationFormModalProps | |||
} from '../AlmPRDecorationFormModalRenderer'; | |||
@@ -32,14 +30,12 @@ it('should render correctly', () => { | |||
function shallowRender(props: Partial<AlmPRDecorationFormModalProps> = {}) { | |||
return shallow( | |||
<AlmPRDecorationFormModalRenderer | |||
alm={ALM_KEYS.GITHUB} | |||
canSubmit={jest.fn()} | |||
formData={mockGithubDefinition()} | |||
onCancel={jest.fn()} | |||
onFieldChange={jest.fn()} | |||
onSubmit={jest.fn()} | |||
originalKey="" | |||
{...props} | |||
/> | |||
{...props}> | |||
{() => null} | |||
</AlmPRDecorationFormModalRenderer> | |||
); | |||
} |
@@ -0,0 +1,38 @@ | |||
/* | |||
* 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/testMocks'; | |||
import AzureFormModal, { AzureFormModalProps } from '../AzureFormModal'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockAzureDefinition() })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<AzureFormModalProps> = {}) { | |||
return shallow( | |||
<AzureFormModal | |||
formData={{ key: '', personalAccessToken: '' }} | |||
onFieldChange={jest.fn()} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,96 @@ | |||
/* | |||
* 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 { createAzureConfiguration, updateAzureConfiguration } from '../../../../../api/almSettings'; | |||
import { mockAzureDefinition } from '../../../../../helpers/testMocks'; | |||
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(); | |||
}); | |||
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 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>( | |||
<AzureTab | |||
definitions={[]} | |||
loading={false} | |||
onDelete={jest.fn()} | |||
onUpdateDefinitions={jest.fn()} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,44 @@ | |||
/* | |||
* 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/testMocks'; | |||
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} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,40 @@ | |||
/* | |||
* 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/testMocks'; | |||
import AzureTable, { AzureTableProps } from '../AzureTable'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ definitions: [mockAzureDefinition()] })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<AzureTableProps> = {}) { | |||
return shallow( | |||
<AzureTable | |||
definitions={[]} | |||
loading={false} | |||
onDelete={jest.fn()} | |||
onEdit={jest.fn()} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,38 @@ | |||
/* | |||
* 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 { mockGithubDefinition } from '../../../../../helpers/testMocks'; | |||
import GithubFormModal, { GithubFormModalProps } from '../GithubFormModal'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockGithubDefinition() })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<GithubFormModalProps> = {}) { | |||
return shallow( | |||
<GithubFormModal | |||
formData={{ key: '', appId: '', privateKey: '', url: '' }} | |||
onFieldChange={jest.fn()} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -22,7 +22,6 @@ import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import { | |||
createGithubConfiguration, | |||
deleteConfiguration, | |||
updateGithubConfiguration | |||
} from '../../../../../api/almSettings'; | |||
import { mockGithubDefinition } from '../../../../../helpers/testMocks'; | |||
@@ -47,81 +46,54 @@ it('should handle cancel', async () => { | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ | |||
definitionKeyForDeletion: '12321', | |||
definitionInEdition: mockGithubDefinition() | |||
editedDefinition: mockGithubDefinition() | |||
}); | |||
wrapper.instance().handleCancel(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().definitionKeyForDeletion).toBeUndefined(); | |||
expect(wrapper.state().definitionInEdition).toBeUndefined(); | |||
}); | |||
it('should delete config', async () => { | |||
const onUpdateDefinitions = jest.fn(); | |||
const wrapper = shallowRender({ onUpdateDefinitions }); | |||
wrapper.setState({ definitionKeyForDeletion: '123' }); | |||
await wrapper | |||
.instance() | |||
.deleteConfiguration('123') | |||
.then(() => { | |||
expect(deleteConfiguration).toBeCalledWith('123'); | |||
expect(onUpdateDefinitions).toBeCalled(); | |||
expect(wrapper.state().definitionKeyForDeletion).toBeUndefined(); | |||
}); | |||
expect(wrapper.state().editedDefinition).toBeUndefined(); | |||
}); | |||
it('should create config', async () => { | |||
const onUpdateDefinitions = jest.fn(); | |||
const config = { | |||
key: 'new conf', | |||
url: 'ewrqewr', | |||
appId: '3742985', | |||
privateKey: 'rt7r78ew6t87ret' | |||
}; | |||
const config = mockGithubDefinition(); | |||
const wrapper = shallowRender({ onUpdateDefinitions }); | |||
wrapper.setState({ definitionInEdition: config }); | |||
wrapper.setState({ editedDefinition: config }); | |||
await wrapper.instance().handleSubmit(config, ''); | |||
await wrapper | |||
.instance() | |||
.handleSubmit(config, '') | |||
.then(() => { | |||
expect(createGithubConfiguration).toBeCalledWith(config); | |||
expect(onUpdateDefinitions).toBeCalled(); | |||
expect(wrapper.state().definitionInEdition).toBeUndefined(); | |||
}); | |||
expect(createGithubConfiguration).toBeCalledWith(config); | |||
expect(onUpdateDefinitions).toBeCalled(); | |||
expect(wrapper.state().editedDefinition).toBeUndefined(); | |||
}); | |||
it('should update config', async () => { | |||
const onUpdateDefinitions = jest.fn(); | |||
const config = { | |||
key: 'new conf', | |||
url: 'ewrqewr', | |||
appId: '3742985', | |||
privateKey: 'rt7r78ew6t87ret' | |||
}; | |||
const config = mockGithubDefinition(); | |||
const wrapper = shallowRender({ onUpdateDefinitions }); | |||
wrapper.setState({ definitionInEdition: config }); | |||
wrapper.setState({ editedDefinition: config }); | |||
await wrapper | |||
.instance() | |||
.handleSubmit(config, 'originalKey') | |||
.then(() => { | |||
expect(updateGithubConfiguration).toBeCalledWith({ | |||
newKey: 'new conf', | |||
...config, | |||
key: 'originalKey' | |||
}); | |||
expect(onUpdateDefinitions).toBeCalled(); | |||
expect(wrapper.state().definitionInEdition).toBeUndefined(); | |||
}); | |||
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>( | |||
<GithubTab definitions={[]} onUpdateDefinitions={jest.fn()} {...props} /> | |||
<GithubTab | |||
definitions={[]} | |||
loading={false} | |||
onDelete={jest.fn()} | |||
onUpdateDefinitions={jest.fn()} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -20,22 +20,20 @@ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGithubDefinition } from '../../../../../helpers/testMocks'; | |||
import { ALM_KEYS } from '../../../utils'; | |||
import TabRenderer, { TabRendererProps } from '../TabRenderer'; | |||
import GithubTabRenderer, { GithubTabRendererProps } from '../GithubTabRenderer'; | |||
it('should render correctly', () => { | |||
expect(shallowRender({ loading: true })).toMatchSnapshot(); | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ definitionKeyForDeletion: '123' })).toMatchSnapshot(); | |||
expect(shallowRender({ definitionInEdition: mockGithubDefinition() })).toMatchSnapshot(); | |||
expect(shallowRender({ editedDefinition: mockGithubDefinition() })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<TabRendererProps> = {}) { | |||
function shallowRender(props: Partial<GithubTabRendererProps> = {}) { | |||
return shallow( | |||
<TabRenderer | |||
alm={ALM_KEYS.GITHUB} | |||
<GithubTabRenderer | |||
definitions={[]} | |||
loading={false} | |||
onCancel={jest.fn()} | |||
onConfirmDelete={jest.fn()} | |||
onCreate={jest.fn()} | |||
onDelete={jest.fn()} | |||
onEdit={jest.fn()} |
@@ -20,19 +20,18 @@ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGithubDefinition } from '../../../../../helpers/testMocks'; | |||
import { ALM_KEYS } from '../../../utils'; | |||
import PRDecorationTable, { PRDecorationTableProps } from '../PRDecorationTable'; | |||
import GithubTable, { GithubTableProps } from '../GithubTable'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ definitions: [mockGithubDefinition()] })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<PRDecorationTableProps> = {}) { | |||
function shallowRender(props: Partial<GithubTableProps> = {}) { | |||
return shallow( | |||
<PRDecorationTable | |||
alm={ALM_KEYS.GITHUB} | |||
<GithubTable | |||
definitions={[]} | |||
loading={false} | |||
onDelete={jest.fn()} | |||
onEdit={jest.fn()} | |||
{...props} |
@@ -23,16 +23,21 @@ import { ALM_KEYS } from '../../../utils'; | |||
import PRDecorationTabs, { PRDecorationTabsProps } from '../PRDecorationTabs'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ loading: false })).toMatchSnapshot(); | |||
expect(shallowRender({ loading: true })).toMatchSnapshot(); | |||
expect(shallowRender({ definitionKeyForDeletion: 'keyToDelete' })).toMatchSnapshot(); | |||
expect(shallowRender({ currentAlm: ALM_KEYS.AZURE })).toMatchSnapshot(); | |||
expect(shallowRender({ currentAlm: ALM_KEYS.GITHUB })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<PRDecorationTabsProps> = {}) { | |||
return shallow( | |||
<PRDecorationTabs | |||
currentAlm={ALM_KEYS.GITHUB} | |||
definitions={{ github: [] }} | |||
loading={true} | |||
definitions={{ azure: [], github: [] }} | |||
loading={false} | |||
onCancel={jest.fn()} | |||
onConfirmDelete={jest.fn()} | |||
onDelete={jest.fn()} | |||
onSelectAlm={jest.fn()} | |||
onUpdateDefinitions={jest.fn()} | |||
{...props} |
@@ -20,11 +20,17 @@ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import { getAlmDefinitions } from '../../../../../api/almSettings'; | |||
import { | |||
countBindedProjects, | |||
deleteConfiguration, | |||
getAlmDefinitions | |||
} from '../../../../../api/almSettings'; | |||
import { ALM_KEYS } from '../../../utils'; | |||
import PullRequestDecoration from '../PullRequestDecoration'; | |||
jest.mock('../../../../../api/almSettings', () => ({ | |||
countBindedProjects: jest.fn().mockResolvedValue(0), | |||
deleteConfiguration: jest.fn().mockResolvedValue(undefined), | |||
getAlmDefinitions: jest.fn().mockResolvedValue({ github: [] }) | |||
})); | |||
@@ -39,7 +45,7 @@ it('should render correctly', () => { | |||
it('should handle alm selection', async () => { | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ currentAlm: ALM_KEYS.BITBUCKET }); | |||
wrapper.setState({ currentAlm: ALM_KEYS.AZURE }); | |||
wrapper.instance().handleSelectAlm(ALM_KEYS.GITHUB); | |||
@@ -48,6 +54,28 @@ it('should handle alm selection', async () => { | |||
expect(wrapper.state().currentAlm).toBe(ALM_KEYS.GITHUB); | |||
}); | |||
it('should handle delete', async () => { | |||
const toBeDeleted = '45672'; | |||
(countBindedProjects as jest.Mock).mockResolvedValueOnce(7); | |||
const wrapper = shallowRender(); | |||
wrapper.instance().handleDelete(toBeDeleted); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().projectCount).toBe(7); | |||
expect(wrapper.state().definitionKeyForDeletion).toBe(toBeDeleted); | |||
}); | |||
it('should delete configuration', async () => { | |||
(deleteConfiguration as jest.Mock).mockResolvedValueOnce(undefined); | |||
const wrapper = shallowRender(); | |||
wrapper.instance().deleteConfiguration('8345678'); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().projectCount).toBeUndefined(); | |||
expect(wrapper.state().definitionKeyForDeletion).toBeUndefined(); | |||
}); | |||
it('should fetch settings', async () => { | |||
const wrapper = shallowRender(); | |||
@@ -0,0 +1,32 @@ | |||
/* | |||
* 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 { ALM_KEYS } from '../../../utils'; | |||
import TabHeader, { TabHeaderProps } from '../TabHeader'; | |||
it('should render correctly', () => { | |||
expect(shallowRender(ALM_KEYS.AZURE)).toMatchSnapshot(); | |||
expect(shallowRender(ALM_KEYS.GITHUB)).toMatchSnapshot(); | |||
}); | |||
function shallowRender(alm: ALM_KEYS, props: Partial<TabHeaderProps> = {}) { | |||
return shallow(<TabHeader alm={alm} onCreate={jest.fn()} {...props} />); | |||
} |
@@ -0,0 +1,87 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="key" | |||
> | |||
settings.pr_decoration.form.key | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
</label> | |||
<input | |||
className="input-super-large" | |||
id="key" | |||
maxLength={40} | |||
name="key" | |||
onChange={[Function]} | |||
size={50} | |||
type="text" | |||
value="key" | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="key" | |||
> | |||
settings.pr_decoration.form.key | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
<HelpTooltip | |||
overlay="settings.pr_decoration.form.key.help" | |||
/> | |||
</label> | |||
<input | |||
className="input-super-large" | |||
id="key" | |||
maxLength={40} | |||
name="key" | |||
onChange={[Function]} | |||
size={50} | |||
type="text" | |||
value="key" | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly 3`] = ` | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="key" | |||
> | |||
settings.pr_decoration.form.key | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
</label> | |||
<textarea | |||
className="settings-large-input" | |||
id="privateKey" | |||
maxLength={40} | |||
onChange={[Function]} | |||
required={true} | |||
rows={5} | |||
value="key" | |||
/> | |||
</div> | |||
`; |
@@ -2,18 +2,8 @@ | |||
exports[`should render correctly 1`] = ` | |||
<AlmPRDecorationFormModalRenderer | |||
alm="github" | |||
canSubmit={[Function]} | |||
formData={ | |||
Object { | |||
"appId": "", | |||
"key": "", | |||
"privateKey": "", | |||
"url": "", | |||
} | |||
} | |||
onCancel={[MockFunction]} | |||
onFieldChange={[Function]} | |||
onSubmit={[Function]} | |||
originalKey="" | |||
/> |
@@ -20,109 +20,7 @@ exports[`should render correctly 1`] = ` | |||
<div | |||
className="modal-body modal-container" | |||
> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="name" | |||
> | |||
settings.pr_decoration.form.name | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
<HelpTooltip | |||
overlay="settings.pr_decoration.form.name.help" | |||
/> | |||
</label> | |||
<input | |||
autoFocus={true} | |||
className="input-super-large" | |||
id="name" | |||
maxLength={40} | |||
name="name" | |||
onChange={[Function]} | |||
size={50} | |||
type="text" | |||
value="key" | |||
/> | |||
</div> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="url.github" | |||
> | |||
settings.pr_decoration.form.url.github | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
</label> | |||
<input | |||
className="input-super-large" | |||
id="url.github" | |||
maxLength={2000} | |||
name="url.github" | |||
onChange={[Function]} | |||
size={50} | |||
type="text" | |||
value="http:alm.enterprise.com" | |||
/> | |||
</div> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="app_id" | |||
> | |||
settings.pr_decoration.form.app_id | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
</label> | |||
<input | |||
className="input-super-large" | |||
id="app_id" | |||
maxLength={80} | |||
name="app_id" | |||
onChange={[Function]} | |||
size={50} | |||
type="text" | |||
value="123456" | |||
/> | |||
</div> | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="private_key" | |||
> | |||
settings.pr_decoration.form.private_key | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
</label> | |||
<textarea | |||
className="settings-large-input" | |||
id="privateKey" | |||
maxLength={2000} | |||
onChange={[Function]} | |||
required={true} | |||
rows={5} | |||
value="asdf1234" | |||
/> | |||
</div> | |||
<Component /> | |||
</div> | |||
<div | |||
className="modal-foot" |
@@ -0,0 +1,69 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<AlmDefinitionFormField | |||
autoFocus={true} | |||
formData={ | |||
Object { | |||
"key": "", | |||
"personalAccessToken": "", | |||
} | |||
} | |||
help={true} | |||
id="name" | |||
isTextArea={false} | |||
maxLength={40} | |||
onFieldChange={[MockFunction]} | |||
propKey="key" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"key": "", | |||
"personalAccessToken": "", | |||
} | |||
} | |||
help={true} | |||
id="personal_access_token" | |||
isTextArea={true} | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
propKey="personalAccessToken" | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<Fragment> | |||
<AlmDefinitionFormField | |||
autoFocus={true} | |||
formData={ | |||
Object { | |||
"key": "key", | |||
"personalAccessToken": "asdf1234", | |||
} | |||
} | |||
help={true} | |||
id="name" | |||
isTextArea={false} | |||
maxLength={40} | |||
onFieldChange={[MockFunction]} | |||
propKey="key" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"key": "key", | |||
"personalAccessToken": "asdf1234", | |||
} | |||
} | |||
help={true} | |||
id="personal_access_token" | |||
isTextArea={true} | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
propKey="personalAccessToken" | |||
/> | |||
</Fragment> | |||
`; |
@@ -0,0 +1,13 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<AzureTabRenderer | |||
definitions={Array []} | |||
loading={false} | |||
onCancel={[Function]} | |||
onCreate={[Function]} | |||
onDelete={[MockFunction]} | |||
onEdit={[Function]} | |||
onSubmit={[Function]} | |||
/> | |||
`; |
@@ -0,0 +1,58 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<TabHeader | |||
alm="azure" | |||
onCreate={[MockFunction]} | |||
/> | |||
<AzureTable | |||
definitions={Array []} | |||
loading={true} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<Fragment> | |||
<TabHeader | |||
alm="azure" | |||
onCreate={[MockFunction]} | |||
/> | |||
<AzureTable | |||
definitions={Array []} | |||
loading={false} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 3`] = ` | |||
<Fragment> | |||
<TabHeader | |||
alm="azure" | |||
onCreate={[MockFunction]} | |||
/> | |||
<AzureTable | |||
definitions={Array []} | |||
loading={false} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
<AlmPRDecorationFormModal | |||
bindingDefinition={ | |||
Object { | |||
"key": "key", | |||
"personalAccessToken": "asdf1234", | |||
} | |||
} | |||
onCancel={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
> | |||
<Component /> | |||
</AlmPRDecorationFormModal> | |||
</Fragment> | |||
`; |
@@ -0,0 +1,79 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<table | |||
className="data zebra spacer-bottom" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
settings.pr_decoration.table.column.name | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.edit | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.delete | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td | |||
colSpan={3} | |||
> | |||
settings.pr_decoration.table.empty.azure | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<table | |||
className="data zebra spacer-bottom" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
settings.pr_decoration.table.column.name | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.edit | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.delete | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr | |||
key="key" | |||
> | |||
<td> | |||
key | |||
</td> | |||
<td> | |||
<ButtonIcon | |||
onClick={[Function]} | |||
> | |||
<EditIcon /> | |||
</ButtonIcon> | |||
</td> | |||
<td> | |||
<DeleteButton | |||
onClick={[Function]} | |||
/> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
`; |
@@ -5,6 +5,7 @@ exports[`should render correctly 1`] = ` | |||
confirmButtonText="delete" | |||
confirmData="1" | |||
header="settings.pr_decoration.delete.header" | |||
isDestructive={true} | |||
onClose={[MockFunction]} | |||
onConfirm={[MockFunction]} | |||
> | |||
@@ -35,6 +36,7 @@ exports[`should render correctly 2`] = ` | |||
confirmButtonText="delete" | |||
confirmData="1" | |||
header="settings.pr_decoration.delete.header" | |||
isDestructive={true} | |||
onClose={[MockFunction]} | |||
onConfirm={[MockFunction]} | |||
> |
@@ -0,0 +1,141 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<AlmDefinitionFormField | |||
autoFocus={true} | |||
formData={ | |||
Object { | |||
"appId": "", | |||
"key": "", | |||
"privateKey": "", | |||
"url": "", | |||
} | |||
} | |||
help={true} | |||
id="name" | |||
isTextArea={false} | |||
maxLength={40} | |||
onFieldChange={[MockFunction]} | |||
propKey="key" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"appId": "", | |||
"key": "", | |||
"privateKey": "", | |||
"url": "", | |||
} | |||
} | |||
help={false} | |||
id="url.github" | |||
isTextArea={false} | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
propKey="url" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"appId": "", | |||
"key": "", | |||
"privateKey": "", | |||
"url": "", | |||
} | |||
} | |||
help={false} | |||
id="app_id" | |||
isTextArea={false} | |||
maxLength={80} | |||
onFieldChange={[MockFunction]} | |||
propKey="appId" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"appId": "", | |||
"key": "", | |||
"privateKey": "", | |||
"url": "", | |||
} | |||
} | |||
help={false} | |||
id="private_key" | |||
isTextArea={true} | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
propKey="privateKey" | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<Fragment> | |||
<AlmDefinitionFormField | |||
autoFocus={true} | |||
formData={ | |||
Object { | |||
"appId": "123456", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http:alm.enterprise.com", | |||
} | |||
} | |||
help={true} | |||
id="name" | |||
isTextArea={false} | |||
maxLength={40} | |||
onFieldChange={[MockFunction]} | |||
propKey="key" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"appId": "123456", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http:alm.enterprise.com", | |||
} | |||
} | |||
help={false} | |||
id="url.github" | |||
isTextArea={false} | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
propKey="url" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"appId": "123456", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http:alm.enterprise.com", | |||
} | |||
} | |||
help={false} | |||
id="app_id" | |||
isTextArea={false} | |||
maxLength={80} | |||
onFieldChange={[MockFunction]} | |||
propKey="appId" | |||
/> | |||
<AlmDefinitionFormField | |||
formData={ | |||
Object { | |||
"appId": "123456", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http:alm.enterprise.com", | |||
} | |||
} | |||
help={false} | |||
id="private_key" | |||
isTextArea={true} | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
propKey="privateKey" | |||
/> | |||
</Fragment> | |||
`; |
@@ -1,13 +1,12 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<TabRenderer | |||
alm="github" | |||
<GithubTabRenderer | |||
definitions={Array []} | |||
loading={false} | |||
onCancel={[Function]} | |||
onConfirmDelete={[Function]} | |||
onCreate={[Function]} | |||
onDelete={[Function]} | |||
onDelete={[MockFunction]} | |||
onEdit={[Function]} | |||
onSubmit={[Function]} | |||
/> |
@@ -0,0 +1,60 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<TabHeader | |||
alm="github" | |||
onCreate={[MockFunction]} | |||
/> | |||
<GithubTable | |||
definitions={Array []} | |||
loading={true} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<Fragment> | |||
<TabHeader | |||
alm="github" | |||
onCreate={[MockFunction]} | |||
/> | |||
<GithubTable | |||
definitions={Array []} | |||
loading={false} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 3`] = ` | |||
<Fragment> | |||
<TabHeader | |||
alm="github" | |||
onCreate={[MockFunction]} | |||
/> | |||
<GithubTable | |||
definitions={Array []} | |||
loading={false} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
<AlmPRDecorationFormModal | |||
bindingDefinition={ | |||
Object { | |||
"appId": "123456", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http:alm.enterprise.com", | |||
} | |||
} | |||
onCancel={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
> | |||
<Component /> | |||
</AlmPRDecorationFormModal> | |||
</Fragment> | |||
`; |
@@ -0,0 +1,89 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<table | |||
className="data zebra spacer-bottom" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
settings.pr_decoration.table.column.name | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.github.url | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.app_id | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.edit | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.delete | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody /> | |||
</table> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<table | |||
className="data zebra spacer-bottom" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
settings.pr_decoration.table.column.name | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.github.url | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.app_id | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.edit | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.delete | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr | |||
key="key" | |||
> | |||
<td> | |||
key | |||
</td> | |||
<td> | |||
http:alm.enterprise.com | |||
</td> | |||
<td> | |||
123456 | |||
</td> | |||
<td> | |||
<ButtonIcon | |||
onClick={[Function]} | |||
> | |||
<EditIcon /> | |||
</ButtonIcon> | |||
</td> | |||
<td> | |||
<DeleteButton | |||
onClick={[Function]} | |||
/> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
`; |
@@ -1,95 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<table | |||
className="data zebra spacer-bottom" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
settings.pr_decoration.table.column.name | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.github.url | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.app_id | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.edit | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.delete | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody /> | |||
</table> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
<Fragment> | |||
<table | |||
className="data zebra spacer-bottom" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
settings.pr_decoration.table.column.name | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.github.url | |||
</th> | |||
<th> | |||
settings.pr_decoration.table.column.app_id | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.edit | |||
</th> | |||
<th | |||
className="thin" | |||
> | |||
settings.pr_decoration.table.column.delete | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr | |||
key="key" | |||
> | |||
<td> | |||
key | |||
</td> | |||
<td> | |||
http:alm.enterprise.com | |||
</td> | |||
<td> | |||
123456 | |||
</td> | |||
<td> | |||
<ButtonIcon | |||
onClick={[Function]} | |||
> | |||
<EditIcon /> | |||
</ButtonIcon> | |||
</td> | |||
<td> | |||
<ButtonIcon | |||
onClick={[Function]} | |||
> | |||
<DeleteIcon /> | |||
</ButtonIcon> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</Fragment> | |||
`; |
@@ -1,9 +1,48 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<DeferredSpinner | |||
timeout={100} | |||
/> | |||
<Fragment> | |||
<header | |||
className="page-header" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
settings.pr_decoration.title | |||
</h1> | |||
</header> | |||
<div | |||
className="markdown small spacer-top big-spacer-bottom" | |||
> | |||
settings.pr_decoration.description | |||
</div> | |||
<BoxedTabs | |||
onSelect={[MockFunction]} | |||
selected="github" | |||
tabs={ | |||
Array [ | |||
Object { | |||
"key": "github", | |||
"label": "Github Enterprise", | |||
}, | |||
Object { | |||
"key": "azure", | |||
"label": "Azure DevOps Server", | |||
}, | |||
] | |||
} | |||
/> | |||
<div | |||
className="boxed-group boxed-group-inner" | |||
> | |||
<GithubTab | |||
definitions={Array []} | |||
loading={true} | |||
onDelete={[MockFunction]} | |||
onUpdateDefinitions={[MockFunction]} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
@@ -31,6 +70,105 @@ exports[`should render correctly 2`] = ` | |||
"key": "github", | |||
"label": "Github Enterprise", | |||
}, | |||
Object { | |||
"key": "azure", | |||
"label": "Azure DevOps Server", | |||
}, | |||
] | |||
} | |||
/> | |||
<div | |||
className="boxed-group boxed-group-inner" | |||
> | |||
<GithubTab | |||
definitions={Array []} | |||
loading={false} | |||
onDelete={[MockFunction]} | |||
onUpdateDefinitions={[MockFunction]} | |||
/> | |||
</div> | |||
<DeleteModal | |||
id="keyToDelete" | |||
onCancel={[MockFunction]} | |||
onDelete={[MockFunction]} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 3`] = ` | |||
<Fragment> | |||
<header | |||
className="page-header" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
settings.pr_decoration.title | |||
</h1> | |||
</header> | |||
<div | |||
className="markdown small spacer-top big-spacer-bottom" | |||
> | |||
settings.pr_decoration.description | |||
</div> | |||
<BoxedTabs | |||
onSelect={[MockFunction]} | |||
selected="azure" | |||
tabs={ | |||
Array [ | |||
Object { | |||
"key": "github", | |||
"label": "Github Enterprise", | |||
}, | |||
Object { | |||
"key": "azure", | |||
"label": "Azure DevOps Server", | |||
}, | |||
] | |||
} | |||
/> | |||
<div | |||
className="boxed-group boxed-group-inner" | |||
> | |||
<AzureTab | |||
definitions={Array []} | |||
loading={false} | |||
onDelete={[MockFunction]} | |||
onUpdateDefinitions={[MockFunction]} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 4`] = ` | |||
<Fragment> | |||
<header | |||
className="page-header" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
settings.pr_decoration.title | |||
</h1> | |||
</header> | |||
<div | |||
className="markdown small spacer-top big-spacer-bottom" | |||
> | |||
settings.pr_decoration.description | |||
</div> | |||
<BoxedTabs | |||
onSelect={[MockFunction]} | |||
selected="github" | |||
tabs={ | |||
Array [ | |||
Object { | |||
"key": "github", | |||
"label": "Github Enterprise", | |||
}, | |||
Object { | |||
"key": "azure", | |||
"label": "Azure DevOps Server", | |||
}, | |||
] | |||
} | |||
/> | |||
@@ -39,6 +177,8 @@ exports[`should render correctly 2`] = ` | |||
> | |||
<GithubTab | |||
definitions={Array []} | |||
loading={false} | |||
onDelete={[MockFunction]} | |||
onUpdateDefinitions={[MockFunction]} | |||
/> | |||
</div> |
@@ -5,10 +5,14 @@ exports[`should render correctly 1`] = ` | |||
currentAlm="github" | |||
definitions={ | |||
Object { | |||
"azure": Array [], | |||
"github": Array [], | |||
} | |||
} | |||
loading={true} | |||
onCancel={[Function]} | |||
onConfirmDelete={[Function]} | |||
onDelete={[Function]} | |||
onSelectAlm={[Function]} | |||
onUpdateDefinitions={[Function]} | |||
/> |
@@ -0,0 +1,79 @@ | |||
// 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 {}} | |||
to="/documentation/analysis/pull-request/#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 | |||
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 {}} | |||
to="/documentation/analysis/pull-request/#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 | |||
onClick={[MockFunction]} | |||
> | |||
settings.pr_decoration.table.create | |||
</Button> | |||
</div> | |||
</Fragment> | |||
`; |
@@ -1,154 +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.github.info" | |||
id="settings.pr_decoration.github.info" | |||
values={ | |||
Object { | |||
"link": <Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to="/documentation/analysis/pull-request/#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 | |||
onClick={[MockFunction]} | |||
> | |||
settings.pr_decoration.table.create | |||
</Button> | |||
</div> | |||
<PRDecorationTable | |||
alm="github" | |||
definitions={Array []} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
</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 {}} | |||
to="/documentation/analysis/pull-request/#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 | |||
onClick={[MockFunction]} | |||
> | |||
settings.pr_decoration.table.create | |||
</Button> | |||
</div> | |||
<PRDecorationTable | |||
alm="github" | |||
definitions={Array []} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
<DeleteModal | |||
id="123" | |||
onCancel={[MockFunction]} | |||
onDelete={[MockFunction]} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 3`] = ` | |||
<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 {}} | |||
to="/documentation/analysis/pull-request/#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 | |||
onClick={[MockFunction]} | |||
> | |||
settings.pr_decoration.table.create | |||
</Button> | |||
</div> | |||
<PRDecorationTable | |||
alm="github" | |||
definitions={Array []} | |||
onDelete={[MockFunction]} | |||
onEdit={[MockFunction]} | |||
/> | |||
<AlmPRDecorationFormModal | |||
alm="github" | |||
bindingDefinition={ | |||
Object { | |||
"appId": "123456", | |||
"key": "key", | |||
"privateKey": "asdf1234", | |||
"url": "http:alm.enterprise.com", | |||
} | |||
} | |||
onCancel={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
/> | |||
</Fragment> | |||
`; |
@@ -40,6 +40,10 @@ export interface PRDecorationBindingRendererProps { | |||
success: boolean; | |||
} | |||
function renderLabel(v: T.AlmSettingsInstance) { | |||
return v.url ? `${v.key} — ${v.url}` : v.key; | |||
} | |||
export default function PRDecorationBindingRenderer(props: PRDecorationBindingRendererProps) { | |||
const { | |||
formData: { repository, key }, | |||
@@ -100,7 +104,7 @@ export default function PRDecorationBindingRenderer(props: PRDecorationBindingRe | |||
clearable={false} | |||
id="name" | |||
onChange={({ value }: { value: string }) => props.onFieldChange('key', value)} | |||
options={instances.map(v => ({ value: v.key, label: `${v.key} — ${v.url}` }))} | |||
options={instances.map(v => ({ value: v.key, label: renderLabel(v) }))} | |||
searchable={false} | |||
value={key} | |||
/> |
@@ -23,14 +23,14 @@ import { hasMessage, translate } from 'sonar-ui-common/helpers/l10n'; | |||
export const DEFAULT_CATEGORY = 'general'; | |||
export enum ALM_KEYS { | |||
BITBUCKET = 'bitbucket', | |||
GITHUB = 'github', | |||
AZURE_DEVOPS = 'azure_devops' | |||
AZURE = 'azure', | |||
// BITBUCKET = 'bitbucket', | |||
GITHUB = 'github' | |||
} | |||
export const almName = { | |||
[ALM_KEYS.AZURE_DEVOPS]: 'Azure DevOps Server', | |||
[ALM_KEYS.BITBUCKET]: 'Bitbucket Server', | |||
[ALM_KEYS.AZURE]: 'Azure DevOps Server', | |||
// [ALM_KEYS.BITBUCKET]: 'Bitbucket Server', | |||
[ALM_KEYS.GITHUB]: 'Github Enterprise' | |||
}; | |||
@@ -50,6 +50,16 @@ export function mockAlmOrganization(overrides: Partial<T.AlmOrganization> = {}): | |||
}; | |||
} | |||
export function mockAzureDefinition( | |||
overrides: Partial<T.AzureBindingDefinition> = {} | |||
): T.AzureBindingDefinition { | |||
return { | |||
key: 'key', | |||
personalAccessToken: 'asdf1234', | |||
...overrides | |||
}; | |||
} | |||
export function mockGithubDefinition( | |||
overrides: Partial<T.GithubBindingDefinition> = {} | |||
): T.GithubBindingDefinition { |
@@ -20,22 +20,29 @@ | |||
declare namespace T { | |||
export interface AlmSettingsBinding { | |||
key: string; | |||
url: string; | |||
} | |||
export interface AlmSettingsInstance extends AlmSettingsBinding { | |||
export interface AlmSettingsInstance { | |||
alm: string; | |||
key: string; | |||
url?: string; | |||
} | |||
export interface AlmSettingsBindingDefinitions { | |||
azure: AzureBindingDefinition[]; | |||
github: GithubBindingDefinition[]; | |||
} | |||
export interface GithubBindingDefinition extends AlmSettingsBinding { | |||
url: string; | |||
appId: string; | |||
privateKey: string; | |||
} | |||
export interface AzureBindingDefinition extends AlmSettingsBinding { | |||
personalAccessToken: string; | |||
} | |||
export interface ProjectAlmBinding { | |||
key: string; | |||
alm: string; |
@@ -924,6 +924,7 @@ settings.pr_decoration.category=Pull Requests | |||
settings.pr_decoration.title=Pull Requests decoration | |||
settings.pr_decoration.description=When Pull Request decoration is enabled, SonarQube publishes the status of the analysis directly in your ALM Pull requests. | |||
settings.pr_decoration.manage_instances=Manage instances | |||
settings.pr_decoration.azure.info=The account that will be used to decorate Pull Requests needs write permission. {link} | |||
settings.pr_decoration.github.info=You need to install a Github App with specific settings and permissions to enable Pull Request Decoration on your Organization or Repository. {link} | |||
settings.pr_decoration.table.title=Pull Request decoration configurations | |||
settings.pr_decoration.table.create=Create configuration | |||
@@ -943,6 +944,8 @@ settings.pr_decoration.form.name.help=Give your configuration a clear and succin | |||
settings.pr_decoration.form.url.github=GitHub Enterprise URL | |||
settings.pr_decoration.form.app_id=GitHub App ID | |||
settings.pr_decoration.form.private_key=Private Key | |||
settings.pr_decoration.form.personal_access_token=Personal Access token | |||
settings.pr_decoration.form.personal_access_token.help=Token of the user that will be used to decorate the pull requests. Needs authorized scope: "Code (read and write)". | |||
settings.pr_decoration.form.save=Save configuration | |||
settings.pr_decoration.form.cancel=Cancel | |||