diff options
author | Jeremy Davis <jeremy.davis@sonarsource.com> | 2022-08-24 11:39:23 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-08-25 20:03:09 +0000 |
commit | b70e3dd64c5c9a37b212ae6ff3d6f83d66a64e08 (patch) | |
tree | 04c44060c9484d45a80bb220a3dbf5987b01c820 /server/sonar-web/src | |
parent | 0df3e30a3ca9d5edbcfd675f31e8e0bc2a08c0c5 (diff) | |
download | sonarqube-b70e3dd64c5c9a37b212ae6ff3d6f83d66a64e08.tar.gz sonarqube-b70e3dd64c5c9a37b212ae6ff3d6f83d66a64e08.zip |
SONAR-17228 tabs for Authentication settings
Diffstat (limited to 'server/sonar-web/src')
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() || ''; } |