@@ -40,6 +40,7 @@ interface Props<B> { | |||
onDelete?: (definitionKey: string) => void; | |||
onEdit?: (definitionKey: string) => void; | |||
onSubmit: (data: B, originalKey: string) => void; | |||
optionalFields?: Array<keyof B>; | |||
readOnly?: boolean; | |||
showInModal?: boolean; | |||
success?: boolean; | |||
@@ -98,7 +99,7 @@ export default class AlmBindingDefinitionForm< | |||
}; | |||
canSubmit = () => { | |||
const { hideKeyField } = this.props; | |||
const { hideKeyField, optionalFields } = this.props; | |||
const { formData, touched } = this.state; | |||
let values; | |||
@@ -108,6 +109,10 @@ export default class AlmBindingDefinitionForm< | |||
values = { ...formData }; | |||
} | |||
if (optionalFields && optionalFields.length > 0) { | |||
values = omit(values, optionalFields); | |||
} | |||
return touched && !Object.values(values).some(v => !v); | |||
}; | |||
@@ -29,6 +29,7 @@ export interface AlmBindingDefinitionFormFieldProps<B extends AlmBindingDefiniti | |||
isTextArea?: boolean; | |||
maxLength?: number; | |||
onFieldChange: (id: keyof B, value: string) => void; | |||
optional?: boolean; | |||
propKey: keyof B; | |||
readOnly?: boolean; | |||
value: string; | |||
@@ -44,6 +45,7 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>( | |||
isTextArea, | |||
maxLength, | |||
onFieldChange, | |||
optional, | |||
propKey, | |||
readOnly = false, | |||
value | |||
@@ -53,8 +55,8 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>( | |||
<div className="modal-field"> | |||
<label className="display-flex-center" htmlFor={id}> | |||
{translate('settings.almintegration.form', id)} | |||
<em className="mandatory spacer-right">*</em> | |||
{help && <HelpTooltip overlay={help} placement="right" />} | |||
{!optional && <em className="mandatory">*</em>} | |||
{help && <HelpTooltip className="spacer-left" overlay={help} placement="right" />} | |||
</label> | |||
{isTextArea ? ( | |||
<textarea | |||
@@ -63,7 +65,7 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>( | |||
id={id} | |||
maxLength={maxLength || 2000} | |||
onChange={e => onFieldChange(propKey, e.currentTarget.value)} | |||
required={true} | |||
required={!optional} | |||
rows={5} | |||
value={value} | |||
/> |
@@ -38,6 +38,7 @@ interface Props<B> { | |||
multipleAlmEnabled: boolean; | |||
onDelete: (definitionKey: string) => void; | |||
onUpdateDefinitions: () => void; | |||
optionalFields?: Array<keyof B>; | |||
updateConfiguration: (data: B & { newKey?: string }) => Promise<void>; | |||
} | |||
@@ -112,7 +113,8 @@ export default class AlmTab<B extends AlmBindingDefinition> extends React.PureCo | |||
form, | |||
help, | |||
loading, | |||
multipleAlmEnabled | |||
multipleAlmEnabled, | |||
optionalFields | |||
} = this.props; | |||
const { editedDefinition, submitting, success } = this.state; | |||
@@ -135,6 +137,7 @@ export default class AlmTab<B extends AlmBindingDefinition> extends React.PureCo | |||
onDelete={this.props.onDelete} | |||
onEdit={this.handleEdit} | |||
onSubmit={this.handleSubmit} | |||
optionalFields={optionalFields} | |||
success={success} | |||
/> | |||
); |
@@ -49,6 +49,7 @@ export interface AlmTabRendererProps<B> { | |||
onDelete: (definitionKey: string) => void; | |||
onEdit: (definitionKey: string) => void; | |||
onSubmit: (config: B, originalKey: string) => void; | |||
optionalFields?: Array<keyof B>; | |||
success: boolean; | |||
} | |||
@@ -67,6 +68,7 @@ export default function AlmTabRenderer<B extends AlmBindingDefinition>( | |||
form, | |||
loading, | |||
multipleAlmEnabled, | |||
optionalFields, | |||
success, | |||
help = ( | |||
<FormattedMessage | |||
@@ -123,6 +125,7 @@ export default function AlmTabRenderer<B extends AlmBindingDefinition>( | |||
help={help} | |||
onCancel={props.onCancel} | |||
onSubmit={props.onSubmit} | |||
optionalFields={optionalFields} | |||
showInModal={true}> | |||
{form} | |||
</AlmBindingDefinitionForm> | |||
@@ -138,6 +141,7 @@ export default function AlmTabRenderer<B extends AlmBindingDefinition>( | |||
onDelete={definition ? props.onDelete : undefined} | |||
onEdit={showEdit ? props.onEdit : undefined} | |||
onSubmit={props.onSubmit} | |||
optionalFields={optionalFields} | |||
readOnly={showEdit} | |||
success={success}> | |||
{form} |
@@ -45,6 +45,25 @@ export default function GitlabForm(props: GitlabFormProps) { | |||
value={formData.key} | |||
/> | |||
)} | |||
<AlmBindingDefinitionFormField | |||
help={ | |||
<> | |||
{translate('settings.almintegration.form.url.gitlab.help1')} | |||
<br /> | |||
<br /> | |||
{translate('settings.almintegration.form.url.gitlab.help2')} | |||
<br /> | |||
<em>https://gitlab.com/api/v4</em> | |||
</> | |||
} | |||
id="url.gitlab" | |||
maxLength={2000} | |||
onFieldChange={onFieldChange} | |||
optional={true} | |||
propKey="url" | |||
readOnly={readOnly} | |||
value={formData.url || ''} | |||
/> | |||
<AlmBindingDefinitionFormField | |||
help={translate('settings.almintegration.form.personal_access_token.gitlab.help')} | |||
id="personal_access_token" |
@@ -44,9 +44,13 @@ export default function GitlabTab(props: GitlabTabProps) { | |||
{branchesEnabled && ( | |||
<> | |||
<AlmTab | |||
additionalColumnsHeaders={[ | |||
translate('settings.almintegration.table.column.gitlab.url') | |||
]} | |||
additionalColumnsKeys={['url']} | |||
alm={AlmKeys.GitLab} | |||
createConfiguration={createGitlabConfiguration} | |||
defaultBinding={{ key: '', personalAccessToken: '' }} | |||
defaultBinding={{ key: '', personalAccessToken: '', url: '' }} | |||
definitions={definitions} | |||
features={[ | |||
{ | |||
@@ -61,6 +65,7 @@ export default function GitlabTab(props: GitlabTabProps) { | |||
multipleAlmEnabled={multipleAlmEnabled} | |||
onDelete={props.onDelete} | |||
onUpdateDefinitions={props.onUpdateDefinitions} | |||
optionalFields={['url']} | |||
updateConfiguration={updateGitlabConfiguration} | |||
/> | |||
@@ -119,6 +119,10 @@ it('should (dis)allow submit by validating its state', () => { | |||
wrapper.setState({ formData: mockGithubDefinition({ key: '' }), touched: true }); | |||
wrapper.setProps({ hideKeyField: true }); | |||
expect(wrapper.instance().canSubmit()).toBe(true); | |||
wrapper.setState({ formData: mockGithubDefinition({ url: '' }), touched: true }); | |||
wrapper.setProps({ optionalFields: ['url'] }); | |||
expect(wrapper.instance().canSubmit()).toBe(true); | |||
}); | |||
function shallowRender( |
@@ -26,9 +26,10 @@ import { | |||
} from '../AlmBindingDefinitionFormField'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
expect(shallowRender({ help: 'help' })).toMatchSnapshot(); | |||
expect(shallowRender({ isTextArea: true })).toMatchSnapshot(); | |||
expect(shallowRender()).toMatchSnapshot('default'); | |||
expect(shallowRender({ help: 'help' })).toMatchSnapshot('with help'); | |||
expect(shallowRender({ isTextArea: true })).toMatchSnapshot('textarea'); | |||
expect(shallowRender({ optional: true })).toMatchSnapshot('optional'); | |||
}); | |||
it('should call onFieldChange', () => { |
@@ -1,6 +1,6 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
exports[`should render correctly: default 1`] = ` | |||
<div | |||
className="modal-field" | |||
> | |||
@@ -10,7 +10,7 @@ exports[`should render correctly 1`] = ` | |||
> | |||
settings.almintegration.form.key | |||
<em | |||
className="mandatory spacer-right" | |||
className="mandatory" | |||
> | |||
* | |||
</em> | |||
@@ -29,7 +29,7 @@ exports[`should render correctly 1`] = ` | |||
</div> | |||
`; | |||
exports[`should render correctly 2`] = ` | |||
exports[`should render correctly: optional 1`] = ` | |||
<div | |||
className="modal-field" | |||
> | |||
@@ -38,15 +38,6 @@ exports[`should render correctly 2`] = ` | |||
htmlFor="key" | |||
> | |||
settings.almintegration.form.key | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
<HelpTooltip | |||
overlay="help" | |||
placement="right" | |||
/> | |||
</label> | |||
<input | |||
className="input-super-large" | |||
@@ -62,7 +53,7 @@ exports[`should render correctly 2`] = ` | |||
</div> | |||
`; | |||
exports[`should render correctly 3`] = ` | |||
exports[`should render correctly: textarea 1`] = ` | |||
<div | |||
className="modal-field" | |||
> | |||
@@ -72,7 +63,7 @@ exports[`should render correctly 3`] = ` | |||
> | |||
settings.almintegration.form.key | |||
<em | |||
className="mandatory spacer-right" | |||
className="mandatory" | |||
> | |||
* | |||
</em> | |||
@@ -89,3 +80,37 @@ exports[`should render correctly 3`] = ` | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly: with help 1`] = ` | |||
<div | |||
className="modal-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="key" | |||
> | |||
settings.almintegration.form.key | |||
<em | |||
className="mandatory" | |||
> | |||
* | |||
</em> | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay="help" | |||
placement="right" | |||
/> | |||
</label> | |||
<input | |||
className="input-super-large" | |||
disabled={false} | |||
id="key" | |||
maxLength={40} | |||
name="key" | |||
onChange={[Function]} | |||
size={50} | |||
type="text" | |||
value="key" | |||
/> | |||
</div> | |||
`; |
@@ -10,6 +10,26 @@ exports[`should render correctly 1`] = ` | |||
propKey="key" | |||
value="" | |||
/> | |||
<AlmBindingDefinitionFormField | |||
help={ | |||
<React.Fragment> | |||
settings.almintegration.form.url.gitlab.help1 | |||
<br /> | |||
<br /> | |||
settings.almintegration.form.url.gitlab.help2 | |||
<br /> | |||
<em> | |||
https://gitlab.com/api/v4 | |||
</em> | |||
</React.Fragment> | |||
} | |||
id="url.gitlab" | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
optional={true} | |||
propKey="url" | |||
value="" | |||
/> | |||
<AlmBindingDefinitionFormField | |||
help="settings.almintegration.form.personal_access_token.gitlab.help" | |||
id="personal_access_token" | |||
@@ -31,6 +51,26 @@ exports[`should render correctly 2`] = ` | |||
propKey="key" | |||
value="foo" | |||
/> | |||
<AlmBindingDefinitionFormField | |||
help={ | |||
<React.Fragment> | |||
settings.almintegration.form.url.gitlab.help1 | |||
<br /> | |||
<br /> | |||
settings.almintegration.form.url.gitlab.help2 | |||
<br /> | |||
<em> | |||
https://gitlab.com/api/v4 | |||
</em> | |||
</React.Fragment> | |||
} | |||
id="url.gitlab" | |||
maxLength={2000} | |||
onFieldChange={[MockFunction]} | |||
optional={true} | |||
propKey="url" | |||
value="" | |||
/> | |||
<AlmBindingDefinitionFormField | |||
help="settings.almintegration.form.personal_access_token.gitlab.help" | |||
id="personal_access_token" |
@@ -5,12 +5,23 @@ exports[`should render correctly: with branch support 1`] = ` | |||
className="bordered" | |||
> | |||
<AlmTab | |||
additionalColumnsHeaders={ | |||
Array [ | |||
"settings.almintegration.table.column.gitlab.url", | |||
] | |||
} | |||
additionalColumnsKeys={ | |||
Array [ | |||
"url", | |||
] | |||
} | |||
alm="gitlab" | |||
createConfiguration={[Function]} | |||
defaultBinding={ | |||
Object { | |||
"key": "", | |||
"personalAccessToken": "", | |||
"url": "", | |||
} | |||
} | |||
definitions={ | |||
@@ -36,6 +47,11 @@ exports[`should render correctly: with branch support 1`] = ` | |||
multipleAlmEnabled={true} | |||
onDelete={[MockFunction]} | |||
onUpdateDefinitions={[MockFunction]} | |||
optionalFields={ | |||
Array [ | |||
"url", | |||
] | |||
} | |||
updateConfiguration={[Function]} | |||
/> | |||
<div |
@@ -45,7 +45,9 @@ interface State { | |||
success: boolean; | |||
} | |||
const FIELDS_BY_ALM: { [almKey in AlmKeys]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>> } = { | |||
const REQUIRED_FIELDS_BY_ALM: { | |||
[almKey in AlmKeys]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>>; | |||
} = { | |||
[AlmKeys.Azure]: [], | |||
[AlmKeys.Bitbucket]: ['repository', 'slug'], | |||
[AlmKeys.GitHub]: ['repository'], | |||
@@ -170,11 +172,14 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat | |||
}); | |||
} | |||
case AlmKeys.GitLab: | |||
case AlmKeys.GitLab: { | |||
const repository = almSpecificFields && almSpecificFields.repository; | |||
return setProjectGitlabBinding({ | |||
almSetting, | |||
project | |||
project, | |||
repository | |||
}); | |||
} | |||
default: | |||
return Promise.reject(); | |||
@@ -228,7 +233,7 @@ export default class PRDecorationBinding extends React.PureComponent<Props, Stat | |||
if (!key || !selected) { | |||
return false; | |||
} | |||
return FIELDS_BY_ALM[selected.alm].reduce( | |||
return REQUIRED_FIELDS_BY_ALM[selected.alm].reduce( | |||
(result: boolean, field) => result && Boolean(additionalFields[field]), | |||
true | |||
); |
@@ -58,17 +58,19 @@ function renderField(props: { | |||
helpParams?: { [key: string]: string | JSX.Element }; | |||
id: string; | |||
onFieldChange: (id: keyof ProjectAlmBinding, value: string) => void; | |||
optional?: boolean; | |||
propKey: keyof ProjectAlmBinding; | |||
value: string; | |||
}) { | |||
const { help, helpParams, id, propKey, value, onFieldChange } = props; | |||
const { help, helpParams, id, propKey, optional, value, onFieldChange } = props; | |||
return ( | |||
<div className="form-field"> | |||
<label className="display-flex-center" htmlFor={id}> | |||
{translate('settings.pr_decoration.binding.form', id)} | |||
<em className="mandatory spacer-right">*</em> | |||
{!optional && <em className="mandatory">*</em>} | |||
{help && ( | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay={ | |||
<FormattedMessage | |||
defaultMessage={translate('settings.pr_decoration.binding.form', id, 'help')} | |||
@@ -226,6 +228,16 @@ export default function PRDecorationBindingRenderer(props: PRDecorationBindingRe | |||
value: repository || '' | |||
})} | |||
{alm === AlmKeys.GitLab && | |||
renderField({ | |||
help: true, | |||
id: 'gitlab.repository', | |||
onFieldChange: props.onFieldChange, | |||
optional: true, | |||
propKey: 'repository', | |||
value: repository || '' | |||
})} | |||
<div className="display-flex-center"> | |||
<DeferredSpinner className="spacer-right" loading={saving} /> | |||
{isChanged && ( |
@@ -69,15 +69,15 @@ it('should fill selects and fill formdata', async () => { | |||
expect(wrapper.state().originalData).toEqual(formdata); | |||
}); | |||
const formData = { | |||
key: 'whatever', | |||
repository: 'something/else' | |||
}; | |||
it('should handle reset', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
wrapper.setState({ formData }); | |||
wrapper.setState({ | |||
formData: { | |||
key: 'whatever', | |||
repository: 'something/else' | |||
} | |||
}); | |||
wrapper.instance().handleReset(); | |||
await waitAndUpdate(wrapper); | |||
@@ -153,7 +153,12 @@ it('should handle failures gracefully', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
wrapper.setState({ formData }); | |||
wrapper.setState({ | |||
formData: { | |||
key: 'whatever', | |||
repository: 'something/else' | |||
} | |||
}); | |||
wrapper.instance().handleSubmit(); | |||
await waitAndUpdate(wrapper); | |||
@@ -197,9 +202,11 @@ it('should validate form', async () => { | |||
instances: [ | |||
{ key: 'azure', alm: AlmKeys.Azure }, | |||
{ key: 'bitbucket', alm: AlmKeys.Bitbucket }, | |||
{ key: 'github', alm: AlmKeys.GitHub } | |||
{ key: 'github', alm: AlmKeys.GitHub }, | |||
{ key: 'gitlab', alm: AlmKeys.GitLab } | |||
] | |||
}); | |||
expect(wrapper.instance().validateForm({ key: 'azure' })).toBe(true); | |||
expect(wrapper.instance().validateForm({ key: 'github', repository: '' })).toBe(false); | |||
@@ -209,6 +216,9 @@ it('should validate form', async () => { | |||
expect( | |||
wrapper.instance().validateForm({ key: 'bitbucket', repository: 'key', slug: 'slug' }) | |||
).toBe(true); | |||
expect(wrapper.instance().validateForm({ key: 'gitlab' })).toBe(true); | |||
expect(wrapper.instance().validateForm({ key: 'gitlab', repository: 'key' })).toBe(true); | |||
}); | |||
function shallowRender(props: Partial<PRDecorationBinding['props']> = {}) { |
@@ -131,6 +131,18 @@ it('should render select options correctly', async () => { | |||
expect(optionRenderer!(instances[1])).toMatchSnapshot(); | |||
}); | |||
it('should render optional fields correctly', () => { | |||
expect( | |||
shallowRender({ | |||
formData: { | |||
key: 'key' | |||
}, | |||
instances: [{ key: 'key', url: 'http://example.com', alm: AlmKeys.GitLab }], | |||
loading: false | |||
}) | |||
).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<PRDecorationBindingRendererProps> = {}) { | |||
return shallow( | |||
<PRDecorationBindingRenderer |
@@ -428,11 +428,12 @@ exports[`should render multiple instances correctly 2`] = ` | |||
> | |||
settings.pr_decoration.binding.form.github.repository | |||
<em | |||
className="mandatory spacer-right" | |||
className="mandatory" | |||
> | |||
* | |||
</em> | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay={ | |||
<FormattedMessage | |||
defaultMessage="settings.pr_decoration.binding.form.github.repository.help" | |||
@@ -480,6 +481,119 @@ exports[`should render multiple instances correctly 2`] = ` | |||
</div> | |||
`; | |||
exports[`should render optional fields correctly 1`] = ` | |||
<div> | |||
<header | |||
className="page-header" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
settings.pr_decoration.binding.title | |||
</h1> | |||
</header> | |||
<div | |||
className="markdown small spacer-top big-spacer-bottom" | |||
> | |||
settings.pr_decoration.binding.description | |||
</div> | |||
<form | |||
onSubmit={[Function]} | |||
> | |||
<div | |||
className="form-field" | |||
> | |||
<label | |||
htmlFor="name" | |||
> | |||
settings.pr_decoration.binding.form.name | |||
<em | |||
className="mandatory spacer-right" | |||
> | |||
* | |||
</em> | |||
</label> | |||
<Select | |||
autosize={true} | |||
className="abs-width-400" | |||
clearable={false} | |||
id="name" | |||
menuContainerStyle={ | |||
Object { | |||
"maxWidth": "210%", | |||
"width": "auto", | |||
} | |||
} | |||
onChange={[Function]} | |||
optionRenderer={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"alm": "gitlab", | |||
"key": "key", | |||
"url": "http://example.com", | |||
}, | |||
] | |||
} | |||
searchable={false} | |||
value="key" | |||
valueKey="key" | |||
valueRenderer={[Function]} | |||
/> | |||
</div> | |||
<div | |||
className="form-field" | |||
> | |||
<label | |||
className="display-flex-center" | |||
htmlFor="gitlab.repository" | |||
> | |||
settings.pr_decoration.binding.form.gitlab.repository | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay={ | |||
<FormattedMessage | |||
defaultMessage="settings.pr_decoration.binding.form.gitlab.repository.help" | |||
id="settings.pr_decoration.binding.form.gitlab.repository.help" | |||
values={Object {}} | |||
/> | |||
} | |||
placement="right" | |||
/> | |||
</label> | |||
<input | |||
className="input-super-large" | |||
id="gitlab.repository" | |||
maxLength={256} | |||
name="gitlab.repository" | |||
onChange={[Function]} | |||
type="text" | |||
value="" | |||
/> | |||
</div> | |||
<div | |||
className="display-flex-center" | |||
> | |||
<DeferredSpinner | |||
className="spacer-right" | |||
loading={false} | |||
timeout={100} | |||
/> | |||
<SubmitButton | |||
className="spacer-right button-success" | |||
disabled={true} | |||
> | |||
<span | |||
data-test="project-settings__alm-save" | |||
> | |||
save | |||
</span> | |||
</SubmitButton> | |||
</div> | |||
</form> | |||
</div> | |||
`; | |||
exports[`should render select options correctly 1`] = ` | |||
<span> | |||
azure |
@@ -45,6 +45,7 @@ export interface GithubBindingDefinition extends AlmBindingDefinition { | |||
export interface GitlabBindingDefinition extends AlmBindingDefinition { | |||
personalAccessToken: string; | |||
url?: string; | |||
} | |||
export interface ProjectAlmBinding { | |||
@@ -74,6 +75,7 @@ export interface GithubProjectAlmBinding { | |||
export interface GitlabProjectAlmBinding { | |||
almSetting: string; | |||
project: string; | |||
repository?: string; | |||
} | |||
export interface AlmSettingsInstance { |
@@ -1035,6 +1035,7 @@ 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.gitlab.url=GitLab Self-Managed or GitLab.com URL | |||
settings.almintegration.table.column.app_id=App ID | |||
settings.almintegration.table.column.edit=Edit | |||
settings.almintegration.table.column.delete=Delete | |||
@@ -1057,6 +1058,9 @@ 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.url.gitlab=GitLab URL | |||
settings.almintegration.form.url.gitlab.help1=You do not have to provide this value if you're using GitLab CI. | |||
settings.almintegration.form.url.gitlab.help2=If you're using another CI, provide the GitLab API URL. For example: | |||
settings.almintegration.form.app_id=GitHub App ID | |||
settings.almintegration.form.private_key=Private Key | |||
settings.almintegration.form.personal_access_token=Personal Access token | |||
@@ -1088,6 +1092,8 @@ settings.pr_decoration.binding.form.bitbucket.repository=Project Key | |||
settings.pr_decoration.binding.form.bitbucket.repository.help=The project key is part of your Bitbucket Server repository URL. Example: ({example}) | |||
settings.pr_decoration.binding.form.bitbucket.slug=Repository SLUG | |||
settings.pr_decoration.binding.form.bitbucket.slug.help=The Repository Slug is part of your Bitbucket Server repository URL. Example: ({example}) | |||
settings.pr_decoration.binding.form.gitlab.repository=Project ID | |||
settings.pr_decoration.binding.form.gitlab.repository.help=If you are using GitLab CI, you do not have to provide this value. For any other CI, provide the project's numerical ID. | |||
property.category.general=General | |||
property.category.general.email=Email |