aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js
diff options
context:
space:
mode:
authorPhilippe Perrin <philippe.perrin@sonarsource.com>2022-10-26 11:12:22 +0200
committersonartech <sonartech@sonarsource.com>2022-10-26 20:03:10 +0000
commit47012e64f35a8b63575e40efed7981a37979945a (patch)
tree2b51c0450b1aa58ffe4f946e1fe6585afb9437d4 /server/sonar-web/src/main/js
parentdc592db7bb160b5c43fae1fcfd7e222ed0c875a1 (diff)
downloadsonarqube-47012e64f35a8b63575e40efed7981a37979945a.tar.gz
sonarqube-47012e64f35a8b63575e40efed7981a37979945a.zip
SONAR-17515 Add an info box on the authentication settings page to advertise about the login message feature
Diffstat (limited to 'server/sonar-web/src/main/js')
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx27
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-test.tsx224
3 files changed, 154 insertions, 99 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap
index 190caae8682..4d5762daebd 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap
@@ -120,7 +120,7 @@ exports[`should render additional categories component correctly 5`] = `
`;
exports[`should render additional categories component correctly 6`] = `
-<Authentication
+<withAvailableFeaturesContext(Authentication)
categories={Array []}
component={
Object {
diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
index 4653c2a69fb..316c8099252 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
@@ -20,7 +20,11 @@
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { useSearchParams } from 'react-router-dom';
+import withAvailableFeatures, {
+ WithAvailableFeaturesProps
+} from '../../../../app/components/available-features/withAvailableFeatures';
import DocLink from '../../../../components/common/DocLink';
+import Link from '../../../../components/common/Link';
import ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper';
import BoxedTabs, { getTabId, getTabPanelId } from '../../../../components/controls/BoxedTabs';
import { Alert } from '../../../../components/ui/Alert';
@@ -28,6 +32,7 @@ import { translate } from '../../../../helpers/l10n';
import { getBaseUrl } from '../../../../helpers/system';
import { searchParamsToQuery } from '../../../../helpers/urls';
import { AlmKeys } from '../../../../types/alm-settings';
+import { Feature } from '../../../../types/features';
import { ExtendedSettingDefinition } from '../../../../types/settings';
import { AUTHENTICATION_CATEGORY } from '../../constants';
import CategoryDefinitionsList from '../CategoryDefinitionsList';
@@ -65,7 +70,7 @@ function renderDevOpsIcon(key: string) {
);
}
-export default function Authentication(props: Props) {
+export function Authentication(props: Props & WithAvailableFeaturesProps) {
const { definitions } = props;
const [query, setSearchParams] = useSearchParams();
@@ -112,7 +117,23 @@ export default function Authentication(props: Props) {
<h1 className="page-title">{translate('settings.authentication.title')}</h1>
</header>
- <div className="spacer-top huge-spacer-bottom">
+ {props.hasFeature(Feature.LoginMessage) && (
+ <Alert variant="info">
+ <FormattedMessage
+ id="settings.authentication.custom_message_information"
+ defaultMessage={translate('settings.authentication.custom_message_information')}
+ values={{
+ link: (
+ <Link to="/admin/settings?category=general#sonar.login.message">
+ {translate('settings.authentication.custom_message_information.link')}
+ </Link>
+ )
+ }}
+ />
+ </Alert>
+ )}
+
+ <div className="big-spacer-top huge-spacer-bottom">
<p>{translate('settings.authentication.description')}</p>
</div>
@@ -171,3 +192,5 @@ export default function Authentication(props: Props) {
</>
);
}
+
+export default withAvailableFeatures(Authentication);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-test.tsx
index 7027cbef4e4..0671022d940 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-test.tsx
@@ -21,8 +21,10 @@ import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import AuthenticationServiceMock from '../../../../../api/mocks/AuthenticationServiceMock';
+import { AvailableFeaturesContext } from '../../../../../app/components/available-features/AvailableFeaturesContext';
import { mockDefinition } from '../../../../../helpers/mocks/settings';
import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
+import { Feature } from '../../../../../types/features';
import { ExtendedSettingDefinition, SettingType } from '../../../../../types/settings';
import Authentication from '../Authentication';
@@ -86,103 +88,133 @@ it('should render tabs and allow navigation', async () => {
);
});
-it('should allow user to test the configuration', async () => {
- const user = userEvent.setup();
-
- const definitions = [
- mockDefinition({
- key: 'sonar.auth.saml.certificate.secured',
- category: 'authentication',
- subCategory: 'saml',
- name: 'Certificate',
- description: 'Secured certificate',
- type: SettingType.PASSWORD
- }),
- mockDefinition({
- key: 'sonar.auth.saml.enabled',
- category: 'authentication',
- subCategory: 'saml',
- name: 'Enabled',
- description: 'To enable the flag',
- type: SettingType.BOOLEAN
- })
- ];
-
- renderAuthentication(definitions);
-
- await user.click(await screen.findByText('settings.almintegration.form.secret.update_field'));
-
- await user.click(screen.getByRole('textbox', { name: 'Certificate' }));
- await user.keyboard('new certificate');
-
- expect(screen.getByText('settings.authentication.saml.form.test')).toHaveClass('disabled');
-
- await user.click(screen.getByRole('button', { name: 'settings.authentication.saml.form.save' }));
-
- expect(screen.getByText('settings.authentication.saml.form.test')).not.toHaveClass('disabled');
+describe('SAML tab', () => {
+ it('should allow user to test the configuration', async () => {
+ const user = userEvent.setup();
+
+ const definitions = [
+ mockDefinition({
+ key: 'sonar.auth.saml.certificate.secured',
+ category: 'authentication',
+ subCategory: 'saml',
+ name: 'Certificate',
+ description: 'Secured certificate',
+ type: SettingType.PASSWORD
+ }),
+ mockDefinition({
+ key: 'sonar.auth.saml.enabled',
+ category: 'authentication',
+ subCategory: 'saml',
+ name: 'Enabled',
+ description: 'To enable the flag',
+ type: SettingType.BOOLEAN
+ })
+ ];
+
+ renderAuthentication(definitions);
+
+ await user.click(await screen.findByText('settings.almintegration.form.secret.update_field'));
+
+ await user.click(screen.getByRole('textbox', { name: 'Certificate' }));
+ await user.keyboard('new certificate');
+
+ expect(screen.getByText('settings.authentication.saml.form.test')).toHaveClass('disabled');
+
+ await user.click(
+ screen.getByRole('button', { name: 'settings.authentication.saml.form.save' })
+ );
+
+ expect(screen.getByText('settings.authentication.saml.form.test')).not.toHaveClass('disabled');
+ });
+
+ it('should allow user to edit fields and save configuration', async () => {
+ const user = userEvent.setup();
+ const definitions = mockDefinitionFields;
+ renderAuthentication(definitions);
+
+ expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'true');
+ // update fields
+ await user.click(screen.getByRole('textbox', { name: 'test1' }));
+ await user.keyboard('new test1');
+
+ await user.click(screen.getByRole('textbox', { name: 'test2' }));
+ await user.keyboard('new test2');
+ // check if enable is allowed after updating
+ expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'false');
+
+ // reset value
+ await user.click(screen.getByRole('textbox', { name: 'test2' }));
+ await user.keyboard('{Control>}a{/Control}{Backspace}');
+ await user.click(
+ screen.getByRole('button', { name: 'settings.authentication.saml.form.save' })
+ );
+ expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'true');
+
+ await user.click(screen.getByRole('textbox', { name: 'test2' }));
+ await user.keyboard('new test2');
+ expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'false');
+
+ expect(
+ screen.getByRole('button', { name: 'settings.almintegration.form.secret.update_field' })
+ ).toBeInTheDocument();
+ await user.click(
+ screen.getByRole('button', { name: 'settings.almintegration.form.secret.update_field' })
+ );
+ // check for secure fields
+ expect(screen.getByRole('textbox', { name: 'Certificate' })).toBeInTheDocument();
+ await user.click(screen.getByRole('textbox', { name: 'Certificate' }));
+ await user.keyboard('new certificate');
+ // enable the configuration
+ await user.click(screen.getByRole('button', { name: 'off' }));
+ expect(screen.getByRole('button', { name: 'on' })).toBeInTheDocument();
+
+ await user.click(
+ screen.getByRole('button', { name: 'settings.authentication.saml.form.save' })
+ );
+ expect(screen.getByText('settings.authentication.saml.form.save_success')).toBeInTheDocument();
+ // check after switching tab that the flag is still enabled
+ await user.click(screen.getByRole('tab', { name: 'github GitHub' }));
+ await user.click(screen.getByRole('tab', { name: 'SAML' }));
+
+ expect(screen.getByRole('button', { name: 'on' })).toBeInTheDocument();
+ });
+
+ it('should handle and show errors to the user', async () => {
+ const user = userEvent.setup();
+ const definitions = mockDefinitionFields;
+ renderAuthentication(definitions);
+
+ await user.click(screen.getByRole('textbox', { name: 'test1' }));
+ await user.keyboard('value');
+ await user.click(screen.getByRole('textbox', { name: 'test2' }));
+ await user.keyboard('{Control>}a{/Control}error');
+ await user.click(
+ screen.getByRole('button', { name: 'settings.authentication.saml.form.save' })
+ );
+ expect(screen.getByText('settings.authentication.saml.form.save_partial')).toBeInTheDocument();
+ });
+
+ it('should not display the login message feature info box', () => {
+ renderAuthentication([]);
+
+ expect(
+ screen.queryByText('settings.authentication.custom_message_information')
+ ).not.toBeInTheDocument();
+ });
+
+ it('should display the login message feature info box', () => {
+ renderAuthentication([], [Feature.LoginMessage]);
+
+ expect(
+ screen.getByText('settings.authentication.custom_message_information')
+ ).toBeInTheDocument();
+ });
});
-it('should allow user to edit fields and save configuration', async () => {
- const user = userEvent.setup();
- const definitions = mockDefinitionFields;
- renderAuthentication(definitions);
-
- expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'true');
- // update fields
- await user.click(screen.getByRole('textbox', { name: 'test1' }));
- await user.keyboard('new test1');
-
- await user.click(screen.getByRole('textbox', { name: 'test2' }));
- await user.keyboard('new test2');
- // check if enable is allowed after updating
- expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'false');
-
- // reset value
- await user.click(screen.getByRole('textbox', { name: 'test2' }));
- await user.keyboard('{Control>}a{/Control}{Backspace}');
- await user.click(screen.getByRole('button', { name: 'settings.authentication.saml.form.save' }));
- expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'true');
-
- await user.click(screen.getByRole('textbox', { name: 'test2' }));
- await user.keyboard('new test2');
- expect(screen.getByRole('button', { name: 'off' })).toHaveAttribute('aria-disabled', 'false');
-
- expect(
- screen.getByRole('button', { name: 'settings.almintegration.form.secret.update_field' })
- ).toBeInTheDocument();
- await user.click(
- screen.getByRole('button', { name: 'settings.almintegration.form.secret.update_field' })
+function renderAuthentication(definitions: ExtendedSettingDefinition[], features: Feature[] = []) {
+ renderComponent(
+ <AvailableFeaturesContext.Provider value={features}>
+ <Authentication definitions={definitions} />
+ </AvailableFeaturesContext.Provider>
);
- // check for secure fields
- expect(screen.getByRole('textbox', { name: 'Certificate' })).toBeInTheDocument();
- await user.click(screen.getByRole('textbox', { name: 'Certificate' }));
- await user.keyboard('new certificate');
- // enable the configuration
- await user.click(screen.getByRole('button', { name: 'off' }));
- expect(screen.getByRole('button', { name: 'on' })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'settings.authentication.saml.form.save' }));
- expect(screen.getByText('settings.authentication.saml.form.save_success')).toBeInTheDocument();
- // check after switching tab that the flag is still enabled
- await user.click(screen.getByRole('tab', { name: 'github GitHub' }));
- await user.click(screen.getByRole('tab', { name: 'SAML' }));
-
- expect(screen.getByRole('button', { name: 'on' })).toBeInTheDocument();
-});
-
-it('should handle and show error to the user', async () => {
- const user = userEvent.setup();
- const definitions = mockDefinitionFields;
- renderAuthentication(definitions);
-
- await user.click(screen.getByRole('textbox', { name: 'test1' }));
- await user.keyboard('value');
- await user.click(screen.getByRole('textbox', { name: 'test2' }));
- await user.keyboard('{Control>}a{/Control}error');
- await user.click(screen.getByRole('button', { name: 'settings.authentication.saml.form.save' }));
- expect(screen.getByText('settings.authentication.saml.form.save_partial')).toBeInTheDocument();
-});
-
-function renderAuthentication(definitions: ExtendedSettingDefinition[]) {
- renderComponent(<Authentication definitions={definitions} />);
}