aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2023-09-11 12:05:25 +0200
committersonartech <sonartech@sonarsource.com>2023-09-12 20:02:41 +0000
commit6d021927d626cbe78bb2ee17bb2cc40ac5e6ee02 (patch)
tree0f86f86f3bb7742bd3ce9397795fc79bbed62baa
parent9c2bd22c1d14c61976dde84bc7ed79cb9032378e (diff)
downloadsonarqube-6d021927d626cbe78bb2ee17bb2cc40ac5e6ee02.tar.gz
sonarqube-6d021927d626cbe78bb2ee17bb2cc40ac5e6ee02.zip
SONAR-20402 Align authentication settings card verticaly
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts24
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/AuthenticationFormField.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx92
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/SamlAuthenticationTab.tsx30
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx30
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/hook/useGithubConfiguration.ts6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/styles.css12
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties3
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.