diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2021-01-04 11:42:25 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-01-11 20:20:39 +0000 |
commit | 16d235022a4711857cde9d0953be3a864b1bfb83 (patch) | |
tree | f005208b8deb8fecbce1d89852bcc81cfa4afe24 | |
parent | fc6cecacf8b26c016bceddf5e34185af368555d0 (diff) | |
download | sonarqube-16d235022a4711857cde9d0953be3a864b1bfb83.tar.gz sonarqube-16d235022a4711857cde9d0953be3a864b1bfb83.zip |
SONAR-12840 Toggle private field visibility on update
12 files changed, 82 insertions, 5 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx index 33e6912b5ed..b86c8209f8f 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import { ButtonLink } from 'sonar-ui-common/components/controls/buttons'; import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { AlmBindingDefinition } from '../../../../types/alm-settings'; @@ -30,6 +31,7 @@ export interface AlmBindingDefinitionFormFieldProps<B extends AlmBindingDefiniti maxLength?: number; onFieldChange: (id: keyof B, value: string) => void; optional?: boolean; + overwriteOnly?: boolean; propKey: keyof B; readOnly?: boolean; value: string; @@ -44,12 +46,13 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>( id, isTextArea, maxLength, - onFieldChange, optional, + overwriteOnly = false, propKey, readOnly = false, value } = props; + const [showField, setShowField] = React.useState(!overwriteOnly); return ( <div className="modal-field"> @@ -58,18 +61,34 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>( {!optional && <em className="mandatory">*</em>} {help && <HelpTooltip className="spacer-left" overlay={help} placement="right" />} </label> - {isTextArea ? ( + + {!showField && overwriteOnly && ( + <div> + <p>{translate('settings.almintegration.form.secret_field')}</p> + <ButtonLink + onClick={() => { + props.onFieldChange(propKey, ''); + setShowField(true); + }}> + {translate('settings.almintegration.form.update_secret_field')} + </ButtonLink> + </div> + )} + + {showField && isTextArea && ( <textarea className="settings-large-input" disabled={readOnly} id={id} maxLength={maxLength || 2000} - onChange={e => onFieldChange(propKey, e.currentTarget.value)} + onChange={e => props.onFieldChange(propKey, e.currentTarget.value)} required={!optional} rows={5} value={value} /> - ) : ( + )} + + {showField && !isTextArea && ( <input autoFocus={autoFocus} className="input-super-large" @@ -77,7 +96,7 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinition>( id={id} maxLength={maxLength || 100} name={id} - onChange={e => onFieldChange(propKey, e.currentTarget.value)} + onChange={e => props.onFieldChange(propKey, e.currentTarget.value)} size={50} type="text" value={value} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx index d9256003073..182a44de178 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx @@ -65,6 +65,7 @@ export default function AzureForm(props: AzureFormProps) { id="personal_access_token" isTextArea={true} onFieldChange={onFieldChange} + overwriteOnly={Boolean(formData.key)} propKey="personalAccessToken" readOnly={readOnly} value={formData.personalAccessToken} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx index b0ad59b927e..504222cbdca 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketForm.tsx @@ -66,6 +66,7 @@ export default function BitbucketForm(props: BitbucketFormProps) { id="personal_access_token" isTextArea={true} onFieldChange={onFieldChange} + overwriteOnly={Boolean(formData.key)} propKey="personalAccessToken" readOnly={readOnly} value={formData.personalAccessToken} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx index 69bb366ef17..fe097ae0d60 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx @@ -85,6 +85,7 @@ export default function GithubForm(props: GithubFormProps) { id="client_secret" maxLength={80} onFieldChange={onFieldChange} + overwriteOnly={Boolean(formData.key)} propKey="clientSecret" readOnly={readOnly} value={formData.clientSecret} @@ -93,6 +94,7 @@ export default function GithubForm(props: GithubFormProps) { id="private_key" isTextArea={true} onFieldChange={onFieldChange} + overwriteOnly={Boolean(formData.key)} propKey="privateKey" readOnly={readOnly} value={formData.privateKey} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx index 0c96f708b93..2ef0b83a92a 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx @@ -65,6 +65,7 @@ export default function GitlabForm(props: GitlabFormProps) { id="personal_access_token" isTextArea={true} onFieldChange={onFieldChange} + overwriteOnly={Boolean(formData.key)} propKey="personalAccessToken" readOnly={readOnly} value={formData.personalAccessToken} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormField-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormField-test.tsx index e7dc957f134..1137b35be28 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormField-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionFormField-test.tsx @@ -19,6 +19,8 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import { ButtonLink } from 'sonar-ui-common/components/controls/buttons'; +import { click } from 'sonar-ui-common/helpers/testUtils'; import { AlmBindingDefinition } from '../../../../../types/alm-settings'; import { AlmBindingDefinitionFormField, @@ -30,6 +32,7 @@ it('should render correctly', () => { expect(shallowRender({ help: 'help' })).toMatchSnapshot('with help'); expect(shallowRender({ isTextArea: true })).toMatchSnapshot('textarea'); expect(shallowRender({ optional: true })).toMatchSnapshot('optional'); + expect(shallowRender({ overwriteOnly: true })).toMatchSnapshot('secret'); }); it('should call onFieldChange', () => { @@ -46,6 +49,16 @@ it('should call onFieldChange', () => { expect(onTextAreaChange).toBeCalled(); }); +it('should correctly toggle visibility for secret fields', () => { + const onFieldChange = jest.fn(); + const wrapper = shallowRender({ onFieldChange, overwriteOnly: true }); + expect(wrapper.find('input').exists()).toBe(false); + + click(wrapper.find(ButtonLink)); + expect(onFieldChange).toHaveBeenCalledWith('key', ''); + expect(wrapper.find('input').exists()).toBe(true); +}); + function shallowRender( props: Partial<AlmBindingDefinitionFormFieldProps<AlmBindingDefinition>> = {} ) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap index df0e1be514e..246cfcb1745 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap @@ -53,6 +53,34 @@ exports[`should render correctly: optional 1`] = ` </div> `; +exports[`should render correctly: secret 1`] = ` +<div + className="modal-field" +> + <label + className="display-flex-center" + htmlFor="key" + > + settings.almintegration.form.key + <em + className="mandatory" + > + * + </em> + </label> + <div> + <p> + settings.almintegration.form.secret_field + </p> + <ButtonLink + onClick={[Function]} + > + settings.almintegration.form.update_secret_field + </ButtonLink> + </div> +</div> +`; + exports[`should render correctly: textarea 1`] = ` <div className="modal-field" diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap index 48b2949cad4..e12787f70fd 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap @@ -31,6 +31,7 @@ exports[`should render correctly: create 1`] = ` id="personal_access_token" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={false} propKey="personalAccessToken" value="" /> @@ -68,6 +69,7 @@ exports[`should render correctly: edit 1`] = ` id="personal_access_token" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={true} propKey="personalAccessToken" value="asdf1234" /> diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap index b936abc487c..e19b6f4af80 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketForm-test.tsx.snap @@ -33,6 +33,7 @@ exports[`should render correctly 1`] = ` id="personal_access_token" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={false} propKey="personalAccessToken" value="" /> @@ -72,6 +73,7 @@ exports[`should render correctly 2`] = ` id="personal_access_token" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={true} propKey="personalAccessToken" value="asdf1234" /> diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap index e64c54eb136..6ae40e3ac21 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap @@ -51,6 +51,7 @@ exports[`should render correctly 1`] = ` id="client_secret" maxLength={80} onFieldChange={[MockFunction]} + overwriteOnly={false} propKey="clientSecret" value="" /> @@ -58,6 +59,7 @@ exports[`should render correctly 1`] = ` id="private_key" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={false} propKey="privateKey" value="" /> @@ -115,6 +117,7 @@ exports[`should render correctly 2`] = ` id="client_secret" maxLength={80} onFieldChange={[MockFunction]} + overwriteOnly={true} propKey="clientSecret" value="**clientsecret**" /> @@ -122,6 +125,7 @@ exports[`should render correctly 2`] = ` id="private_key" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={true} propKey="privateKey" value="asdf1234" /> diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap index b3c74682498..10b9473011a 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap @@ -31,6 +31,7 @@ exports[`should render correctly 1`] = ` id="personal_access_token" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={false} propKey="personalAccessToken" value="" /> @@ -68,6 +69,7 @@ exports[`should render correctly 2`] = ` id="personal_access_token" isTextArea={true} onFieldChange={[MockFunction]} + overwriteOnly={true} propKey="personalAccessToken" value="foobar" /> diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 881cf90af17..5e02164729c 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1118,6 +1118,8 @@ settings.almintegration.form.personal_access_token.azure.help=Token of the user 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.form.secret_field=This field is hidden for security reasons. +settings.almintegration.form.update_secret_field=Update field value 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 |