@@ -23,14 +23,14 @@ import { | |||
AlmSettingsBindingDefinitions, | |||
AlmSettingsInstance, | |||
AzureBindingDefinition, | |||
AzureProjectAlmBinding, | |||
AzureProjectAlmBindingParams, | |||
BitbucketBindingDefinition, | |||
BitbucketProjectAlmBinding, | |||
BitbucketProjectAlmBindingParams, | |||
GithubBindingDefinition, | |||
GithubProjectAlmBinding, | |||
GithubProjectAlmBindingParams, | |||
GitlabBindingDefinition, | |||
GitlabProjectAlmBinding, | |||
ProjectAlmBinding | |||
GitlabProjectAlmBindingParams, | |||
ProjectAlmBindingResponse | |||
} from '../types/alm-settings'; | |||
export function getAlmDefinitions(): Promise<AlmSettingsBindingDefinitions> { | |||
@@ -87,7 +87,7 @@ export function countBindedProjects(almSetting: string) { | |||
.catch(throwGlobalError); | |||
} | |||
export function getProjectAlmBinding(project: string): Promise<ProjectAlmBinding> { | |||
export function getProjectAlmBinding(project: string): Promise<ProjectAlmBindingResponse> { | |||
return getJSON('/api/alm_settings/get_binding', { project }); | |||
} | |||
@@ -95,18 +95,18 @@ export function deleteProjectAlmBinding(project: string): Promise<void> { | |||
return post('/api/alm_settings/delete_binding', { project }).catch(throwGlobalError); | |||
} | |||
export function setProjectAzureBinding(data: AzureProjectAlmBinding) { | |||
export function setProjectAzureBinding(data: AzureProjectAlmBindingParams) { | |||
return post('/api/alm_settings/set_azure_binding', data).catch(throwGlobalError); | |||
} | |||
export function setProjectBitbucketBinding(data: BitbucketProjectAlmBinding) { | |||
export function setProjectBitbucketBinding(data: BitbucketProjectAlmBindingParams) { | |||
return post('/api/alm_settings/set_bitbucket_binding', data).catch(throwGlobalError); | |||
} | |||
export function setProjectGithubBinding(data: GithubProjectAlmBinding) { | |||
export function setProjectGithubBinding(data: GithubProjectAlmBindingParams) { | |||
return post('/api/alm_settings/set_github_binding', data).catch(throwGlobalError); | |||
} | |||
export function setProjectGitlabBinding(data: GitlabProjectAlmBinding) { | |||
export function setProjectGitlabBinding(data: GitlabProjectAlmBindingParams) { | |||
return post('/api/alm_settings/set_gitlab_binding', data).catch(throwGlobalError); | |||
} |
@@ -47,7 +47,6 @@ import { hasAdvancedALMIntegration, sanitizeAlmId } from '../../../helpers/almIn | |||
import { getOrganizationUrl } from '../../../helpers/urls'; | |||
import { skipOnboarding } from '../../../store/users'; | |||
import { deleteOrganization } from '../../organizations/actions'; | |||
import '../../tutorials/styles.css'; // TODO remove me | |||
import { createOrganization } from './actions'; | |||
import AlmApplicationInstalling from './AlmApplicationInstalling'; | |||
import AutoOrganizationCreate from './AutoOrganizationCreate'; |
@@ -20,7 +20,7 @@ | |||
import * as React from 'react'; | |||
import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import Step from '../../tutorials/components/Step'; | |||
import Step from '../../../components/tutorials/components/Step'; | |||
interface Props { | |||
children: React.ReactNode; |
@@ -22,8 +22,8 @@ import { SubmitButton } from 'sonar-ui-common/components/controls/buttons'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; | |||
import Step from '../../../components/tutorials/components/Step'; | |||
import { getExtensionStart } from '../../../helpers/extensions'; | |||
import Step from '../../tutorials/components/Step'; | |||
import BillingFormShim from '../components/BillingFormShim'; | |||
import PlanSelect, { Plan } from './PlanSelect'; | |||
@@ -22,7 +22,7 @@ import { Button } from 'sonar-ui-common/components/controls/buttons'; | |||
import OnboardingAddMembersIcon from 'sonar-ui-common/components/icons/OnboardingAddMembersIcon'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { Router, withRouter } from '../../../components/hoc/withRouter'; | |||
import '../../tutorials/styles.css'; | |||
import '../../../components/tutorials/styles.css'; | |||
import './OrganizationEmpty.css'; | |||
interface Props { |
@@ -22,12 +22,12 @@ import { FormattedMessage } from 'react-intl'; | |||
import { connect } from 'react-redux'; | |||
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import AnalyzeTutorial from '../../../components/tutorials/manual/AnalyzeTutorial'; | |||
import { getBranchLikeDisplayName, isBranch, isMainBranch } from '../../../helpers/branch-like'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import { getCurrentUser, Store } from '../../../store/rootReducer'; | |||
import { BranchLike } from '../../../types/branch-like'; | |||
import { ComponentQualifier } from '../../../types/component'; | |||
import AnalyzeTutorial from '../../tutorials/analyzeProject/AnalyzeTutorial'; | |||
interface Props { | |||
branchLike?: BranchLike; |
@@ -20,7 +20,7 @@ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockGithubBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { GithubBindingDefinition } from '../../../../../types/alm-settings'; | |||
import AlmBindingDefinitionForm from '../AlmBindingDefinitionForm'; | |||
@@ -29,14 +29,14 @@ it('should render correctly', () => { | |||
}); | |||
it('should reset if the props change', () => { | |||
const bindingDefinition = mockGithubDefinition(); | |||
const bindingDefinition = mockGithubBindingDefinition(); | |||
const wrapper = shallowRender({ bindingDefinition }); | |||
wrapper.setState({ formData: { ...bindingDefinition, appId: 'newAppId' }, touched: true }); | |||
wrapper.setProps({ bindingDefinition: { ...bindingDefinition } }); | |||
expect(wrapper.state('touched')).toBe(true); | |||
wrapper.setProps({ bindingDefinition: mockGithubDefinition({ key: 'diffKey' }) }); | |||
wrapper.setProps({ bindingDefinition: mockGithubBindingDefinition({ key: 'diffKey' }) }); | |||
expect(wrapper.state('touched')).toBe(false); | |||
}); | |||
@@ -90,7 +90,7 @@ it('should handle cancelling', () => { | |||
onCancel | |||
}); | |||
wrapper.setState({ formData: mockGithubDefinition() }); | |||
wrapper.setState({ formData: mockGithubBindingDefinition() }); | |||
wrapper.instance().handleCancel(); | |||
expect(wrapper.state().formData).toBe(bindingDefinition); | |||
@@ -99,7 +99,7 @@ it('should handle cancelling', () => { | |||
it('should handle deleting', () => { | |||
const onDelete = jest.fn(); | |||
const bindingDefinition = mockGithubDefinition(); | |||
const bindingDefinition = mockGithubBindingDefinition(); | |||
const wrapper = shallowRender({ | |||
bindingDefinition, | |||
onDelete | |||
@@ -113,14 +113,14 @@ it('should (dis)allow submit by validating its state', () => { | |||
const wrapper = shallowRender(); | |||
expect(wrapper.instance().canSubmit()).toBe(false); | |||
wrapper.setState({ formData: mockGithubDefinition(), touched: true }); | |||
wrapper.setState({ formData: mockGithubBindingDefinition(), touched: true }); | |||
expect(wrapper.instance().canSubmit()).toBe(true); | |||
wrapper.setState({ formData: mockGithubDefinition({ key: '' }), touched: true }); | |||
wrapper.setState({ formData: mockGithubBindingDefinition({ key: '' }), touched: true }); | |||
wrapper.setProps({ hideKeyField: true }); | |||
expect(wrapper.instance().canSubmit()).toBe(true); | |||
wrapper.setState({ formData: mockGithubDefinition({ url: '' }), touched: true }); | |||
wrapper.setState({ formData: mockGithubBindingDefinition({ url: '' }), touched: true }); | |||
wrapper.setProps({ optionalFields: ['url'] }); | |||
expect(wrapper.instance().canSubmit()).toBe(true); | |||
}); |
@@ -20,7 +20,7 @@ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockAzureBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { AlmKeys, AzureBindingDefinition } from '../../../../../types/alm-settings'; | |||
import AlmTab from '../AlmTab'; | |||
@@ -37,7 +37,7 @@ it('should handle cancel', async () => { | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ | |||
editedDefinition: mockAzureDefinition() | |||
editedDefinition: mockAzureBindingDefinition() | |||
}); | |||
wrapper.instance().handleCancel(); | |||
@@ -48,7 +48,7 @@ it('should handle cancel', async () => { | |||
}); | |||
it('should handle edit', async () => { | |||
const config = mockAzureDefinition(); | |||
const config = mockAzureBindingDefinition(); | |||
const wrapper = shallowRender({ definitions: [config] }); | |||
wrapper.instance().handleEdit(config.key); | |||
await waitAndUpdate(wrapper); | |||
@@ -58,7 +58,7 @@ it('should handle edit', async () => { | |||
it('should create config', async () => { | |||
const onUpdateDefinitions = jest.fn(); | |||
const createConfiguration = jest.fn(() => Promise.resolve()); | |||
const config = mockAzureDefinition(); | |||
const config = mockAzureBindingDefinition(); | |||
const wrapper = shallowRender({ createConfiguration, onUpdateDefinitions }); | |||
wrapper.instance().handleCreate(); | |||
@@ -75,7 +75,7 @@ it('should create config', async () => { | |||
it('should update config', async () => { | |||
const onUpdateDefinitions = jest.fn(); | |||
const updateConfiguration = jest.fn(() => Promise.resolve()); | |||
const config = mockAzureDefinition(); | |||
const config = mockAzureBindingDefinition(); | |||
const wrapper = shallowRender({ onUpdateDefinitions, updateConfiguration }); | |||
wrapper.setState({ editedDefinition: config }); | |||
@@ -96,7 +96,7 @@ function shallowRender(props: Partial<AlmTab<AzureBindingDefinition>['props']> = | |||
alm={AlmKeys.Azure} | |||
createConfiguration={jest.fn()} | |||
defaultBinding={DEFAULT_BINDING} | |||
definitions={[mockAzureDefinition()]} | |||
definitions={[mockAzureBindingDefinition()]} | |||
form={jest.fn()} | |||
loading={false} | |||
multipleAlmEnabled={true} |
@@ -19,14 +19,14 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockGithubBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { AlmKeys, GithubBindingDefinition } from '../../../../../types/alm-settings'; | |||
import AlmTabRenderer, { AlmTabRendererProps } from '../AlmTabRenderer'; | |||
it('should render correctly for multi-ALM binding', () => { | |||
expect(shallowRender({ loading: true })).toMatchSnapshot('loading'); | |||
expect(shallowRender()).toMatchSnapshot('loaded'); | |||
expect(shallowRender({ editedDefinition: mockGithubDefinition() })).toMatchSnapshot( | |||
expect(shallowRender({ editedDefinition: mockGithubBindingDefinition() })).toMatchSnapshot( | |||
'editing a definition' | |||
); | |||
expect( | |||
@@ -51,7 +51,7 @@ it('should render correctly for single-ALM binding', () => { | |||
expect(shallowRender({ loading: true, multipleAlmEnabled: false })).toMatchSnapshot(); | |||
expect(shallowRender({ multipleAlmEnabled: false })).toMatchSnapshot(); | |||
expect( | |||
shallowRender({ definitions: [mockGithubDefinition()], multipleAlmEnabled: false }) | |||
shallowRender({ definitions: [mockGithubBindingDefinition()], multipleAlmEnabled: false }) | |||
).toMatchSnapshot(); | |||
}); | |||
@@ -61,8 +61,8 @@ function shallowRender(props: Partial<AlmTabRendererProps<GithubBindingDefinitio | |||
additionalColumnsHeaders={['url', 'app_id']} | |||
additionalColumnsKeys={['url', 'appId']} | |||
alm={AlmKeys.GitHub} | |||
defaultBinding={mockGithubDefinition()} | |||
definitions={[mockGithubDefinition()]} | |||
defaultBinding={mockGithubBindingDefinition()} | |||
definitions={[mockGithubBindingDefinition()]} | |||
form={jest.fn()} | |||
loading={false} | |||
multipleAlmEnabled={true} |
@@ -19,12 +19,12 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockAzureBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import AzureForm, { AzureFormProps } from '../AzureForm'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockAzureDefinition() })).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockAzureBindingDefinition() })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<AzureFormProps> = {}) { |
@@ -19,7 +19,7 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockAzureDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockAzureBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import AzureTab, { AzureTabProps } from '../AzureTab'; | |||
it('should render correctly', () => { | |||
@@ -29,7 +29,7 @@ it('should render correctly', () => { | |||
function shallowRender(props: Partial<AzureTabProps> = {}) { | |||
return shallow( | |||
<AzureTab | |||
definitions={[mockAzureDefinition()]} | |||
definitions={[mockAzureBindingDefinition()]} | |||
loading={false} | |||
multipleAlmEnabled={true} | |||
onDelete={jest.fn()} |
@@ -19,12 +19,12 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockBitbucketDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockBitbucketBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import BitbucketForm, { BitbucketFormProps } from '../BitbucketForm'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockBitbucketDefinition() })).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockBitbucketBindingDefinition() })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<BitbucketFormProps> = {}) { |
@@ -19,7 +19,7 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockBitbucketDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockBitbucketBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import BitbucketTab, { BitbucketTabProps } from '../BitbucketTab'; | |||
it('should render correctly', () => { | |||
@@ -29,7 +29,7 @@ it('should render correctly', () => { | |||
function shallowRender(props: Partial<BitbucketTabProps> = {}) { | |||
return shallow( | |||
<BitbucketTab | |||
definitions={[mockBitbucketDefinition()]} | |||
definitions={[mockBitbucketBindingDefinition()]} | |||
loading={false} | |||
multipleAlmEnabled={true} | |||
onDelete={jest.fn()} |
@@ -19,12 +19,12 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockGithubBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import GithubForm, { GithubFormProps } from '../GithubForm'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockGithubDefinition() })).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockGithubBindingDefinition() })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<GithubFormProps> = {}) { |
@@ -19,7 +19,7 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGithubDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockGithubBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import GithubTab, { GithubTabProps } from '../GithubTab'; | |||
it('should render correctly', () => { | |||
@@ -31,7 +31,7 @@ function shallowRender(props: Partial<GithubTabProps> = {}) { | |||
return shallow( | |||
<GithubTab | |||
branchesEnabled={true} | |||
definitions={[mockGithubDefinition()]} | |||
definitions={[mockGithubBindingDefinition()]} | |||
loading={false} | |||
multipleAlmEnabled={true} | |||
onDelete={jest.fn()} |
@@ -19,12 +19,12 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGitlabDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockGitlabBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import GitlabForm, { GitlabFormProps } from '../GitlabForm'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockGitlabDefinition() })).toMatchSnapshot(); | |||
expect(shallowRender({ formData: mockGitlabBindingDefinition() })).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<GitlabFormProps> = {}) { |
@@ -19,7 +19,7 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockGitlabDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import { mockGitlabBindingDefinition } from '../../../../../helpers/mocks/alm-settings'; | |||
import GitlabTab, { GitlabTabProps } from '../GitlabTab'; | |||
it('should render correctly', () => { | |||
@@ -31,7 +31,7 @@ function shallowRender(props: Partial<GitlabTabProps> = {}) { | |||
return shallow( | |||
<GitlabTab | |||
branchesEnabled={true} | |||
definitions={[mockGitlabDefinition()]} | |||
definitions={[mockGitlabBindingDefinition()]} | |||
loading={false} | |||
multipleAlmEnabled={true} | |||
onDelete={jest.fn()} |
@@ -28,27 +28,33 @@ import { | |||
setProjectGitlabBinding | |||
} from '../../../../api/alm-settings'; | |||
import throwGlobalError from '../../../../app/utils/throwGlobalError'; | |||
import { AlmKeys, AlmSettingsInstance, ProjectAlmBinding } from '../../../../types/alm-settings'; | |||
import { | |||
AlmKeys, | |||
AlmSettingsInstance, | |||
ProjectAlmBindingResponse | |||
} from '../../../../types/alm-settings'; | |||
import PRDecorationBindingRenderer from './PRDecorationBindingRenderer'; | |||
type FormData = T.Omit<ProjectAlmBindingResponse, 'alm'>; | |||
interface Props { | |||
component: T.Component; | |||
} | |||
interface State { | |||
formData: ProjectAlmBinding; | |||
formData: FormData; | |||
instances: AlmSettingsInstance[]; | |||
isChanged: boolean; | |||
isConfigured: boolean; | |||
isValid: boolean; | |||
loading: boolean; | |||
orignalData?: ProjectAlmBinding; | |||
orignalData?: FormData; | |||
saving: boolean; | |||
success: boolean; | |||
} | |||
const REQUIRED_FIELDS_BY_ALM: { | |||
[almKey in AlmKeys]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>>; | |||
[almKey in AlmKeys]: Array<keyof T.Omit<FormData, 'key'>>; | |||
} = { | |||
[AlmKeys.Azure]: [], | |||
[AlmKeys.Bitbucket]: ['repository', 'slug'], | |||
@@ -104,7 +110,7 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat | |||
}); | |||
}; | |||
getProjectBinding(project: string): Promise<ProjectAlmBinding | undefined> { | |||
getProjectBinding(project: string): Promise<ProjectAlmBindingResponse | undefined> { | |||
return getProjectAlmBinding(project).catch((response: Response) => { | |||
if (response && response.status === 404) { | |||
return undefined; | |||
@@ -144,7 +150,7 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat | |||
submitProjectAlmBinding( | |||
alm: AlmKeys, | |||
key: string, | |||
almSpecificFields?: T.Omit<ProjectAlmBinding, 'key'> | |||
almSpecificFields?: T.Omit<FormData, 'key'> | |||
): Promise<void> { | |||
const almSetting = key; | |||
const project = this.props.component.key; | |||
@@ -225,13 +231,13 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat | |||
}; | |||
isDataSame( | |||
{ key, repository = '', slug = '', summaryCommentEnabled = false }: ProjectAlmBinding, | |||
{ key, repository = '', slug = '', summaryCommentEnabled = false }: FormData, | |||
{ | |||
key: oKey = '', | |||
repository: oRepository = '', | |||
slug: oSlug = '', | |||
summaryCommentEnabled: osummaryCommentEnabled = false | |||
}: ProjectAlmBinding | |||
}: FormData | |||
) { | |||
return ( | |||
key === oKey && | |||
@@ -241,7 +247,7 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat | |||
); | |||
} | |||
handleFieldChange = (id: keyof ProjectAlmBinding, value: string | boolean) => { | |||
handleFieldChange = (id: keyof ProjectAlmBindingResponse, value: string | boolean) => { | |||
this.setState(({ formData, orignalData }) => { | |||
const newFormData = { | |||
...formData, |
@@ -27,17 +27,21 @@ import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon' | |||
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | |||
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { AlmKeys, AlmSettingsInstance, ProjectAlmBinding } from '../../../../types/alm-settings'; | |||
import { | |||
AlmKeys, | |||
AlmSettingsInstance, | |||
ProjectAlmBindingResponse | |||
} from '../../../../types/alm-settings'; | |||
import InputForBoolean from '../inputs/InputForBoolean'; | |||
export interface PRDecorationBindingRendererProps { | |||
formData: ProjectAlmBinding; | |||
formData: T.Omit<ProjectAlmBindingResponse, 'alm'>; | |||
instances: AlmSettingsInstance[]; | |||
isChanged: boolean; | |||
isConfigured: boolean; | |||
isValid: boolean; | |||
loading: boolean; | |||
onFieldChange: (id: keyof ProjectAlmBinding, value: string | boolean) => void; | |||
onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void; | |||
onReset: () => void; | |||
onSubmit: () => void; | |||
saving: boolean; | |||
@@ -52,8 +56,8 @@ interface LabelProps { | |||
} | |||
interface CommonFieldProps extends LabelProps { | |||
onFieldChange: (id: keyof ProjectAlmBinding, value: string | boolean) => void; | |||
propKey: keyof ProjectAlmBinding; | |||
onFieldChange: (id: keyof ProjectAlmBindingResponse, value: string | boolean) => void; | |||
propKey: keyof ProjectAlmBindingResponse; | |||
} | |||
function optionRenderer(instance: AlmSettingsInstance) { |
@@ -1,55 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`renders correctly 1`] = ` | |||
<Fragment> | |||
<div | |||
className="page-header big-spacer-bottom" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
onboarding.project_analysis.header | |||
</h1> | |||
<p | |||
className="page-description" | |||
> | |||
<InstanceMessage | |||
message="onboarding.project_analysis.description" | |||
/> | |||
</p> | |||
</div> | |||
<TokenStep | |||
currentUser={ | |||
Object { | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
finished={false} | |||
initialTokenName="Analyze \\"Foo\\"" | |||
onContinue={[Function]} | |||
onOpen={[Function]} | |||
open={true} | |||
stepNumber={1} | |||
/> | |||
<ProjectAnalysisStep | |||
component={ | |||
Object { | |||
"analysisDate": "2016-01-01", | |||
"breadcrumbs": Array [], | |||
"key": "foo", | |||
"name": "Foo", | |||
"organization": "org", | |||
"qualifier": "TRK", | |||
"version": "0.0.1", | |||
} | |||
} | |||
displayRowLayout={true} | |||
open={false} | |||
stepNumber={2} | |||
/> | |||
</Fragment> | |||
`; |
@@ -21,7 +21,7 @@ import * as React from 'react'; | |||
import RadioToggle from 'sonar-ui-common/components/controls/RadioToggle'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
interface RenderOptionsProps { | |||
export interface RenderOptionsProps { | |||
checked: string | undefined; | |||
name: string; | |||
onCheck: (checked: string) => void; | |||
@@ -30,7 +30,7 @@ interface RenderOptionsProps { | |||
titleLabelKey?: string; | |||
} | |||
export function RenderOptions({ | |||
export default function RenderOptions({ | |||
checked, | |||
onCheck, | |||
optionLabelKey, |
@@ -20,6 +20,7 @@ | |||
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/no-noninteractive-tabindex */ | |||
import * as classNames from 'classnames'; | |||
import * as React from 'react'; | |||
import './Step.css'; | |||
interface Props { | |||
finished?: boolean; |
@@ -19,32 +19,23 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import AnalyzeTutorial from '../AnalyzeTutorial'; | |||
import RenderOptions, { RenderOptionsProps } from '../RenderOptions'; | |||
Date.now = jest.fn().mockReturnValue(1540457859031); | |||
const component = { | |||
key: 'foo', | |||
analysisDate: '2016-01-01', | |||
breadcrumbs: [], | |||
name: 'Foo', | |||
organization: 'org', | |||
qualifier: 'TRK', | |||
version: '0.0.1' | |||
}; | |||
const loggedInUser: T.LoggedInUser = { | |||
groups: [], | |||
isLoggedIn: true, | |||
login: 'luke', | |||
name: 'Skywalker', | |||
scmAccounts: [] | |||
}; | |||
it('renders correctly', () => { | |||
expect(getWrapper()).toMatchSnapshot(); | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('default'); | |||
expect(shallowRender({ checked: 'baz' })).toMatchSnapshot('option checked'); | |||
expect(shallowRender({ titleLabelKey: 'title.key' })).toMatchSnapshot('with title'); | |||
}); | |||
function getWrapper(props = {}) { | |||
return shallow(<AnalyzeTutorial component={component} currentUser={loggedInUser} {...props} />); | |||
function shallowRender(props: Partial<RenderOptionsProps> = {}) { | |||
return shallow<RenderOptionsProps>( | |||
<RenderOptions | |||
checked={undefined} | |||
name="bar" | |||
onCheck={jest.fn()} | |||
optionLabelKey="foo.bar" | |||
options={['foo', 'baz']} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,81 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: default 1`] = ` | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<RadioToggle | |||
disabled={false} | |||
name="" | |||
onCheck={[MockFunction]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "foo.bar.foo", | |||
"value": "foo", | |||
}, | |||
Object { | |||
"label": "foo.bar.baz", | |||
"value": "baz", | |||
}, | |||
] | |||
} | |||
value={null} | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly: option checked 1`] = ` | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<RadioToggle | |||
disabled={false} | |||
name="" | |||
onCheck={[MockFunction]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "foo.bar.foo", | |||
"value": "foo", | |||
}, | |||
Object { | |||
"label": "foo.bar.baz", | |||
"value": "baz", | |||
}, | |||
] | |||
} | |||
value="baz" | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly: with title 1`] = ` | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
title.key | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="" | |||
onCheck={[MockFunction]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "foo.bar.foo", | |||
"value": "foo", | |||
}, | |||
Object { | |||
"label": "foo.bar.baz", | |||
"value": "baz", | |||
}, | |||
] | |||
} | |||
value={null} | |||
/> | |||
</div> | |||
`; |
@@ -20,8 +20,9 @@ | |||
import * as React from 'react'; | |||
import RadioToggle from 'sonar-ui-common/components/controls/RadioToggle'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { isLanguageConfigured, LanguageConfig } from '../utils'; | |||
import { RenderOptions } from './RenderOptions'; | |||
import RenderOptions from '../components/RenderOptions'; | |||
import { LanguageConfig } from '../types'; | |||
import { isLanguageConfigured } from '../utils'; | |||
interface Props { | |||
component: T.Component; |
@@ -18,12 +18,13 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import Tooltip from 'sonar-ui-common/components/controls/Tooltip'; | |||
import BackIcon from 'sonar-ui-common/components/icons/BackIcon'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import InstanceMessage from '../../../components/common/InstanceMessage'; | |||
import { isVSTS } from '../../../helpers/almIntegrations'; | |||
import ProjectAnalysisStep from '../components/ProjectAnalysisStep'; | |||
import TokenStep from '../components/TokenStep'; | |||
import '../styles.css'; | |||
import InstanceMessage from '../../common/InstanceMessage'; | |||
import ProjectAnalysisStep from './ProjectAnalysisStep'; | |||
import TokenStep from './TokenStep'; | |||
export enum Steps { | |||
ANALYSIS, | |||
@@ -33,6 +34,7 @@ export enum Steps { | |||
interface Props { | |||
component: T.Component; | |||
currentUser: T.LoggedInUser; | |||
onBack?: () => void; | |||
} | |||
interface State { | |||
@@ -40,7 +42,7 @@ interface State { | |||
token?: string; | |||
} | |||
export default class AnalyzeTutorial extends React.PureComponent<Props, State> { | |||
export default class ManualTutorial extends React.PureComponent<Props, State> { | |||
state: State = { step: Steps.TOKEN }; | |||
handleTokenDone = (token: string) => { | |||
@@ -59,7 +61,19 @@ export default class AnalyzeTutorial extends React.PureComponent<Props, State> { | |||
return ( | |||
<> | |||
<div className="page-header big-spacer-bottom"> | |||
<h1 className="page-title">{translate('onboarding.project_analysis.header')}</h1> | |||
<h1 className="page-title"> | |||
{this.props.onBack !== undefined && ( | |||
<Tooltip overlay={translate('onboarding.tutorial.return_to_list')}> | |||
<a | |||
aria-label={translate('onboarding.tutorial.return_to_list')} | |||
className="link-no-underline big-spacer-right" | |||
onClick={this.props.onBack}> | |||
<BackIcon /> | |||
</a> | |||
</Tooltip> | |||
)} | |||
{translate('onboarding.project_analysis.header')} | |||
</h1> | |||
<p className="page-description"> | |||
<InstanceMessage message={translate('onboarding.project_analysis.description')} /> | |||
</p> |
@@ -19,10 +19,10 @@ | |||
*/ | |||
import * as React from 'react'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { LanguageConfig } from '../utils'; | |||
import Step from '../components/Step'; | |||
import { LanguageConfig } from '../types'; | |||
import AnalysisCommand from './commands/AnalysisCommand'; | |||
import LanguageForm from './LanguageForm'; | |||
import Step from './Step'; | |||
interface Props { | |||
component: T.Component; |
@@ -26,8 +26,8 @@ import AlertErrorIcon from 'sonar-ui-common/components/icons/AlertErrorIcon'; | |||
import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { generateToken, getTokens, revokeToken } from '../../../api/user-tokens'; | |||
import Step from '../components/Step'; | |||
import { getUniqueTokenName } from '../utils'; | |||
import Step from './Step'; | |||
interface Props { | |||
currentUser: Pick<T.LoggedInUser, 'login'>; |
@@ -0,0 +1,51 @@ | |||
/* | |||
* 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 { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks'; | |||
import ManualTutorial from '../ManualTutorial'; | |||
import ProjectAnalysisStep from '../ProjectAnalysisStep'; | |||
import TokenStep from '../TokenStep'; | |||
it('renders correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('default'); | |||
expect(shallowRender({ onBack: jest.fn() })).toMatchSnapshot('with back button'); | |||
}); | |||
it('allows to navigate between steps', () => { | |||
const wrapper = shallowRender(); | |||
const instance = wrapper.instance(); | |||
expect(wrapper.find(TokenStep).props().open).toBe(true); | |||
instance.handleTokenDone('foo'); | |||
expect(wrapper.find(TokenStep).props().open).toBe(false); | |||
expect(wrapper.find(ProjectAnalysisStep).props().open).toBe(true); | |||
instance.handleTokenOpen(); | |||
expect(wrapper.find(TokenStep).props().open).toBe(true); | |||
expect(wrapper.find(ProjectAnalysisStep).props().open).toBe(false); | |||
}); | |||
function shallowRender(props: Partial<ManualTutorial['props']> = {}) { | |||
return shallow<ManualTutorial>( | |||
<ManualTutorial component={mockComponent()} currentUser={mockLoggedInUser()} {...props} /> | |||
); | |||
} |
@@ -0,0 +1,144 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`renders correctly: default 1`] = ` | |||
<Fragment> | |||
<div | |||
className="page-header big-spacer-bottom" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
onboarding.project_analysis.header | |||
</h1> | |||
<p | |||
className="page-description" | |||
> | |||
<InstanceMessage | |||
message="onboarding.project_analysis.description" | |||
/> | |||
</p> | |||
</div> | |||
<TokenStep | |||
currentUser={ | |||
Object { | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
finished={false} | |||
initialTokenName="Analyze \\"MyProject\\"" | |||
onContinue={[Function]} | |||
onOpen={[Function]} | |||
open={true} | |||
stepNumber={1} | |||
/> | |||
<ProjectAnalysisStep | |||
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 [], | |||
} | |||
} | |||
displayRowLayout={true} | |||
open={false} | |||
stepNumber={2} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`renders correctly: with back button 1`] = ` | |||
<Fragment> | |||
<div | |||
className="page-header big-spacer-bottom" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
<Tooltip | |||
overlay="onboarding.tutorial.return_to_list" | |||
> | |||
<a | |||
aria-label="onboarding.tutorial.return_to_list" | |||
className="link-no-underline big-spacer-right" | |||
onClick={[MockFunction]} | |||
> | |||
<BackIcon /> | |||
</a> | |||
</Tooltip> | |||
onboarding.project_analysis.header | |||
</h1> | |||
<p | |||
className="page-description" | |||
> | |||
<InstanceMessage | |||
message="onboarding.project_analysis.description" | |||
/> | |||
</p> | |||
</div> | |||
<TokenStep | |||
currentUser={ | |||
Object { | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
finished={false} | |||
initialTokenName="Analyze \\"MyProject\\"" | |||
onContinue={[Function]} | |||
onOpen={[Function]} | |||
open={true} | |||
stepNumber={1} | |||
/> | |||
<ProjectAnalysisStep | |||
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 [], | |||
} | |||
} | |||
displayRowLayout={true} | |||
open={false} | |||
stepNumber={2} | |||
/> | |||
</Fragment> | |||
`; |
@@ -19,7 +19,7 @@ | |||
*/ | |||
import * as React from 'react'; | |||
import { getHostUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { LanguageConfig } from '../../utils'; | |||
import { LanguageConfig } from '../../types'; | |||
import { getProjectKey } from '../ProjectAnalysisStep'; | |||
import DotNet from './DotNet'; | |||
import JavaGradle from './JavaGradle'; |
@@ -20,8 +20,8 @@ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import CodeSnippet from '../../../common/CodeSnippet'; | |||
import InstanceMessage from '../../../common/InstanceMessage'; | |||
import MSBuildScanner from './MSBuildScanner'; | |||
export interface Props { |
@@ -20,8 +20,8 @@ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import CodeSnippet from '../../../common/CodeSnippet'; | |||
import InstanceMessage from '../../../common/InstanceMessage'; | |||
export interface Props { | |||
host: string; |
@@ -20,8 +20,8 @@ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import CodeSnippet from '../../../common/CodeSnippet'; | |||
import InstanceMessage from '../../../common/InstanceMessage'; | |||
export interface Props { | |||
host: string; |
@@ -20,8 +20,8 @@ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import CodeSnippet from '../../../common/CodeSnippet'; | |||
import InstanceMessage from '../../../common/InstanceMessage'; | |||
import { quote } from '../../utils'; | |||
import SQScanner from './SQScanner'; | |||
@@ -36,7 +36,7 @@ export function mockAlmSettingsInstance( | |||
}; | |||
} | |||
export function mockAzureDefinition( | |||
export function mockAzureBindingDefinition( | |||
overrides: Partial<AzureBindingDefinition> = {} | |||
): AzureBindingDefinition { | |||
return { | |||
@@ -46,7 +46,7 @@ export function mockAzureDefinition( | |||
}; | |||
} | |||
export function mockBitbucketDefinition( | |||
export function mockBitbucketBindingDefinition( | |||
overrides: Partial<BitbucketBindingDefinition> = {} | |||
): BitbucketBindingDefinition { | |||
return { | |||
@@ -57,7 +57,7 @@ export function mockBitbucketDefinition( | |||
}; | |||
} | |||
export function mockGithubDefinition( | |||
export function mockGithubBindingDefinition( | |||
overrides: Partial<GithubBindingDefinition> = {} | |||
): GithubBindingDefinition { | |||
return { | |||
@@ -69,7 +69,7 @@ export function mockGithubDefinition( | |||
}; | |||
} | |||
export function mockGitlabDefinition( | |||
export function mockGitlabBindingDefinition( | |||
overrides: Partial<GitlabBindingDefinition> = {} | |||
): GitlabBindingDefinition { | |||
return { |
@@ -48,35 +48,32 @@ export interface GitlabBindingDefinition extends AlmBindingDefinition { | |||
url?: string; | |||
} | |||
export interface ProjectAlmBinding { | |||
export interface ProjectAlmBindingResponse { | |||
alm: AlmKeys; | |||
key: string; | |||
repository?: string; | |||
slug?: string; | |||
summaryCommentEnabled?: boolean; | |||
} | |||
export interface AzureProjectAlmBinding { | |||
export interface ProjectAlmBindingParams { | |||
almSetting: string; | |||
project: string; | |||
} | |||
export interface BitbucketProjectAlmBinding { | |||
almSetting: string; | |||
project: string; | |||
export interface AzureProjectAlmBindingParams extends ProjectAlmBindingParams {} | |||
export interface BitbucketProjectAlmBindingParams extends ProjectAlmBindingParams { | |||
repository: string; | |||
slug: string; | |||
} | |||
export interface GithubProjectAlmBinding { | |||
almSetting: string; | |||
project: string; | |||
export interface GithubProjectAlmBindingParams extends ProjectAlmBindingParams { | |||
repository: string; | |||
summaryCommentEnabled: boolean; | |||
} | |||
export interface GitlabProjectAlmBinding { | |||
almSetting: string; | |||
project: string; | |||
export interface GitlabProjectAlmBindingParams extends ProjectAlmBindingParams { | |||
repository?: string; | |||
} | |||
@@ -87,8 +84,8 @@ export interface AlmSettingsInstance { | |||
} | |||
export interface AlmSettingsBindingDefinitions { | |||
azure: AzureBindingDefinition[]; | |||
bitbucket: BitbucketBindingDefinition[]; | |||
github: GithubBindingDefinition[]; | |||
gitlab: GitlabBindingDefinition[]; | |||
[AlmKeys.Azure]: AzureBindingDefinition[]; | |||
[AlmKeys.Bitbucket]: BitbucketBindingDefinition[]; | |||
[AlmKeys.GitHub]: GithubBindingDefinition[]; | |||
[AlmKeys.GitLab]: GitlabBindingDefinition[]; | |||
} |