import java.util.List; | import java.util.List; | ||||
import javax.annotation.CheckForNull; | import javax.annotation.CheckForNull; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.api.CoreProperties; | |||||
import org.sonar.api.config.Configuration; | import org.sonar.api.config.Configuration; | ||||
import org.sonar.api.config.PropertyDefinition; | import org.sonar.api.config.PropertyDefinition; | ||||
private static final String ORGANIZATIONS = "sonar.auth.github.organizations"; | private static final String ORGANIZATIONS = "sonar.auth.github.organizations"; | ||||
private static final String CATEGORY = "security"; | |||||
private static final String CATEGORY = CoreProperties.CATEGORY_ALM_INTEGRATION; | |||||
private static final String SUBCATEGORY = "github"; | private static final String SUBCATEGORY = "github"; | ||||
private final Configuration configuration; | private final Configuration configuration; |
static final String GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP = "sonar.auth.gitlab.allowUsersToSignUp"; | static final String GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP = "sonar.auth.gitlab.allowUsersToSignUp"; | ||||
static final String GITLAB_AUTH_SYNC_USER_GROUPS = "sonar.auth.gitlab.groupsSync"; | static final String GITLAB_AUTH_SYNC_USER_GROUPS = "sonar.auth.gitlab.groupsSync"; | ||||
private static final String CATEGORY = CoreProperties.CATEGORY_SECURITY; | |||||
private static final String CATEGORY = CoreProperties.CATEGORY_ALM_INTEGRATION; | |||||
private static final String SUBCATEGORY = "gitlab"; | private static final String SUBCATEGORY = "gitlab"; | ||||
private final Configuration configuration; | private final Configuration configuration; |
padding-top: calc(var(--gridSize) / 2) !important; | padding-top: calc(var(--gridSize) / 2) !important; | ||||
} | } | ||||
.big-padded-top { | |||||
padding-top: calc(2 * var(--gridSize)); | |||||
} | |||||
.huge-padded-top { | |||||
padding-top: 40px; | |||||
} | |||||
td.little-spacer-left { | td.little-spacer-left { | ||||
padding-left: 4px !important; | padding-left: 4px !important; | ||||
} | } | ||||
width: 600px !important; | width: 600px !important; | ||||
} | } | ||||
.abs-height-100 { | |||||
height: 100% !important; | |||||
} | |||||
.max-height-100 { | .max-height-100 { | ||||
max-height: 100% !important; | max-height: 100% !important; | ||||
} | } |
import { WithRouterProps } from 'react-router'; | import { WithRouterProps } from 'react-router'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages'; | import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages'; | ||||
import { getAlmSettings } from '../../../api/almSettings'; | |||||
import { getAlmSettings } from '../../../api/alm-settings'; | |||||
import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn'; | import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn'; | ||||
import { withAppState } from '../../../components/hoc/withAppState'; | import { withAppState } from '../../../components/hoc/withAppState'; | ||||
import { getProjectUrl } from '../../../helpers/urls'; | import { getProjectUrl } from '../../../helpers/urls'; | ||||
import { AlmSettingsInstance, ALM_KEYS } from '../../../types/alm-settings'; | |||||
import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; | |||||
import BitbucketProjectCreate from './BitbucketProjectCreate'; | import BitbucketProjectCreate from './BitbucketProjectCreate'; | ||||
import CreateProjectModeSelection from './CreateProjectModeSelection'; | import CreateProjectModeSelection from './CreateProjectModeSelection'; | ||||
import ManualProjectCreate from './ManualProjectCreate'; | import ManualProjectCreate from './ManualProjectCreate'; | ||||
.then(almSettings => { | .then(almSettings => { | ||||
if (this.mounted) { | if (this.mounted) { | ||||
this.setState({ | this.setState({ | ||||
bitbucketSettings: almSettings.filter(s => s.alm === ALM_KEYS.BITBUCKET), | |||||
bitbucketSettings: almSettings.filter(s => s.alm === AlmKeys.Bitbucket), | |||||
loading: false | loading: false | ||||
}); | }); | ||||
} | } |
import { SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | import { SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | ||||
import { change, submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | import { change, submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | ||||
import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings'; | import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings'; | ||||
import { ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import { AlmKeys } from '../../../../types/alm-settings'; | |||||
import BitbucketPersonalAccessTokenForm, { | import BitbucketPersonalAccessTokenForm, { | ||||
BitbucketPersonalAccessTokenFormProps | BitbucketPersonalAccessTokenFormProps | ||||
} from '../BitbucketPersonalAccessTokenForm'; | } from '../BitbucketPersonalAccessTokenForm'; | ||||
return shallow<BitbucketPersonalAccessTokenFormProps>( | return shallow<BitbucketPersonalAccessTokenFormProps>( | ||||
<BitbucketPersonalAccessTokenForm | <BitbucketPersonalAccessTokenForm | ||||
bitbucketSetting={mockAlmSettingsInstance({ | bitbucketSetting={mockAlmSettingsInstance({ | ||||
alm: ALM_KEYS.BITBUCKET, | |||||
alm: AlmKeys.Bitbucket, | |||||
url: 'http://www.example.com' | url: 'http://www.example.com' | ||||
})} | })} | ||||
onPersonalAccessTokenCreate={jest.fn()} | onPersonalAccessTokenCreate={jest.fn()} |
import { mockBitbucketRepository } from '../../../../helpers/mocks/alm-integrations'; | import { mockBitbucketRepository } from '../../../../helpers/mocks/alm-integrations'; | ||||
import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings'; | import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings'; | ||||
import { mockLocation } from '../../../../helpers/testMocks'; | import { mockLocation } from '../../../../helpers/testMocks'; | ||||
import { ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import { AlmKeys } from '../../../../types/alm-settings'; | |||||
import { BitbucketProjectCreate } from '../BitbucketProjectCreate'; | import { BitbucketProjectCreate } from '../BitbucketProjectCreate'; | ||||
jest.mock('../../../../api/alm-integrations', () => { | jest.mock('../../../../api/alm-integrations', () => { | ||||
function shallowRender(props: Partial<BitbucketProjectCreate['props']> = {}) { | function shallowRender(props: Partial<BitbucketProjectCreate['props']> = {}) { | ||||
return shallow<BitbucketProjectCreate>( | return shallow<BitbucketProjectCreate>( | ||||
<BitbucketProjectCreate | <BitbucketProjectCreate | ||||
bitbucketSettings={[mockAlmSettingsInstance({ alm: ALM_KEYS.BITBUCKET, key: 'foo' })]} | |||||
bitbucketSettings={[mockAlmSettingsInstance({ alm: AlmKeys.Bitbucket, key: 'foo' })]} | |||||
loadingBindings={false} | loadingBindings={false} | ||||
location={mockLocation()} | location={mockLocation()} | ||||
onProjectCreate={jest.fn()} | onProjectCreate={jest.fn()} |
mockBitbucketRepository | mockBitbucketRepository | ||||
} from '../../../../helpers/mocks/alm-integrations'; | } from '../../../../helpers/mocks/alm-integrations'; | ||||
import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings'; | import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings'; | ||||
import { ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import { AlmKeys } from '../../../../types/alm-settings'; | |||||
import BitbucketProjectCreateRenderer, { | import BitbucketProjectCreateRenderer, { | ||||
BitbucketProjectCreateRendererProps | BitbucketProjectCreateRendererProps | ||||
} from '../BitbucketProjectCreateRenderer'; | } from '../BitbucketProjectCreateRenderer'; | ||||
function shallowRender(props: Partial<BitbucketProjectCreateRendererProps> = {}) { | function shallowRender(props: Partial<BitbucketProjectCreateRendererProps> = {}) { | ||||
return shallow<BitbucketProjectCreateRendererProps>( | return shallow<BitbucketProjectCreateRendererProps>( | ||||
<BitbucketProjectCreateRenderer | <BitbucketProjectCreateRenderer | ||||
bitbucketSetting={mockAlmSettingsInstance({ alm: ALM_KEYS.BITBUCKET })} | |||||
bitbucketSetting={mockAlmSettingsInstance({ alm: AlmKeys.Bitbucket })} | |||||
importing={false} | importing={false} | ||||
loading={false} | loading={false} | ||||
onImportRepository={jest.fn()} | onImportRepository={jest.fn()} |
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { addWhitePageClass } from 'sonar-ui-common/helpers/pages'; | import { addWhitePageClass } from 'sonar-ui-common/helpers/pages'; | ||||
import { getAlmSettings } from '../../../../api/almSettings'; | |||||
import { getAlmSettings } from '../../../../api/alm-settings'; | |||||
import { mockLocation, mockLoggedInUser, mockRouter } from '../../../../helpers/testMocks'; | import { mockLocation, mockLoggedInUser, mockRouter } from '../../../../helpers/testMocks'; | ||||
import { ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import { AlmKeys } from '../../../../types/alm-settings'; | |||||
import { CreateProjectPageSonarQube } from '../CreateProjectPageSonarQube'; | import { CreateProjectPageSonarQube } from '../CreateProjectPageSonarQube'; | ||||
import { CreateProjectModes } from '../types'; | import { CreateProjectModes } from '../types'; | ||||
jest.mock('../../../../api/almSettings', () => ({ | |||||
getAlmSettings: jest.fn().mockResolvedValue([{ alm: ALM_KEYS.BITBUCKET, key: 'foo' }]) | |||||
jest.mock('../../../../api/alm-settings', () => ({ | |||||
getAlmSettings: jest.fn().mockResolvedValue([{ alm: AlmKeys.Bitbucket, key: 'foo' }]) | |||||
})); | })); | ||||
jest.mock('sonar-ui-common/helpers/pages', () => ({ | jest.mock('sonar-ui-common/helpers/pages', () => ({ |
Object { | Object { | ||||
"pathname": "/admin/settings", | "pathname": "/admin/settings", | ||||
"query": Object { | "query": Object { | ||||
"category": "pull_request_decoration", | |||||
"category": "almintegration", | |||||
}, | }, | ||||
} | } | ||||
} | } |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { | import { | ||||
ALM_INTEGRATION, | |||||
ANALYSIS_SCOPE_CATEGORY, | ANALYSIS_SCOPE_CATEGORY, | ||||
LANGUAGES_CATEGORY, | LANGUAGES_CATEGORY, | ||||
NEW_CODE_PERIOD_CATEGORY, | NEW_CODE_PERIOD_CATEGORY, | ||||
PULL_REQUEST_DECORATION_BINDING_CATEGORY, | |||||
PULL_REQUEST_DECORATION_CATEGORY | |||||
PULL_REQUEST_DECORATION_BINDING_CATEGORY | |||||
} from './AdditionalCategoryKeys'; | } from './AdditionalCategoryKeys'; | ||||
import AlmIntegration from './almIntegration/AlmIntegration'; | |||||
import { AnalysisScope } from './AnalysisScope'; | import { AnalysisScope } from './AnalysisScope'; | ||||
import Languages from './Languages'; | import Languages from './Languages'; | ||||
import NewCodePeriod from './NewCodePeriod'; | import NewCodePeriod from './NewCodePeriod'; | ||||
import PullRequestDecoration from './pullRequestDecoration/PullRequestDecoration'; | |||||
import PullRequestDecorationBinding from './pullRequestDecorationBinding/PRDecorationBinding'; | import PullRequestDecorationBinding from './pullRequestDecorationBinding/PRDecorationBinding'; | ||||
export interface AdditionalCategoryComponentProps { | export interface AdditionalCategoryComponentProps { | ||||
displayTab: false | displayTab: false | ||||
}, | }, | ||||
{ | { | ||||
key: PULL_REQUEST_DECORATION_CATEGORY, | |||||
name: translate('settings.pr_decoration.category'), | |||||
renderComponent: getPullRequestDecorationComponent, | |||||
key: ALM_INTEGRATION, | |||||
name: translate('property.category.almintegration'), | |||||
renderComponent: getAlmIntegrationComponent, | |||||
availableGlobally: true, | availableGlobally: true, | ||||
availableForProject: false, | availableForProject: false, | ||||
displayTab: true, | |||||
requiresBranchesEnabled: true | |||||
displayTab: false | |||||
}, | }, | ||||
{ | { | ||||
key: PULL_REQUEST_DECORATION_BINDING_CATEGORY, | key: PULL_REQUEST_DECORATION_BINDING_CATEGORY, | ||||
return <AnalysisScope {...props} />; | return <AnalysisScope {...props} />; | ||||
} | } | ||||
function getPullRequestDecorationComponent() { | |||||
return <PullRequestDecoration />; | |||||
function getAlmIntegrationComponent(props: AdditionalCategoryComponentProps) { | |||||
return <AlmIntegration {...props} />; | |||||
} | } | ||||
function getPullRequestDecorationBindingComponent(props: AdditionalCategoryComponentProps) { | function getPullRequestDecorationBindingComponent(props: AdditionalCategoryComponentProps) { |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
export const ALM_INTEGRATION = 'almintegration'; | |||||
export const ANALYSIS_SCOPE_CATEGORY = 'exclusions'; | export const ANALYSIS_SCOPE_CATEGORY = 'exclusions'; | ||||
export const LANGUAGES_CATEGORY = 'languages'; | export const LANGUAGES_CATEGORY = 'languages'; | ||||
export const NEW_CODE_PERIOD_CATEGORY = 'new_code_period'; | export const NEW_CODE_PERIOD_CATEGORY = 'new_code_period'; | ||||
export const PULL_REQUEST_DECORATION_CATEGORY = 'pull_request_decoration'; | |||||
export const PULL_REQUEST_DECORATION_BINDING_CATEGORY = 'pull_request_decoration_binding'; | export const PULL_REQUEST_DECORATION_BINDING_CATEGORY = 'pull_request_decoration_binding'; |
component?: T.Component; | component?: T.Component; | ||||
fetchValues: Function; | fetchValues: Function; | ||||
settings: Array<T.Setting & { definition: T.SettingCategoryDefinition }>; | settings: Array<T.Setting & { definition: T.SettingCategoryDefinition }>; | ||||
subCategory?: string; | |||||
} | } | ||||
export default class SubCategoryDefinitionsList extends React.PureComponent<Props> { | export default class SubCategoryDefinitionsList extends React.PureComponent<Props> { | ||||
const sortedSubCategories = sortBy(subCategories, subCategory => | const sortedSubCategories = sortBy(subCategories, subCategory => | ||||
subCategory.name.toLowerCase() | subCategory.name.toLowerCase() | ||||
); | ); | ||||
const filteredSubCategories = this.props.subCategory | |||||
? sortedSubCategories.filter(c => c.key === this.props.subCategory) | |||||
: sortedSubCategories; | |||||
return ( | return ( | ||||
<ul className="settings-sub-categories-list"> | <ul className="settings-sub-categories-list"> | ||||
{sortedSubCategories.map(subCategory => ( | |||||
{filteredSubCategories.map(subCategory => ( | |||||
<li key={subCategory.key}> | <li key={subCategory.key}> | ||||
<h2 className="settings-sub-category-name">{subCategory.name}</h2> | <h2 className="settings-sub-category-name">{subCategory.name}</h2> | ||||
{subCategory.description != null && ( | {subCategory.description != null && ( |
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | ||||
import { mockLocation, mockRouter } from '../../../../helpers/testMocks'; | import { mockLocation, mockRouter } from '../../../../helpers/testMocks'; | ||||
import { | import { | ||||
ALM_INTEGRATION, | |||||
ANALYSIS_SCOPE_CATEGORY, | ANALYSIS_SCOPE_CATEGORY, | ||||
LANGUAGES_CATEGORY, | LANGUAGES_CATEGORY, | ||||
NEW_CODE_PERIOD_CATEGORY, | NEW_CODE_PERIOD_CATEGORY, | ||||
PULL_REQUEST_DECORATION_BINDING_CATEGORY, | |||||
PULL_REQUEST_DECORATION_CATEGORY | |||||
PULL_REQUEST_DECORATION_BINDING_CATEGORY | |||||
} from '../AdditionalCategoryKeys'; | } from '../AdditionalCategoryKeys'; | ||||
import { App } from '../AppContainer'; | import { App } from '../AppContainer'; | ||||
expect(wrapper).toMatchSnapshot(); | expect(wrapper).toMatchSnapshot(); | ||||
}); | }); | ||||
it('should render pull request decoration correctly', async () => { | |||||
it('should render ALM integration correctly', async () => { | |||||
const wrapper = shallowRender({ | const wrapper = shallowRender({ | ||||
location: mockLocation({ query: { category: PULL_REQUEST_DECORATION_CATEGORY } }) | |||||
location: mockLocation({ query: { category: ALM_INTEGRATION } }) | |||||
}); | }); | ||||
await waitAndUpdate(wrapper); | await waitAndUpdate(wrapper); |
/> | /> | ||||
`; | `; | ||||
exports[`should render additional categories component correctly 4`] = `<PullRequestDecoration />`; | |||||
exports[`should render additional categories component correctly 4`] = ` | |||||
<Connect(withAppState(AlmIntegration)) | |||||
component={ | |||||
Object { | |||||
"breadcrumbs": Array [], | |||||
"key": "my-project", | |||||
"name": "MyProject", | |||||
"organization": "foo", | |||||
"qualifier": "TRK", | |||||
"qualityGate": Object { | |||||
"isDefault": true, | |||||
"key": "30", | |||||
"name": "Sonar way", | |||||
}, | |||||
"qualityProfiles": Array [ | |||||
Object { | |||||
"deleted": false, | |||||
"key": "my-qp", | |||||
"language": "ts", | |||||
"name": "Sonar way", | |||||
}, | |||||
], | |||||
"tags": Array [], | |||||
} | |||||
} | |||||
selectedCategory="TEST" | |||||
/> | |||||
`; | |||||
exports[`should render additional categories component correctly 5`] = ` | exports[`should render additional categories component correctly 5`] = ` | ||||
<PRDecorationBinding | <PRDecorationBinding |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render analysis scope correctly 1`] = ` | |||||
exports[`should render ALM integration correctly 1`] = ` | |||||
<div | <div | ||||
className="page page-limited" | className="page page-limited" | ||||
id="settings-page" | id="settings-page" | ||||
> | > | ||||
<Connect(CategoriesList) | <Connect(CategoriesList) | ||||
defaultCategory="general" | defaultCategory="general" | ||||
selectedCategory="exclusions" | |||||
selectedCategory="almintegration" | |||||
/> | /> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="side-tabs-main" | className="side-tabs-main" | ||||
> | > | ||||
<AnalysisScope | |||||
selectedCategory="exclusions" | |||||
<Connect(withAppState(AlmIntegration)) | |||||
selectedCategory="almintegration" | |||||
/> | /> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; | ||||
exports[`should render default view correctly 1`] = ` | |||||
exports[`should render analysis scope correctly 1`] = ` | |||||
<div | <div | ||||
className="page page-limited" | className="page page-limited" | ||||
id="settings-page" | id="settings-page" | ||||
> | > | ||||
<Connect(CategoriesList) | <Connect(CategoriesList) | ||||
defaultCategory="general" | defaultCategory="general" | ||||
selectedCategory="general" | |||||
selectedCategory="exclusions" | |||||
/> | /> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="side-tabs-main" | className="side-tabs-main" | ||||
> | > | ||||
<Connect(SubCategoryDefinitionsList) | |||||
category="general" | |||||
<AnalysisScope | |||||
selectedCategory="exclusions" | |||||
/> | /> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; | ||||
exports[`should render languages correctly 1`] = ` | |||||
exports[`should render default view correctly 1`] = ` | |||||
<div | <div | ||||
className="page page-limited" | className="page page-limited" | ||||
id="settings-page" | id="settings-page" | ||||
> | > | ||||
<Connect(CategoriesList) | <Connect(CategoriesList) | ||||
defaultCategory="general" | defaultCategory="general" | ||||
selectedCategory="languages" | |||||
selectedCategory="general" | |||||
/> | /> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="side-tabs-main" | className="side-tabs-main" | ||||
> | > | ||||
<withRouter(Connect(Languages)) | |||||
selectedCategory="languages" | |||||
<Connect(SubCategoryDefinitionsList) | |||||
category="general" | |||||
/> | /> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; | ||||
exports[`should render newCodePeriod correctly 1`] = ` | |||||
exports[`should render languages correctly 1`] = ` | |||||
<div | <div | ||||
className="page page-limited" | className="page page-limited" | ||||
id="settings-page" | id="settings-page" | ||||
> | > | ||||
<Connect(CategoriesList) | <Connect(CategoriesList) | ||||
defaultCategory="general" | defaultCategory="general" | ||||
selectedCategory="new_code_period" | |||||
selectedCategory="languages" | |||||
/> | /> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="side-tabs-main" | className="side-tabs-main" | ||||
> | > | ||||
<NewCodePeriod /> | |||||
<withRouter(Connect(Languages)) | |||||
selectedCategory="languages" | |||||
/> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; | ||||
exports[`should render pull request decoration binding correctly 1`] = ` | |||||
exports[`should render newCodePeriod correctly 1`] = ` | |||||
<div | <div | ||||
className="page page-limited" | className="page page-limited" | ||||
id="settings-page" | id="settings-page" | ||||
> | > | ||||
<Connect(CategoriesList) | <Connect(CategoriesList) | ||||
defaultCategory="general" | defaultCategory="general" | ||||
selectedCategory="pull_request_decoration_binding" | |||||
selectedCategory="new_code_period" | |||||
/> | /> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="side-tabs-main" | className="side-tabs-main" | ||||
> | > | ||||
<Connect(SubCategoryDefinitionsList) | |||||
category="pull_request_decoration_binding" | |||||
/> | |||||
<NewCodePeriod /> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; | ||||
exports[`should render pull request decoration correctly 1`] = ` | |||||
exports[`should render pull request decoration binding correctly 1`] = ` | |||||
<div | <div | ||||
className="page page-limited" | className="page page-limited" | ||||
id="settings-page" | id="settings-page" | ||||
> | > | ||||
<Connect(CategoriesList) | <Connect(CategoriesList) | ||||
defaultCategory="general" | defaultCategory="general" | ||||
selectedCategory="pull_request_decoration" | |||||
selectedCategory="pull_request_decoration_binding" | |||||
/> | /> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="side-tabs-main" | className="side-tabs-main" | ||||
> | > | ||||
<PullRequestDecoration /> | |||||
<Connect(SubCategoryDefinitionsList) | |||||
category="pull_request_decoration_binding" | |||||
/> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> |
*/ | */ | ||||
import { isEqual, omit } from 'lodash'; | import { isEqual, omit } from 'lodash'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import AlmPRDecorationFormModalRenderer from './AlmPRDecorationFormModalRenderer'; | |||||
import AlmPRDecorationFormRenderer from './AlmPRDecorationFormRenderer'; | |||||
import { AlmBindingDefinition } from '../../../../types/alm-settings'; | |||||
import AlmBindingDefinitionFormModalRenderer from './AlmBindingDefinitionFormModalRenderer'; | |||||
import AlmBindingDefinitionFormRenderer from './AlmBindingDefinitionFormRenderer'; | |||||
export interface AlmPRDecorationFormChildrenProps<B> { | |||||
export interface AlmBindingDefinitionFormChildrenProps<B> { | |||||
formData: B; | formData: B; | ||||
hideKeyField?: boolean; | hideKeyField?: boolean; | ||||
onFieldChange: (fieldId: keyof B, value: string) => void; | onFieldChange: (fieldId: keyof B, value: string) => void; | ||||
} | } | ||||
interface Props<B> { | interface Props<B> { | ||||
alm: ALM_KEYS; | |||||
bindingDefinition: B; | bindingDefinition: B; | ||||
children: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode; | |||||
children: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode; | |||||
help?: React.ReactNode; | help?: React.ReactNode; | ||||
hideKeyField?: boolean; | hideKeyField?: boolean; | ||||
loading?: boolean; | loading?: boolean; | ||||
touched: boolean; | touched: boolean; | ||||
} | } | ||||
export default class AlmPRDecorationForm<B extends AlmSettingsBinding> extends React.PureComponent< | |||||
Props<B>, | |||||
State<B> | |||||
> { | |||||
export default class AlmBindingDefinitionForm< | |||||
B extends AlmBindingDefinition | |||||
> extends React.PureComponent<Props<B>, State<B>> { | |||||
constructor(props: Props<B>) { | constructor(props: Props<B>) { | ||||
super(props); | super(props); | ||||
this.state = { formData: props.bindingDefinition, touched: false }; | this.state = { formData: props.bindingDefinition, touched: false }; | ||||
render() { | render() { | ||||
const { | const { | ||||
alm, | |||||
bindingDefinition, | bindingDefinition, | ||||
children, | children, | ||||
help, | help, | ||||
const showDelete = showEdit && this.props.onDelete !== undefined; | const showDelete = showEdit && this.props.onDelete !== undefined; | ||||
return showInModal ? ( | return showInModal ? ( | ||||
<AlmPRDecorationFormModalRenderer | |||||
<AlmBindingDefinitionFormModalRenderer | |||||
action={bindingDefinition.key ? 'edit' : 'create'} | action={bindingDefinition.key ? 'edit' : 'create'} | ||||
alm={alm} | |||||
canSubmit={this.canSubmit} | canSubmit={this.canSubmit} | ||||
help={help} | help={help} | ||||
onCancel={this.handleCancel} | onCancel={this.handleCancel} | ||||
formData, | formData, | ||||
onFieldChange: this.handleFieldChange | onFieldChange: this.handleFieldChange | ||||
})} | })} | ||||
</AlmPRDecorationFormModalRenderer> | |||||
</AlmBindingDefinitionFormModalRenderer> | |||||
) : ( | ) : ( | ||||
<AlmPRDecorationFormRenderer | |||||
<AlmBindingDefinitionFormRenderer | |||||
canSubmit={this.canSubmit} | canSubmit={this.canSubmit} | ||||
help={help} | help={help} | ||||
loading={loading} | loading={loading} | ||||
onFieldChange: this.handleFieldChange, | onFieldChange: this.handleFieldChange, | ||||
readOnly | readOnly | ||||
})} | })} | ||||
</AlmPRDecorationFormRenderer> | |||||
</AlmBindingDefinitionFormRenderer> | |||||
); | ); | ||||
} | } | ||||
} | } |
import * as React from 'react'; | import * as React from 'react'; | ||||
import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip'; | import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { AlmSettingsBinding } from '../../../../types/alm-settings'; | |||||
import { AlmBindingDefinition } from '../../../../types/alm-settings'; | |||||
export interface AlmDefinitionFormFieldProps<B extends AlmSettingsBinding> { | |||||
export interface AlmBindingDefinitionFormFieldProps<B extends AlmBindingDefinition> { | |||||
autoFocus?: boolean; | autoFocus?: boolean; | ||||
help?: React.ReactNode; | help?: React.ReactNode; | ||||
id: string; | id: string; | ||||
value: string; | value: string; | ||||
} | } | ||||
export function AlmDefinitionFormField<B extends AlmSettingsBinding>( | |||||
props: AlmDefinitionFormFieldProps<B> | |||||
export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>( | |||||
props: AlmBindingDefinitionFormFieldProps<B> | |||||
) { | ) { | ||||
const { | const { | ||||
autoFocus, | autoFocus, | ||||
return ( | return ( | ||||
<div className="modal-field"> | <div className="modal-field"> | ||||
<label className="display-flex-center" htmlFor={id}> | <label className="display-flex-center" htmlFor={id}> | ||||
{translate('settings.pr_decoration.form', id)} | |||||
{translate('settings.almintegration.form', id)} | |||||
<em className="mandatory spacer-right">*</em> | <em className="mandatory spacer-right">*</em> | ||||
{help && <HelpTooltip overlay={help} placement="right" />} | {help && <HelpTooltip overlay={help} placement="right" />} | ||||
</label> | </label> |
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | import { Alert } from 'sonar-ui-common/components/ui/Alert'; | ||||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { ALM_KEYS } from '../../../../types/alm-settings'; | |||||
export interface AlmPRDecorationFormModalProps { | |||||
export interface AlmBindingDefinitionFormModalProps { | |||||
action: 'edit' | 'create'; | action: 'edit' | 'create'; | ||||
alm: ALM_KEYS; | |||||
canSubmit: () => boolean; | canSubmit: () => boolean; | ||||
children: React.ReactNode; | children: React.ReactNode; | ||||
help?: React.ReactNode; | help?: React.ReactNode; | ||||
onSubmit: () => void; | onSubmit: () => void; | ||||
} | } | ||||
export default function AlmPRDecorationFormModalRenderer(props: AlmPRDecorationFormModalProps) { | |||||
const { alm, action, children, help } = props; | |||||
const header = translate( | |||||
'settings', | |||||
alm === ALM_KEYS.GITLAB ? 'mr_decoration' : 'pr_decoration', | |||||
'form.header', | |||||
action | |||||
); | |||||
export default function AlmBindingDefinitionFormModalRenderer( | |||||
props: AlmBindingDefinitionFormModalProps | |||||
) { | |||||
const { action, children, help } = props; | |||||
const header = translate('settings.almintegration.form.header', action); | |||||
return ( | return ( | ||||
<SimpleModal header={header} onClose={props.onCancel} onSubmit={props.onSubmit} size="medium"> | <SimpleModal header={header} onClose={props.onCancel} onSubmit={props.onSubmit} size="medium"> | ||||
</div> | </div> | ||||
<div className="modal-body modal-container"> | <div className="modal-body modal-container"> | ||||
{help && ( | |||||
<Alert className="big-spacer-bottom" variant="info"> | |||||
{help} | |||||
</Alert> | |||||
)} | |||||
{children} | |||||
<div className="display-flex-start"> | |||||
<div className="flex-1">{children}</div> | |||||
{help && ( | |||||
<Alert className="huge-spacer-left flex-1" variant="info"> | |||||
{help} | |||||
</Alert> | |||||
)} | |||||
</div> | |||||
</div> | </div> | ||||
<div className="modal-foot"> | <div className="modal-foot"> | ||||
<DeferredSpinner className="spacer-right" loading={submitting} /> | <DeferredSpinner className="spacer-right" loading={submitting} /> | ||||
<SubmitButton disabled={submitting || !props.canSubmit()}> | <SubmitButton disabled={submitting || !props.canSubmit()}> | ||||
{translate('settings.pr_decoration.form.save')} | |||||
{translate('settings.almintegration.form.save')} | |||||
</SubmitButton> | </SubmitButton> | ||||
<ResetButtonLink onClick={onCloseClick}>{translate('cancel')}</ResetButtonLink> | <ResetButtonLink onClick={onCloseClick}>{translate('cancel')}</ResetButtonLink> | ||||
</div> | </div> |
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
export interface AlmPRDecorationFormRendererProps { | |||||
export interface AlmBindingDefinitionFormRendererProps { | |||||
canSubmit: () => boolean; | canSubmit: () => boolean; | ||||
children: React.ReactNode; | children: React.ReactNode; | ||||
help?: React.ReactNode; | help?: React.ReactNode; | ||||
success: boolean; | success: boolean; | ||||
} | } | ||||
export default function AlmPRDecorationFormRenderer(props: AlmPRDecorationFormRendererProps) { | |||||
export default function AlmBindingDefinitionFormRenderer( | |||||
props: AlmBindingDefinitionFormRendererProps | |||||
) { | |||||
const { children, help, loading, success } = props; | const { children, help, loading, success } = props; | ||||
return ( | return ( | ||||
e.preventDefault(); | e.preventDefault(); | ||||
props.onSubmit(); | props.onSubmit(); | ||||
}}> | }}> | ||||
{help && ( | |||||
<Alert className="big-spacer-bottom" variant="info"> | |||||
{help} | |||||
</Alert> | |||||
)} | |||||
<div className="display-flex-start"> | |||||
<div className="flex-1"> | |||||
{children} | |||||
{children} | |||||
<div className="display-flex-center"> | |||||
{props.onEdit === undefined ? ( | |||||
<SubmitButton disabled={loading || !props.canSubmit()}> | |||||
{translate('settings.almintegration.form.save')} | |||||
</SubmitButton> | |||||
) : ( | |||||
<Button disabled={loading} onClick={props.onEdit}> | |||||
{translate('edit')} | |||||
</Button> | |||||
)} | |||||
{props.onDelete && ( | |||||
<Button | |||||
className="button-red spacer-left" | |||||
disabled={loading} | |||||
onClick={props.onDelete}> | |||||
{translate('delete')} | |||||
</Button> | |||||
)} | |||||
{props.onCancel && ( | |||||
<ResetButtonLink className="spacer-left" onClick={props.onCancel}> | |||||
{translate('cancel')} | |||||
</ResetButtonLink> | |||||
)} | |||||
{loading && <DeferredSpinner className="spacer-left" />} | |||||
{!loading && success && ( | |||||
<span className="text-success spacer-left"> | |||||
<AlertSuccessIcon className="spacer-right" /> | |||||
{translate('settings.state.saved')} | |||||
</span> | |||||
)} | |||||
</div> | |||||
</div> | |||||
<div className="display-flex-center"> | |||||
{props.onEdit === undefined ? ( | |||||
<SubmitButton disabled={loading || !props.canSubmit()}> | |||||
{translate('settings.pr_decoration.form.save')} | |||||
</SubmitButton> | |||||
) : ( | |||||
<Button disabled={loading} onClick={props.onEdit}> | |||||
{translate('edit')} | |||||
</Button> | |||||
)} | |||||
{props.onDelete && ( | |||||
<Button className="button-red spacer-left" disabled={loading} onClick={props.onDelete}> | |||||
{translate('delete')} | |||||
</Button> | |||||
)} | |||||
{props.onCancel && ( | |||||
<ResetButtonLink className="spacer-left" onClick={props.onCancel}> | |||||
{translate('cancel')} | |||||
</ResetButtonLink> | |||||
)} | |||||
{loading && <DeferredSpinner className="spacer-left" />} | |||||
{!loading && success && ( | |||||
<span className="text-success spacer-left"> | |||||
<AlertSuccessIcon className="spacer-right" /> | |||||
{translate('settings.state.saved')} | |||||
</span> | |||||
{help && ( | |||||
<Alert className="huge-spacer-left flex-1" variant="info"> | |||||
{help} | |||||
</Alert> | |||||
)} | )} | ||||
</div> | </div> | ||||
</form> | </form> |
import { Button, ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons'; | import { Button, ButtonIcon, DeleteButton } from 'sonar-ui-common/components/controls/buttons'; | ||||
import EditIcon from 'sonar-ui-common/components/icons/EditIcon'; | import EditIcon from 'sonar-ui-common/components/icons/EditIcon'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import { AlmKeys } from '../../../../types/alm-settings'; | |||||
export interface AlmPRDecorationTableProps { | |||||
export interface AlmBindingDefinitionsTableProps { | |||||
additionalColumnsHeaders: Array<string>; | additionalColumnsHeaders: Array<string>; | ||||
alm: ALM_KEYS; | |||||
additionalTableInfo?: React.ReactNode; | |||||
alm: AlmKeys; | |||||
definitions: Array<{ | definitions: Array<{ | ||||
key: string; | key: string; | ||||
additionalColumns: Array<string>; | additionalColumns: Array<string>; | ||||
onEdit: (definitionKey: string) => void; | onEdit: (definitionKey: string) => void; | ||||
} | } | ||||
export default function AlmPRDecorationTable(props: AlmPRDecorationTableProps) { | |||||
const { additionalColumnsHeaders, alm, definitions } = props; | |||||
export default function AlmBindingDefinitionsTable(props: AlmBindingDefinitionsTableProps) { | |||||
const { additionalColumnsHeaders, additionalTableInfo, alm, definitions } = props; | |||||
return ( | return ( | ||||
<> | <> | ||||
<div className="spacer-top big-spacer-bottom display-flex-space-between"> | <div className="spacer-top big-spacer-bottom display-flex-space-between"> | ||||
<h4 className="display-inline"> | |||||
{translate( | |||||
'settings', | |||||
alm === ALM_KEYS.GITLAB ? 'mr_decoration' : 'pr_decoration', | |||||
'table.title' | |||||
)} | |||||
</h4> | |||||
<h2 className="settings-sub-category-name"> | |||||
{translate('settings.almintegration.table.title')} | |||||
</h2> | |||||
<Button data-test="settings__alm-create" onClick={props.onCreate}> | <Button data-test="settings__alm-create" onClick={props.onCreate}> | ||||
{translate('settings.pr_decoration.table.create')} | |||||
{translate('settings.almintegration.table.create')} | |||||
</Button> | </Button> | ||||
</div> | </div> | ||||
{additionalTableInfo} | |||||
<table className="data zebra fixed spacer-bottom"> | <table className="data zebra fixed spacer-bottom"> | ||||
<thead> | <thead> | ||||
<tr> | <tr> | ||||
<th>{translate('settings.pr_decoration.table.column.name')}</th> | |||||
<th>{translate('settings.almintegration.table.column.name')}</th> | |||||
{additionalColumnsHeaders.map(h => ( | {additionalColumnsHeaders.map(h => ( | ||||
<th key={h}>{h}</th> | <th key={h}>{h}</th> | ||||
))} | ))} | ||||
<th className="action-small text-center"> | <th className="action-small text-center"> | ||||
{translate('settings.pr_decoration.table.column.edit')} | |||||
{translate('settings.almintegration.table.column.edit')} | |||||
</th> | </th> | ||||
<th className="action text-center"> | <th className="action text-center"> | ||||
{translate('settings.pr_decoration.table.column.delete')} | |||||
{translate('settings.almintegration.table.column.delete')} | |||||
</th> | </th> | ||||
</tr> | </tr> | ||||
</thead> | </thead> | ||||
{definitions.length === 0 ? ( | {definitions.length === 0 ? ( | ||||
<tr data-test="settings__alm-empty-table"> | <tr data-test="settings__alm-empty-table"> | ||||
<td colSpan={3 + additionalColumnsHeaders.length}> | <td colSpan={3 + additionalColumnsHeaders.length}> | ||||
{translate('settings.pr_decoration.table.empty', alm)} | |||||
{translate('settings.almintegration.table.empty', alm)} | |||||
</td> | </td> | ||||
</tr> | </tr> | ||||
) : ( | ) : ( |
countBindedProjects, | countBindedProjects, | ||||
deleteConfiguration, | deleteConfiguration, | ||||
getAlmDefinitions | getAlmDefinitions | ||||
} from '../../../../api/almSettings'; | |||||
import { AlmSettingsBindingDefinitions, ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import PRDecorationTabs from './PRDecorationTabs'; | |||||
} from '../../../../api/alm-settings'; | |||||
import { withAppState } from '../../../../components/hoc/withAppState'; | |||||
import { AlmKeys, AlmSettingsBindingDefinitions } from '../../../../types/alm-settings'; | |||||
import AlmIntegrationRenderer from './AlmIntegrationRenderer'; | |||||
interface Props { | |||||
appState: Pick<T.AppState, 'branchesEnabled' | 'multipleAlmEnabled'>; | |||||
component?: T.Component; | |||||
} | |||||
interface State { | interface State { | ||||
currentAlm: ALM_KEYS; | |||||
currentAlm: AlmKeys; | |||||
definitionKeyForDeletion?: string; | definitionKeyForDeletion?: string; | ||||
definitions: AlmSettingsBindingDefinitions; | definitions: AlmSettingsBindingDefinitions; | ||||
loading: boolean; | loading: boolean; | ||||
projectCount?: number; | projectCount?: number; | ||||
} | } | ||||
export default class PullRequestDecoration extends React.PureComponent<{}, State> { | |||||
export class AlmIntegration extends React.PureComponent<Props, State> { | |||||
mounted = false; | mounted = false; | ||||
state: State = { | state: State = { | ||||
currentAlm: ALM_KEYS.GITHUB, | |||||
currentAlm: AlmKeys.GitHub, | |||||
definitions: { | definitions: { | ||||
[ALM_KEYS.AZURE]: [], | |||||
[ALM_KEYS.BITBUCKET]: [], | |||||
[ALM_KEYS.GITHUB]: [], | |||||
[ALM_KEYS.GITLAB]: [] | |||||
[AlmKeys.Azure]: [], | |||||
[AlmKeys.Bitbucket]: [], | |||||
[AlmKeys.GitHub]: [], | |||||
[AlmKeys.GitLab]: [] | |||||
}, | }, | ||||
loading: true | loading: true | ||||
}; | }; | ||||
}; | }; | ||||
fetchPullRequestDecorationSetting = () => { | fetchPullRequestDecorationSetting = () => { | ||||
const { | |||||
appState: { branchesEnabled } | |||||
} = this.props; | |||||
if (!branchesEnabled) { | |||||
return Promise.resolve(); | |||||
} | |||||
this.setState({ loading: true }); | this.setState({ loading: true }); | ||||
return getAlmDefinitions() | return getAlmDefinitions() | ||||
.then(definitions => { | .then(definitions => { | ||||
}); | }); | ||||
}; | }; | ||||
handleSelectAlm = (currentAlm: ALM_KEYS) => { | |||||
handleSelectAlm = (currentAlm: AlmKeys) => { | |||||
this.setState({ currentAlm }); | this.setState({ currentAlm }); | ||||
}; | }; | ||||
}; | }; | ||||
render() { | render() { | ||||
const { | |||||
appState: { branchesEnabled, multipleAlmEnabled }, | |||||
component | |||||
} = this.props; | |||||
return ( | return ( | ||||
<PRDecorationTabs | |||||
<AlmIntegrationRenderer | |||||
branchesEnabled={Boolean(branchesEnabled)} | |||||
component={component} | |||||
multipleAlmEnabled={Boolean(multipleAlmEnabled)} | |||||
onCancel={this.handleCancel} | onCancel={this.handleCancel} | ||||
onConfirmDelete={this.deleteConfiguration} | onConfirmDelete={this.deleteConfiguration} | ||||
onDelete={this.handleDelete} | onDelete={this.handleDelete} | ||||
); | ); | ||||
} | } | ||||
} | } | ||||
export default withAppState(AlmIntegration); |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 classNames from 'classnames'; | |||||
import * as React from 'react'; | |||||
import CheckIcon from 'sonar-ui-common/components/icons/CheckIcon'; | |||||
import ClearIcon from 'sonar-ui-common/components/icons/ClearIcon'; | |||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { colors } from '../../../../app/theme'; | |||||
export interface AlmIntegrationFeatureBoxProps { | |||||
active: boolean; | |||||
description: React.ReactNode; | |||||
inactiveReason?: React.ReactNode; | |||||
name: React.ReactNode; | |||||
} | |||||
export default function AlmIntegrationFeatureBox(props: AlmIntegrationFeatureBoxProps) { | |||||
const { active, description, inactiveReason, name } = props; | |||||
return ( | |||||
<div | |||||
className={classNames( | |||||
'boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered', | |||||
{ | |||||
'bg-muted': !active | |||||
} | |||||
)}> | |||||
{active ? ( | |||||
<CheckIcon className="little-spacer-top spacer-right" fill={colors.green} /> | |||||
) : ( | |||||
<ClearIcon className="little-spacer-top spacer-right" fill={colors.gray60} /> | |||||
)} | |||||
<div className="display-flex-column abs-height-100"> | |||||
<h4>{name}</h4> | |||||
<div className="spacer-top flex-1">{description}</div> | |||||
<div className="spacer-top"> | |||||
{active ? ( | |||||
<em className="text-success">{translate('settings.almintegration.feature.enabled')}</em> | |||||
) : ( | |||||
<em className="text-muted"> | |||||
{inactiveReason || translate('settings.almintegration.feature.disabled')} | |||||
</em> | |||||
)} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs'; | |||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||||
import { AlmKeys, AlmSettingsBindingDefinitions } from '../../../../types/alm-settings'; | |||||
import AzureTab from './AzureTab'; | |||||
import BitbucketTab from './BitbucketTab'; | |||||
import DeleteModal from './DeleteModal'; | |||||
import GithubTab from './GithubTab'; | |||||
import GitlabTab from './GitlabTab'; | |||||
export interface AlmIntegrationRendererProps { | |||||
branchesEnabled: boolean; | |||||
component?: T.Component; | |||||
currentAlm: AlmKeys; | |||||
definitionKeyForDeletion?: string; | |||||
definitions: AlmSettingsBindingDefinitions; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onCancel: () => void; | |||||
onConfirmDelete: (definitionKey: string) => void; | |||||
onDelete: (definitionKey: string) => void; | |||||
onSelectAlm: (alm: AlmKeys) => void; | |||||
onUpdateDefinitions: () => void; | |||||
projectCount?: number; | |||||
} | |||||
const tabs = [ | |||||
{ | |||||
key: AlmKeys.GitHub, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="github" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/github.svg`} | |||||
/> | |||||
GitHub | |||||
</> | |||||
) | |||||
}, | |||||
{ | |||||
key: AlmKeys.Bitbucket, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="bitbucket" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/bitbucket.svg`} | |||||
/> | |||||
Bitbucket Server | |||||
</> | |||||
), | |||||
requiresBranchesEnabled: true | |||||
}, | |||||
{ | |||||
key: AlmKeys.Azure, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="azure" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/azure.svg`} | |||||
/> | |||||
Azure DevOps Server | |||||
</> | |||||
), | |||||
requiresBranchesEnabled: true | |||||
}, | |||||
{ | |||||
key: AlmKeys.GitLab, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="gitlab" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/gitlab.svg`} | |||||
/> | |||||
GitLab | |||||
</> | |||||
) | |||||
} | |||||
]; | |||||
export default function AlmIntegrationRenderer(props: AlmIntegrationRendererProps) { | |||||
const { | |||||
component, | |||||
definitionKeyForDeletion, | |||||
definitions, | |||||
currentAlm, | |||||
loading, | |||||
branchesEnabled, | |||||
multipleAlmEnabled, | |||||
projectCount | |||||
} = props; | |||||
return ( | |||||
<> | |||||
<header className="page-header"> | |||||
<h1 className="page-title">{translate('settings.almintegration.title')}</h1> | |||||
</header> | |||||
<div className="markdown small spacer-top big-spacer-bottom"> | |||||
{translate('settings.almintegration.description')} | |||||
</div> | |||||
<BoxedTabs | |||||
onSelect={props.onSelectAlm} | |||||
selected={currentAlm} | |||||
tabs={tabs.filter(tab => !(tab.requiresBranchesEnabled && !branchesEnabled))} | |||||
/> | |||||
{currentAlm === AlmKeys.Azure && ( | |||||
<AzureTab | |||||
definitions={definitions.azure} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
{currentAlm === AlmKeys.Bitbucket && ( | |||||
<BitbucketTab | |||||
definitions={definitions.bitbucket} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
{currentAlm === AlmKeys.GitHub && ( | |||||
<GithubTab | |||||
branchesEnabled={branchesEnabled} | |||||
component={component} | |||||
definitions={definitions.github} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
{currentAlm === AlmKeys.GitLab && ( | |||||
<GitlabTab | |||||
branchesEnabled={branchesEnabled} | |||||
definitions={definitions.gitlab} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
{definitionKeyForDeletion && ( | |||||
<DeleteModal | |||||
id={definitionKeyForDeletion} | |||||
onCancel={props.onCancel} | |||||
onDelete={props.onConfirmDelete} | |||||
projectCount={projectCount} | |||||
/> | |||||
)} | |||||
</> | |||||
); | |||||
} |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import { AlmPRDecorationFormChildrenProps } from './AlmPRDecorationForm'; | |||||
import { AlmBindingDefinition, AlmKeys } from '../../../../types/alm-settings'; | |||||
import { AlmBindingDefinitionFormChildrenProps } from './AlmBindingDefinitionForm'; | |||||
import { AlmIntegrationFeatureBoxProps } from './AlmIntegrationFeatureBox'; | |||||
import AlmTabRenderer from './AlmTabRenderer'; | import AlmTabRenderer from './AlmTabRenderer'; | ||||
interface Props<B> { | interface Props<B> { | ||||
alm: ALM_KEYS; | |||||
alm: AlmKeys; | |||||
additionalColumnsHeaders?: string[]; | additionalColumnsHeaders?: string[]; | ||||
additionalColumnsKeys?: Array<keyof B>; | additionalColumnsKeys?: Array<keyof B>; | ||||
additionalTableInfo?: React.ReactNode; | |||||
createConfiguration: (data: B) => Promise<void>; | createConfiguration: (data: B) => Promise<void>; | ||||
defaultBinding: B; | defaultBinding: B; | ||||
definitions: B[]; | definitions: B[]; | ||||
form: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode; | |||||
features?: AlmIntegrationFeatureBoxProps[]; | |||||
form: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode; | |||||
help?: React.ReactNode; | |||||
loading: boolean; | loading: boolean; | ||||
multipleAlmEnabled: boolean; | multipleAlmEnabled: boolean; | ||||
onDelete: (definitionKey: string) => void; | onDelete: (definitionKey: string) => void; | ||||
success: boolean; | success: boolean; | ||||
} | } | ||||
export default class AlmTab<B extends AlmSettingsBinding> extends React.PureComponent< | |||||
export default class AlmTab<B extends AlmBindingDefinition> extends React.PureComponent< | |||||
Props<B>, | Props<B>, | ||||
State<B> | State<B> | ||||
> { | > { | ||||
const { | const { | ||||
additionalColumnsHeaders = [], | additionalColumnsHeaders = [], | ||||
additionalColumnsKeys = [], | additionalColumnsKeys = [], | ||||
additionalTableInfo, | |||||
alm, | alm, | ||||
defaultBinding, | defaultBinding, | ||||
definitions, | definitions, | ||||
features, | |||||
form, | form, | ||||
help, | |||||
loading, | loading, | ||||
multipleAlmEnabled | multipleAlmEnabled | ||||
} = this.props; | } = this.props; | ||||
<AlmTabRenderer | <AlmTabRenderer | ||||
additionalColumnsHeaders={additionalColumnsHeaders} | additionalColumnsHeaders={additionalColumnsHeaders} | ||||
additionalColumnsKeys={additionalColumnsKeys} | additionalColumnsKeys={additionalColumnsKeys} | ||||
additionalTableInfo={additionalTableInfo} | |||||
alm={alm} | alm={alm} | ||||
defaultBinding={defaultBinding} | defaultBinding={defaultBinding} | ||||
definitions={definitions} | definitions={definitions} | ||||
editedDefinition={editedDefinition} | editedDefinition={editedDefinition} | ||||
features={features} | |||||
form={form} | form={form} | ||||
help={help} | |||||
loading={loading || submitting} | loading={loading || submitting} | ||||
multipleAlmEnabled={multipleAlmEnabled} | multipleAlmEnabled={multipleAlmEnabled} | ||||
onCancel={this.handleCancel} | onCancel={this.handleCancel} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
import * as React from 'react'; | |||||
import { FormattedMessage } from 'react-intl'; | |||||
import { Link } from 'react-router'; | |||||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { AlmBindingDefinition, AlmKeys } from '../../../../types/alm-settings'; | |||||
import AlmBindingDefinitionForm, { | |||||
AlmBindingDefinitionFormChildrenProps | |||||
} from './AlmBindingDefinitionForm'; | |||||
import AlmBindingDefinitionsTable from './AlmBindingDefinitionsTable'; | |||||
import AlmIntegrationFeatureBox, { | |||||
AlmIntegrationFeatureBoxProps | |||||
} from './AlmIntegrationFeatureBox'; | |||||
export interface AlmTabRendererProps<B> { | |||||
additionalColumnsHeaders: string[]; | |||||
additionalColumnsKeys: Array<keyof B>; | |||||
additionalTableInfo?: React.ReactNode; | |||||
alm: AlmKeys; | |||||
editedDefinition?: B; | |||||
defaultBinding: B; | |||||
definitions: B[]; | |||||
features?: AlmIntegrationFeatureBoxProps[]; | |||||
form: (props: AlmBindingDefinitionFormChildrenProps<B>) => React.ReactNode; | |||||
help?: React.ReactNode; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onCancel: () => void; | |||||
onCreate: () => void; | |||||
onDelete: (definitionKey: string) => void; | |||||
onEdit: (definitionKey: string) => void; | |||||
onSubmit: (config: B, originalKey: string) => void; | |||||
success: boolean; | |||||
} | |||||
export default function AlmTabRenderer<B extends AlmBindingDefinition>( | |||||
props: AlmTabRendererProps<B> | |||||
) { | |||||
const { | |||||
additionalColumnsHeaders, | |||||
additionalColumnsKeys, | |||||
additionalTableInfo, | |||||
alm, | |||||
defaultBinding, | |||||
definitions, | |||||
editedDefinition, | |||||
features = [], | |||||
form, | |||||
loading, | |||||
multipleAlmEnabled, | |||||
success, | |||||
help = ( | |||||
<FormattedMessage | |||||
defaultMessage={translate(`settings.almintegration.${alm}.info`)} | |||||
id={`settings.almintegration.${alm}.info`} | |||||
values={{ | |||||
link: ( | |||||
<Link target="_blank" to="/documentation/analysis/pr-decoration/"> | |||||
{translate('learn_more')} | |||||
</Link> | |||||
) | |||||
}} | |||||
/> | |||||
) | |||||
} = props; | |||||
let definition: B | undefined; | |||||
let mappedDefinitions: Array<{ key: string; additionalColumns: string[] }> = []; | |||||
let showEdit: boolean | undefined; | |||||
if (!multipleAlmEnabled) { | |||||
definition = editedDefinition; | |||||
if (definition === undefined && definitions.length > 0) { | |||||
definition = definitions[0]; | |||||
} | |||||
showEdit = definition && editedDefinition === undefined; | |||||
} else { | |||||
mappedDefinitions = definitions.map(({ key, ...properties }) => { | |||||
const additionalColumns = additionalColumnsKeys.map(k => (properties as any)[k]); | |||||
return { | |||||
key, | |||||
additionalColumns | |||||
}; | |||||
}); | |||||
} | |||||
return ( | |||||
<div className="big-padded"> | |||||
{multipleAlmEnabled ? ( | |||||
<DeferredSpinner loading={loading}> | |||||
<AlmBindingDefinitionsTable | |||||
additionalColumnsHeaders={additionalColumnsHeaders} | |||||
additionalTableInfo={additionalTableInfo} | |||||
alm={alm} | |||||
definitions={mappedDefinitions} | |||||
onCreate={props.onCreate} | |||||
onDelete={props.onDelete} | |||||
onEdit={props.onEdit} | |||||
/> | |||||
{editedDefinition && ( | |||||
<AlmBindingDefinitionForm | |||||
bindingDefinition={editedDefinition} | |||||
help={help} | |||||
onCancel={props.onCancel} | |||||
onSubmit={props.onSubmit} | |||||
showInModal={true}> | |||||
{form} | |||||
</AlmBindingDefinitionForm> | |||||
)} | |||||
</DeferredSpinner> | |||||
) : ( | |||||
<AlmBindingDefinitionForm | |||||
bindingDefinition={definition || defaultBinding} | |||||
help={help} | |||||
hideKeyField={true} | |||||
loading={loading} | |||||
onCancel={props.onCancel} | |||||
onDelete={definition ? props.onDelete : undefined} | |||||
onEdit={showEdit ? props.onEdit : undefined} | |||||
onSubmit={props.onSubmit} | |||||
readOnly={showEdit} | |||||
success={success}> | |||||
{form} | |||||
</AlmBindingDefinitionForm> | |||||
)} | |||||
{features.length > 0 && ( | |||||
<div className="big-spacer-top big-padded-top bordered-top"> | |||||
<h3 className="big-spacer-bottom">{translate('settings.almintegration.features')}</h3> | |||||
<div className="display-flex-wrap"> | |||||
{features.map((feature, i) => ( | |||||
<AlmIntegrationFeatureBox key={i} {...feature} /> | |||||
))} | |||||
</div> | |||||
</div> | |||||
)} | |||||
</div> | |||||
); | |||||
} |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { AzureBindingDefinition } from '../../../../types/alm-settings'; | import { AzureBindingDefinition } from '../../../../types/alm-settings'; | ||||
import { AlmDefinitionFormField } from './AlmDefinitionFormField'; | |||||
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField'; | |||||
export interface AzureFormProps { | export interface AzureFormProps { | ||||
formData: AzureBindingDefinition; | formData: AzureBindingDefinition; | ||||
return ( | return ( | ||||
<> | <> | ||||
{!hideKeyField && ( | {!hideKeyField && ( | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help={translate('settings.pr_decoration.form.name.azure.help')} | |||||
help={translate('settings.almintegration.form.name.azure.help')} | |||||
id="name.azure" | id="name.azure" | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} | ||||
propKey="key" | propKey="key" | ||||
value={formData.key} | value={formData.key} | ||||
/> | /> | ||||
)} | )} | ||||
<AlmDefinitionFormField | |||||
help={translate('settings.pr_decoration.form.personal_access_token.azure.help')} | |||||
<AlmBindingDefinitionFormField | |||||
help={translate('settings.almintegration.form.personal_access_token.azure.help')} | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { createAzureConfiguration, updateAzureConfiguration } from '../../../../api/almSettings'; | |||||
import { ALM_KEYS, AzureBindingDefinition } from '../../../../types/alm-settings'; | |||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { createAzureConfiguration, updateAzureConfiguration } from '../../../../api/alm-settings'; | |||||
import { AlmKeys, AzureBindingDefinition } from '../../../../types/alm-settings'; | |||||
import AlmTab from './AlmTab'; | import AlmTab from './AlmTab'; | ||||
import AzureForm from './AzureForm'; | import AzureForm from './AzureForm'; | ||||
const { multipleAlmEnabled, definitions, loading } = props; | const { multipleAlmEnabled, definitions, loading } = props; | ||||
return ( | return ( | ||||
<AlmTab | |||||
alm={ALM_KEYS.AZURE} | |||||
createConfiguration={createAzureConfiguration} | |||||
defaultBinding={{ key: '', personalAccessToken: '' }} | |||||
definitions={definitions} | |||||
form={childProps => <AzureForm {...childProps} />} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateAzureConfiguration} | |||||
/> | |||||
<div className="bordered"> | |||||
<AlmTab | |||||
alm={AlmKeys.Azure} | |||||
createConfiguration={createAzureConfiguration} | |||||
defaultBinding={{ key: '', personalAccessToken: '' }} | |||||
definitions={definitions} | |||||
features={[ | |||||
{ | |||||
name: translate('settings.almintegration.feature.pr_decoration.title'), | |||||
active: definitions.length > 0, | |||||
description: translate('settings.almintegration.feature.pr_decoration.description'), | |||||
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding') | |||||
} | |||||
]} | |||||
form={childProps => <AzureForm {...childProps} />} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateAzureConfiguration} | |||||
/> | |||||
</div> | |||||
); | ); | ||||
} | } |
import { FormattedMessage } from 'react-intl'; | import { FormattedMessage } from 'react-intl'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { BitbucketBindingDefinition } from '../../../../types/alm-settings'; | import { BitbucketBindingDefinition } from '../../../../types/alm-settings'; | ||||
import { AlmDefinitionFormField } from './AlmDefinitionFormField'; | |||||
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField'; | |||||
export interface BitbucketFormProps { | export interface BitbucketFormProps { | ||||
formData: BitbucketBindingDefinition; | formData: BitbucketBindingDefinition; | ||||
return ( | return ( | ||||
<> | <> | ||||
{!hideKeyField && ( | {!hideKeyField && ( | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help={translate('settings.pr_decoration.form.name.bitbucket.help')} | |||||
help={translate('settings.almintegration.form.name.bitbucket.help')} | |||||
id="name.bitbucket" | id="name.bitbucket" | ||||
maxLength={100} | maxLength={100} | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} | ||||
value={formData.key} | value={formData.key} | ||||
/> | /> | ||||
)} | )} | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
help={ | help={ | ||||
<FormattedMessage | <FormattedMessage | ||||
defaultMessage={translate('settings.pr_decoration.form.url.bitbucket.help')} | |||||
id="settings.pr_decoration.form.url.bitbucket.help" | |||||
defaultMessage={translate('settings.almintegration.form.url.bitbucket.help')} | |||||
id="settings.almintegration.form.url.bitbucket.help" | |||||
values={{ example: 'https://bitbucket-server.your-company.com' }} | values={{ example: 'https://bitbucket-server.your-company.com' }} | ||||
/> | /> | ||||
} | } | ||||
readOnly={readOnly} | readOnly={readOnly} | ||||
value={formData.url} | value={formData.url} | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
import * as React from 'react'; | |||||
import { FormattedMessage } from 'react-intl'; | |||||
import { Link } from 'react-router'; | |||||
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | |||||
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; | |||||
import { | |||||
createBitbucketConfiguration, | |||||
updateBitbucketConfiguration | |||||
} from '../../../../api/alm-settings'; | |||||
import { AlmKeys, BitbucketBindingDefinition } from '../../../../types/alm-settings'; | |||||
import AlmTab from './AlmTab'; | |||||
import BitbucketForm from './BitbucketForm'; | |||||
export interface BitbucketTabProps { | |||||
definitions: BitbucketBindingDefinition[]; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onDelete: (definitionKey: string) => void; | |||||
onUpdateDefinitions: () => void; | |||||
} | |||||
export default function BitbucketTab(props: BitbucketTabProps) { | |||||
const { multipleAlmEnabled, definitions, loading } = props; | |||||
return ( | |||||
<div className="bordered"> | |||||
<AlmTab | |||||
additionalColumnsHeaders={[translate('settings.almintegration.table.column.bitbucket.url')]} | |||||
additionalColumnsKeys={['url']} | |||||
additionalTableInfo={ | |||||
<Alert className="big-spacer-bottom width-50" variant="info"> | |||||
<FormattedMessage | |||||
defaultMessage={translate( | |||||
'settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances' | |||||
)} | |||||
id="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances" | |||||
values={{ | |||||
feature: ( | |||||
<em>{translate('settings.almintegration.feature.alm_repo_import.title')}</em> | |||||
) | |||||
}} | |||||
/> | |||||
</Alert> | |||||
} | |||||
alm={AlmKeys.Bitbucket} | |||||
createConfiguration={createBitbucketConfiguration} | |||||
defaultBinding={{ key: '', url: '', personalAccessToken: '' }} | |||||
definitions={definitions} | |||||
features={[ | |||||
{ | |||||
name: translate('settings.almintegration.feature.pr_decoration.title'), | |||||
active: definitions.length > 0, | |||||
description: translate('settings.almintegration.feature.pr_decoration.description'), | |||||
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding') | |||||
}, | |||||
{ | |||||
name: translate('settings.almintegration.feature.alm_repo_import.title'), | |||||
active: definitions.length === 1, | |||||
description: translate('settings.almintegration.feature.alm_repo_import.description'), | |||||
inactiveReason: translateWithParameters( | |||||
'onboarding.create_project.too_many_bbs_instances_X', | |||||
definitions.length | |||||
) | |||||
} | |||||
]} | |||||
form={childProps => <BitbucketForm {...childProps} />} | |||||
help={ | |||||
<> | |||||
<h3>{translate('onboarding.create_project.pat_help.title')}</h3> | |||||
<p className="big-spacer-top"> | |||||
{translate('settings.almintegration.bitbucket.help_1')} | |||||
</p> | |||||
<ul className="big-spacer-top list-styled"> | |||||
<li>{translate('settings.almintegration.bitbucket.help_2')}</li> | |||||
<li>{translate('settings.almintegration.bitbucket.help_3')}</li> | |||||
</ul> | |||||
<p className="big-spacer-top big-spacer-bottom"> | |||||
<Link target="_blank" to="/documentation/analysis/pr-decoration/"> | |||||
{translate('learn_more')} | |||||
</Link> | |||||
</p> | |||||
</> | |||||
} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateBitbucketConfiguration} | |||||
/> | |||||
</div> | |||||
); | |||||
} |
function showProjectCountWarning(projectCount?: number) { | function showProjectCountWarning(projectCount?: number) { | ||||
if (projectCount === undefined) { | if (projectCount === undefined) { | ||||
return <p>{translate('settings.pr_decoration.delete.no_info')}</p>; | |||||
return <p>{translate('settings.almintegration.delete.no_info')}</p>; | |||||
} | } | ||||
return projectCount ? ( | return projectCount ? ( | ||||
<p>{translateWithParameters('settings.pr_decoration.delete.info', projectCount)} </p> | |||||
<p>{translateWithParameters('settings.almintegration.delete.info', projectCount)} </p> | |||||
) : null; | ) : null; | ||||
} | } | ||||
<ConfirmModal | <ConfirmModal | ||||
confirmButtonText={translate('delete')} | confirmButtonText={translate('delete')} | ||||
confirmData={id} | confirmData={id} | ||||
header={translate('settings.pr_decoration.delete.header')} | |||||
header={translate('settings.almintegration.delete.header')} | |||||
isDestructive={true} | isDestructive={true} | ||||
onClose={onCancel} | onClose={onCancel} | ||||
onConfirm={onDelete}> | onConfirm={onDelete}> | ||||
<> | <> | ||||
<p className="spacer-bottom"> | <p className="spacer-bottom"> | ||||
<FormattedMessage | <FormattedMessage | ||||
defaultMessage={translate('settings.pr_decoration.delete.message')} | |||||
id="settings.pr_decoration.delete.message" | |||||
defaultMessage={translate('settings.almintegration.delete.message')} | |||||
id="settings.almintegration.delete.message" | |||||
values={{ id: <b>{id}</b> }} | values={{ id: <b>{id}</b> }} | ||||
/> | /> | ||||
</p> | </p> |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { GithubBindingDefinition } from '../../../../types/alm-settings'; | import { GithubBindingDefinition } from '../../../../types/alm-settings'; | ||||
import { AlmDefinitionFormField } from './AlmDefinitionFormField'; | |||||
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField'; | |||||
export interface GithubFormProps { | export interface GithubFormProps { | ||||
formData: GithubBindingDefinition; | formData: GithubBindingDefinition; | ||||
return ( | return ( | ||||
<> | <> | ||||
{!hideKeyField && ( | {!hideKeyField && ( | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help={translate('settings.pr_decoration.form.name.github.help')} | |||||
help={translate('settings.almintegration.form.name.github.help')} | |||||
id="name.github" | id="name.github" | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} | ||||
propKey="key" | propKey="key" | ||||
value={formData.key} | value={formData.key} | ||||
/> | /> | ||||
)} | )} | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
help={ | help={ | ||||
<> | <> | ||||
{translate('settings.pr_decoration.form.url.github.help1')} | |||||
{translate('settings.almintegration.form.url.github.help1')} | |||||
<br /> | <br /> | ||||
<em>https://github.company.com/api/v3</em> | <em>https://github.company.com/api/v3</em> | ||||
<br /> | <br /> | ||||
<br /> | <br /> | ||||
{translate('settings.pr_decoration.form.url.github.help2')} | |||||
{translate('settings.almintegration.form.url.github.help2')} | |||||
<br /> | <br /> | ||||
<em>https://api.github.com/</em> | <em>https://api.github.com/</em> | ||||
</> | </> | ||||
readOnly={readOnly} | readOnly={readOnly} | ||||
value={formData.url} | value={formData.url} | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="app_id" | id="app_id" | ||||
maxLength={80} | maxLength={80} | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} | ||||
readOnly={readOnly} | readOnly={readOnly} | ||||
value={formData.appId} | value={formData.appId} | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="private_key" | id="private_key" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { createGithubConfiguration, updateGithubConfiguration } from '../../../../api/alm-settings'; | |||||
import { AlmKeys, GithubBindingDefinition } from '../../../../types/alm-settings'; | |||||
import { ALM_INTEGRATION } from '../AdditionalCategoryKeys'; | |||||
import CategoryDefinitionsList from '../CategoryDefinitionsList'; | |||||
import AlmTab from './AlmTab'; | |||||
import GithubForm from './GithubForm'; | |||||
export interface GithubTabProps { | |||||
branchesEnabled: boolean; | |||||
component?: T.Component; | |||||
definitions: GithubBindingDefinition[]; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onDelete: (definitionKey: string) => void; | |||||
onUpdateDefinitions: () => void; | |||||
} | |||||
export default function GithubTab(props: GithubTabProps) { | |||||
const { branchesEnabled, component, multipleAlmEnabled, definitions, loading } = props; | |||||
return ( | |||||
<div className="bordered"> | |||||
{branchesEnabled && ( | |||||
<> | |||||
<AlmTab | |||||
additionalColumnsHeaders={[ | |||||
translate('settings.almintegration.table.column.github.url'), | |||||
translate('settings.almintegration.table.column.app_id') | |||||
]} | |||||
additionalColumnsKeys={['appId', 'url']} | |||||
alm={AlmKeys.GitHub} | |||||
createConfiguration={createGithubConfiguration} | |||||
defaultBinding={{ key: '', appId: '', url: '', privateKey: '' }} | |||||
definitions={definitions} | |||||
features={[ | |||||
{ | |||||
name: translate('settings.almintegration.feature.pr_decoration.title'), | |||||
active: definitions.length > 0, | |||||
description: translate('settings.almintegration.feature.pr_decoration.description'), | |||||
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding') | |||||
} | |||||
]} | |||||
form={childProps => <GithubForm {...childProps} />} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateGithubConfiguration} | |||||
/> | |||||
<div className="huge-spacer-top huge-spacer-bottom bordered-top" /> | |||||
</> | |||||
)} | |||||
<div className="big-padded"> | |||||
<CategoryDefinitionsList | |||||
category={ALM_INTEGRATION} | |||||
component={component} | |||||
subCategory={AlmKeys.GitHub} | |||||
/> | |||||
</div> | |||||
</div> | |||||
); | |||||
} |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { GitlabBindingDefinition } from '../../../../types/alm-settings'; | import { GitlabBindingDefinition } from '../../../../types/alm-settings'; | ||||
import { AlmDefinitionFormField } from './AlmDefinitionFormField'; | |||||
import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField'; | |||||
export interface GitlabFormProps { | export interface GitlabFormProps { | ||||
formData: GitlabBindingDefinition; | formData: GitlabBindingDefinition; | ||||
return ( | return ( | ||||
<> | <> | ||||
{!hideKeyField && ( | {!hideKeyField && ( | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help={translate('settings.pr_decoration.form.name.gitlab.help')} | |||||
help={translate('settings.almintegration.form.name.gitlab.help')} | |||||
id="name.gitlab" | id="name.gitlab" | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} | ||||
propKey="key" | propKey="key" | ||||
value={formData.key} | value={formData.key} | ||||
/> | /> | ||||
)} | )} | ||||
<AlmDefinitionFormField | |||||
help={translate('settings.pr_decoration.form.personal_access_token.gitlab.help')} | |||||
<AlmBindingDefinitionFormField | |||||
help={translate('settings.almintegration.form.personal_access_token.gitlab.help')} | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={onFieldChange} | onFieldChange={onFieldChange} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { createGitlabConfiguration, updateGitlabConfiguration } from '../../../../api/alm-settings'; | |||||
import { AlmKeys, GitlabBindingDefinition } from '../../../../types/alm-settings'; | |||||
import { ALM_INTEGRATION } from '../AdditionalCategoryKeys'; | |||||
import CategoryDefinitionsList from '../CategoryDefinitionsList'; | |||||
import AlmTab from './AlmTab'; | |||||
import GitlabForm from './GitlabForm'; | |||||
export interface GitlabTabProps { | |||||
branchesEnabled: boolean; | |||||
component?: T.Component; | |||||
definitions: GitlabBindingDefinition[]; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onDelete: (definitionKey: string) => void; | |||||
onUpdateDefinitions: () => void; | |||||
} | |||||
export default function GitlabTab(props: GitlabTabProps) { | |||||
const { branchesEnabled, component, multipleAlmEnabled, definitions, loading } = props; | |||||
return ( | |||||
<div className="bordered"> | |||||
{branchesEnabled && ( | |||||
<> | |||||
<AlmTab | |||||
alm={AlmKeys.GitLab} | |||||
createConfiguration={createGitlabConfiguration} | |||||
defaultBinding={{ key: '', personalAccessToken: '' }} | |||||
definitions={definitions} | |||||
features={[ | |||||
{ | |||||
name: translate('settings.almintegration.feature.mr_decoration.title'), | |||||
active: definitions.length > 0, | |||||
description: translate('settings.almintegration.feature.mr_decoration.description'), | |||||
inactiveReason: translate('settings.almintegration.feature.need_at_least_1_binding') | |||||
} | |||||
]} | |||||
form={childProps => <GitlabForm {...childProps} />} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateGitlabConfiguration} | |||||
/> | |||||
<div className="huge-spacer-top huge-spacer-bottom bordered-top" /> | |||||
</> | |||||
)} | |||||
<div className="big-padded"> | |||||
<CategoryDefinitionsList | |||||
category={ALM_INTEGRATION} | |||||
component={component} | |||||
subCategory={AlmKeys.GitLab} | |||||
/> | |||||
</div> | |||||
</div> | |||||
); | |||||
} |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | ||||
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | ||||
import { ALM_KEYS, GithubBindingDefinition } from '../../../../../types/alm-settings'; | |||||
import AlmPRDecorationForm from '../AlmPRDecorationForm'; | |||||
import { GithubBindingDefinition } from '../../../../../types/alm-settings'; | |||||
import AlmBindingDefinitionForm from '../AlmBindingDefinitionForm'; | |||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender()).toMatchSnapshot(); | expect(shallowRender()).toMatchSnapshot(); | ||||
expect(wrapper.instance().canSubmit()).toBe(true); | expect(wrapper.instance().canSubmit()).toBe(true); | ||||
}); | }); | ||||
function shallowRender(props: Partial<AlmPRDecorationForm<GithubBindingDefinition>['props']> = {}) { | |||||
return shallow<AlmPRDecorationForm<GithubBindingDefinition>>( | |||||
<AlmPRDecorationForm | |||||
alm={ALM_KEYS.GITHUB} | |||||
function shallowRender( | |||||
props: Partial<AlmBindingDefinitionForm<GithubBindingDefinition>['props']> = {} | |||||
) { | |||||
return shallow<AlmBindingDefinitionForm<GithubBindingDefinition>>( | |||||
<AlmBindingDefinitionForm | |||||
bindingDefinition={{ appId: '', key: '', privateKey: '', url: '' }} | bindingDefinition={{ appId: '', key: '', privateKey: '', url: '' }} | ||||
onCancel={jest.fn()} | onCancel={jest.fn()} | ||||
onSubmit={jest.fn()} | onSubmit={jest.fn()} | ||||
{...props}> | {...props}> | ||||
{() => null} | {() => null} | ||||
</AlmPRDecorationForm> | |||||
</AlmBindingDefinitionForm> | |||||
); | ); | ||||
} | } |
*/ | */ | ||||
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { AlmSettingsBinding } from '../../../../../types/alm-settings'; | |||||
import { AlmDefinitionFormField, AlmDefinitionFormFieldProps } from '../AlmDefinitionFormField'; | |||||
import { AlmBindingDefinition } from '../../../../../types/alm-settings'; | |||||
import { | |||||
AlmBindingDefinitionFormField, | |||||
AlmBindingDefinitionFormFieldProps | |||||
} from '../AlmBindingDefinitionFormField'; | |||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender()).toMatchSnapshot(); | expect(shallowRender()).toMatchSnapshot(); | ||||
expect(onTextAreaChange).toBeCalled(); | expect(onTextAreaChange).toBeCalled(); | ||||
}); | }); | ||||
function shallowRender(props: Partial<AlmDefinitionFormFieldProps<AlmSettingsBinding>> = {}) { | |||||
function shallowRender( | |||||
props: Partial<AlmBindingDefinitionFormFieldProps<AlmBindingDefinition>> = {} | |||||
) { | |||||
return shallow( | return shallow( | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="key" | id="key" | ||||
isTextArea={false} | isTextArea={false} | ||||
maxLength={40} | maxLength={40} |
*/ | */ | ||||
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { ALM_KEYS } from '../../../../../types/alm-settings'; | |||||
import AlmPRDecorationFormModalRenderer, { | |||||
AlmPRDecorationFormModalProps | |||||
} from '../AlmPRDecorationFormModalRenderer'; | |||||
import AlmBindingDefinitionFormModalRenderer, { | |||||
AlmBindingDefinitionFormModalProps | |||||
} from '../AlmBindingDefinitionFormModalRenderer'; | |||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender().dive()).toMatchSnapshot(); | expect(shallowRender().dive()).toMatchSnapshot(); | ||||
expect(shallowRender({ help: <span>Help me</span> }).dive()).toMatchSnapshot(); | expect(shallowRender({ help: <span>Help me</span> }).dive()).toMatchSnapshot(); | ||||
}); | }); | ||||
function shallowRender(props: Partial<AlmPRDecorationFormModalProps> = {}) { | |||||
function shallowRender(props: Partial<AlmBindingDefinitionFormModalProps> = {}) { | |||||
return shallow( | return shallow( | ||||
<AlmPRDecorationFormModalRenderer | |||||
<AlmBindingDefinitionFormModalRenderer | |||||
action="create" | action="create" | ||||
alm={ALM_KEYS.GITHUB} | |||||
canSubmit={jest.fn()} | canSubmit={jest.fn()} | ||||
onCancel={jest.fn()} | onCancel={jest.fn()} | ||||
onSubmit={jest.fn()} | onSubmit={jest.fn()} | ||||
{...props}> | {...props}> | ||||
{() => null} | {() => null} | ||||
</AlmPRDecorationFormModalRenderer> | |||||
</AlmBindingDefinitionFormModalRenderer> | |||||
); | ); | ||||
} | } |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | import { SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | ||||
import { submit } from 'sonar-ui-common/helpers/testUtils'; | import { submit } from 'sonar-ui-common/helpers/testUtils'; | ||||
import AlmPRDecorationFormRenderer, { | |||||
AlmPRDecorationFormRendererProps | |||||
} from '../AlmPRDecorationFormRenderer'; | |||||
import AlmBindingDefinitionFormRenderer, { | |||||
AlmBindingDefinitionFormRendererProps | |||||
} from '../AlmBindingDefinitionFormRenderer'; | |||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender()).toMatchSnapshot(); | expect(shallowRender()).toMatchSnapshot(); | ||||
expect(onSubmit).toBeCalled(); | expect(onSubmit).toBeCalled(); | ||||
}); | }); | ||||
function shallowRender(props: Partial<AlmPRDecorationFormRendererProps> = {}) { | |||||
function shallowRender(props: Partial<AlmBindingDefinitionFormRendererProps> = {}) { | |||||
return shallow( | return shallow( | ||||
<AlmPRDecorationFormRenderer | |||||
<AlmBindingDefinitionFormRenderer | |||||
canSubmit={jest.fn()} | canSubmit={jest.fn()} | ||||
loading={false} | loading={false} | ||||
onSubmit={jest.fn()} | onSubmit={jest.fn()} | ||||
success={false} | success={false} | ||||
{...props}> | {...props}> | ||||
{() => null} | {() => null} | ||||
</AlmPRDecorationFormRenderer> | |||||
</AlmBindingDefinitionFormRenderer> | |||||
); | ); | ||||
} | } |
*/ | */ | ||||
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { ALM_KEYS } from '../../../../../types/alm-settings'; | |||||
import AlmPRDecorationTable, { AlmPRDecorationTableProps } from '../AlmPRDecorationTable'; | |||||
import { AlmKeys } from '../../../../../types/alm-settings'; | |||||
import AlmBindingDefinitionsTable, { | |||||
AlmBindingDefinitionsTableProps | |||||
} from '../AlmBindingDefinitionsTable'; | |||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender()).toMatchSnapshot(); | expect(shallowRender()).toMatchSnapshot(); | ||||
expect( | expect( | ||||
shallowRender({ | shallowRender({ | ||||
additionalColumnsHeaders: ['additional1', 'additional2'], | additionalColumnsHeaders: ['additional1', 'additional2'], | ||||
alm: ALM_KEYS.GITHUB, | |||||
alm: AlmKeys.GitHub, | |||||
definitions: [ | definitions: [ | ||||
{ key: 'definition1', additionalColumns: ['def1-v1', 'def1-v2'] }, | { key: 'definition1', additionalColumns: ['def1-v1', 'def1-v2'] }, | ||||
{ key: 'definition2', additionalColumns: ['def2-v1', 'def2-v2'] } | { key: 'definition2', additionalColumns: ['def2-v1', 'def2-v2'] } | ||||
] | ] | ||||
}) | }) | ||||
).toMatchSnapshot('additional columns'); | ).toMatchSnapshot('additional columns'); | ||||
expect(shallowRender({ alm: ALM_KEYS.GITHUB })).toMatchSnapshot('title adjusts for GitLab'); | |||||
expect(shallowRender({ alm: AlmKeys.GitLab })).toMatchSnapshot('title adjusts for GitLab'); | |||||
}); | }); | ||||
it('should correctly trigger create, delete, and edit', () => { | it('should correctly trigger create, delete, and edit', () => { | ||||
const wrapper = shallowRender({ | const wrapper = shallowRender({ | ||||
additionalColumnsHeaders: [], | additionalColumnsHeaders: [], | ||||
alm: ALM_KEYS.BITBUCKET, | |||||
alm: AlmKeys.Bitbucket, | |||||
definitions: [{ key: 'defKey', additionalColumns: [] }], | definitions: [{ key: 'defKey', additionalColumns: [] }], | ||||
onCreate, | onCreate, | ||||
onDelete, | onDelete, | ||||
expect(onEdit).toBeCalledWith('defKey'); | expect(onEdit).toBeCalledWith('defKey'); | ||||
}); | }); | ||||
function shallowRender(props: Partial<AlmPRDecorationTableProps> = {}) { | |||||
function shallowRender(props: Partial<AlmBindingDefinitionsTableProps> = {}) { | |||||
return shallow( | return shallow( | ||||
<AlmPRDecorationTable | |||||
<AlmBindingDefinitionsTable | |||||
additionalColumnsHeaders={[]} | additionalColumnsHeaders={[]} | ||||
alm={ALM_KEYS.AZURE} | |||||
alm={AlmKeys.Azure} | |||||
definitions={[]} | definitions={[]} | ||||
onCreate={jest.fn()} | onCreate={jest.fn()} | ||||
onDelete={jest.fn()} | onDelete={jest.fn()} |
countBindedProjects, | countBindedProjects, | ||||
deleteConfiguration, | deleteConfiguration, | ||||
getAlmDefinitions | getAlmDefinitions | ||||
} from '../../../../../api/almSettings'; | |||||
import { ALM_KEYS } from '../../../../../types/alm-settings'; | |||||
import PullRequestDecoration from '../PullRequestDecoration'; | |||||
} from '../../../../../api/alm-settings'; | |||||
import { AlmKeys } from '../../../../../types/alm-settings'; | |||||
import { AlmIntegration } from '../AlmIntegration'; | |||||
jest.mock('../../../../../api/almSettings', () => ({ | |||||
jest.mock('../../../../../api/alm-settings', () => ({ | |||||
countBindedProjects: jest.fn().mockResolvedValue(0), | countBindedProjects: jest.fn().mockResolvedValue(0), | ||||
deleteConfiguration: jest.fn().mockResolvedValue(undefined), | deleteConfiguration: jest.fn().mockResolvedValue(undefined), | ||||
getAlmDefinitions: jest.fn().mockResolvedValue({ github: [] }) | getAlmDefinitions: jest.fn().mockResolvedValue({ github: [] }) | ||||
it('should handle alm selection', async () => { | it('should handle alm selection', async () => { | ||||
const wrapper = shallowRender(); | const wrapper = shallowRender(); | ||||
wrapper.setState({ currentAlm: ALM_KEYS.AZURE }); | |||||
wrapper.setState({ currentAlm: AlmKeys.Azure }); | |||||
wrapper.instance().handleSelectAlm(ALM_KEYS.GITHUB); | |||||
wrapper.instance().handleSelectAlm(AlmKeys.GitHub); | |||||
await waitAndUpdate(wrapper); | await waitAndUpdate(wrapper); | ||||
expect(wrapper.state().currentAlm).toBe(ALM_KEYS.GITHUB); | |||||
expect(wrapper.state().currentAlm).toBe(AlmKeys.GitHub); | |||||
}); | }); | ||||
it('should handle delete', async () => { | it('should handle delete', async () => { | ||||
}); | }); | ||||
function shallowRender() { | function shallowRender() { | ||||
return shallow<PullRequestDecoration>(<PullRequestDecoration />); | |||||
return shallow<AlmIntegration>(<AlmIntegration appState={{ branchesEnabled: true }} />); | |||||
} | } |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 AlmIntegrationFeatureBox, { | |||||
AlmIntegrationFeatureBoxProps | |||||
} from '../AlmIntegrationFeatureBox'; | |||||
it('should render correctly', () => { | |||||
expect(shallowRender()).toMatchSnapshot('default'); | |||||
expect(shallowRender({ active: false })).toMatchSnapshot('inactive'); | |||||
expect(shallowRender({ active: false, inactiveReason: "Bar is foo'd" })).toMatchSnapshot( | |||||
'inactive, with reason' | |||||
); | |||||
}); | |||||
function shallowRender(props: Partial<AlmIntegrationFeatureBoxProps> = {}) { | |||||
return shallow<AlmIntegrationFeatureBoxProps>( | |||||
<AlmIntegrationFeatureBox active={true} description="Foo bar..." name="Foo" {...props} /> | |||||
); | |||||
} |
*/ | */ | ||||
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { ALM_KEYS } from '../../../../../types/alm-settings'; | |||||
import { PRDecorationTabs, PRDecorationTabsProps } from '../PRDecorationTabs'; | |||||
import { AlmKeys } from '../../../../../types/alm-settings'; | |||||
import AlmIntegrationRenderer, { AlmIntegrationRendererProps } from '../AlmIntegrationRenderer'; | |||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender({ loading: true })).toMatchSnapshot(); | |||||
expect(shallowRender({ definitionKeyForDeletion: 'keyToDelete' })).toMatchSnapshot(); | |||||
expect(shallowRender({ currentAlm: ALM_KEYS.AZURE })).toMatchSnapshot(); | |||||
expect(shallowRender({ currentAlm: ALM_KEYS.BITBUCKET })).toMatchSnapshot(); | |||||
expect(shallowRender({ currentAlm: ALM_KEYS.GITLAB })).toMatchSnapshot(); | |||||
expect(shallowRender()).toMatchSnapshot('default'); | |||||
expect(shallowRender({ loading: true })).toMatchSnapshot('loading'); | |||||
expect(shallowRender({ definitionKeyForDeletion: 'keyToDelete' })).toMatchSnapshot( | |||||
'delete modal' | |||||
); | |||||
expect(shallowRender({ currentAlm: AlmKeys.Azure })).toMatchSnapshot('azure'); | |||||
expect(shallowRender({ currentAlm: AlmKeys.Bitbucket })).toMatchSnapshot('bitbucket'); | |||||
expect(shallowRender({ currentAlm: AlmKeys.GitLab })).toMatchSnapshot('gitlab'); | |||||
}); | }); | ||||
function shallowRender(props: Partial<PRDecorationTabsProps> = {}) { | |||||
function shallowRender(props: Partial<AlmIntegrationRendererProps> = {}) { | |||||
return shallow( | return shallow( | ||||
<PRDecorationTabs | |||||
appState={{ multipleAlmEnabled: false }} | |||||
currentAlm={ALM_KEYS.GITHUB} | |||||
<AlmIntegrationRenderer | |||||
branchesEnabled={true} | |||||
currentAlm={AlmKeys.GitHub} | |||||
definitions={{ azure: [], bitbucket: [], github: [], gitlab: [] }} | definitions={{ azure: [], bitbucket: [], github: [], gitlab: [] }} | ||||
loading={false} | loading={false} | ||||
multipleAlmEnabled={false} | |||||
onCancel={jest.fn()} | onCancel={jest.fn()} | ||||
onConfirmDelete={jest.fn()} | onConfirmDelete={jest.fn()} | ||||
onDelete={jest.fn()} | onDelete={jest.fn()} |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | ||||
import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings'; | import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings'; | ||||
import { ALM_KEYS, AzureBindingDefinition } from '../../../../../types/alm-settings'; | |||||
import { AlmKeys, AzureBindingDefinition } from '../../../../../types/alm-settings'; | |||||
import AlmTab from '../AlmTab'; | import AlmTab from '../AlmTab'; | ||||
const DEFAULT_BINDING = { | const DEFAULT_BINDING = { | ||||
function shallowRender(props: Partial<AlmTab<AzureBindingDefinition>['props']> = {}) { | function shallowRender(props: Partial<AlmTab<AzureBindingDefinition>['props']> = {}) { | ||||
return shallow<AlmTab<AzureBindingDefinition>>( | return shallow<AlmTab<AzureBindingDefinition>>( | ||||
<AlmTab | <AlmTab | ||||
alm={ALM_KEYS.AZURE} | |||||
alm={AlmKeys.Azure} | |||||
createConfiguration={jest.fn()} | createConfiguration={jest.fn()} | ||||
defaultBinding={DEFAULT_BINDING} | defaultBinding={DEFAULT_BINDING} | ||||
definitions={[mockAzureDefinition()]} | definitions={[mockAzureDefinition()]} |
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | ||||
import { ALM_KEYS, GithubBindingDefinition } from '../../../../../types/alm-settings'; | |||||
import { AlmKeys, GithubBindingDefinition } from '../../../../../types/alm-settings'; | |||||
import AlmTabRenderer, { AlmTabRendererProps } from '../AlmTabRenderer'; | import AlmTabRenderer, { AlmTabRendererProps } from '../AlmTabRenderer'; | ||||
it('should render correctly for multi-ALM binding', () => { | it('should render correctly for multi-ALM binding', () => { | ||||
expect(shallowRender({ editedDefinition: mockGithubDefinition() })).toMatchSnapshot( | expect(shallowRender({ editedDefinition: mockGithubDefinition() })).toMatchSnapshot( | ||||
'editing a definition' | 'editing a definition' | ||||
); | ); | ||||
expect( | |||||
shallowRender({ | |||||
features: [ | |||||
{ | |||||
active: true, | |||||
name: 'Foo', | |||||
description: 'Bar' | |||||
}, | |||||
{ | |||||
active: false, | |||||
name: 'Baz', | |||||
description: 'Bim' | |||||
} | |||||
] | |||||
}) | |||||
).toMatchSnapshot('with features'); | |||||
}); | }); | ||||
it('should render correctly for single-ALM binding', () => { | it('should render correctly for single-ALM binding', () => { | ||||
<AlmTabRenderer | <AlmTabRenderer | ||||
additionalColumnsHeaders={['url', 'app_id']} | additionalColumnsHeaders={['url', 'app_id']} | ||||
additionalColumnsKeys={['url', 'appId']} | additionalColumnsKeys={['url', 'appId']} | ||||
alm={ALM_KEYS.GITHUB} | |||||
alm={AlmKeys.GitHub} | |||||
defaultBinding={mockGithubDefinition()} | defaultBinding={mockGithubDefinition()} | ||||
definitions={[mockGithubDefinition()]} | definitions={[mockGithubDefinition()]} | ||||
form={jest.fn()} | form={jest.fn()} |
import GithubTab, { GithubTabProps } from '../GithubTab'; | import GithubTab, { GithubTabProps } from '../GithubTab'; | ||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender()).toMatchSnapshot(); | |||||
expect(shallowRender()).toMatchSnapshot('with branch support'); | |||||
expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch support'); | |||||
}); | }); | ||||
function shallowRender(props: Partial<GithubTabProps> = {}) { | function shallowRender(props: Partial<GithubTabProps> = {}) { | ||||
return shallow( | return shallow( | ||||
<GithubTab | <GithubTab | ||||
branchesEnabled={true} | |||||
definitions={[mockGithubDefinition()]} | definitions={[mockGithubDefinition()]} | ||||
loading={false} | loading={false} | ||||
multipleAlmEnabled={true} | multipleAlmEnabled={true} |
import GitlabTab, { GitlabTabProps } from '../GitlabTab'; | import GitlabTab, { GitlabTabProps } from '../GitlabTab'; | ||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect(shallowRender()).toMatchSnapshot(); | |||||
expect(shallowRender()).toMatchSnapshot('with branch support'); | |||||
expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot('without branch support'); | |||||
}); | }); | ||||
function shallowRender(props: Partial<GitlabTabProps> = {}) { | function shallowRender(props: Partial<GitlabTabProps> = {}) { | ||||
return shallow( | return shallow( | ||||
<GitlabTab | <GitlabTab | ||||
branchesEnabled={true} | |||||
definitions={[mockGitlabDefinition()]} | definitions={[mockGitlabDefinition()]} | ||||
loading={false} | loading={false} | ||||
multipleAlmEnabled={true} | multipleAlmEnabled={true} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<AlmPRDecorationFormRenderer | |||||
<AlmBindingDefinitionFormRenderer | |||||
canSubmit={[Function]} | canSubmit={[Function]} | ||||
loading={false} | loading={false} | ||||
onCancel={[Function]} | onCancel={[Function]} |
className="display-flex-center" | className="display-flex-center" | ||||
htmlFor="key" | htmlFor="key" | ||||
> | > | ||||
settings.pr_decoration.form.key | |||||
settings.almintegration.form.key | |||||
<em | <em | ||||
className="mandatory spacer-right" | className="mandatory spacer-right" | ||||
> | > | ||||
className="display-flex-center" | className="display-flex-center" | ||||
htmlFor="key" | htmlFor="key" | ||||
> | > | ||||
settings.pr_decoration.form.key | |||||
settings.almintegration.form.key | |||||
<em | <em | ||||
className="mandatory spacer-right" | className="mandatory spacer-right" | ||||
> | > | ||||
className="display-flex-center" | className="display-flex-center" | ||||
htmlFor="key" | htmlFor="key" | ||||
> | > | ||||
settings.pr_decoration.form.key | |||||
settings.almintegration.form.key | |||||
<em | <em | ||||
className="mandatory spacer-right" | className="mandatory spacer-right" | ||||
> | > |
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<Modal | <Modal | ||||
contentLabel="settings.pr_decoration.form.header.create" | |||||
contentLabel="settings.almintegration.form.header.create" | |||||
onRequestClose={[MockFunction]} | onRequestClose={[MockFunction]} | ||||
size="medium" | size="medium" | ||||
> | > | ||||
className="modal-head" | className="modal-head" | ||||
> | > | ||||
<h2> | <h2> | ||||
settings.pr_decoration.form.header.create | |||||
settings.almintegration.form.header.create | |||||
</h2> | </h2> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="modal-body modal-container" | className="modal-body modal-container" | ||||
> | > | ||||
<Component /> | |||||
<div | |||||
className="display-flex-start" | |||||
> | |||||
<div | |||||
className="flex-1" | |||||
> | |||||
<Component /> | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="modal-foot" | className="modal-foot" | ||||
<SubmitButton | <SubmitButton | ||||
disabled={true} | disabled={true} | ||||
> | > | ||||
settings.pr_decoration.form.save | |||||
settings.almintegration.form.save | |||||
</SubmitButton> | </SubmitButton> | ||||
<ResetButtonLink | <ResetButtonLink | ||||
onClick={[Function]} | onClick={[Function]} | ||||
exports[`should render correctly 2`] = ` | exports[`should render correctly 2`] = ` | ||||
<Modal | <Modal | ||||
contentLabel="settings.pr_decoration.form.header.create" | |||||
contentLabel="settings.almintegration.form.header.create" | |||||
onRequestClose={[MockFunction]} | onRequestClose={[MockFunction]} | ||||
size="medium" | size="medium" | ||||
> | > | ||||
className="modal-head" | className="modal-head" | ||||
> | > | ||||
<h2> | <h2> | ||||
settings.pr_decoration.form.header.create | |||||
settings.almintegration.form.header.create | |||||
</h2> | </h2> | ||||
</div> | </div> | ||||
<div | <div | ||||
className="modal-body modal-container" | className="modal-body modal-container" | ||||
> | > | ||||
<Alert | |||||
className="big-spacer-bottom" | |||||
variant="info" | |||||
<div | |||||
className="display-flex-start" | |||||
> | > | ||||
<span> | |||||
Help me | |||||
</span> | |||||
</Alert> | |||||
<Component /> | |||||
<div | |||||
className="flex-1" | |||||
> | |||||
<Component /> | |||||
</div> | |||||
<Alert | |||||
className="huge-spacer-left flex-1" | |||||
variant="info" | |||||
> | |||||
<span> | |||||
Help me | |||||
</span> | |||||
</Alert> | |||||
</div> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="modal-foot" | className="modal-foot" | ||||
<SubmitButton | <SubmitButton | ||||
disabled={true} | disabled={true} | ||||
> | > | ||||
settings.pr_decoration.form.save | |||||
settings.almintegration.form.save | |||||
</SubmitButton> | </SubmitButton> | ||||
<ResetButtonLink | <ResetButtonLink | ||||
onClick={[Function]} | onClick={[Function]} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<div | |||||
className="display-flex-start" | |||||
> | |||||
<div | |||||
className="flex-1" | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.almintegration.form.save | |||||
</SubmitButton> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 2`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<div | |||||
className="display-flex-start" | |||||
> | |||||
<div | |||||
className="flex-1" | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.almintegration.form.save | |||||
</SubmitButton> | |||||
<ResetButtonLink | |||||
className="spacer-left" | |||||
onClick={[MockFunction]} | |||||
> | |||||
cancel | |||||
</ResetButtonLink> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 3`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<div | |||||
className="display-flex-start" | |||||
> | |||||
<div | |||||
className="flex-1" | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.almintegration.form.save | |||||
</SubmitButton> | |||||
<Button | |||||
className="button-red spacer-left" | |||||
disabled={false} | |||||
onClick={[MockFunction]} | |||||
> | |||||
delete | |||||
</Button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 4`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<div | |||||
className="display-flex-start" | |||||
> | |||||
<div | |||||
className="flex-1" | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.almintegration.form.save | |||||
</SubmitButton> | |||||
<span | |||||
className="text-success spacer-left" | |||||
> | |||||
<AlertSuccessIcon | |||||
className="spacer-right" | |||||
/> | |||||
settings.state.saved | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 5`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<div | |||||
className="display-flex-start" | |||||
> | |||||
<div | |||||
className="flex-1" | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.almintegration.form.save | |||||
</SubmitButton> | |||||
<DeferredSpinner | |||||
className="spacer-left" | |||||
timeout={100} | |||||
/> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
`; |
<div | <div | ||||
className="spacer-top big-spacer-bottom display-flex-space-between" | className="spacer-top big-spacer-bottom display-flex-space-between" | ||||
> | > | ||||
<h4 | |||||
className="display-inline" | |||||
<h2 | |||||
className="settings-sub-category-name" | |||||
> | > | ||||
settings.pr_decoration.table.title | |||||
</h4> | |||||
settings.almintegration.table.title | |||||
</h2> | |||||
<Button | <Button | ||||
data-test="settings__alm-create" | data-test="settings__alm-create" | ||||
onClick={[MockFunction]} | onClick={[MockFunction]} | ||||
> | > | ||||
settings.pr_decoration.table.create | |||||
settings.almintegration.table.create | |||||
</Button> | </Button> | ||||
</div> | </div> | ||||
<table | <table | ||||
<thead> | <thead> | ||||
<tr> | <tr> | ||||
<th> | <th> | ||||
settings.pr_decoration.table.column.name | |||||
settings.almintegration.table.column.name | |||||
</th> | </th> | ||||
<th | <th | ||||
className="action-small text-center" | className="action-small text-center" | ||||
> | > | ||||
settings.pr_decoration.table.column.edit | |||||
settings.almintegration.table.column.edit | |||||
</th> | </th> | ||||
<th | <th | ||||
className="action text-center" | className="action text-center" | ||||
> | > | ||||
settings.pr_decoration.table.column.delete | |||||
settings.almintegration.table.column.delete | |||||
</th> | </th> | ||||
</tr> | </tr> | ||||
</thead> | </thead> | ||||
<td | <td | ||||
colSpan={3} | colSpan={3} | ||||
> | > | ||||
settings.pr_decoration.table.empty.azure | |||||
settings.almintegration.table.empty.azure | |||||
</td> | </td> | ||||
</tr> | </tr> | ||||
</tbody> | </tbody> | ||||
<div | <div | ||||
className="spacer-top big-spacer-bottom display-flex-space-between" | className="spacer-top big-spacer-bottom display-flex-space-between" | ||||
> | > | ||||
<h4 | |||||
className="display-inline" | |||||
<h2 | |||||
className="settings-sub-category-name" | |||||
> | > | ||||
settings.pr_decoration.table.title | |||||
</h4> | |||||
settings.almintegration.table.title | |||||
</h2> | |||||
<Button | <Button | ||||
data-test="settings__alm-create" | data-test="settings__alm-create" | ||||
onClick={[MockFunction]} | onClick={[MockFunction]} | ||||
> | > | ||||
settings.pr_decoration.table.create | |||||
settings.almintegration.table.create | |||||
</Button> | </Button> | ||||
</div> | </div> | ||||
<table | <table | ||||
<thead> | <thead> | ||||
<tr> | <tr> | ||||
<th> | <th> | ||||
settings.pr_decoration.table.column.name | |||||
settings.almintegration.table.column.name | |||||
</th> | </th> | ||||
<th | <th | ||||
key="additional1" | key="additional1" | ||||
<th | <th | ||||
className="action-small text-center" | className="action-small text-center" | ||||
> | > | ||||
settings.pr_decoration.table.column.edit | |||||
settings.almintegration.table.column.edit | |||||
</th> | </th> | ||||
<th | <th | ||||
className="action text-center" | className="action text-center" | ||||
> | > | ||||
settings.pr_decoration.table.column.delete | |||||
settings.almintegration.table.column.delete | |||||
</th> | </th> | ||||
</tr> | </tr> | ||||
</thead> | </thead> | ||||
<div | <div | ||||
className="spacer-top big-spacer-bottom display-flex-space-between" | className="spacer-top big-spacer-bottom display-flex-space-between" | ||||
> | > | ||||
<h4 | |||||
className="display-inline" | |||||
<h2 | |||||
className="settings-sub-category-name" | |||||
> | > | ||||
settings.pr_decoration.table.title | |||||
</h4> | |||||
settings.almintegration.table.title | |||||
</h2> | |||||
<Button | <Button | ||||
data-test="settings__alm-create" | data-test="settings__alm-create" | ||||
onClick={[MockFunction]} | onClick={[MockFunction]} | ||||
> | > | ||||
settings.pr_decoration.table.create | |||||
settings.almintegration.table.create | |||||
</Button> | </Button> | ||||
</div> | </div> | ||||
<table | <table | ||||
<thead> | <thead> | ||||
<tr> | <tr> | ||||
<th> | <th> | ||||
settings.pr_decoration.table.column.name | |||||
settings.almintegration.table.column.name | |||||
</th> | </th> | ||||
<th | <th | ||||
className="action-small text-center" | className="action-small text-center" | ||||
> | > | ||||
settings.pr_decoration.table.column.edit | |||||
settings.almintegration.table.column.edit | |||||
</th> | </th> | ||||
<th | <th | ||||
className="action text-center" | className="action text-center" | ||||
> | > | ||||
settings.pr_decoration.table.column.delete | |||||
settings.almintegration.table.column.delete | |||||
</th> | </th> | ||||
</tr> | </tr> | ||||
</thead> | </thead> | ||||
<td | <td | ||||
colSpan={3} | colSpan={3} | ||||
> | > | ||||
settings.pr_decoration.table.empty.github | |||||
settings.almintegration.table.empty.gitlab | |||||
</td> | </td> | ||||
</tr> | </tr> | ||||
</tbody> | </tbody> |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<Connect(withAppState(PRDecorationTabs)) | |||||
<AlmIntegrationRenderer | |||||
branchesEnabled={true} | |||||
currentAlm="github" | currentAlm="github" | ||||
definitions={ | definitions={ | ||||
Object { | Object { | ||||
} | } | ||||
} | } | ||||
loading={true} | loading={true} | ||||
multipleAlmEnabled={false} | |||||
onCancel={[Function]} | onCancel={[Function]} | ||||
onConfirmDelete={[Function]} | onConfirmDelete={[Function]} | ||||
onDelete={[Function]} | onDelete={[Function]} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly: default 1`] = ` | |||||
<div | |||||
className="boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered" | |||||
> | |||||
<CheckIcon | |||||
className="little-spacer-top spacer-right" | |||||
fill="#00aa00" | |||||
/> | |||||
<div | |||||
className="display-flex-column abs-height-100" | |||||
> | |||||
<h4> | |||||
Foo | |||||
</h4> | |||||
<div | |||||
className="spacer-top flex-1" | |||||
> | |||||
Foo bar... | |||||
</div> | |||||
<div | |||||
className="spacer-top" | |||||
> | |||||
<em | |||||
className="text-success" | |||||
> | |||||
settings.almintegration.feature.enabled | |||||
</em> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly: inactive 1`] = ` | |||||
<div | |||||
className="boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered bg-muted" | |||||
> | |||||
<ClearIcon | |||||
className="little-spacer-top spacer-right" | |||||
fill="#999" | |||||
/> | |||||
<div | |||||
className="display-flex-column abs-height-100" | |||||
> | |||||
<h4> | |||||
Foo | |||||
</h4> | |||||
<div | |||||
className="spacer-top flex-1" | |||||
> | |||||
Foo bar... | |||||
</div> | |||||
<div | |||||
className="spacer-top" | |||||
> | |||||
<em | |||||
className="text-muted" | |||||
> | |||||
settings.almintegration.feature.disabled | |||||
</em> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly: inactive, with reason 1`] = ` | |||||
<div | |||||
className="boxed-group-inner display-flex-start width-30 spacer-right spacer-bottom bordered bg-muted" | |||||
> | |||||
<ClearIcon | |||||
className="little-spacer-top spacer-right" | |||||
fill="#999" | |||||
/> | |||||
<div | |||||
className="display-flex-column abs-height-100" | |||||
> | |||||
<h4> | |||||
Foo | |||||
</h4> | |||||
<div | |||||
className="spacer-top flex-1" | |||||
> | |||||
Foo bar... | |||||
</div> | |||||
<div | |||||
className="spacer-top" | |||||
> | |||||
<em | |||||
className="text-muted" | |||||
> | |||||
Bar is foo'd | |||||
</em> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render correctly 1`] = ` | |||||
exports[`should render correctly: azure 1`] = ` | |||||
<Fragment> | <Fragment> | ||||
<header | <header | ||||
className="page-header" | className="page-header" | ||||
<h1 | <h1 | ||||
className="page-title" | className="page-title" | ||||
> | > | ||||
settings.pr_decoration.title | |||||
settings.almintegration.title | |||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<div | <div | ||||
className="markdown small spacer-top big-spacer-bottom" | className="markdown small spacer-top big-spacer-bottom" | ||||
> | > | ||||
settings.pr_decoration.description | |||||
settings.almintegration.description | |||||
</div> | </div> | ||||
<BoxedTabs | <BoxedTabs | ||||
onSelect={[MockFunction]} | onSelect={[MockFunction]} | ||||
selected="github" | |||||
selected="azure" | |||||
tabs={ | tabs={ | ||||
Array [ | Array [ | ||||
Object { | Object { | ||||
/> | /> | ||||
Bitbucket Server | Bitbucket Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "azure", | "key": "azure", | ||||
/> | /> | ||||
Azure DevOps Server | Azure DevOps Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "gitlab", | "key": "gitlab", | ||||
] | ] | ||||
} | } | ||||
/> | /> | ||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | |||||
<GithubTab | |||||
definitions={Array []} | |||||
loading={true} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</div> | |||||
<AzureTab | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</Fragment> | </Fragment> | ||||
`; | `; | ||||
exports[`should render correctly 2`] = ` | |||||
exports[`should render correctly: bitbucket 1`] = ` | |||||
<Fragment> | <Fragment> | ||||
<header | <header | ||||
className="page-header" | className="page-header" | ||||
<h1 | <h1 | ||||
className="page-title" | className="page-title" | ||||
> | > | ||||
settings.pr_decoration.title | |||||
settings.almintegration.title | |||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<div | <div | ||||
className="markdown small spacer-top big-spacer-bottom" | className="markdown small spacer-top big-spacer-bottom" | ||||
> | > | ||||
settings.pr_decoration.description | |||||
settings.almintegration.description | |||||
</div> | </div> | ||||
<BoxedTabs | <BoxedTabs | ||||
onSelect={[MockFunction]} | onSelect={[MockFunction]} | ||||
selected="github" | |||||
selected="bitbucket" | |||||
tabs={ | tabs={ | ||||
Array [ | Array [ | ||||
Object { | Object { | ||||
/> | /> | ||||
Bitbucket Server | Bitbucket Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "azure", | "key": "azure", | ||||
/> | /> | ||||
Azure DevOps Server | Azure DevOps Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "gitlab", | "key": "gitlab", | ||||
] | ] | ||||
} | } | ||||
/> | /> | ||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | |||||
<GithubTab | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</div> | |||||
<DeleteModal | |||||
id="keyToDelete" | |||||
onCancel={[MockFunction]} | |||||
<BitbucketTab | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | onDelete={[MockFunction]} | ||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | /> | ||||
</Fragment> | </Fragment> | ||||
`; | `; | ||||
exports[`should render correctly 3`] = ` | |||||
exports[`should render correctly: default 1`] = ` | |||||
<Fragment> | <Fragment> | ||||
<header | <header | ||||
className="page-header" | className="page-header" | ||||
<h1 | <h1 | ||||
className="page-title" | className="page-title" | ||||
> | > | ||||
settings.pr_decoration.title | |||||
settings.almintegration.title | |||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<div | <div | ||||
className="markdown small spacer-top big-spacer-bottom" | className="markdown small spacer-top big-spacer-bottom" | ||||
> | > | ||||
settings.pr_decoration.description | |||||
settings.almintegration.description | |||||
</div> | </div> | ||||
<BoxedTabs | <BoxedTabs | ||||
onSelect={[MockFunction]} | onSelect={[MockFunction]} | ||||
selected="azure" | |||||
selected="github" | |||||
tabs={ | tabs={ | ||||
Array [ | Array [ | ||||
Object { | Object { | ||||
/> | /> | ||||
Bitbucket Server | Bitbucket Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "azure", | "key": "azure", | ||||
/> | /> | ||||
Azure DevOps Server | Azure DevOps Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "gitlab", | "key": "gitlab", | ||||
] | ] | ||||
} | } | ||||
/> | /> | ||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | |||||
<AzureTab | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</div> | |||||
<GithubTab | |||||
branchesEnabled={true} | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</Fragment> | </Fragment> | ||||
`; | `; | ||||
exports[`should render correctly 4`] = ` | |||||
exports[`should render correctly: delete modal 1`] = ` | |||||
<Fragment> | <Fragment> | ||||
<header | <header | ||||
className="page-header" | className="page-header" | ||||
<h1 | <h1 | ||||
className="page-title" | className="page-title" | ||||
> | > | ||||
settings.pr_decoration.title | |||||
settings.almintegration.title | |||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<div | <div | ||||
className="markdown small spacer-top big-spacer-bottom" | className="markdown small spacer-top big-spacer-bottom" | ||||
> | > | ||||
settings.pr_decoration.description | |||||
settings.almintegration.description | |||||
</div> | </div> | ||||
<BoxedTabs | <BoxedTabs | ||||
onSelect={[MockFunction]} | onSelect={[MockFunction]} | ||||
selected="bitbucket" | |||||
selected="github" | |||||
tabs={ | tabs={ | ||||
Array [ | Array [ | ||||
Object { | Object { | ||||
/> | /> | ||||
Bitbucket Server | Bitbucket Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "azure", | "key": "azure", | ||||
/> | /> | ||||
Azure DevOps Server | Azure DevOps Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "gitlab", | "key": "gitlab", | ||||
] | ] | ||||
} | } | ||||
/> | /> | ||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | |||||
<BitbucketTab | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</div> | |||||
<GithubTab | |||||
branchesEnabled={true} | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
<DeleteModal | |||||
id="keyToDelete" | |||||
onCancel={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
/> | |||||
</Fragment> | </Fragment> | ||||
`; | `; | ||||
exports[`should render correctly 5`] = ` | |||||
exports[`should render correctly: gitlab 1`] = ` | |||||
<Fragment> | <Fragment> | ||||
<header | <header | ||||
className="page-header" | className="page-header" | ||||
<h1 | <h1 | ||||
className="page-title" | className="page-title" | ||||
> | > | ||||
settings.pr_decoration.title | |||||
settings.almintegration.title | |||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<div | <div | ||||
className="markdown small spacer-top big-spacer-bottom" | className="markdown small spacer-top big-spacer-bottom" | ||||
> | > | ||||
settings.pr_decoration.description | |||||
settings.almintegration.description | |||||
</div> | </div> | ||||
<BoxedTabs | <BoxedTabs | ||||
onSelect={[MockFunction]} | onSelect={[MockFunction]} | ||||
/> | /> | ||||
Bitbucket Server | Bitbucket Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "azure", | "key": "azure", | ||||
/> | /> | ||||
Azure DevOps Server | Azure DevOps Server | ||||
</React.Fragment>, | </React.Fragment>, | ||||
"requiresBranchesEnabled": true, | |||||
}, | }, | ||||
Object { | Object { | ||||
"key": "gitlab", | "key": "gitlab", | ||||
] | ] | ||||
} | } | ||||
/> | /> | ||||
<GitlabTab | |||||
branchesEnabled={true} | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</Fragment> | |||||
`; | |||||
exports[`should render correctly: loading 1`] = ` | |||||
<Fragment> | |||||
<header | |||||
className="page-header" | |||||
> | |||||
<h1 | |||||
className="page-title" | |||||
> | |||||
settings.almintegration.title | |||||
</h1> | |||||
</header> | |||||
<div | <div | ||||
className="boxed-group boxed-group-inner" | |||||
className="markdown small spacer-top big-spacer-bottom" | |||||
> | > | ||||
<GitlabTab | |||||
definitions={Array []} | |||||
loading={false} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
settings.almintegration.description | |||||
</div> | </div> | ||||
<BoxedTabs | |||||
onSelect={[MockFunction]} | |||||
selected="github" | |||||
tabs={ | |||||
Array [ | |||||
Object { | |||||
"key": "github", | |||||
"label": <React.Fragment> | |||||
<img | |||||
alt="github" | |||||
className="spacer-right" | |||||
height={16} | |||||
src="/images/alm/github.svg" | |||||
/> | |||||
GitHub | |||||
</React.Fragment>, | |||||
}, | |||||
Object { | |||||
"key": "bitbucket", | |||||
"label": <React.Fragment> | |||||
<img | |||||
alt="bitbucket" | |||||
className="spacer-right" | |||||
height={16} | |||||
src="/images/alm/bitbucket.svg" | |||||
/> | |||||
Bitbucket Server | |||||
</React.Fragment>, | |||||
"requiresBranchesEnabled": true, | |||||
}, | |||||
Object { | |||||
"key": "azure", | |||||
"label": <React.Fragment> | |||||
<img | |||||
alt="azure" | |||||
className="spacer-right" | |||||
height={16} | |||||
src="/images/alm/azure.svg" | |||||
/> | |||||
Azure DevOps Server | |||||
</React.Fragment>, | |||||
"requiresBranchesEnabled": true, | |||||
}, | |||||
Object { | |||||
"key": "gitlab", | |||||
"label": <React.Fragment> | |||||
<img | |||||
alt="gitlab" | |||||
className="spacer-right" | |||||
height={16} | |||||
src="/images/alm/gitlab.svg" | |||||
/> | |||||
GitLab | |||||
</React.Fragment>, | |||||
}, | |||||
] | |||||
} | |||||
/> | |||||
<GithubTab | |||||
branchesEnabled={true} | |||||
definitions={Array []} | |||||
loading={true} | |||||
multipleAlmEnabled={false} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
/> | |||||
</Fragment> | </Fragment> | ||||
`; | `; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly for multi-ALM binding: editing a definition 1`] = ` | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<DeferredSpinner | |||||
loading={false} | |||||
timeout={100} | |||||
> | |||||
<AlmBindingDefinitionsTable | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"url", | |||||
"app_id", | |||||
] | |||||
} | |||||
alm="github" | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"additionalColumns": Array [ | |||||
"http://github.enterprise.com", | |||||
"123456", | |||||
], | |||||
"key": "key", | |||||
}, | |||||
] | |||||
} | |||||
onCreate={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
/> | |||||
<AlmBindingDefinitionForm | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.almintegration.github.info" | |||||
id="settings.almintegration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
onCancel={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
showInModal={true} | |||||
> | |||||
<Component /> | |||||
</AlmBindingDefinitionForm> | |||||
</DeferredSpinner> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly for multi-ALM binding: loaded 1`] = ` | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<DeferredSpinner | |||||
loading={false} | |||||
timeout={100} | |||||
> | |||||
<AlmBindingDefinitionsTable | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"url", | |||||
"app_id", | |||||
] | |||||
} | |||||
alm="github" | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"additionalColumns": Array [ | |||||
"http://github.enterprise.com", | |||||
"123456", | |||||
], | |||||
"key": "key", | |||||
}, | |||||
] | |||||
} | |||||
onCreate={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
/> | |||||
</DeferredSpinner> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly for multi-ALM binding: loading 1`] = ` | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<DeferredSpinner | |||||
loading={true} | |||||
timeout={100} | |||||
> | |||||
<AlmBindingDefinitionsTable | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"url", | |||||
"app_id", | |||||
] | |||||
} | |||||
alm="github" | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"additionalColumns": Array [ | |||||
"http://github.enterprise.com", | |||||
"123456", | |||||
], | |||||
"key": "key", | |||||
}, | |||||
] | |||||
} | |||||
onCreate={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
/> | |||||
</DeferredSpinner> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly for multi-ALM binding: with features 1`] = ` | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<DeferredSpinner | |||||
loading={false} | |||||
timeout={100} | |||||
> | |||||
<AlmBindingDefinitionsTable | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"url", | |||||
"app_id", | |||||
] | |||||
} | |||||
alm="github" | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"additionalColumns": Array [ | |||||
"http://github.enterprise.com", | |||||
"123456", | |||||
], | |||||
"key": "key", | |||||
}, | |||||
] | |||||
} | |||||
onCreate={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
/> | |||||
</DeferredSpinner> | |||||
<div | |||||
className="big-spacer-top big-padded-top bordered-top" | |||||
> | |||||
<h3 | |||||
className="big-spacer-bottom" | |||||
> | |||||
settings.almintegration.features | |||||
</h3> | |||||
<div | |||||
className="display-flex-wrap" | |||||
> | |||||
<AlmIntegrationFeatureBox | |||||
active={true} | |||||
description="Bar" | |||||
key="0" | |||||
name="Foo" | |||||
/> | |||||
<AlmIntegrationFeatureBox | |||||
active={false} | |||||
description="Bim" | |||||
key="1" | |||||
name="Baz" | |||||
/> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly for single-ALM binding 1`] = ` | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<AlmBindingDefinitionForm | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.almintegration.github.info" | |||||
id="settings.almintegration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
hideKeyField={true} | |||||
loading={true} | |||||
onCancel={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
readOnly={true} | |||||
success={false} | |||||
> | |||||
<Component /> | |||||
</AlmBindingDefinitionForm> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly for single-ALM binding 2`] = ` | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<AlmBindingDefinitionForm | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.almintegration.github.info" | |||||
id="settings.almintegration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
hideKeyField={true} | |||||
loading={false} | |||||
onCancel={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
readOnly={true} | |||||
success={false} | |||||
> | |||||
<Component /> | |||||
</AlmBindingDefinitionForm> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly for single-ALM binding 3`] = ` | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<AlmBindingDefinitionForm | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.almintegration.github.info" | |||||
id="settings.almintegration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
hideKeyField={true} | |||||
loading={false} | |||||
onCancel={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
readOnly={true} | |||||
success={false} | |||||
> | |||||
<Component /> | |||||
</AlmBindingDefinitionForm> | |||||
</div> | |||||
`; |
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.azure.help" | |||||
help="settings.almintegration.form.name.azure.help" | |||||
id="name.azure" | id="name.azure" | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="" | value="" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
help="settings.pr_decoration.form.personal_access_token.azure.help" | |||||
<AlmBindingDefinitionFormField | |||||
help="settings.almintegration.form.personal_access_token.azure.help" | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
exports[`should render correctly 2`] = ` | exports[`should render correctly 2`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.azure.help" | |||||
help="settings.almintegration.form.name.azure.help" | |||||
id="name.azure" | id="name.azure" | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="key" | value="key" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
help="settings.pr_decoration.form.personal_access_token.azure.help" | |||||
<AlmBindingDefinitionFormField | |||||
help="settings.almintegration.form.personal_access_token.azure.help" | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<div | |||||
className="bordered" | |||||
> | |||||
<AlmTab | |||||
alm="azure" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"key": "", | |||||
"personalAccessToken": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"key": "key", | |||||
"personalAccessToken": "asdf1234", | |||||
}, | |||||
] | |||||
} | |||||
features={ | |||||
Array [ | |||||
Object { | |||||
"active": true, | |||||
"description": "settings.almintegration.feature.pr_decoration.description", | |||||
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding", | |||||
"name": "settings.almintegration.feature.pr_decoration.title", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
</div> | |||||
`; |
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.bitbucket.help" | |||||
help="settings.almintegration.form.name.bitbucket.help" | |||||
id="name.bitbucket" | id="name.bitbucket" | ||||
maxLength={100} | maxLength={100} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="" | value="" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
help={ | help={ | ||||
<FormattedMessage | <FormattedMessage | ||||
defaultMessage="settings.pr_decoration.form.url.bitbucket.help" | |||||
id="settings.pr_decoration.form.url.bitbucket.help" | |||||
defaultMessage="settings.almintegration.form.url.bitbucket.help" | |||||
id="settings.almintegration.form.url.bitbucket.help" | |||||
values={ | values={ | ||||
Object { | Object { | ||||
"example": "https://bitbucket-server.your-company.com", | "example": "https://bitbucket-server.your-company.com", | ||||
propKey="url" | propKey="url" | ||||
value="" | value="" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
exports[`should render correctly 2`] = ` | exports[`should render correctly 2`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.bitbucket.help" | |||||
help="settings.almintegration.form.name.bitbucket.help" | |||||
id="name.bitbucket" | id="name.bitbucket" | ||||
maxLength={100} | maxLength={100} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="key" | value="key" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
help={ | help={ | ||||
<FormattedMessage | <FormattedMessage | ||||
defaultMessage="settings.pr_decoration.form.url.bitbucket.help" | |||||
id="settings.pr_decoration.form.url.bitbucket.help" | |||||
defaultMessage="settings.almintegration.form.url.bitbucket.help" | |||||
id="settings.almintegration.form.url.bitbucket.help" | |||||
values={ | values={ | ||||
Object { | Object { | ||||
"example": "https://bitbucket-server.your-company.com", | "example": "https://bitbucket-server.your-company.com", | ||||
propKey="url" | propKey="url" | ||||
value="http://bbs.enterprise.com" | value="http://bbs.enterprise.com" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<div | |||||
className="bordered" | |||||
> | |||||
<AlmTab | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"settings.almintegration.table.column.bitbucket.url", | |||||
] | |||||
} | |||||
additionalColumnsKeys={ | |||||
Array [ | |||||
"url", | |||||
] | |||||
} | |||||
additionalTableInfo={ | |||||
<Alert | |||||
className="big-spacer-bottom width-50" | |||||
variant="info" | |||||
> | |||||
<FormattedMessage | |||||
defaultMessage="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances" | |||||
id="settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances" | |||||
values={ | |||||
Object { | |||||
"feature": <em> | |||||
settings.almintegration.feature.alm_repo_import.title | |||||
</em>, | |||||
} | |||||
} | |||||
/> | |||||
</Alert> | |||||
} | |||||
alm="bitbucket" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"key": "", | |||||
"personalAccessToken": "", | |||||
"url": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"key": "key", | |||||
"personalAccessToken": "asdf1234", | |||||
"url": "http://bbs.enterprise.com", | |||||
}, | |||||
] | |||||
} | |||||
features={ | |||||
Array [ | |||||
Object { | |||||
"active": true, | |||||
"description": "settings.almintegration.feature.pr_decoration.description", | |||||
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding", | |||||
"name": "settings.almintegration.feature.pr_decoration.title", | |||||
}, | |||||
Object { | |||||
"active": true, | |||||
"description": "settings.almintegration.feature.alm_repo_import.description", | |||||
"inactiveReason": "onboarding.create_project.too_many_bbs_instances_X.1", | |||||
"name": "settings.almintegration.feature.alm_repo_import.title", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
help={ | |||||
<React.Fragment> | |||||
<h3> | |||||
onboarding.create_project.pat_help.title | |||||
</h3> | |||||
<p | |||||
className="big-spacer-top" | |||||
> | |||||
settings.almintegration.bitbucket.help_1 | |||||
</p> | |||||
<ul | |||||
className="big-spacer-top list-styled" | |||||
> | |||||
<li> | |||||
settings.almintegration.bitbucket.help_2 | |||||
</li> | |||||
<li> | |||||
settings.almintegration.bitbucket.help_3 | |||||
</li> | |||||
</ul> | |||||
<p | |||||
className="big-spacer-top big-spacer-bottom" | |||||
> | |||||
<Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link> | |||||
</p> | |||||
</React.Fragment> | |||||
} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
</div> | |||||
`; |
<ConfirmModal | <ConfirmModal | ||||
confirmButtonText="delete" | confirmButtonText="delete" | ||||
confirmData="1" | confirmData="1" | ||||
header="settings.pr_decoration.delete.header" | |||||
header="settings.almintegration.delete.header" | |||||
isDestructive={true} | isDestructive={true} | ||||
onClose={[MockFunction]} | onClose={[MockFunction]} | ||||
onConfirm={[MockFunction]} | onConfirm={[MockFunction]} | ||||
className="spacer-bottom" | className="spacer-bottom" | ||||
> | > | ||||
<FormattedMessage | <FormattedMessage | ||||
defaultMessage="settings.pr_decoration.delete.message" | |||||
id="settings.pr_decoration.delete.message" | |||||
defaultMessage="settings.almintegration.delete.message" | |||||
id="settings.almintegration.delete.message" | |||||
values={ | values={ | ||||
Object { | Object { | ||||
"id": <b> | "id": <b> | ||||
/> | /> | ||||
</p> | </p> | ||||
<p> | <p> | ||||
settings.pr_decoration.delete.info.4 | |||||
settings.almintegration.delete.info.4 | |||||
</p> | </p> | ||||
</ConfirmModal> | </ConfirmModal> | ||||
<ConfirmModal | <ConfirmModal | ||||
confirmButtonText="delete" | confirmButtonText="delete" | ||||
confirmData="1" | confirmData="1" | ||||
header="settings.pr_decoration.delete.header" | |||||
header="settings.almintegration.delete.header" | |||||
isDestructive={true} | isDestructive={true} | ||||
onClose={[MockFunction]} | onClose={[MockFunction]} | ||||
onConfirm={[MockFunction]} | onConfirm={[MockFunction]} | ||||
className="spacer-bottom" | className="spacer-bottom" | ||||
> | > | ||||
<FormattedMessage | <FormattedMessage | ||||
defaultMessage="settings.pr_decoration.delete.message" | |||||
id="settings.pr_decoration.delete.message" | |||||
defaultMessage="settings.almintegration.delete.message" | |||||
id="settings.almintegration.delete.message" | |||||
values={ | values={ | ||||
Object { | Object { | ||||
"id": <b> | "id": <b> | ||||
/> | /> | ||||
</p> | </p> | ||||
<p> | <p> | ||||
settings.pr_decoration.delete.no_info | |||||
settings.almintegration.delete.no_info | |||||
</p> | </p> | ||||
</ConfirmModal> | </ConfirmModal> | ||||
`; | `; |
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.github.help" | |||||
help="settings.almintegration.form.name.github.help" | |||||
id="name.github" | id="name.github" | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="" | value="" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
help={ | help={ | ||||
<React.Fragment> | <React.Fragment> | ||||
settings.pr_decoration.form.url.github.help1 | |||||
settings.almintegration.form.url.github.help1 | |||||
<br /> | <br /> | ||||
<em> | <em> | ||||
https://github.company.com/api/v3 | https://github.company.com/api/v3 | ||||
</em> | </em> | ||||
<br /> | <br /> | ||||
<br /> | <br /> | ||||
settings.pr_decoration.form.url.github.help2 | |||||
settings.almintegration.form.url.github.help2 | |||||
<br /> | <br /> | ||||
<em> | <em> | ||||
https://api.github.com/ | https://api.github.com/ | ||||
propKey="url" | propKey="url" | ||||
value="" | value="" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="app_id" | id="app_id" | ||||
maxLength={80} | maxLength={80} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="appId" | propKey="appId" | ||||
value="" | value="" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="private_key" | id="private_key" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
exports[`should render correctly 2`] = ` | exports[`should render correctly 2`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.github.help" | |||||
help="settings.almintegration.form.name.github.help" | |||||
id="name.github" | id="name.github" | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="key" | value="key" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
help={ | help={ | ||||
<React.Fragment> | <React.Fragment> | ||||
settings.pr_decoration.form.url.github.help1 | |||||
settings.almintegration.form.url.github.help1 | |||||
<br /> | <br /> | ||||
<em> | <em> | ||||
https://github.company.com/api/v3 | https://github.company.com/api/v3 | ||||
</em> | </em> | ||||
<br /> | <br /> | ||||
<br /> | <br /> | ||||
settings.pr_decoration.form.url.github.help2 | |||||
settings.almintegration.form.url.github.help2 | |||||
<br /> | <br /> | ||||
<em> | <em> | ||||
https://api.github.com/ | https://api.github.com/ | ||||
propKey="url" | propKey="url" | ||||
value="http://github.enterprise.com" | value="http://github.enterprise.com" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="app_id" | id="app_id" | ||||
maxLength={80} | maxLength={80} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="appId" | propKey="appId" | ||||
value="123456" | value="123456" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
id="private_key" | id="private_key" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly: with branch support 1`] = ` | |||||
<div | |||||
className="bordered" | |||||
> | |||||
<AlmTab | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"settings.almintegration.table.column.github.url", | |||||
"settings.almintegration.table.column.app_id", | |||||
] | |||||
} | |||||
additionalColumnsKeys={ | |||||
Array [ | |||||
"appId", | |||||
"url", | |||||
] | |||||
} | |||||
alm="github" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"appId": "", | |||||
"key": "", | |||||
"privateKey": "", | |||||
"url": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
}, | |||||
] | |||||
} | |||||
features={ | |||||
Array [ | |||||
Object { | |||||
"active": true, | |||||
"description": "settings.almintegration.feature.pr_decoration.description", | |||||
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding", | |||||
"name": "settings.almintegration.feature.pr_decoration.title", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
<div | |||||
className="huge-spacer-top huge-spacer-bottom bordered-top" | |||||
/> | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<Connect(SubCategoryDefinitionsList) | |||||
category="almintegration" | |||||
subCategory="github" | |||||
/> | |||||
</div> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly: without branch support 1`] = ` | |||||
<div | |||||
className="bordered" | |||||
> | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<Connect(SubCategoryDefinitionsList) | |||||
category="almintegration" | |||||
subCategory="github" | |||||
/> | |||||
</div> | |||||
</div> | |||||
`; |
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.gitlab.help" | |||||
help="settings.almintegration.form.name.gitlab.help" | |||||
id="name.gitlab" | id="name.gitlab" | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="" | value="" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
help="settings.pr_decoration.form.personal_access_token.gitlab.help" | |||||
<AlmBindingDefinitionFormField | |||||
help="settings.almintegration.form.personal_access_token.gitlab.help" | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
exports[`should render correctly 2`] = ` | exports[`should render correctly 2`] = ` | ||||
<Fragment> | <Fragment> | ||||
<AlmDefinitionFormField | |||||
<AlmBindingDefinitionFormField | |||||
autoFocus={true} | autoFocus={true} | ||||
help="settings.pr_decoration.form.name.gitlab.help" | |||||
help="settings.almintegration.form.name.gitlab.help" | |||||
id="name.gitlab" | id="name.gitlab" | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} | ||||
propKey="key" | propKey="key" | ||||
value="foo" | value="foo" | ||||
/> | /> | ||||
<AlmDefinitionFormField | |||||
help="settings.pr_decoration.form.personal_access_token.gitlab.help" | |||||
<AlmBindingDefinitionFormField | |||||
help="settings.almintegration.form.personal_access_token.gitlab.help" | |||||
id="personal_access_token" | id="personal_access_token" | ||||
isTextArea={true} | isTextArea={true} | ||||
onFieldChange={[MockFunction]} | onFieldChange={[MockFunction]} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly: with branch support 1`] = ` | |||||
<div | |||||
className="bordered" | |||||
> | |||||
<AlmTab | |||||
alm="gitlab" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"key": "", | |||||
"personalAccessToken": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"key": "foo", | |||||
"personalAccessToken": "foobar", | |||||
}, | |||||
] | |||||
} | |||||
features={ | |||||
Array [ | |||||
Object { | |||||
"active": true, | |||||
"description": "settings.almintegration.feature.mr_decoration.description", | |||||
"inactiveReason": "settings.almintegration.feature.need_at_least_1_binding", | |||||
"name": "settings.almintegration.feature.mr_decoration.title", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
<div | |||||
className="huge-spacer-top huge-spacer-bottom bordered-top" | |||||
/> | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<Connect(SubCategoryDefinitionsList) | |||||
category="almintegration" | |||||
subCategory="gitlab" | |||||
/> | |||||
</div> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly: without branch support 1`] = ` | |||||
<div | |||||
className="bordered" | |||||
> | |||||
<div | |||||
className="big-padded" | |||||
> | |||||
<Connect(SubCategoryDefinitionsList) | |||||
category="almintegration" | |||||
subCategory="gitlab" | |||||
/> | |||||
</div> | |||||
</div> | |||||
`; |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
import * as React from 'react'; | |||||
import { FormattedMessage } from 'react-intl'; | |||||
import { Link } from 'react-router'; | |||||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { AlmSettingsBinding, ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import AlmPRDecorationForm, { AlmPRDecorationFormChildrenProps } from './AlmPRDecorationForm'; | |||||
import AlmPRDecorationTable from './AlmPRDecorationTable'; | |||||
export interface AlmTabRendererProps<B> { | |||||
additionalColumnsHeaders: string[]; | |||||
additionalColumnsKeys: Array<keyof B>; | |||||
alm: ALM_KEYS; | |||||
editedDefinition?: B; | |||||
defaultBinding: B; | |||||
definitions: B[]; | |||||
form: (props: AlmPRDecorationFormChildrenProps<B>) => React.ReactNode; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onCancel: () => void; | |||||
onCreate: () => void; | |||||
onDelete: (definitionKey: string) => void; | |||||
onEdit: (definitionKey: string) => void; | |||||
onSubmit: (config: B, originalKey: string) => void; | |||||
success: boolean; | |||||
} | |||||
export default function AlmTabRenderer<B extends AlmSettingsBinding>( | |||||
props: AlmTabRendererProps<B> | |||||
) { | |||||
const { | |||||
additionalColumnsHeaders, | |||||
additionalColumnsKeys, | |||||
alm, | |||||
defaultBinding, | |||||
definitions, | |||||
editedDefinition, | |||||
form, | |||||
loading, | |||||
multipleAlmEnabled, | |||||
success | |||||
} = props; | |||||
let definition: B | undefined; | |||||
let mappedDefinitions: Array<{ key: string; additionalColumns: string[] }> = []; | |||||
let showEdit: boolean | undefined; | |||||
if (!multipleAlmEnabled) { | |||||
definition = editedDefinition; | |||||
if (definition === undefined && definitions.length > 0) { | |||||
definition = definitions[0]; | |||||
} | |||||
showEdit = definition && editedDefinition === undefined; | |||||
} else { | |||||
mappedDefinitions = definitions.map(({ key, ...properties }) => { | |||||
const additionalColumns = additionalColumnsKeys.map(k => (properties as any)[k]); | |||||
return { | |||||
key, | |||||
additionalColumns | |||||
}; | |||||
}); | |||||
} | |||||
const help = ( | |||||
<FormattedMessage | |||||
defaultMessage={translate(`settings.pr_decoration.${alm}.info`)} | |||||
id={`settings.pr_decoration.${alm}.info`} | |||||
values={{ | |||||
link: ( | |||||
<Link target="_blank" to="/documentation/analysis/pr-decoration/"> | |||||
{translate('learn_more')} | |||||
</Link> | |||||
) | |||||
}} | |||||
/> | |||||
); | |||||
return multipleAlmEnabled ? ( | |||||
<DeferredSpinner loading={loading}> | |||||
<AlmPRDecorationTable | |||||
additionalColumnsHeaders={additionalColumnsHeaders} | |||||
alm={alm} | |||||
definitions={mappedDefinitions} | |||||
onCreate={props.onCreate} | |||||
onDelete={props.onDelete} | |||||
onEdit={props.onEdit} | |||||
/> | |||||
{editedDefinition && ( | |||||
<AlmPRDecorationForm | |||||
alm={alm} | |||||
bindingDefinition={editedDefinition} | |||||
help={help} | |||||
onCancel={props.onCancel} | |||||
onSubmit={props.onSubmit} | |||||
showInModal={true}> | |||||
{form} | |||||
</AlmPRDecorationForm> | |||||
)} | |||||
</DeferredSpinner> | |||||
) : ( | |||||
<AlmPRDecorationForm | |||||
alm={alm} | |||||
bindingDefinition={definition || defaultBinding} | |||||
help={help} | |||||
hideKeyField={true} | |||||
loading={loading} | |||||
onCancel={props.onCancel} | |||||
onDelete={definition ? props.onDelete : undefined} | |||||
onEdit={showEdit ? props.onEdit : undefined} | |||||
onSubmit={props.onSubmit} | |||||
readOnly={showEdit} | |||||
success={success}> | |||||
{form} | |||||
</AlmPRDecorationForm> | |||||
); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { | |||||
createBitbucketConfiguration, | |||||
updateBitbucketConfiguration | |||||
} from '../../../../api/almSettings'; | |||||
import { ALM_KEYS, BitbucketBindingDefinition } from '../../../../types/alm-settings'; | |||||
import AlmTab from './AlmTab'; | |||||
import BitbucketForm from './BitbucketForm'; | |||||
export interface BitbucketTabProps { | |||||
definitions: BitbucketBindingDefinition[]; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onDelete: (definitionKey: string) => void; | |||||
onUpdateDefinitions: () => void; | |||||
} | |||||
export default function BitbucketTab(props: BitbucketTabProps) { | |||||
const { multipleAlmEnabled, definitions, loading } = props; | |||||
return ( | |||||
<AlmTab | |||||
additionalColumnsHeaders={[translate('settings.pr_decoration.table.column.bitbucket.url')]} | |||||
additionalColumnsKeys={['url']} | |||||
alm={ALM_KEYS.BITBUCKET} | |||||
createConfiguration={createBitbucketConfiguration} | |||||
defaultBinding={{ key: '', url: '', personalAccessToken: '' }} | |||||
definitions={definitions} | |||||
form={childProps => <BitbucketForm {...childProps} />} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateBitbucketConfiguration} | |||||
/> | |||||
); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { createGithubConfiguration, updateGithubConfiguration } from '../../../../api/almSettings'; | |||||
import { ALM_KEYS, GithubBindingDefinition } from '../../../../types/alm-settings'; | |||||
import AlmTab from './AlmTab'; | |||||
import GithubForm from './GithubForm'; | |||||
export interface GithubTabProps { | |||||
definitions: GithubBindingDefinition[]; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onDelete: (definitionKey: string) => void; | |||||
onUpdateDefinitions: () => void; | |||||
} | |||||
export default function GithubTab(props: GithubTabProps) { | |||||
const { multipleAlmEnabled, definitions, loading } = props; | |||||
return ( | |||||
<AlmTab | |||||
additionalColumnsHeaders={[ | |||||
translate('settings.pr_decoration.table.column.github.url'), | |||||
translate('settings.pr_decoration.table.column.app_id') | |||||
]} | |||||
additionalColumnsKeys={['appId', 'url']} | |||||
alm={ALM_KEYS.GITHUB} | |||||
createConfiguration={createGithubConfiguration} | |||||
defaultBinding={{ key: '', appId: '', url: '', privateKey: '' }} | |||||
definitions={definitions} | |||||
form={childProps => <GithubForm {...childProps} />} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateGithubConfiguration} | |||||
/> | |||||
); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 { createGitlabConfiguration, updateGitlabConfiguration } from '../../../../api/almSettings'; | |||||
import { ALM_KEYS, GitlabBindingDefinition } from '../../../../types/alm-settings'; | |||||
import AlmTab from './AlmTab'; | |||||
import GitlabForm from './GitlabForm'; | |||||
export interface GitlabTabProps { | |||||
definitions: GitlabBindingDefinition[]; | |||||
loading: boolean; | |||||
multipleAlmEnabled: boolean; | |||||
onDelete: (definitionKey: string) => void; | |||||
onUpdateDefinitions: () => void; | |||||
} | |||||
export default function GitlabTab(props: GitlabTabProps) { | |||||
const { multipleAlmEnabled, definitions, loading } = props; | |||||
return ( | |||||
<AlmTab | |||||
alm={ALM_KEYS.GITLAB} | |||||
createConfiguration={createGitlabConfiguration} | |||||
defaultBinding={{ key: '', personalAccessToken: '' }} | |||||
definitions={definitions} | |||||
form={childProps => <GitlabForm {...childProps} />} | |||||
loading={loading} | |||||
multipleAlmEnabled={multipleAlmEnabled} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
updateConfiguration={updateGitlabConfiguration} | |||||
/> | |||||
); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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 BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs'; | |||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||||
import { withAppState } from '../../../../components/hoc/withAppState'; | |||||
import { AlmSettingsBindingDefinitions, ALM_KEYS } from '../../../../types/alm-settings'; | |||||
import AzureTab from './AzureTab'; | |||||
import BitbucketTab from './BitbucketTab'; | |||||
import DeleteModal from './DeleteModal'; | |||||
import GithubTab from './GithubTab'; | |||||
import GitlabTab from './GitlabTab'; | |||||
export interface PRDecorationTabsProps { | |||||
appState: Pick<T.AppState, 'multipleAlmEnabled'>; | |||||
currentAlm: ALM_KEYS; | |||||
definitionKeyForDeletion?: string; | |||||
definitions: AlmSettingsBindingDefinitions; | |||||
loading: boolean; | |||||
onCancel: () => void; | |||||
onConfirmDelete: (definitionKey: string) => void; | |||||
onDelete: (definitionKey: string) => void; | |||||
onSelectAlm: (alm: ALM_KEYS) => void; | |||||
onUpdateDefinitions: () => void; | |||||
projectCount?: number; | |||||
} | |||||
export const almName = { | |||||
[ALM_KEYS.AZURE]: 'Azure DevOps Server', | |||||
[ALM_KEYS.BITBUCKET]: 'Bitbucket Server', | |||||
[ALM_KEYS.GITHUB]: 'GitHub', | |||||
[ALM_KEYS.GITLAB]: 'GitLab' | |||||
}; | |||||
export function PRDecorationTabs(props: PRDecorationTabsProps) { | |||||
const { | |||||
appState: { multipleAlmEnabled }, | |||||
definitionKeyForDeletion, | |||||
definitions, | |||||
currentAlm, | |||||
loading, | |||||
projectCount | |||||
} = props; | |||||
return ( | |||||
<> | |||||
<header className="page-header"> | |||||
<h1 className="page-title">{translate('settings.pr_decoration.title')}</h1> | |||||
</header> | |||||
<div className="markdown small spacer-top big-spacer-bottom"> | |||||
{translate('settings.pr_decoration.description')} | |||||
</div> | |||||
<BoxedTabs | |||||
onSelect={props.onSelectAlm} | |||||
selected={currentAlm} | |||||
tabs={[ | |||||
{ | |||||
key: ALM_KEYS.GITHUB, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="github" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/github.svg`} | |||||
/> | |||||
{almName[ALM_KEYS.GITHUB]} | |||||
</> | |||||
) | |||||
}, | |||||
{ | |||||
key: ALM_KEYS.BITBUCKET, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="bitbucket" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/bitbucket.svg`} | |||||
/> | |||||
{almName[ALM_KEYS.BITBUCKET]} | |||||
</> | |||||
) | |||||
}, | |||||
{ | |||||
key: ALM_KEYS.AZURE, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="azure" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/azure.svg`} | |||||
/> | |||||
{almName[ALM_KEYS.AZURE]} | |||||
</> | |||||
) | |||||
}, | |||||
{ | |||||
key: ALM_KEYS.GITLAB, | |||||
label: ( | |||||
<> | |||||
<img | |||||
alt="gitlab" | |||||
className="spacer-right" | |||||
height={16} | |||||
src={`${getBaseUrl()}/images/alm/gitlab.svg`} | |||||
/> | |||||
{almName[ALM_KEYS.GITLAB]} | |||||
</> | |||||
) | |||||
} | |||||
]} | |||||
/> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
{currentAlm === ALM_KEYS.AZURE && ( | |||||
<AzureTab | |||||
definitions={definitions.azure} | |||||
loading={loading} | |||||
multipleAlmEnabled={Boolean(multipleAlmEnabled)} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
{currentAlm === ALM_KEYS.BITBUCKET && ( | |||||
<BitbucketTab | |||||
definitions={definitions.bitbucket} | |||||
loading={loading} | |||||
multipleAlmEnabled={Boolean(multipleAlmEnabled)} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
{currentAlm === ALM_KEYS.GITHUB && ( | |||||
<GithubTab | |||||
definitions={definitions.github} | |||||
loading={loading} | |||||
multipleAlmEnabled={Boolean(multipleAlmEnabled)} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
{currentAlm === ALM_KEYS.GITLAB && ( | |||||
<GitlabTab | |||||
definitions={definitions.gitlab} | |||||
loading={loading} | |||||
multipleAlmEnabled={Boolean(multipleAlmEnabled)} | |||||
onDelete={props.onDelete} | |||||
onUpdateDefinitions={props.onUpdateDefinitions} | |||||
/> | |||||
)} | |||||
</div> | |||||
{definitionKeyForDeletion && ( | |||||
<DeleteModal | |||||
id={definitionKeyForDeletion} | |||||
onCancel={props.onCancel} | |||||
onDelete={props.onConfirmDelete} | |||||
projectCount={projectCount} | |||||
/> | |||||
)} | |||||
</> | |||||
); | |||||
} | |||||
export default withAppState(PRDecorationTabs); |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.pr_decoration.form.save | |||||
</SubmitButton> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 2`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.pr_decoration.form.save | |||||
</SubmitButton> | |||||
<ResetButtonLink | |||||
className="spacer-left" | |||||
onClick={[MockFunction]} | |||||
> | |||||
cancel | |||||
</ResetButtonLink> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 3`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.pr_decoration.form.save | |||||
</SubmitButton> | |||||
<Button | |||||
className="button-red spacer-left" | |||||
disabled={false} | |||||
onClick={[MockFunction]} | |||||
> | |||||
delete | |||||
</Button> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 4`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.pr_decoration.form.save | |||||
</SubmitButton> | |||||
<span | |||||
className="text-success spacer-left" | |||||
> | |||||
<AlertSuccessIcon | |||||
className="spacer-right" | |||||
/> | |||||
settings.state.saved | |||||
</span> | |||||
</div> | |||||
</form> | |||||
`; | |||||
exports[`should render correctly 5`] = ` | |||||
<form | |||||
className="views-form" | |||||
data-test="settings__alm-form" | |||||
onSubmit={[Function]} | |||||
> | |||||
<Component /> | |||||
<div | |||||
className="display-flex-center" | |||||
> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
settings.pr_decoration.form.save | |||||
</SubmitButton> | |||||
<DeferredSpinner | |||||
className="spacer-left" | |||||
timeout={100} | |||||
/> | |||||
</div> | |||||
</form> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly for multi-ALM binding: editing a definition 1`] = ` | |||||
<DeferredSpinner | |||||
loading={false} | |||||
timeout={100} | |||||
> | |||||
<AlmPRDecorationTable | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"url", | |||||
"app_id", | |||||
] | |||||
} | |||||
alm="github" | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"additionalColumns": Array [ | |||||
"http://github.enterprise.com", | |||||
"123456", | |||||
], | |||||
"key": "key", | |||||
}, | |||||
] | |||||
} | |||||
onCreate={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
/> | |||||
<AlmPRDecorationForm | |||||
alm="github" | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.pr_decoration.github.info" | |||||
id="settings.pr_decoration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
onCancel={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
showInModal={true} | |||||
> | |||||
<Component /> | |||||
</AlmPRDecorationForm> | |||||
</DeferredSpinner> | |||||
`; | |||||
exports[`should render correctly for multi-ALM binding: loaded 1`] = ` | |||||
<DeferredSpinner | |||||
loading={false} | |||||
timeout={100} | |||||
> | |||||
<AlmPRDecorationTable | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"url", | |||||
"app_id", | |||||
] | |||||
} | |||||
alm="github" | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"additionalColumns": Array [ | |||||
"http://github.enterprise.com", | |||||
"123456", | |||||
], | |||||
"key": "key", | |||||
}, | |||||
] | |||||
} | |||||
onCreate={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
/> | |||||
</DeferredSpinner> | |||||
`; | |||||
exports[`should render correctly for multi-ALM binding: loading 1`] = ` | |||||
<DeferredSpinner | |||||
loading={true} | |||||
timeout={100} | |||||
> | |||||
<AlmPRDecorationTable | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"url", | |||||
"app_id", | |||||
] | |||||
} | |||||
alm="github" | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"additionalColumns": Array [ | |||||
"http://github.enterprise.com", | |||||
"123456", | |||||
], | |||||
"key": "key", | |||||
}, | |||||
] | |||||
} | |||||
onCreate={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
/> | |||||
</DeferredSpinner> | |||||
`; | |||||
exports[`should render correctly for single-ALM binding 1`] = ` | |||||
<AlmPRDecorationForm | |||||
alm="github" | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.pr_decoration.github.info" | |||||
id="settings.pr_decoration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
hideKeyField={true} | |||||
loading={true} | |||||
onCancel={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
readOnly={true} | |||||
success={false} | |||||
> | |||||
<Component /> | |||||
</AlmPRDecorationForm> | |||||
`; | |||||
exports[`should render correctly for single-ALM binding 2`] = ` | |||||
<AlmPRDecorationForm | |||||
alm="github" | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.pr_decoration.github.info" | |||||
id="settings.pr_decoration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
hideKeyField={true} | |||||
loading={false} | |||||
onCancel={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
readOnly={true} | |||||
success={false} | |||||
> | |||||
<Component /> | |||||
</AlmPRDecorationForm> | |||||
`; | |||||
exports[`should render correctly for single-ALM binding 3`] = ` | |||||
<AlmPRDecorationForm | |||||
alm="github" | |||||
bindingDefinition={ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
} | |||||
} | |||||
help={ | |||||
<FormattedMessage | |||||
defaultMessage="settings.pr_decoration.github.info" | |||||
id="settings.pr_decoration.github.info" | |||||
values={ | |||||
Object { | |||||
"link": <Link | |||||
onlyActiveOnIndex={false} | |||||
style={Object {}} | |||||
target="_blank" | |||||
to="/documentation/analysis/pr-decoration/" | |||||
> | |||||
learn_more | |||||
</Link>, | |||||
} | |||||
} | |||||
/> | |||||
} | |||||
hideKeyField={true} | |||||
loading={false} | |||||
onCancel={[MockFunction]} | |||||
onDelete={[MockFunction]} | |||||
onEdit={[MockFunction]} | |||||
onSubmit={[MockFunction]} | |||||
readOnly={true} | |||||
success={false} | |||||
> | |||||
<Component /> | |||||
</AlmPRDecorationForm> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<AlmTab | |||||
alm="azure" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"key": "", | |||||
"personalAccessToken": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"key": "key", | |||||
"personalAccessToken": "asdf1234", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<AlmTab | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"settings.pr_decoration.table.column.bitbucket.url", | |||||
] | |||||
} | |||||
additionalColumnsKeys={ | |||||
Array [ | |||||
"url", | |||||
] | |||||
} | |||||
alm="bitbucket" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"key": "", | |||||
"personalAccessToken": "", | |||||
"url": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"key": "key", | |||||
"personalAccessToken": "asdf1234", | |||||
"url": "http://bbs.enterprise.com", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<AlmTab | |||||
additionalColumnsHeaders={ | |||||
Array [ | |||||
"settings.pr_decoration.table.column.github.url", | |||||
"settings.pr_decoration.table.column.app_id", | |||||
] | |||||
} | |||||
additionalColumnsKeys={ | |||||
Array [ | |||||
"appId", | |||||
"url", | |||||
] | |||||
} | |||||
alm="github" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"appId": "", | |||||
"key": "", | |||||
"privateKey": "", | |||||
"url": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"appId": "123456", | |||||
"key": "key", | |||||
"privateKey": "asdf1234", | |||||
"url": "http://github.enterprise.com", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<AlmTab | |||||
alm="gitlab" | |||||
createConfiguration={[Function]} | |||||
defaultBinding={ | |||||
Object { | |||||
"key": "", | |||||
"personalAccessToken": "", | |||||
} | |||||
} | |||||
definitions={ | |||||
Array [ | |||||
Object { | |||||
"key": "foo", | |||||
"personalAccessToken": "foobar", | |||||
}, | |||||
] | |||||
} | |||||
form={[Function]} | |||||
loading={false} | |||||
multipleAlmEnabled={true} | |||||
onDelete={[MockFunction]} | |||||
onUpdateDefinitions={[MockFunction]} | |||||
updateConfiguration={[Function]} | |||||
/> | |||||
`; |
setProjectBitbucketBinding, | setProjectBitbucketBinding, | ||||
setProjectGithubBinding, | setProjectGithubBinding, | ||||
setProjectGitlabBinding | setProjectGitlabBinding | ||||
} from '../../../../api/almSettings'; | |||||
} from '../../../../api/alm-settings'; | |||||
import throwGlobalError from '../../../../app/utils/throwGlobalError'; | import throwGlobalError from '../../../../app/utils/throwGlobalError'; | ||||
import { AlmSettingsInstance, ALM_KEYS, ProjectAlmBinding } from '../../../../types/alm-settings'; | |||||
import { AlmKeys, AlmSettingsInstance, ProjectAlmBinding } from '../../../../types/alm-settings'; | |||||
import PRDecorationBindingRenderer from './PRDecorationBindingRenderer'; | import PRDecorationBindingRenderer from './PRDecorationBindingRenderer'; | ||||
interface Props { | interface Props { | ||||
success: boolean; | success: boolean; | ||||
} | } | ||||
const FIELDS_BY_ALM: { [almKey in ALM_KEYS]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>> } = { | |||||
[ALM_KEYS.AZURE]: [], | |||||
[ALM_KEYS.BITBUCKET]: ['repository', 'slug'], | |||||
[ALM_KEYS.GITHUB]: ['repository'], | |||||
[ALM_KEYS.GITLAB]: [] | |||||
const FIELDS_BY_ALM: { [almKey in AlmKeys]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>> } = { | |||||
[AlmKeys.Azure]: [], | |||||
[AlmKeys.Bitbucket]: ['repository', 'slug'], | |||||
[AlmKeys.GitHub]: ['repository'], | |||||
[AlmKeys.GitLab]: [] | |||||
}; | }; | ||||
export default class PRDecorationBinding extends React.PureComponent<Props, State> { | export default class PRDecorationBinding extends React.PureComponent<Props, State> { | ||||
}; | }; | ||||
submitProjectAlmBinding( | submitProjectAlmBinding( | ||||
alm: ALM_KEYS, | |||||
alm: AlmKeys, | |||||
key: string, | key: string, | ||||
almSpecificFields?: T.Omit<ProjectAlmBinding, 'key'> | almSpecificFields?: T.Omit<ProjectAlmBinding, 'key'> | ||||
): Promise<void> { | ): Promise<void> { | ||||
const project = this.props.component.key; | const project = this.props.component.key; | ||||
switch (alm) { | switch (alm) { | ||||
case ALM_KEYS.AZURE: | |||||
case AlmKeys.Azure: | |||||
return setProjectAzureBinding({ | return setProjectAzureBinding({ | ||||
almSetting, | almSetting, | ||||
project | project | ||||
}); | }); | ||||
case ALM_KEYS.BITBUCKET: { | |||||
case AlmKeys.Bitbucket: { | |||||
if (!almSpecificFields) { | if (!almSpecificFields) { | ||||
return Promise.reject(); | return Promise.reject(); | ||||
} | } | ||||
slug | slug | ||||
}); | }); | ||||
} | } | ||||
case ALM_KEYS.GITHUB: { | |||||
case AlmKeys.GitHub: { | |||||
const repository = almSpecificFields && almSpecificFields.repository; | const repository = almSpecificFields && almSpecificFields.repository; | ||||
if (!repository) { | if (!repository) { | ||||
return Promise.reject(); | return Promise.reject(); | ||||
}); | }); | ||||
} | } | ||||
case ALM_KEYS.GITLAB: | |||||
case AlmKeys.GitLab: | |||||
return setProjectGitlabBinding({ | return setProjectGitlabBinding({ | ||||
almSetting, | almSetting, | ||||
project | project |
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | import { Alert } from 'sonar-ui-common/components/ui/Alert'; | ||||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | ||||
import { translate } from 'sonar-ui-common/helpers/l10n'; | import { translate } from 'sonar-ui-common/helpers/l10n'; | ||||
import { AlmSettingsInstance, ALM_KEYS, ProjectAlmBinding } from '../../../../types/alm-settings'; | |||||
import { AlmKeys, AlmSettingsInstance, ProjectAlmBinding } from '../../../../types/alm-settings'; | |||||
export interface PRDecorationBindingRendererProps { | export interface PRDecorationBindingRendererProps { | ||||
formData: ProjectAlmBinding; | formData: ProjectAlmBinding; | ||||
/> | /> | ||||
</div> | </div> | ||||
{alm === ALM_KEYS.BITBUCKET && ( | |||||
{alm === AlmKeys.Bitbucket && ( | |||||
<> | <> | ||||
{renderField({ | {renderField({ | ||||
help: true, | help: true, | ||||
</> | </> | ||||
)} | )} | ||||
{alm === ALM_KEYS.GITHUB && | |||||
{alm === AlmKeys.GitHub && | |||||
renderField({ | renderField({ | ||||
help: true, | help: true, | ||||
helpParams: { example: 'SonarSource/sonarqube' }, | helpParams: { example: 'SonarSource/sonarqube' }, |
setProjectAzureBinding, | setProjectAzureBinding, | ||||
setProjectBitbucketBinding, | setProjectBitbucketBinding, | ||||
setProjectGithubBinding | setProjectGithubBinding | ||||
} from '../../../../../api/almSettings'; | |||||
} from '../../../../../api/alm-settings'; | |||||
import { mockComponent } from '../../../../../helpers/testMocks'; | import { mockComponent } from '../../../../../helpers/testMocks'; | ||||
import { ALM_KEYS } from '../../../../../types/alm-settings'; | |||||
import { AlmKeys } from '../../../../../types/alm-settings'; | |||||
import PRDecorationBinding from '../PRDecorationBinding'; | import PRDecorationBinding from '../PRDecorationBinding'; | ||||
jest.mock('../../../../../api/almSettings', () => ({ | |||||
jest.mock('../../../../../api/alm-settings', () => ({ | |||||
getAlmSettings: jest.fn().mockResolvedValue([]), | getAlmSettings: jest.fn().mockResolvedValue([]), | ||||
getProjectAlmBinding: jest.fn().mockResolvedValue(undefined), | getProjectAlmBinding: jest.fn().mockResolvedValue(undefined), | ||||
setProjectAzureBinding: jest.fn().mockResolvedValue(undefined), | setProjectAzureBinding: jest.fn().mockResolvedValue(undefined), | ||||
it('should fill selects and fill formdata', async () => { | it('should fill selects and fill formdata', async () => { | ||||
const url = 'github.com'; | const url = 'github.com'; | ||||
const instances = [{ key: 'instance1', url, alm: ALM_KEYS.GITHUB }]; | |||||
const instances = [{ key: 'instance1', url, alm: AlmKeys.GitHub }]; | |||||
const formdata = { | const formdata = { | ||||
key: 'instance1', | key: 'instance1', | ||||
repository: 'account/repo' | repository: 'account/repo' | ||||
describe('handleSubmit', () => { | describe('handleSubmit', () => { | ||||
const instances = [ | const instances = [ | ||||
{ key: 'github', alm: ALM_KEYS.GITHUB }, | |||||
{ key: 'azure', alm: ALM_KEYS.AZURE }, | |||||
{ key: 'bitbucket', alm: ALM_KEYS.BITBUCKET } | |||||
{ key: 'github', alm: AlmKeys.GitHub }, | |||||
{ key: 'azure', alm: AlmKeys.Azure }, | |||||
{ key: 'bitbucket', alm: AlmKeys.Bitbucket } | |||||
]; | ]; | ||||
it('should work for github', async () => { | it('should work for github', async () => { | ||||
wrapper.setState({ | wrapper.setState({ | ||||
instances: [ | instances: [ | ||||
{ key: 'azure', alm: ALM_KEYS.AZURE }, | |||||
{ key: 'bitbucket', alm: ALM_KEYS.BITBUCKET }, | |||||
{ key: 'github', alm: ALM_KEYS.GITHUB } | |||||
{ key: 'azure', alm: AlmKeys.Azure }, | |||||
{ key: 'bitbucket', alm: AlmKeys.Bitbucket }, | |||||
{ key: 'github', alm: AlmKeys.GitHub } | |||||
] | ] | ||||
}); | }); | ||||
expect(wrapper.instance().validateForm({ key: 'azure' })).toBe(true); | expect(wrapper.instance().validateForm({ key: 'azure' })).toBe(true); |
import * as React from 'react'; | import * as React from 'react'; | ||||
import Select from 'sonar-ui-common/components/controls/Select'; | import Select from 'sonar-ui-common/components/controls/Select'; | ||||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | ||||
import { ALM_KEYS } from '../../../../../types/alm-settings'; | |||||
import { AlmKeys } from '../../../../../types/alm-settings'; | |||||
import PRDecorationBindingRenderer, { | import PRDecorationBindingRenderer, { | ||||
PRDecorationBindingRendererProps | PRDecorationBindingRendererProps | ||||
} from '../PRDecorationBindingRenderer'; | } from '../PRDecorationBindingRenderer'; | ||||
const singleInstance = { | const singleInstance = { | ||||
key: 'single', | key: 'single', | ||||
url: 'http://single.url', | url: 'http://single.url', | ||||
alm: ALM_KEYS.GITHUB | |||||
alm: AlmKeys.GitHub | |||||
}; | }; | ||||
expect( | expect( | ||||
shallowRender({ | shallowRender({ | ||||
const urls = ['http://github.enterprise.com', 'http://bbs.enterprise.com']; | const urls = ['http://github.enterprise.com', 'http://bbs.enterprise.com']; | ||||
const instances = [ | const instances = [ | ||||
{ | { | ||||
alm: ALM_KEYS.GITHUB, | |||||
alm: AlmKeys.GitHub, | |||||
key: 'i1', | key: 'i1', | ||||
url: urls[0] | url: urls[0] | ||||
}, | }, | ||||
{ | { | ||||
alm: ALM_KEYS.GITHUB, | |||||
alm: AlmKeys.GitHub, | |||||
key: 'i2', | key: 'i2', | ||||
url: urls[0] | url: urls[0] | ||||
}, | }, | ||||
{ | { | ||||
alm: ALM_KEYS.BITBUCKET, | |||||
alm: AlmKeys.Bitbucket, | |||||
key: 'i3', | key: 'i3', | ||||
url: urls[1] | url: urls[1] | ||||
}, | }, | ||||
{ | { | ||||
alm: ALM_KEYS.AZURE, | |||||
alm: AlmKeys.Azure, | |||||
key: 'i4' | key: 'i4' | ||||
} | } | ||||
]; | ]; | ||||
it('should display action state correctly', () => { | it('should display action state correctly', () => { | ||||
const urls = ['http://url.com']; | const urls = ['http://url.com']; | ||||
const instances = [{ key: 'key', url: urls[0], alm: ALM_KEYS.GITHUB }]; | |||||
const instances = [{ key: 'key', url: urls[0], alm: AlmKeys.GitHub }]; | |||||
expect(shallowRender({ instances, loading: false, saving: true })).toMatchSnapshot(); | expect(shallowRender({ instances, loading: false, saving: true })).toMatchSnapshot(); | ||||
expect(shallowRender({ instances, loading: false, success: true })).toMatchSnapshot(); | expect(shallowRender({ instances, loading: false, success: true })).toMatchSnapshot(); | ||||
it('should render select options correctly', async () => { | it('should render select options correctly', async () => { | ||||
const instances = [ | const instances = [ | ||||
{ | { | ||||
alm: ALM_KEYS.AZURE, | |||||
alm: AlmKeys.Azure, | |||||
key: 'azure' | key: 'azure' | ||||
}, | }, | ||||
{ | { | ||||
alm: ALM_KEYS.GITHUB, | |||||
alm: AlmKeys.GitHub, | |||||
key: 'github', | key: 'github', | ||||
url: 'gh.url.com' | url: 'gh.url.com' | ||||
} | } |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
import { | import { | ||||
AlmKeys, | |||||
AlmSettingsInstance, | AlmSettingsInstance, | ||||
ALM_KEYS, | |||||
AzureBindingDefinition, | AzureBindingDefinition, | ||||
BitbucketBindingDefinition, | BitbucketBindingDefinition, | ||||
GithubBindingDefinition, | GithubBindingDefinition, | ||||
overrides: Partial<AlmSettingsInstance> = {} | overrides: Partial<AlmSettingsInstance> = {} | ||||
): AlmSettingsInstance { | ): AlmSettingsInstance { | ||||
return { | return { | ||||
alm: ALM_KEYS.GITHUB, | |||||
alm: AlmKeys.GitHub, | |||||
key: 'key', | key: 'key', | ||||
...overrides | ...overrides | ||||
}; | }; |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
export const enum ALM_KEYS { | |||||
AZURE = 'azure', | |||||
BITBUCKET = 'bitbucket', | |||||
GITHUB = 'github', | |||||
GITLAB = 'gitlab' | |||||
export const enum AlmKeys { | |||||
Azure = 'azure', | |||||
Bitbucket = 'bitbucket', | |||||
GitHub = 'github', | |||||
GitLab = 'gitlab' | |||||
} | } | ||||
export interface AlmSettingsBinding { | |||||
export interface AlmBindingDefinition { | |||||
key: string; | key: string; | ||||
} | } | ||||
export interface AlmSettingsInstance { | |||||
alm: ALM_KEYS; | |||||
key: string; | |||||
url?: string; | |||||
} | |||||
export interface AlmSettingsBindingDefinitions { | |||||
azure: AzureBindingDefinition[]; | |||||
bitbucket: BitbucketBindingDefinition[]; | |||||
github: GithubBindingDefinition[]; | |||||
gitlab: GitlabBindingDefinition[]; | |||||
} | |||||
export interface AzureBindingDefinition extends AlmSettingsBinding { | |||||
export interface AzureBindingDefinition extends AlmBindingDefinition { | |||||
personalAccessToken: string; | personalAccessToken: string; | ||||
} | } | ||||
export interface BitbucketBindingDefinition extends AlmSettingsBinding { | |||||
export interface BitbucketBindingDefinition extends AlmBindingDefinition { | |||||
personalAccessToken: string; | personalAccessToken: string; | ||||
url: string; | url: string; | ||||
} | } | ||||
export interface GithubBindingDefinition extends AlmSettingsBinding { | |||||
export interface GithubBindingDefinition extends AlmBindingDefinition { | |||||
appId: string; | appId: string; | ||||
privateKey: string; | privateKey: string; | ||||
url: string; | url: string; | ||||
} | } | ||||
export interface GitlabBindingDefinition extends AlmSettingsBinding { | |||||
export interface GitlabBindingDefinition extends AlmBindingDefinition { | |||||
personalAccessToken: string; | personalAccessToken: string; | ||||
} | } | ||||
almSetting: string; | almSetting: string; | ||||
project: string; | project: string; | ||||
} | } | ||||
export interface AlmSettingsInstance { | |||||
alm: AlmKeys; | |||||
key: string; | |||||
url?: string; | |||||
} | |||||
export interface AlmSettingsBindingDefinitions { | |||||
azure: AzureBindingDefinition[]; | |||||
bitbucket: BitbucketBindingDefinition[]; | |||||
github: GithubBindingDefinition[]; | |||||
gitlab: GitlabBindingDefinition[]; | |||||
} |
settings.languages.select_a_language_placeholder=Select a language | settings.languages.select_a_language_placeholder=Select a language | ||||
settings.pr_decoration.category=Pull Request Decoration | |||||
settings.pr_decoration.title=Pull Request Decoration | |||||
settings.pr_decoration.description=Pull Request Decoration adds SonarQube analysis and a Quality Gate to your Pull Requests directly in your ALM provider's interface. | |||||
settings.pr_decoration.manage_instances=Manage instances | |||||
settings.pr_decoration.azure.info=Accounts that will be used to decorate Pull Requests need Code: Read & Write permission. {link} | |||||
settings.pr_decoration.bitbucket.info=Accounts that will be used to decorate Pull Requests need 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.gitlab.info=Accounts that will be used to decorate Merge Requests need comment permissions on projects. The personal key needs the API scope permission. {link} | |||||
settings.pr_decoration.table.title=Pull Request Decoration configurations | |||||
settings.mr_decoration.table.title=Merge Request Decoration configurations | |||||
settings.pr_decoration.table.empty.azure=Create your first Azure DevOps configuration to enable Pull Request Decoration on your projects. | |||||
settings.pr_decoration.table.empty.bitbucket=Create your first Bitbucket configuration to enable Pull Request Decoration on your projects. | |||||
settings.pr_decoration.table.empty.github=Create your first GitHub configuration to enable Pull Request Decoration on your organization or repository. | |||||
settings.pr_decoration.table.empty.gitlab=Create your first GitLab configuration to enable Merge Request Decoration on your repository. | |||||
settings.pr_decoration.table.create=Create configuration | |||||
settings.pr_decoration.table.column.name=Name | |||||
settings.pr_decoration.table.column.bitbucket.url=Bitbucket Server URL | |||||
settings.pr_decoration.table.column.github.url=GitHub Enterprise or GitHub.com URL | |||||
settings.pr_decoration.table.column.app_id=App ID | |||||
settings.pr_decoration.table.column.edit=Edit | |||||
settings.pr_decoration.table.column.delete=Delete | |||||
settings.pr_decoration.delete.header=Delete configuration | |||||
settings.pr_decoration.delete.message=Are you sure you want to delete the {id} configuration? | |||||
settings.pr_decoration.delete.info={0} projects will no longer get Pull Request Decorations. | |||||
settings.pr_decoration.delete.no_info=An unknown number of projects will no longer get Pull Request Decorations. | |||||
settings.pr_decoration.form.header.create=Create a Pull Request Decoration configuration | |||||
settings.mr_decoration.form.header.create=Create a Merge Request Decoration configuration | |||||
settings.pr_decoration.form.header.edit=Edit the Pull Request Decoration configuration | |||||
settings.mr_decoration.form.header.edit=Edit the Merge Request Decoration configuration | |||||
settings.pr_decoration.form.name.azure=Configuration name | |||||
settings.pr_decoration.form.name.azure.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Azure instance for a project. | |||||
settings.pr_decoration.form.name.bitbucket=Configuration name | |||||
settings.pr_decoration.form.name.bitbucket.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Bitbucket instance for a project. | |||||
settings.pr_decoration.form.name.github=Configuration name | |||||
settings.pr_decoration.form.name.github.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitHub App for a project. | |||||
settings.pr_decoration.form.name.gitlab=Configuration name | |||||
settings.pr_decoration.form.name.gitlab.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitLab instance for a project. | |||||
settings.pr_decoration.form.url.bitbucket=Bitbucket Server URL | |||||
settings.pr_decoration.form.url.bitbucket.help=Example: {example} | |||||
settings.pr_decoration.form.url.github=GitHub URL | |||||
settings.pr_decoration.form.url.github.help1=Example for Github Enterprise: | |||||
settings.pr_decoration.form.url.github.help2=If using GitHub.com: | |||||
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.azure.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.personal_access_token.gitlab.help=Token of the user that will be used to decorate the Merge Requests. Needs API scope authorization. | |||||
settings.pr_decoration.form.save=Save configuration | |||||
settings.pr_decoration.form.cancel=Cancel | |||||
settings.almintegration.title=Integration configurations | |||||
settings.almintegration.description=ALM integrations allow SonarQube to interact with your ALM. This enables things like authentication, or providing analysis details and a Quality Gate to your Pull Requests directly in your ALM provider's interface. | |||||
settings.almintegration.manage_instances=Manage instances | |||||
settings.almintegration.azure.info=Accounts that will be used to decorate Pull Requests need Code: Read & Write permission. {link} | |||||
settings.almintegration.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.almintegration.gitlab.info=Accounts that will be used to decorate Merge Requests need comment permissions on projects. The personal key needs the API scope permission. {link} | |||||
settings.almintegration.bitbucket.help_1=SonarQube needs a Personal Access Token to communicate with Bitbucket Server. This token will be used to decorate Pull Requests. | |||||
settings.almintegration.bitbucket.help_2=The account used for integration needs write permission. | |||||
settings.almintegration.bitbucket.help_3=We recommend to integrate with SonarQube using a Bitbucket Server Service Account. | |||||
settings.almintegration.table.title=ALM integration configurations | |||||
settings.almintegration.table.empty.azure=Create your first Azure DevOps configuration to enable Pull Request Decoration on your projects. | |||||
settings.almintegration.table.empty.bitbucket=Create your first Bitbucket configuration to enable Pull Request Decoration on your projects. | |||||
settings.almintegration.table.empty.github=Create your first GitHub configuration to enable Pull Request Decoration on your organization or repository. | |||||
settings.almintegration.table.empty.gitlab=Create your first GitLab configuration to enable Merge Request Decoration on your repository. | |||||
settings.almintegration.table.create=Create configuration | |||||
settings.almintegration.table.column.name=Name | |||||
settings.almintegration.table.column.bitbucket.url=Bitbucket Server URL | |||||
settings.almintegration.table.column.github.url=GitHub Enterprise or GitHub.com URL | |||||
settings.almintegration.table.column.app_id=App ID | |||||
settings.almintegration.table.column.edit=Edit | |||||
settings.almintegration.table.column.delete=Delete | |||||
settings.almintegration.delete.header=Delete configuration | |||||
settings.almintegration.delete.message=Are you sure you want to delete the {id} configuration? | |||||
settings.almintegration.delete.info={0} projects will no longer get Pull Request Decorations. | |||||
settings.almintegration.delete.no_info=An unknown number of projects will no longer get Pull Request Decorations. | |||||
settings.almintegration.form.header.create=Create a configuration | |||||
settings.almintegration.form.header.edit=Edit the configuration | |||||
settings.almintegration.form.name.azure=Configuration name | |||||
settings.almintegration.form.name.azure.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Azure instance for a project. | |||||
settings.almintegration.form.name.bitbucket=Configuration name | |||||
settings.almintegration.form.name.bitbucket.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured Bitbucket instance for a project. | |||||
settings.almintegration.form.name.github=Configuration name | |||||
settings.almintegration.form.name.github.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitHub App for a project. | |||||
settings.almintegration.form.name.gitlab=Configuration name | |||||
settings.almintegration.form.name.gitlab.help=Give your configuration a clear and succinct name. This name will be used at project level to identify the correct configured GitLab instance for a project. | |||||
settings.almintegration.form.url.bitbucket=Bitbucket Server URL | |||||
settings.almintegration.form.url.bitbucket.help=Example: {example} | |||||
settings.almintegration.form.url.github=GitHub URL | |||||
settings.almintegration.form.url.github.help1=Example for Github Enterprise: | |||||
settings.almintegration.form.url.github.help2=If using GitHub.com: | |||||
settings.almintegration.form.app_id=GitHub App ID | |||||
settings.almintegration.form.private_key=Private Key | |||||
settings.almintegration.form.personal_access_token=Personal Access token | |||||
settings.almintegration.form.personal_access_token.azure.help=Token of the user that will be used to decorate the Pull Requests. Needs authorized scope: "Code (read and write)". | |||||
settings.almintegration.form.personal_access_token.gitlab.help=Token of the user that will be used to decorate the Merge Requests. Needs API scope authorization. | |||||
settings.almintegration.form.save=Save configuration | |||||
settings.almintegration.form.cancel=Cancel | |||||
settings.almintegration.features=ALM integration features | |||||
settings.almintegration.feature.enabled=This feature is enabled | |||||
settings.almintegration.feature.disabled=This feature is currently disabled | |||||
settings.almintegration.feature.need_at_least_1_binding=You need to have at least 1 binding configured to use this feature | |||||
settings.almintegration.feature.pr_decoration.title=Pull Request Decoration | |||||
settings.almintegration.feature.pr_decoration.description=Add analysis and a Quality Gate to your Pull Requests directly in your ALM provider's interface. | |||||
settings.almintegration.feature.mr_decoration.title=Merge Request Decoration | |||||
settings.almintegration.feature.mr_decoration.description=Add analysis and a Quality Gate to your Merge Requests directly in your ALM provider's interface. | |||||
settings.almintegration.feature.alm_repo_import.title=Import repositories from your ALM | |||||
settings.almintegration.feature.alm_repo_import.description=Select repositories from your ALM, and import them into SonarQube. | |||||
settings.almintegration.feature.alm_repo_import.disabled_if_multiple_bbs_instances=Connecting to multiple Bitbucket Server instances will deactivate the {feature} feature. Projects will have to be set up manually. | |||||
settings.pr_decoration.binding.category=Pull Request Decoration | settings.pr_decoration.binding.category=Pull Request Decoration | ||||
settings.pr_decoration.binding.no_bindings=This feature must first be enabled in the global settings. {link} | settings.pr_decoration.binding.no_bindings=This feature must first be enabled in the global settings. {link} | ||||
property.category.general.looknfeel=Look & Feel | property.category.general.looknfeel=Look & Feel | ||||
property.category.general.issues=Issues | property.category.general.issues=Issues | ||||
property.category.general.subProjects=Sub-projects | property.category.general.subProjects=Sub-projects | ||||
property.category.almintegration=ALM Integrations | |||||
property.category.almintegration.github=GitHub Authentication | |||||
property.category.almintegration.github.description=In order to enable authentication on GitHub.com or GitHub Enterprise:<ul><li>SonarQube must be publicly accessible through HTTPS only</li><li>The property 'sonar.core.serverBaseURL' must be set to this public HTTPS URL</li><li>In your GitHub profile, you need to create a Developer Application for which the 'Authorization callback URL' must be set to <code>'<value_of_sonar.core.serverBaseURL_property>/oauth2/callback'</code>.</li></ul> | |||||
property.category.almintegration.gitlab=GitLab Authentication | |||||
property.category.almintegration.gitlab.description=In order to enable GitLab authentication, the property 'sonar.core.serverBaseURL' must be set to the public URL | |||||
property.category.organizations=Organizations | property.category.organizations=Organizations | ||||
property.category.security=Security | property.category.security=Security | ||||
property.category.security.encryption=Encryption | property.category.security.encryption=Encryption | ||||
property.category.security.github=GitHub | |||||
property.category.security.github.description=In order to enable authentication on GitHub.com or GitHub Enterprise:<ul><li>SonarQube must be publicly accessible through HTTPS only</li><li>The property 'sonar.core.serverBaseURL' must be set to this public HTTPS URL</li><li>In your GitHub profile, you need to create a Developer Application for which the 'Authorization callback URL' must be set to <code>'<value_of_sonar.core.serverBaseURL_property>/oauth2/callback'</code>.</li></ul> | |||||
property.category.security.gitlab=Gitlab | |||||
property.category.security.gitlab.description=In order to enable Gitlab authentication, the property 'sonar.core.serverBaseURL' must be set to the public URL | |||||
property.category.security.saml=SAML | property.category.security.saml=SAML | ||||
property.category.security.saml.description=In order to enable SAML authentication, the property 'sonar.core.serverBaseURL' must be set to the public URL | property.category.security.saml.description=In order to enable SAML authentication, the property 'sonar.core.serverBaseURL' must be set to the public URL | ||||
property.category.java=Java | property.category.java=Java |
*/ | */ | ||||
String SUBCATEGORY_DUPLICATIONS = "duplications"; | String SUBCATEGORY_DUPLICATIONS = "duplications"; | ||||
/** | |||||
* @since 8.2 | |||||
*/ | |||||
String CATEGORY_ALM_INTEGRATION = "almintegration"; | |||||
/** | /** | ||||
* @since 8.1 | * @since 8.1 | ||||
*/ | */ |