diff options
author | Mathieu Suen <mathieu.suen@sonarsource.com> | 2023-09-11 12:05:25 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-09-12 20:02:41 +0000 |
commit | 6d021927d626cbe78bb2ee17bb2cc40ac5e6ee02 (patch) | |
tree | 0f86f86f3bb7742bd3ce9397795fc79bbed62baa | |
parent | 9c2bd22c1d14c61976dde84bc7ed79cb9032378e (diff) | |
download | sonarqube-6d021927d626cbe78bb2ee17bb2cc40ac5e6ee02.tar.gz sonarqube-6d021927d626cbe78bb2ee17bb2cc40ac5e6ee02.zip |
SONAR-20402 Align authentication settings card verticaly
8 files changed, 122 insertions, 86 deletions
diff --git a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts index 2505f1661a0..1352b8dcc97 100644 --- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts @@ -20,6 +20,7 @@ import { cloneDeep, isArray, isObject, isString } from 'lodash'; import { HousekeepingPolicy } from '../../apps/audit-logs/utils'; import { mockDefinition, mockSettingFieldDefinition } from '../../helpers/mocks/settings'; +import { isDefined } from '../../helpers/types'; import { BranchParameters } from '../../types/branch-like'; import { ExtendedSettingDefinition, @@ -101,6 +102,15 @@ export const DEFAULT_DEFINITIONS_MOCK = [ mockSettingFieldDefinition({ key: 'value', name: 'Value' }), ], }), + mockDefinition({ + category: 'authentication', + defaultValue: 'true', + key: 'sonar.auth.github.allowUsersToSignUp', + subCategory: 'github', + name: 'Compilation Constants', + description: 'Lets do it', + type: SettingType.BOOLEAN, + }), ]; export default class SettingsServiceMock { @@ -140,7 +150,17 @@ export default class SettingsServiceMock { }; handleGetValues = (data: { keys: string[]; component?: string } & BranchParameters) => { - const settings = this.#settingValues.filter((s) => data.keys.includes(s.key)); + const settings = data.keys + .map((k) => { + const def = this.#definitions.find((d) => d.key === k); + const v = this.#settingValues.find((s) => s.key === k); + if (v === undefined && def?.type === SettingType.BOOLEAN) { + return { key: k, value: def.defaultValue, inherited: true }; + } + return v; + }) + .filter(isDefined); + return this.reply(settings); }; @@ -185,7 +205,7 @@ export default class SettingsServiceMock { setting.fieldValues = []; } else if (definition.multiValues === true) { setting.values = definition.defaultValue?.split(',') ?? []; - } else { + } else if (setting) { setting.value = definition.defaultValue ?? ''; } diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/AuthenticationFormField.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/AuthenticationFormField.tsx index f4197d89ebc..1467e7a8701 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/AuthenticationFormField.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/AuthenticationFormField.tsx @@ -23,7 +23,7 @@ import ValidationInput, { } from '../../../../components/controls/ValidationInput'; import MandatoryFieldMarker from '../../../../components/ui/MandatoryFieldMarker'; import { ExtendedSettingDefinition, SettingType } from '../../../../types/settings'; -import { isSecuredDefinition } from '../../utils'; +import { getPropertyDescription, getPropertyName, isSecuredDefinition } from '../../utils'; import AuthenticationMultiValueField from './AuthenticationMultiValuesField'; import AuthenticationSecuredField from './AuthenticationSecuredField'; import AuthenticationToggleField from './AuthenticationToggleField'; @@ -40,16 +40,17 @@ interface SamlToggleFieldProps { export default function AuthenticationFormField(props: SamlToggleFieldProps) { const { mandatory = false, definition, settingValue, isNotSet, error } = props; + const name = getPropertyName(definition); + const description = getPropertyDescription(definition); + return ( <div className="settings-definition"> <div className="settings-definition-left"> <label className="h3" htmlFor={definition.key}> - {definition.name} + {name} </label> {mandatory && <MandatoryFieldMarker />} - {definition.description && ( - <div className="markdown small spacer-top">{definition.description}</div> - )} + {definition.description && <div className="markdown small spacer-top">{description}</div>} </div> <div className="settings-definition-right big-padded-top display-flex-column"> {definition.multiValues && ( diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx index 9421083b828..19e7d43ceb6 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx @@ -48,11 +48,7 @@ interface GithubAuthenticationProps { currentTab: AuthenticationTabs; } -const GITHUB_EXCLUDED_FIELD = [ - 'sonar.auth.github.enabled', - 'sonar.auth.github.groupsSync', - 'sonar.auth.github.allowUsersToSignUp', -]; +const GITHUB_EXCLUDED_FIELD = ['sonar.auth.github.enabled', 'sonar.auth.github.allowUsersToSignUp']; export default function GithubAuthenticationTab(props: GithubAuthenticationProps) { const { definitions, currentTab } = props; @@ -187,8 +183,58 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps </label> {enabled ? ( - <div className="display-flex-row spacer-top"> + <div className="display-flex-column spacer-top"> <RadioCard + label={translate('settings.authentication.form.provisioning_at_login')} + title={translate('settings.authentication.form.provisioning_at_login')} + selected={!(newGithubProvisioningStatus ?? githubProvisioningStatus)} + onClick={() => setNewGithubProvisioningStatus(false)} + > + <p className="spacer-bottom"> + <FormattedMessage id="settings.authentication.github.form.provisioning_at_login.description" /> + </p> + <p className="spacer-bottom"> + <FormattedMessage + id="settings.authentication.github.form.description.doc" + tagName="p" + values={{ + documentation: ( + <DocLink + to={`/instance-administration/authentication/${ + DOCUMENTATION_LINK_SUFFIXES[AlmKeys.GitHub] + }/`} + > + {translate('documentation')} + </DocLink> + ), + }} + /> + </p> + + {!(newGithubProvisioningStatus ?? githubProvisioningStatus) && ( + <> + <hr /> + {Object.values(values).map((val) => { + if (!GITHUB_JIT_FIELDS.includes(val.key)) { + return null; + } + return ( + <div key={val.key}> + <AuthenticationFormField + settingValue={values[val.key]?.newValue ?? values[val.key]?.value} + definition={val.definition} + mandatory={val.mandatory} + onFieldChange={setNewValue} + isNotSet={val.isNotSet} + /> + </div> + ); + })} + </> + )} + </RadioCard> + <RadioCard + className="spacer-top" label={translate( 'settings.authentication.github.form.provisioning_with_github' )} @@ -202,7 +248,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps {hasGithubProvisioning ? ( <> {hasDifferentProvider && ( - <p className="spacer-bottom text-bold"> + <p className="spacer-bottom text-bold "> {translate('settings.authentication.form.other_provisioning_enabled')} </p> )} @@ -213,10 +259,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps </p> <p className="spacer-bottom"> <FormattedMessage - id="settings.authentication.github.form.provisioning_with_github.description.doc" - defaultMessage={translate( - 'settings.authentication.github.form.provisioning_with_github.description.doc' - )} + id="settings.authentication.github.form.description.doc" values={{ documentation: ( <DocLink @@ -230,8 +273,10 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps }} /> </p> + {githubProvisioningStatus && <GitHubSynchronisationWarning />} - <div className="sw-flex sw-flex-1 sw-items-end"> + + <div className="sw-flex sw-flex-1"> <Button className="spacer-top width-30" onClick={synchronizeNow} @@ -260,29 +305,6 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps </p> )} </RadioCard> - <RadioCard - label={translate('settings.authentication.form.provisioning_at_login')} - title={translate('settings.authentication.form.provisioning_at_login')} - selected={!(newGithubProvisioningStatus ?? githubProvisioningStatus)} - onClick={() => setNewGithubProvisioningStatus(false)} - > - {Object.values(values).map((val) => { - if (!GITHUB_JIT_FIELDS.includes(val.key)) { - return null; - } - return ( - <div key={val.key}> - <AuthenticationFormField - settingValue={values[val.key]?.newValue ?? values[val.key]?.value} - definition={val.definition} - mandatory={val.mandatory} - onFieldChange={setNewValue} - isNotSet={val.isNotSet} - /> - </div> - ); - })} - </RadioCard> </div> ) : ( <Alert className="big-spacer-top" variant="info"> diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/SamlAuthenticationTab.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/SamlAuthenticationTab.tsx index 0deaa73e7aa..04263974303 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/SamlAuthenticationTab.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/SamlAuthenticationTab.tsx @@ -182,8 +182,19 @@ export default function SamlAuthenticationTab(props: SamlAuthenticationProps) { {translate('settings.authentication.form.provisioning')} </label> {samlEnabled ? ( - <div className="display-flex-row spacer-top"> + <div className="display-flex-column spacer-top"> <RadioCard + label={translate('settings.authentication.saml.form.provisioning_at_login')} + title={translate('settings.authentication.saml.form.provisioning_at_login')} + selected={!(newScimStatus ?? scimStatus)} + onClick={() => setNewScimStatus(false)} + > + <p> + {translate('settings.authentication.saml.form.provisioning_at_login.sub')} + </p> + </RadioCard> + <RadioCard + className="spacer-top" label={translate('settings.authentication.saml.form.provisioning_with_scim')} title={translate('settings.authentication.saml.form.provisioning_with_scim')} selected={newScimStatus ?? scimStatus} @@ -194,9 +205,6 @@ export default function SamlAuthenticationTab(props: SamlAuthenticationProps) { <p> <FormattedMessage id="settings.authentication.saml.form.provisioning.disabled" - defaultMessage={translate( - 'settings.authentication.saml.form.provisioning.disabled' - )} values={{ documentation: ( <DocLink to="/instance-administration/authentication/saml/scim/overview"> @@ -213,12 +221,12 @@ export default function SamlAuthenticationTab(props: SamlAuthenticationProps) { {translate('settings.authentication.form.other_provisioning_enabled')} </p> )} - <p className="spacer-bottom"> + <p className="spacer-bottom "> {translate( 'settings.authentication.saml.form.provisioning_with_scim.sub' )} </p> - <p className="spacer-bottom"> + <p className="spacer-bottom "> {translate( 'settings.authentication.saml.form.provisioning_with_scim.description' )} @@ -241,16 +249,6 @@ export default function SamlAuthenticationTab(props: SamlAuthenticationProps) { </> )} </RadioCard> - <RadioCard - label={translate('settings.authentication.saml.form.provisioning_at_login')} - title={translate('settings.authentication.saml.form.provisioning_at_login')} - selected={!(newScimStatus ?? scimStatus)} - onClick={() => setNewScimStatus(false)} - > - <p> - {translate('settings.authentication.saml.form.provisioning_at_login.sub')} - </p> - </RadioCard> </div> ) : ( <Alert className="big-spacer-top" variant="info"> diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx index b0e2cea255a..eb65fdf02dc 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx @@ -83,12 +83,14 @@ const ui = { saml: { noSamlConfiguration: byText('settings.authentication.saml.form.not_configured'), createConfigButton: byRole('button', { name: 'settings.authentication.form.create' }), - providerName: byRole('textbox', { name: 'Provider Name' }), - providerId: byRole('textbox', { name: 'Provider ID' }), - providerCertificate: byRole('textbox', { name: 'Identity provider certificate' }), - loginUrl: byRole('textbox', { name: 'SAML login url' }), - userLoginAttribute: byRole('textbox', { name: 'SAML user login attribute' }), - userNameAttribute: byRole('textbox', { name: 'SAML user name attribute' }), + providerName: byRole('textbox', { name: 'property.sonar.auth.saml.providerName.name' }), + providerId: byRole('textbox', { name: 'property.sonar.auth.saml.providerId.name' }), + providerCertificate: byRole('textbox', { + name: 'property.sonar.auth.saml.certificate.secured.name', + }), + loginUrl: byRole('textbox', { name: 'property.sonar.auth.saml.loginUrl.name' }), + userLoginAttribute: byRole('textbox', { name: 'property.sonar.auth.saml.user.login.name' }), + userNameAttribute: byRole('textbox', { name: 'property.sonar.auth.saml.user.name.name' }), saveConfigButton: byRole('button', { name: 'settings.almintegration.form.save' }), confirmProvisioningButton: byRole('button', { name: 'yes' }), saveScim: byRole('button', { name: 'save' }), @@ -129,17 +131,16 @@ const ui = { tab: byRole('tab', { name: 'github GitHub' }), noGithubConfiguration: byText('settings.authentication.github.form.not_configured'), createConfigButton: byRole('button', { name: 'settings.authentication.form.create' }), - clientId: byRole('textbox', { name: 'Client ID' }), - clientSecret: byRole('textbox', { name: 'Client Secret' }), - githubAppId: byRole('textbox', { name: 'GitHub App ID' }), // not working - privateKey: byRole('textarea', { name: 'Private Key' }), // not working - githubApiUrl: byRole('textbox', { name: 'The API url for a GitHub instance.' }), - githubWebUrl: byRole('textbox', { name: 'The WEB url for a GitHub instance.' }), + clientId: byRole('textbox', { name: 'property.sonar.auth.github.clientId.secured.name' }), + clientSecret: byRole('textbox', { + name: 'property.sonar.auth.github.clientSecret.secured.name', + }), + githubApiUrl: byRole('textbox', { name: 'property.sonar.auth.github.apiUrl.name' }), + githubWebUrl: byRole('textbox', { name: 'property.sonar.auth.github.webUrl.name' }), allowUserToSignUp: byRole('switch', { name: 'sonar.auth.github.allowUsersToSignUp', }), - syncGroupsAsTeams: byRole('switch', { name: 'sonar.auth.github.groupsSync' }), - organizations: byRole('textbox', { name: 'Organizations' }), + organizations: byRole('textbox', { name: 'property.sonar.auth.github.organizations.name' }), saveConfigButton: byRole('button', { name: 'settings.almintegration.form.save' }), confirmProvisioningButton: byRole('button', { name: 'yes' }), saveGithubProvisioning: byRole('button', { name: 'save' }), @@ -436,7 +437,6 @@ describe('Github tab', () => { expect(github.saveGithubProvisioning.get()).toBeDisabled(); await user.click(github.allowUserToSignUp.get()); - await user.click(github.syncGroupsAsTeams.get()); expect(github.saveGithubProvisioning.get()).toBeEnabled(); await user.click(github.saveGithubProvisioning.get()); diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts b/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts index e8ca3a7fb62..01c24408e4b 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts +++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts @@ -33,14 +33,12 @@ export const GITHUB_ENABLED_FIELD = 'sonar.auth.github.enabled'; export const GITHUB_APP_ID_FIELD = 'sonar.auth.github.appId'; export const GITHUB_API_URL_FIELD = 'sonar.auth.github.apiUrl'; export const GITHUB_CLIENT_ID_FIELD = 'sonar.auth.github.clientId.secured'; -export const GITHUB_JIT_FIELDS = [ - 'sonar.auth.github.allowUsersToSignUp', - 'sonar.auth.github.groupsSync', -]; +export const GITHUB_JIT_FIELDS = ['sonar.auth.github.allowUsersToSignUp']; export const OPTIONAL_FIELDS = [ GITHUB_ENABLED_FIELD, ...GITHUB_JIT_FIELDS, 'sonar.auth.github.organizations', + 'sonar.auth.github.groupsSync', ]; export interface SamlSettingValue { diff --git a/server/sonar-web/src/main/js/apps/settings/styles.css b/server/sonar-web/src/main/js/apps/settings/styles.css index a886b08c3fe..11c7821a249 100644 --- a/server/sonar-web/src/main/js/apps/settings/styles.css +++ b/server/sonar-web/src/main/js/apps/settings/styles.css @@ -248,7 +248,8 @@ } .authentication-configuration .radio-card { - width: 50%; + width: 100%; + min-height: 250px; background-color: var(--neutral50); border: 1px solid var(--neutral200); } @@ -266,10 +267,6 @@ justify-content: space-between; } -.authentication-configuration .radio-card-header { - justify-content: space-around; -} - .authentication-configuration .radio-card-body { justify-content: flex-start; } @@ -279,7 +276,6 @@ } .authentication-configuration .settings-definition-right { - display: flex; - align-items: center; - width: 50%; + align-items: end; + width: 20%; } 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 65e020d43fb..b1fa53d3b82 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1505,7 +1505,8 @@ settings.authentication.github.form.provisioning_with_github=Automatic user, gro settings.authentication.github.form.provisioning_with_github_short.autoProvisioning=Automatic provisioning settings.authentication.github.form.provisioning_with_github_short.jit=Just-in-Time provisioning settings.authentication.github.form.provisioning_with_github.description=Users, groups and permissions are automatically provisioned from your GitHub organizations. Once activated, users and groups can only be created and modified from your GitHub organizations/teams. Existing local users will be kept and can only be deactivated. -settings.authentication.github.form.provisioning_with_github.description.doc=For more details, see {documentation}. +settings.authentication.github.form.description.doc=For more details, see {documentation}. +settings.authentication.github.form.provisioning_at_login.description=User and group will be synchronise only when user log into Sonarqube. settings.authentication.github.form.provisioning.disabled=Your current edition does not support provisioning with GitHub. See the {documentation} for more information. settings.authentication.github.synchronize_now=Synchronize now settings.authentication.github.synchronization_in_progress=Synchronization is in progress. |