aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2022-08-24 11:39:23 +0200
committersonartech <sonartech@sonarsource.com>2022-08-25 20:03:09 +0000
commitb70e3dd64c5c9a37b212ae6ff3d6f83d66a64e08 (patch)
tree04c44060c9484d45a80bb220a3dbf5987b01c820 /server/sonar-web/src
parent0df3e30a3ca9d5edbcfd675f31e8e0bc2a08c0c5 (diff)
downloadsonarqube-b70e3dd64c5c9a37b212ae6ff3d6f83d66a64e08.tar.gz
sonarqube-b70e3dd64c5c9a37b212ae6ff3d6f83d66a64e08.zip
SONAR-17228 tabs for Authentication settings
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts13
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap30
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap3
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx161
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-test.tsx45
-rw-r--r--server/sonar-web/src/main/js/apps/settings/constants.ts1
-rw-r--r--server/sonar-web/src/main/js/apps/settings/styles.css5
-rw-r--r--server/sonar-web/src/main/js/apps/settings/utils.ts6
10 files changed, 275 insertions, 6 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts
index 417758c8932..f71d457f4cc 100644
--- a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts
+++ b/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts
@@ -100,7 +100,7 @@ describe('buildSettingLink', () => {
{
hash: '#sonar.auth.gitlab.name',
pathname: '/admin/settings',
- search: '?category=foo+category&alm=gitlab'
+ search: '?category=foo+category&tab=gitlab'
}
],
[
@@ -109,7 +109,16 @@ describe('buildSettingLink', () => {
{
hash: '#sonar.auth.github.token',
pathname: '/admin/settings',
- search: '?category=foo+category&alm=github'
+ search: '?category=foo+category&tab=github'
+ }
+ ],
+ [
+ mockDefinition({ key: 'sonar.auth.bitbucket.token' }),
+ undefined,
+ {
+ hash: '#sonar.auth.bitbucket.token',
+ pathname: '/admin/settings',
+ search: '?category=foo+category&tab=bitbucket'
}
],
[
diff --git a/server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx b/server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx
index 1737728d02c..6476bb8f1bb 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/AdditionalCategories.tsx
@@ -24,12 +24,14 @@ import { Component } from '../../../types/types';
import {
ALM_INTEGRATION_CATEGORY,
ANALYSIS_SCOPE_CATEGORY,
+ AUTHENTICATION_CATEGORY,
LANGUAGES_CATEGORY,
NEW_CODE_PERIOD_CATEGORY,
PULL_REQUEST_DECORATION_BINDING_CATEGORY
} from '../constants';
import AlmIntegration from './almIntegration/AlmIntegration';
import { AnalysisScope } from './AnalysisScope';
+import Authentication from './authentication/Authentication';
import Languages from './Languages';
import NewCodePeriod from './NewCodePeriod';
import PullRequestDecorationBinding from './pullRequestDecorationBinding/PRDecorationBinding';
@@ -92,6 +94,14 @@ export const ADDITIONAL_CATEGORIES: AdditionalCategory[] = [
availableForProject: true,
displayTab: true,
requiresBranchesEnabled: true
+ },
+ {
+ key: AUTHENTICATION_CATEGORY,
+ name: translate('property.category.authentication'),
+ renderComponent: getAuthenticationComponent,
+ availableGlobally: true,
+ availableForProject: false,
+ displayTab: false
}
];
@@ -111,6 +121,10 @@ function getAlmIntegrationComponent(props: AdditionalCategoryComponentProps) {
return <AlmIntegration {...props} />;
}
+function getAuthenticationComponent(props: AdditionalCategoryComponentProps) {
+ return <Authentication {...props} />;
+}
+
function getPullRequestDecorationBindingComponent(props: AdditionalCategoryComponentProps) {
return props.component && <PullRequestDecorationBinding component={props.component} />;
}
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 cb5c37892f5..8a48cd3c24d 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
@@ -118,3 +118,33 @@ exports[`should render additional categories component correctly 5`] = `
}
/>
`;
+
+exports[`should render additional categories component correctly 6`] = `
+<Authentication
+ categories={Array []}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ definitions={Array []}
+ selectedCategory="TEST"
+/>
+`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
index 0ed12fa6221..9405d10f639 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx
@@ -128,7 +128,8 @@ export default function AlmTabRenderer(props: AlmTabRendererProps) {
link: (
<Link
to={{
- pathname: '/admin/settings?category=authentication'
+ pathname: '/admin/settings',
+ search: `category=authentication&tab=${almTab}`
}}>
{translate('property.category.authentication')}
</Link>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
index 4a8a83d0009..5061a09cc58 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap
@@ -551,7 +551,8 @@ exports[`should render correctly with validation: pass the correct key for bitbu
"link": <Link
to={
Object {
- "pathname": "/admin/settings?category=authentication",
+ "pathname": "/admin/settings",
+ "search": "category=authentication&tab=bitbucket",
}
}
>
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
new file mode 100644
index 00000000000..39fae5f8e15
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
@@ -0,0 +1,161 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { Link, useSearchParams } from 'react-router-dom';
+import ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper';
+import BoxedTabs from '../../../../components/controls/BoxedTabs';
+import { Alert } from '../../../../components/ui/Alert';
+import { translate } from '../../../../helpers/l10n';
+import { getBaseUrl } from '../../../../helpers/system';
+import { searchParamsToQuery } from '../../../../helpers/urls';
+import { AlmKeys } from '../../../../types/alm-settings';
+import { ExtendedSettingDefinition } from '../../../../types/settings';
+import { AUTHENTICATION_CATEGORY } from '../../constants';
+import CategoryDefinitionsList from '../CategoryDefinitionsList';
+
+interface Props {
+ definitions: ExtendedSettingDefinition[];
+}
+
+// We substract the footer height with padding (80) and the main layout padding (20)
+const HEIGHT_ADJUSTMENT = 100;
+
+const SAML = 'saml';
+export type AuthenticationTabs =
+ | typeof SAML
+ | AlmKeys.GitHub
+ | AlmKeys.GitLab
+ | AlmKeys.BitbucketServer;
+
+const DOCUMENTATION_LINKS = {
+ [SAML]: '/documentation/instance-administration/delegated-auth/#saml-authentication',
+ [AlmKeys.GitHub]: '/documentation/analysis/github-integration/#authenticating-with-github',
+ [AlmKeys.GitLab]: '/documentation/analysis/gitlab-integration/#authenticating-with-gitlab',
+ [AlmKeys.BitbucketServer]:
+ '/documentation/analysis/bitbucket-cloud-integration/#authenticating-with-bitbucket-cloud'
+};
+
+function renderDevOpsIcon(key: string) {
+ return (
+ <img
+ alt={key}
+ className="spacer-right"
+ height={16}
+ src={`${getBaseUrl()}/images/alm/${key}.svg`}
+ />
+ );
+}
+
+export default function Authentication(props: Props) {
+ const { definitions } = props;
+
+ const [query, setSearchParams] = useSearchParams();
+
+ const currentTab = (query.get('tab') || SAML) as AuthenticationTabs;
+
+ const tabs = [
+ {
+ key: SAML,
+ label: 'SAML'
+ },
+ {
+ key: AlmKeys.GitHub,
+ label: (
+ <>
+ {renderDevOpsIcon(AlmKeys.GitHub)}
+ GitHub
+ </>
+ )
+ },
+ {
+ key: AlmKeys.BitbucketServer,
+ label: (
+ <>
+ {renderDevOpsIcon(AlmKeys.BitbucketServer)}
+ Bitbucket
+ </>
+ )
+ },
+ {
+ key: AlmKeys.GitLab,
+ label: (
+ <>
+ {renderDevOpsIcon(AlmKeys.GitLab)}
+ GitLab
+ </>
+ )
+ }
+ ];
+
+ return (
+ <>
+ <header className="page-header">
+ <h1 className="page-title">{translate('settings.authentication.title')}</h1>
+ </header>
+
+ <div className="spacer-top huge-spacer-bottom">
+ <p>{translate('settings.authentication.description')}</p>
+ </div>
+
+ <BoxedTabs
+ onSelect={(tab: AuthenticationTabs) => {
+ setSearchParams({ ...searchParamsToQuery(query), tab });
+ }}
+ selected={currentTab}
+ tabs={tabs}
+ />
+
+ <ScreenPositionHelper>
+ {({ top }) => (
+ <div
+ style={{
+ maxHeight: `calc(100vh - ${top + HEIGHT_ADJUSTMENT}px)`
+ }}
+ className="bordered overflow-y-auto tabbed-definitions">
+ <div className="big-padded">
+ <Alert variant="info">
+ <FormattedMessage
+ id="settings.authentication.help"
+ defaultMessage={translate('settings.authentication.help')}
+ values={{
+ link: (
+ <Link
+ to={DOCUMENTATION_LINKS[currentTab]}
+ rel="noopener noreferrer"
+ target="_blank">
+ {translate('settings.authentication.help.link')}
+ </Link>
+ )
+ }}
+ />
+ </Alert>
+ <CategoryDefinitionsList
+ category={AUTHENTICATION_CATEGORY}
+ definitions={definitions}
+ subCategory={currentTab}
+ />
+ </div>
+ </div>
+ )}
+ </ScreenPositionHelper>
+ </>
+ );
+}
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
new file mode 100644
index 00000000000..954ef528460
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-test.tsx
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import React from 'react';
+import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
+import Authentication from '../Authentication';
+
+it('should render tabs and allow navigation', async () => {
+ const user = userEvent.setup();
+ renderAuthentication();
+
+ expect(screen.getAllByRole('button')).toHaveLength(4);
+
+ expect(screen.getByRole('button', { name: 'SAML' })).toHaveAttribute('aria-current', 'true');
+
+ await user.click(screen.getByRole('button', { name: 'github GitHub' }));
+
+ expect(screen.getByRole('button', { name: 'SAML' })).toHaveAttribute('aria-current', 'false');
+ expect(screen.getByRole('button', { name: 'github GitHub' })).toHaveAttribute(
+ 'aria-current',
+ 'true'
+ );
+});
+
+function renderAuthentication() {
+ renderComponent(<Authentication definitions={[]} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/constants.ts b/server/sonar-web/src/main/js/apps/settings/constants.ts
index d285466cbd0..de0f66f52f8 100644
--- a/server/sonar-web/src/main/js/apps/settings/constants.ts
+++ b/server/sonar-web/src/main/js/apps/settings/constants.ts
@@ -20,6 +20,7 @@
import { Dict } from '../../types/types';
export const ALM_INTEGRATION_CATEGORY = 'almintegration';
+export const AUTHENTICATION_CATEGORY = 'authentication';
export const ANALYSIS_SCOPE_CATEGORY = 'exclusions';
export const LANGUAGES_CATEGORY = 'languages';
export const NEW_CODE_PERIOD_CATEGORY = 'new_code_period';
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 443d919110b..3c1a6948e14 100644
--- a/server/sonar-web/src/main/js/apps/settings/styles.css
+++ b/server/sonar-web/src/main/js/apps/settings/styles.css
@@ -73,6 +73,11 @@
align-items: stretch;
}
+.tabbed-definitions .settings-definition {
+ margin: 0 -16px;
+ padding: 10px 16px;
+}
+
.settings-definition-changed {
border-top: 1px solid var(--alertBorderWarning);
border-bottom: 1px solid var(--alertBorderWarning);
diff --git a/server/sonar-web/src/main/js/apps/settings/utils.ts b/server/sonar-web/src/main/js/apps/settings/utils.ts
index fd26233e62d..864459c3596 100644
--- a/server/sonar-web/src/main/js/apps/settings/utils.ts
+++ b/server/sonar-web/src/main/js/apps/settings/utils.ts
@@ -225,9 +225,11 @@ export function buildSettingLink(
const query: Dict<string> = {};
if (key.startsWith('sonar.auth.gitlab')) {
- query.alm = 'gitlab';
+ query.tab = 'gitlab';
} else if (key.startsWith('sonar.auth.github')) {
- query.alm = 'github';
+ query.tab = 'github';
+ } else if (key.startsWith('sonar.auth.bitbucket')) {
+ query.tab = 'bitbucket';
} else if (key.startsWith('sonar.almintegration')) {
query.alm = key.split('.').pop() || '';
}