@@ -74,11 +74,6 @@ const StyledBadge = styled.span<{ | |||
&:empty { | |||
${tw`sw-hidden`} | |||
} | |||
.page-actions & { | |||
${tw`sw-my-1`}; | |||
${tw`sw-mx-0`}; | |||
} | |||
`; | |||
const StyledCounter = styled.span<{ |
@@ -17,13 +17,14 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { CenteredLayout } from 'design-system'; | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet-async'; | |||
import { translate } from '../../helpers/l10n'; | |||
export default function FormattingHelp() { | |||
return ( | |||
<div className="page page-limited"> | |||
<CenteredLayout className="sw-py-6 sw-h-screen"> | |||
<Helmet defer={false} title={translate('formatting.page')} /> | |||
<h2 className="spacer-bottom">Formatting Syntax</h2> | |||
<table className="width-100 data zebra"> | |||
@@ -147,6 +148,6 @@ export default function FormattingHelp() { | |||
</tr> | |||
</tbody> | |||
</table> | |||
</div> | |||
</CenteredLayout> | |||
); | |||
} |
@@ -82,38 +82,36 @@ export default function GlobalContainer() { | |||
<SuggestionsProvider> | |||
<A11yProvider> | |||
<A11ySkipLinks /> | |||
<div className="global-container"> | |||
<GlobalContainerWrapper> | |||
<GlobalBackground | |||
secondary={PAGES_WITH_SECONDARY_BACKGROUND.includes(location.pathname)} | |||
className="sw-box-border sw-flex-[1_0_auto]" | |||
id="container" | |||
> | |||
<div className="page-container"> | |||
<Workspace> | |||
<IndexationContextProvider> | |||
<LanguagesContextProvider> | |||
<MetricsContextProvider> | |||
<div className="sw-sticky sw-top-0 sw-z-global-navbar"> | |||
<SystemAnnouncement /> | |||
<IndexationNotification /> | |||
<NCDAutoUpdateMessage /> | |||
<UpdateNotification dismissable /> | |||
<GlobalNav location={location} /> | |||
{/* The following is the portal anchor point for the component nav | |||
* See ComponentContainer.tsx | |||
*/} | |||
<div id="component-nav-portal" /> | |||
</div> | |||
<Outlet /> | |||
</MetricsContextProvider> | |||
</LanguagesContextProvider> | |||
</IndexationContextProvider> | |||
</Workspace> | |||
</div> | |||
<Workspace> | |||
<IndexationContextProvider> | |||
<LanguagesContextProvider> | |||
<MetricsContextProvider> | |||
<div className="sw-sticky sw-top-0 sw-z-global-navbar"> | |||
<SystemAnnouncement /> | |||
<IndexationNotification /> | |||
<NCDAutoUpdateMessage /> | |||
<UpdateNotification dismissable /> | |||
<GlobalNav location={location} /> | |||
{/* The following is the portal anchor point for the component nav | |||
* See ComponentContainer.tsx | |||
*/} | |||
<div id="component-nav-portal" /> | |||
</div> | |||
<Outlet /> | |||
</MetricsContextProvider> | |||
</LanguagesContextProvider> | |||
</IndexationContextProvider> | |||
</Workspace> | |||
<PromotionNotification /> | |||
</GlobalBackground> | |||
<GlobalFooter /> | |||
</div> | |||
</GlobalContainerWrapper> | |||
<StartupModal /> | |||
</A11yProvider> | |||
</SuggestionsProvider> | |||
@@ -121,6 +119,13 @@ export default function GlobalContainer() { | |||
); | |||
} | |||
const GlobalContainerWrapper = styled.div` | |||
display: flex; | |||
flex-direction: column; | |||
height: 100%; | |||
min-height: 100vh; | |||
`; | |||
const GlobalBackground = styled.div<{ secondary: boolean }>` | |||
background-color: ${({ secondary }) => | |||
themeColor(secondary ? 'backgroundSecondary' : 'backgroundPrimary')}; |
@@ -18,7 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { ButtonPrimary, Card, Title } from 'design-system'; | |||
import { ButtonPrimary, Card, CenteredLayout, Title } from 'design-system'; | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet-async'; | |||
import { setSimpleSettingValue } from '../../api/settings'; | |||
@@ -67,11 +67,11 @@ export function PluginRiskConsent(props: Readonly<PluginRiskConsentProps>) { | |||
}; | |||
return ( | |||
<> | |||
<CenteredLayout className="sw-h-screen sw-pt-[10vh]"> | |||
<Helmet defer={false} title={translate('plugin_risk_consent.page')} /> | |||
<Card | |||
className="sw-body-md sw-min-w-[500px] sw-mx-auto sw-mt-[10vh] sw-w-[40%] sw-text-center" | |||
className="sw-body-md sw-min-w-[500px] sw-mx-auto sw-w-[40%] sw-text-center" | |||
data-testid="plugin-risk-consent-page" | |||
> | |||
<Title className="sw-mb-4">{translate('plugin_risk_consent.title')}</Title> | |||
@@ -84,7 +84,7 @@ export function PluginRiskConsent(props: Readonly<PluginRiskConsentProps>) { | |||
{translate('plugin_risk_consent.action')} | |||
</ButtonPrimary> | |||
</Card> | |||
</> | |||
</CenteredLayout> | |||
); | |||
} | |||
@@ -38,10 +38,10 @@ export interface ResetPasswordProps { | |||
export function ResetPassword({ currentUser }: Readonly<ResetPasswordProps>) { | |||
return ( | |||
<LargeCenteredLayout> | |||
<LargeCenteredLayout className="sw-h-screen sw-pt-10"> | |||
<PageContentFontWrapper className="sw-body-sm"> | |||
<Helmet defer={false} title={translate('my_account.reset_password.page')} /> | |||
<div className="sw-flex sw-justify-center sw-mt-10"> | |||
<div className="sw-flex sw-justify-center"> | |||
<div> | |||
<Title>{translate('my_account.reset_password')}</Title> | |||
<FlagMessage variant="warning" className="sw-mb-4"> |
@@ -28,8 +28,8 @@ import MainSonarQubeBar from './nav/global/MainSonarQubeBar'; | |||
*/ | |||
export default function SimpleContainer({ children }: { children?: React.ReactNode }) { | |||
return ( | |||
<div className="global-container new-background"> | |||
<div className="page-wrapper" id="container"> | |||
<div className="sw-flex sw-flex-col sw-h-full sw-min-h-[100vh]"> | |||
<div className="sw-box-border sw-flex-auto" id="container"> | |||
<MainSonarQubeBar /> | |||
{children !== undefined ? children : <Outlet />} | |||
</div> |
@@ -27,8 +27,8 @@ export default function SimpleSessionsContainer() { | |||
<> | |||
<PageTracker /> | |||
<div className="global-container"> | |||
<div className="page-wrapper new-background" id="container"> | |||
<div className="sw-flex sw-flex-col sw-h-full sw-min-h-[100vh]"> | |||
<div className="sw-box-border sw-flex-auto" id="container"> | |||
<Outlet /> | |||
</div> | |||
<GlobalFooter hideLoggedInInfo /> |
@@ -1,268 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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. | |||
*/ | |||
.white-page { | |||
background-color: #fff !important; | |||
} | |||
.global-container { | |||
display: flex; | |||
flex-direction: column; | |||
height: 100%; | |||
min-height: 100vh; | |||
} | |||
.page { | |||
z-index: var(--normalZIndex); | |||
padding: 10px 20px; | |||
} | |||
.page:before, | |||
.page:after { | |||
display: table; | |||
content: ''; | |||
line-height: 0; | |||
} | |||
.page:after { | |||
clear: both; | |||
} | |||
.page-limited { | |||
max-width: 1280px; | |||
margin-left: auto; | |||
margin-right: auto; | |||
padding-top: 20px; | |||
padding-bottom: 20px; | |||
} | |||
.page-container { | |||
min-width: var(--minPageWidth); | |||
} | |||
.page-wrapper { | |||
box-sizing: border-box; | |||
flex: 1 0 auto; | |||
} | |||
.page-header { | |||
position: relative; | |||
margin-bottom: 20px; | |||
} | |||
.page-header:before, | |||
.page-header:after { | |||
display: table; | |||
content: ''; | |||
line-height: 0; | |||
} | |||
.page-header:after { | |||
clear: both; | |||
} | |||
.page-title { | |||
float: left; | |||
margin-bottom: 0; | |||
line-height: var(--controlHeight); | |||
} | |||
.page-actions { | |||
float: right; | |||
margin-bottom: 10px; | |||
margin-left: 10px; | |||
line-height: var(--controlHeight); | |||
text-align: right; | |||
} | |||
.page-actions .badge { | |||
margin: 3px 0; | |||
} | |||
.page-description { | |||
float: left; | |||
clear: left; | |||
max-width: 800px; | |||
line-height: 1.5; | |||
margin-top: 6px; | |||
} | |||
.page-with-sidebar { | |||
display: flex; | |||
} | |||
.page-main { | |||
flex-grow: 1; | |||
} | |||
.page-sidebar { | |||
width: 30%; | |||
min-width: 300px; | |||
flex-shrink: 0; | |||
padding-left: 40px; | |||
box-sizing: border-box; | |||
} | |||
.page-sidebar-fixed { | |||
min-width: 300px; | |||
flex-shrink: 0; | |||
padding-left: 40px; | |||
box-sizing: border-box; | |||
width: 300px; | |||
} | |||
.page-sidebar-sticky { | |||
width: 320px !important; | |||
padding-right: 0; | |||
} | |||
.page-limited .page-sidebar-sticky { | |||
margin: -20px 0 -20px -20px; | |||
padding-right: 0 !important; | |||
} | |||
.page-limited .page-sidebar-sticky .page-sidebar-sticky-inner { | |||
padding: 20px 0; | |||
} | |||
.page-sidebar-sticky .page-sidebar-sticky-inner { | |||
position: fixed; | |||
z-index: 10; | |||
top: 30px; | |||
bottom: 0; | |||
left: 0; | |||
overflow: auto; | |||
width: calc(50vw - 640px + 280px + 3px); | |||
border-right: 1px solid var(--barBorderColor); | |||
box-sizing: border-box; | |||
background: var(--barBackgroundColor); | |||
} | |||
@media (max-width: 1335px) { | |||
.page-sidebar-sticky .page-sidebar-sticky-inner { | |||
width: 310px; | |||
} | |||
} | |||
.layout-page { | |||
display: flex; | |||
align-items: stretch; | |||
width: 100%; | |||
flex-grow: 1; | |||
} | |||
.layout-page-filters { | |||
width: 260px; | |||
padding: 20px; | |||
} | |||
.layout-page-main { | |||
flex-grow: 1; | |||
min-width: 740px; | |||
padding: 20px; | |||
z-index: var(--pageMainZIndex); | |||
} | |||
.layout-page-main-inner { | |||
position: relative; | |||
z-index: var(--normalZIndex); | |||
min-width: 740px; | |||
max-width: 980px; | |||
} | |||
.layout-page-side-outer { | |||
width: calc(50vw - 370px); | |||
flex-grow: 0; | |||
flex-shrink: 0; | |||
background-color: var(--barBackgroundColor); | |||
} | |||
.layout-page-side { | |||
position: fixed; | |||
z-index: var(--pageSideZIndex); | |||
top: 30px; | |||
bottom: 0; | |||
left: 0; | |||
width: calc(50vw - 370px); | |||
border-right: 1px solid var(--barBorderColor); | |||
overflow-y: auto; | |||
overflow-x: hidden; | |||
background-color: var(--barBackgroundColor); | |||
} | |||
.layout-page-side-inner { | |||
width: 300px; | |||
margin-left: calc(50vw - 670px); | |||
background-color: var(--barBackgroundColor); | |||
} | |||
.layout-page-header-panel, | |||
.layout-page-header-panel-inner { | |||
height: 56px; | |||
box-sizing: border-box; | |||
} | |||
.layout-page-header-panel { | |||
margin-top: -20px; | |||
} | |||
.layout-page-header-panel-inner { | |||
position: fixed; | |||
z-index: 30; | |||
line-height: var(--controlHeight); | |||
padding-top: 16px; | |||
padding-bottom: 16px; | |||
border-bottom: 1px solid var(--barBorderColor); | |||
background-color: var(--barBackgroundColor); | |||
} | |||
.layout-page-main-header { | |||
position: relative; | |||
z-index: var(--aboveNormalZIndex); | |||
margin-bottom: 20px; | |||
} | |||
.layout-page-main-header .component-name { | |||
line-height: var(--controlHeight); | |||
} | |||
.layout-page-main-header-inner { | |||
left: calc(50vw - 370px + 1px); | |||
right: 0; | |||
padding-left: 20px; | |||
padding-right: 20px; | |||
} | |||
@media (max-width: 1320px) { | |||
.layout-page-side-outer { | |||
width: 300px; | |||
} | |||
.layout-page-side { | |||
width: 300px; | |||
} | |||
.layout-page-side-inner { | |||
margin-left: 0; | |||
} | |||
.layout-page-main-header-inner { | |||
left: 301px; | |||
} | |||
} |
@@ -24,7 +24,6 @@ import '../../../../../public/fonts/Inter/inter.css'; | |||
import '../../../../../public/fonts/Ubuntu/Ubuntu.css'; | |||
import './components/global-loading.css'; | |||
import './components/page.css'; | |||
import './init/base.css'; | |||
import './init/misc.css'; | |||
import './print.css'; |
@@ -218,8 +218,6 @@ module.exports = { | |||
globalNavContentHeight: `${4 * grid}px`, | |||
maxPageWidth: '1320px', | |||
minPageWidth: '1080px', | |||
pagePadding: '20px', | |||
}, | |||
@@ -17,7 +17,8 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { LargeCenteredLayout, PageContentFontWrapper, Spinner } from 'design-system'; | |||
import { Spinner } from '@sonarsource/echoes-react'; | |||
import { LargeCenteredLayout, PageContentFontWrapper } from 'design-system'; | |||
import { debounce } from 'lodash'; | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet-async'; | |||
@@ -215,15 +216,6 @@ export class BackgroundTasksApp extends React.PureComponent<Props, State> { | |||
const { component, location } = this.props; | |||
const { loading, pagination, types, tasks } = this.state; | |||
if (!types) { | |||
return ( | |||
<div className="page page-limited"> | |||
<Helmet defer={false} title={translate('background_tasks.page')} /> | |||
<Spinner /> | |||
</div> | |||
); | |||
} | |||
const status = location.query.status || DEFAULT_FILTERS.status; | |||
const taskType = location.query.taskType || DEFAULT_FILTERS.taskType; | |||
const currents = location.query.currents || DEFAULT_FILTERS.currents; | |||
@@ -233,48 +225,50 @@ export class BackgroundTasksApp extends React.PureComponent<Props, State> { | |||
return ( | |||
<LargeCenteredLayout id="background-tasks"> | |||
<PageContentFontWrapper className="sw-my-8 sw-body-sm"> | |||
<PageContentFontWrapper className="sw-my-4 sw-body-sm"> | |||
<Suggestions suggestions="background_tasks" /> | |||
<Helmet defer={false} title={translate('background_tasks.page')} /> | |||
<Header component={component} /> | |||
<Stats | |||
component={component} | |||
failingCount={this.state.failingCount} | |||
onCancelAllPending={this.handleCancelAllPending} | |||
onShowFailing={this.handleShowFailing} | |||
pendingCount={this.state.pendingCount} | |||
pendingTime={this.state.pendingTime} | |||
/> | |||
<Search | |||
component={component} | |||
currents={currents} | |||
loading={loading} | |||
maxExecutedAt={maxExecutedAt} | |||
minSubmittedAt={minSubmittedAt} | |||
onFilterUpdate={this.handleFilterUpdate} | |||
onReload={this.loadTasksDebounced} | |||
query={query} | |||
status={status} | |||
taskType={taskType} | |||
types={types} | |||
/> | |||
<Tasks | |||
component={component} | |||
onCancelTask={this.handleCancelTask} | |||
onFilterTask={this.handleFilterTask} | |||
tasks={tasks} | |||
/> | |||
<ListFooter | |||
count={tasks.length} | |||
loadMore={this.loadMoreTasks} | |||
loading={loading} | |||
pageSize={pagination.pageSize} | |||
total={pagination.total} | |||
/> | |||
<Spinner isLoading={!types}> | |||
<Header component={component} /> | |||
<Stats | |||
component={component} | |||
failingCount={this.state.failingCount} | |||
onCancelAllPending={this.handleCancelAllPending} | |||
onShowFailing={this.handleShowFailing} | |||
pendingCount={this.state.pendingCount} | |||
pendingTime={this.state.pendingTime} | |||
/> | |||
<Search | |||
component={component} | |||
currents={currents} | |||
loading={loading} | |||
maxExecutedAt={maxExecutedAt} | |||
minSubmittedAt={minSubmittedAt} | |||
onFilterUpdate={this.handleFilterUpdate} | |||
onReload={this.loadTasksDebounced} | |||
query={query} | |||
status={status} | |||
taskType={taskType} | |||
types={types ?? []} | |||
/> | |||
<Tasks | |||
component={component} | |||
onCancelTask={this.handleCancelTask} | |||
onFilterTask={this.handleFilterTask} | |||
tasks={tasks} | |||
/> | |||
<ListFooter | |||
count={tasks.length} | |||
loadMore={this.loadMoreTasks} | |||
loading={loading} | |||
pageSize={pagination.pageSize} | |||
total={pagination.total} | |||
/> | |||
</Spinner> | |||
</PageContentFontWrapper> | |||
</LargeCenteredLayout> | |||
); |
@@ -74,7 +74,7 @@ export default function ChangeAdminPasswordAppRenderer( | |||
} | |||
return ( | |||
<CenteredLayout> | |||
<CenteredLayout className="sw-h-screen"> | |||
<Helmet defer={false} title={translate('users.change_admin_password.page')} /> | |||
<PageContentFontWrapper className="sw-body-sm sw-flex sw-flex-col sw-items-center sw-justify-center"> |
@@ -42,12 +42,6 @@ import '../../../components/search-navigator.css'; | |||
import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers'; | |||
import { KeyboardKeys } from '../../../helpers/keycodes'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
import { | |||
addSideBarClass, | |||
addWhitePageClass, | |||
removeSideBarClass, | |||
removeWhitePageClass, | |||
} from '../../../helpers/pages'; | |||
import { SecurityStandard } from '../../../types/security'; | |||
import { SettingsKey } from '../../../types/settings'; | |||
import { Dict, Paging, RawQuery, Rule, RuleActivation } from '../../../types/types'; | |||
@@ -135,8 +129,6 @@ export class CodingRulesApp extends React.PureComponent<Props, State> { | |||
componentDidMount() { | |||
this.mounted = true; | |||
addWhitePageClass(); | |||
addSideBarClass(); | |||
this.attachShortcuts(); | |||
this.fetchInitialData(); | |||
} | |||
@@ -154,8 +146,6 @@ export class CodingRulesApp extends React.PureComponent<Props, State> { | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
removeWhitePageClass(); | |||
removeSideBarClass(); | |||
this.detachShortcuts(); | |||
} | |||
@@ -280,7 +280,7 @@ class ComponentMeasuresApp extends React.PureComponent<Props, State> { | |||
<Suggestions suggestions="component_measures" /> | |||
<Helmet defer={false} title={translate('layout.measures')} /> | |||
<PageContentFontWrapper className="sw-body-sm"> | |||
<Spinner className="my-10 sw-flex sw-content-center" isLoading={this.state.loading} /> | |||
<Spinner isLoading={this.state.loading} /> | |||
{measures.length > 0 ? ( | |||
<div className="sw-grid sw-grid-cols-12 sw-w-full"> |
@@ -63,12 +63,6 @@ import { parseIssueFromResponse } from '../../../helpers/issues'; | |||
import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers'; | |||
import { KeyboardKeys } from '../../../helpers/keycodes'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
import { | |||
addSideBarClass, | |||
addWhitePageClass, | |||
removeSideBarClass, | |||
removeWhitePageClass, | |||
} from '../../../helpers/pages'; | |||
import { serializeDate } from '../../../helpers/query'; | |||
import { withBranchLikes } from '../../../queries/branch'; | |||
import { BranchLike } from '../../../types/branch-like'; | |||
@@ -225,8 +219,6 @@ export class App extends React.PureComponent<Props, State> { | |||
return; | |||
} | |||
addWhitePageClass(); | |||
addSideBarClass(); | |||
this.attachShortcuts(); | |||
if (!this.props.isFetchingBranch) { | |||
@@ -272,9 +264,6 @@ export class App extends React.PureComponent<Props, State> { | |||
componentWillUnmount() { | |||
this.detachShortcuts(); | |||
this.mounted = false; | |||
removeWhitePageClass(); | |||
removeSideBarClass(); | |||
} | |||
attachShortcuts() { |
@@ -17,33 +17,6 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
.not-all-issue-warning.open-issue-list { | |||
background-color: var(--barBackgroundColor); | |||
box-sizing: border-box; | |||
display: inline-block; | |||
padding: 16px 16px 0; | |||
position: sticky; | |||
top: 0; | |||
z-index: 1000; | |||
} | |||
.issues .issue-list { | |||
/* no math, just a good guess */ | |||
min-width: 640px; | |||
width: 800px; | |||
} | |||
.issues .issue a:focus, | |||
.issues .issue button:focus { | |||
box-shadow: none; | |||
} | |||
@media (max-width: 1320px) { | |||
.issues .issue-list { | |||
width: calc(60vw - 40px); | |||
} | |||
} | |||
.issue-location { | |||
display: inline-block; | |||
vertical-align: top; | |||
@@ -52,37 +25,3 @@ | |||
background-color: var(--issueBgColor); | |||
transition: background-color 0.3s ease; | |||
} | |||
.issues-workspace-list-component { | |||
padding: 15px 0 6px; | |||
} | |||
.issues-workspace-list-item + .issues-workspace-list-item { | |||
margin-top: 5px; | |||
} | |||
li:first-child .issues-workspace-list-component { | |||
padding-top: 0; | |||
} | |||
.issues-predefined-periods { | |||
display: flex; | |||
} | |||
.issues-predefined-periods .search-navigator-facet { | |||
width: auto; | |||
margin-right: calc(var(--gridSize) / 2); | |||
} | |||
.bulk-change-radio-button { | |||
margin: 0 calc(-1 * var(--gridSize) / 2); | |||
padding: 0 calc(var(--gridSize) / 2); | |||
} | |||
.bulk-change-radio-button:hover { | |||
background-color: var(--barBackgroundColor); | |||
} | |||
.layout-page-main.open-issue { | |||
padding-top: 0; | |||
} |
@@ -41,7 +41,6 @@ import { Location, Router, withRouter } from '../../../components/hoc/withRouter | |||
import '../../../components/search-navigator.css'; | |||
import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { addSideBarClass, removeSideBarClass } from '../../../helpers/pages'; | |||
import { get, save } from '../../../helpers/storage'; | |||
import { isDefined } from '../../../helpers/types'; | |||
import { AppState } from '../../../types/appstate'; | |||
@@ -94,8 +93,6 @@ export class AllProjects extends React.PureComponent<Props, State> { | |||
} | |||
this.handleQueryChange(); | |||
addSideBarClass(); | |||
} | |||
componentDidUpdate(prevProps: Props) { | |||
@@ -106,7 +103,6 @@ export class AllProjects extends React.PureComponent<Props, State> { | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
removeSideBarClass(); | |||
} | |||
fetchMoreProjects = () => { |
@@ -17,176 +17,11 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
.projects-page .layout-page-header-panel-inner, | |||
.projects-page .layout-page-header-panel { | |||
height: 98px; | |||
line-height: normal; | |||
} | |||
.projects-topbar-item + .projects-topbar-item { | |||
padding-left: 24px; | |||
} | |||
.projects-topbar-item.is-last { | |||
margin-left: auto; | |||
padding-left: 32px; | |||
} | |||
.projects-topbar-item-search { | |||
position: relative; | |||
flex: 1; | |||
height: var(--controlHeight); | |||
} | |||
.projects-header-row { | |||
padding-top: 2px; | |||
} | |||
.projects-list .page-actions { | |||
margin-bottom: 0; | |||
} | |||
.project-card-name { | |||
font-weight: 600; | |||
} | |||
.projects-leak-sorting-option.is-focused { | |||
background-color: var(--leakSecondaryColor); | |||
} | |||
.projects-facet-list { | |||
padding-left: 10px; | |||
padding-right: 10px; | |||
} | |||
.projects-facets-header { | |||
margin-bottom: 10px; | |||
padding: 10px 0; | |||
border-bottom: 1px solid var(--barBorderColor); | |||
} | |||
.projects-facets-reset { | |||
float: right; | |||
} | |||
.projects-facet-bar { | |||
display: inline-block; | |||
width: 60px; | |||
margin-left: 8px; | |||
} | |||
.projects-facet-bar-inner { | |||
min-width: 1px; | |||
height: 10px; | |||
background-color: var(--gray60); | |||
transition: width 0.3s ease; | |||
} | |||
.projects-empty-list { | |||
padding: calc(4 * var(--gridSize)) 0; | |||
text-align: center; | |||
} | |||
/*** | |||
Custom filter highlights. | |||
Projects filters are special, as some elements allow the selection of "everything | |||
worse than" filters (e.g., "Rating B or worse"). We still select a single element, | |||
but we want to give a visual indication that we selected multiple fitlers. | |||
That's where the following selectors come in, which extend and override styles | |||
from ../../components/search-navigator.css | |||
***/ | |||
/* | |||
Completely remove the border of the child facet. Handle them at the parent | |||
<li> level. | |||
*/ | |||
.search-navigator-facet-worse-than-highlight .search-navigator-facet { | |||
border: 0 !important; | |||
} | |||
.search-navigator-facet-worse-than-highlight { | |||
padding: 1px 0; | |||
border-width: 0 1px; | |||
border-color: transparent; | |||
border-style: solid; | |||
box-sizing: border-box; | |||
} | |||
/* | |||
When: | |||
- Being hovered | |||
- Or, being a sibling of something hovered | |||
- Or, being active | |||
- Or, being a sibling of something active | |||
show the left and right borders. | |||
*/ | |||
.search-navigator-facet-worse-than-highlight:hover, | |||
.search-navigator-facet-worse-than-highlight:hover ~ .search-navigator-facet-worse-than-highlight, | |||
.search-navigator-facet-worse-than-highlight.active, | |||
.search-navigator-facet-worse-than-highlight.active ~ .search-navigator-facet-worse-than-highlight { | |||
border-left-color: var(--blue); | |||
border-right-color: var(--blue); | |||
} | |||
/* | |||
When: | |||
- Being hovered | |||
- Or, being active | |||
show the top border, and remove the top padding. | |||
*/ | |||
.search-navigator-facet-worse-than-highlight:hover, | |||
.search-navigator-facet-worse-than-highlight.active { | |||
border-top: 1px solid var(--blue) !important; | |||
border-top-left-radius: 2px; | |||
border-top-right-radius: 2px; | |||
padding-top: 0 !important; | |||
} | |||
/* | |||
When: | |||
- Being hovered AND the last element of the highlightable group | |||
- Or, being the last element of the highlightable group AND a sibling of something hovered | |||
- Or, being active AND the last element of the highlightable group | |||
- Or, being the last element of the highlightable group AND a sibling of something active | |||
show the bottom border, and remove the bottom padding. | |||
*/ | |||
.search-navigator-facet-worse-than-highlight.last:hover, | |||
.search-navigator-facet-worse-than-highlight:hover | |||
~ .search-navigator-facet-worse-than-highlight.last, | |||
.search-navigator-facet-worse-than-highlight.active.last, | |||
.search-navigator-facet-worse-than-highlight.active | |||
~ .search-navigator-facet-worse-than-highlight.last { | |||
border-bottom: 1px solid var(--blue) !important; | |||
border-bottom-left-radius: 2px; | |||
border-bottom-right-radius: 2px; | |||
padding-bottom: 0 !important; | |||
} | |||
/* | |||
When: | |||
- Being active | |||
- Or, being a sibling of something active | |||
show a light blue background color. | |||
*/ | |||
.search-navigator-facet-worse-than-highlight.active, | |||
.search-navigator-facet-worse-than-highlight.active ~ .search-navigator-facet-worse-than-highlight { | |||
background-color: var(--veryLightBlue); | |||
} | |||
/* | |||
When: | |||
- Being hovered AND a sibling of something active | |||
- Or, being a sibling of something hovered AND a sibling of something active | |||
show a darker blue background color. | |||
*/ | |||
.search-navigator-facet-worse-than-highlight.active | |||
~ .search-navigator-facet-worse-than-highlight:hover, | |||
.search-navigator-facet-worse-than-highlight.active | |||
~ .search-navigator-facet-worse-than-highlight:hover | |||
~ .search-navigator-facet-worse-than-highlight { | |||
background-color: #a1cde8; | |||
} | |||
.project-filters-list { | |||
/* | |||
* On Firefox on Windows, the scrollbar hides the sidebar's content. |
@@ -20,6 +20,7 @@ | |||
import { withTheme } from '@emotion/react'; | |||
import styled from '@emotion/styled'; | |||
import { | |||
Card, | |||
LAYOUT_FOOTER_HEIGHT, | |||
LAYOUT_GLOBAL_NAV_HEIGHT, | |||
LargeCenteredLayout, | |||
@@ -35,12 +36,6 @@ import { useNavigate, useParams } from 'react-router-dom'; | |||
import Suggestions from '../../../components/embed-docs-modal/Suggestions'; | |||
import '../../../components/search-navigator.css'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
import { | |||
addSideBarClass, | |||
addWhitePageClass, | |||
removeSideBarClass, | |||
removeWhitePageClass, | |||
} from '../../../helpers/pages'; | |||
import { getQualityGateUrl } from '../../../helpers/urls'; | |||
import { useQualityGatesQuery } from '../../../queries/quality-gates'; | |||
import { QualityGate } from '../../../types/types'; | |||
@@ -72,16 +67,6 @@ export default function App() { | |||
[navigate], | |||
); | |||
useEffect(() => { | |||
addWhitePageClass(); | |||
addSideBarClass(); | |||
return () => { | |||
removeWhitePageClass(); | |||
removeSideBarClass(); | |||
}; | |||
}, []); | |||
useEffect(() => { | |||
if (!name) { | |||
openDefault(qualityGates); | |||
@@ -102,7 +87,7 @@ export default function App() { | |||
<Suggestions suggestions="quality_gates" /> | |||
<StyledContentWrapper | |||
className="sw-col-span-3 sw-px-4 sw-py-6 sw-border-y-0 sw-rounded-0" | |||
className="sw-col-span-3 sw-px-4 sw-py-6 sw-border-y-0" | |||
style={{ | |||
height: `calc(100vh - ${LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT}px)`, | |||
}} | |||
@@ -120,9 +105,9 @@ export default function App() { | |||
height: `calc(100vh - ${LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT}px)`, | |||
}} | |||
> | |||
<StyledContentWrapper className="sw-my-12"> | |||
<Card className="sw-my-12"> | |||
<Details qualityGateName={name} /> | |||
</StyledContentWrapper> | |||
</Card> | |||
</div> | |||
)} | |||
</div> | |||
@@ -133,7 +118,6 @@ export default function App() { | |||
const StyledContentWrapper = withTheme(styled.div` | |||
box-sizing: border-box; | |||
border-radius: 4px; | |||
background-color: ${themeColor('filterbar')}; | |||
border: ${themeBorder('default', 'filterbarBorder')}; | |||
overflow-x: hidden; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { Spinner } from 'design-system'; | |||
import { Spinner } from '@sonarsource/echoes-react'; | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet-async'; | |||
import { useQualityGateQuery } from '../../../queries/quality-gates'; | |||
@@ -32,16 +32,14 @@ export default function Details({ qualityGateName }: Readonly<Props>) { | |||
const { data: qualityGate, isLoading, isFetching } = useQualityGateQuery(qualityGateName); | |||
return ( | |||
<main className="layout-page-main"> | |||
<Spinner loading={isLoading}> | |||
{qualityGate && ( | |||
<> | |||
<Helmet defer={false} title={qualityGate.name} /> | |||
<DetailsHeader qualityGate={qualityGate} /> | |||
<DetailsContent qualityGate={qualityGate} isFetching={isFetching} /> | |||
</> | |||
)} | |||
</Spinner> | |||
</main> | |||
<Spinner wrapperClassName="sw-block sw-text-center" isLoading={isLoading}> | |||
{qualityGate && ( | |||
<main> | |||
<Helmet defer={false} title={qualityGate.name} /> | |||
<DetailsHeader qualityGate={qualityGate} /> | |||
<DetailsContent qualityGate={qualityGate} isFetching={isFetching} /> | |||
</main> | |||
)} | |||
</Spinner> | |||
); | |||
} |
@@ -46,7 +46,6 @@ import { | |||
import { Component, Dict } from '../../types/types'; | |||
import { CurrentUser, isLoggedIn } from '../../types/users'; | |||
import SecurityHotspotsAppRenderer from './SecurityHotspotsAppRenderer'; | |||
import './styles.css'; | |||
import { SECURITY_STANDARDS, getLocations } from './utils'; | |||
const PAGE_SIZE = 500; |
@@ -48,7 +48,6 @@ import HotspotSidebarHeader from './components/HotspotSidebarHeader'; | |||
import HotspotSimpleList from './components/HotspotSimpleList'; | |||
import HotspotFilterByStatus from './components/HotspotStatusFilter'; | |||
import HotspotViewer from './components/HotspotViewer'; | |||
import './styles.css'; | |||
export interface SecurityHotspotsAppRendererProps { | |||
branchLike?: BranchLike; |
@@ -25,7 +25,6 @@ import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import ListFooter from '../../../components/controls/ListFooter'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { removeSideBarClass } from '../../../helpers/pages'; | |||
import { HotspotStatusFilter, RawHotspot } from '../../../types/security-hotspots'; | |||
import { Dict, StandardSecurityCategories } from '../../../types/types'; | |||
import { RISK_EXPOSURE_LEVELS, groupByCategory } from '../utils'; | |||
@@ -92,10 +91,6 @@ export default class HotspotList extends React.Component<Props, State> { | |||
} | |||
} | |||
componentWillUnmount() { | |||
removeSideBarClass(); | |||
} | |||
groupHotspots = (hotspots: RawHotspot[], securityCategories: StandardSecurityCategories) => { | |||
const risks = groupBy(hotspots, (h) => h.vulnerabilityProbability); | |||
@@ -1,62 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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. | |||
*/ | |||
#security_hotspots .filter-bar-outer { | |||
height: 62px; | |||
} | |||
#security_hotspots .filter-bar { | |||
position: fixed; | |||
background-color: var(--barBackgroundColor); | |||
z-index: var(--pageHeaderZIndex); | |||
left: 0; | |||
right: 0; | |||
} | |||
#security_hotspots .filter-bar-inner { | |||
max-width: 1280px; | |||
margin: 0 auto; | |||
padding: calc(2 * var(--gridSize)) var(--gridSize); | |||
box-sizing: border-box; | |||
border-bottom: 1px solid var(--barBorderColor); | |||
} | |||
#security_hotspots .layout-page-side, | |||
#security_hotspots .layout-page-side-outer { | |||
width: calc(50vw - 330px); | |||
} | |||
#security_hotspots .layout-page-side-inner { | |||
margin-left: calc(50vw - 645px); | |||
} | |||
#security_hotspots .layout-page-main { | |||
padding: 0; | |||
} | |||
@media (max-width: 1320px) { | |||
#security_hotspots .layout-page-side-outer, | |||
#security_hotspots .layout-page-side { | |||
width: 316px; | |||
} | |||
#security_hotspots .layout-page-side-inner { | |||
margin-left: 0; | |||
} | |||
} |
@@ -20,12 +20,6 @@ | |||
import * as React from 'react'; | |||
import { getDefinitions } from '../../../api/settings'; | |||
import withComponentContext from '../../../app/components/componentContext/withComponentContext'; | |||
import { | |||
addSideBarClass, | |||
addWhitePageClass, | |||
removeSideBarClass, | |||
removeWhitePageClass, | |||
} from '../../../helpers/pages'; | |||
import { ExtendedSettingDefinition } from '../../../types/settings'; | |||
import { Component } from '../../../types/types'; | |||
import '../styles.css'; | |||
@@ -46,8 +40,6 @@ class SettingsApp extends React.PureComponent<Props, State> { | |||
componentDidMount() { | |||
this.mounted = true; | |||
addSideBarClass(); | |||
addWhitePageClass(); | |||
this.fetchSettings(); | |||
} | |||
@@ -59,8 +51,6 @@ class SettingsApp extends React.PureComponent<Props, State> { | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
removeSideBarClass(); | |||
removeWhitePageClass(); | |||
} | |||
fetchSettings = async () => { |
@@ -17,49 +17,6 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
#settings-page .layout-page-side, | |||
#settings-page .layout-page-side-outer { | |||
width: calc(50vw - 480px); | |||
border-right: none; | |||
} | |||
#settings-page .layout-page-side-inner { | |||
width: 160px; | |||
margin-left: calc(50vw - 639px); /* 640px -1px for overlapping the border */ | |||
} | |||
#settings-page .layout-page-main { | |||
padding: 0; | |||
} | |||
#settings-page .layout-page-main-inner { | |||
max-width: 1110px; | |||
} | |||
#settings-page .top-bar-outer { | |||
height: 120px; | |||
} | |||
#settings-page .top-bar { | |||
background-color: #f3f3f3; | |||
position: fixed; | |||
z-index: 55; /* todo */ | |||
left: 0; | |||
right: 0; | |||
} | |||
#settings-page .top-bar-inner { | |||
max-width: 1280px; | |||
margin: 0 auto; | |||
height: 120px; | |||
box-sizing: border-box; | |||
} | |||
#settings-page .page-title, | |||
#settings-page .page-description { | |||
float: none; | |||
} | |||
.settings-definitions-list > li + li { | |||
margin-top: 30px; | |||
} | |||
@@ -73,65 +30,23 @@ | |||
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); | |||
background-color: var(--alertBackgroundWarning); | |||
} | |||
.settings-definition-left { | |||
width: 330px; | |||
padding-right: 30px; | |||
box-sizing: border-box; | |||
} | |||
.radio-card .settings-definition-left { | |||
padding-right: 0; | |||
} | |||
.settings-definition-right { | |||
position: relative; | |||
width: calc(100% - 330px); | |||
box-sizing: border-box; | |||
} | |||
.radio-card .settings-definition-right input { | |||
width: 100%; | |||
} | |||
.settings-definition-name { | |||
text-overflow: ellipsis; | |||
} | |||
.settings-definition-key { | |||
line-height: 1.5; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
} | |||
.settings-definition-state { | |||
min-height: 32px; | |||
padding-bottom: 4px; | |||
} | |||
.settings-definition-state > span { | |||
display: flex; | |||
} | |||
.settings-definition-changes { | |||
margin-top: 20px; | |||
padding-top: 20px; | |||
border-top: 1px dotted var(--barBorderColor); | |||
} | |||
.settings-sub-categories-list > li + li, | |||
.settings-sub-category { | |||
.settings-sub-categories-list > li + li { | |||
margin: 30px -20px 0; | |||
padding: 30px 20px; | |||
border-top: 1px solid var(--barBorderColor); | |||
@@ -142,91 +57,8 @@ | |||
font-size: var(--bigFontSize); | |||
} | |||
.settings-sub-category-description { | |||
margin-top: -15px; | |||
margin-bottom: 20px; | |||
color: var(--secondFontColor); | |||
} | |||
.settings-large-input { | |||
width: 100% !important; | |||
max-width: 400px; | |||
min-width: 200px; | |||
} | |||
.side-tabs-menu { | |||
margin-top: calc(2 * var(--gridSize)); | |||
} | |||
.side-tabs-menu > li { | |||
margin-bottom: 4px; | |||
} | |||
.side-tabs-menu > li > a { | |||
display: block; | |||
padding: 10px 10px; | |||
line-height: 1.5; | |||
border-top-left-radius: 3px; | |||
border-bottom-left-radius: 3px; | |||
border: 1px solid var(--barBorderColor); | |||
border-right: none; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
transition: | |||
color 0.3s ease, | |||
background-color 0.3s ease; | |||
} | |||
.side-tabs-menu > li > a:hover, | |||
.side-tabs-menu > li > a:focus, | |||
.side-tabs-menu > li > a.active { | |||
background-color: #fff; | |||
} | |||
.side-tabs-menu > li > a.active { | |||
color: var(--baseFontColor); | |||
cursor: default; | |||
} | |||
@media (max-width: 1320px) { | |||
#settings-page .layout-page-side-outer, | |||
#settings-page .layout-page-side { | |||
width: 180px; | |||
} | |||
#settings-page .layout-page-side-inner { | |||
margin-left: 20px; | |||
} | |||
#settings-page .top-bar-inner { | |||
margin: 0 20px; | |||
} | |||
} | |||
.settings-search-results { | |||
max-height: 50vh; | |||
width: 500px; | |||
overflow-y: auto; | |||
overflow-x: hidden; | |||
} | |||
.settings-search-results > li > a:hover { | |||
background-color: unset; | |||
border-left-color: unset; | |||
} | |||
.settings-search-results > li.active > a { | |||
background-color: var(--neutral50); | |||
border-left-color: var(--blacka60); | |||
} | |||
.fixed-footer { | |||
position: sticky; | |||
bottom: 0px; | |||
align-items: center; | |||
display: flex; | |||
border: 1px solid var(--gray80); | |||
background-color: white; | |||
justify-content: space-between; | |||
margin: 0px -16px; | |||
} |
@@ -27,11 +27,6 @@ jest.mock('../../../components/common/ScreenPositionHelper'); | |||
const webApiHandler = new WebApiServiceMock(); | |||
jest.mock('../../../helpers/pages', () => ({ | |||
addSideBarClass: jest.fn(), | |||
removeSideBarClass: jest.fn(), | |||
})); | |||
beforeAll(() => { | |||
webApiHandler.reset(); | |||
}); |
@@ -34,7 +34,6 @@ import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget'; | |||
import Suggestions from '../../../components/embed-docs-modal/Suggestions'; | |||
import { Location, Router, withRouter } from '../../../components/hoc/withRouter'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { addSideBarClass, removeSideBarClass } from '../../../helpers/pages'; | |||
import { WebApi } from '../../../types/types'; | |||
import '../styles/web-api.css'; | |||
import { | |||
@@ -66,7 +65,6 @@ export class WebApiApp extends React.PureComponent<Props, State> { | |||
componentDidMount() { | |||
this.mounted = true; | |||
this.fetchList(); | |||
addSideBarClass(); | |||
} | |||
componentDidUpdate() { | |||
@@ -76,7 +74,6 @@ export class WebApiApp extends React.PureComponent<Props, State> { | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
removeSideBarClass(); | |||
} | |||
fetchList() { |
@@ -18,7 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import classNames from 'classnames'; | |||
import { Note, RadioButton } from 'design-system'; | |||
import { RadioButton } from 'design-system'; | |||
import * as React from 'react'; | |||
import { translate } from '../../helpers/l10n'; | |||
import { Visibility } from '../../types/component'; | |||
@@ -27,14 +27,13 @@ export interface VisibilitySelectorProps { | |||
canTurnToPrivate?: boolean; | |||
className?: string; | |||
onChange: (visibility: Visibility) => void; | |||
showDetails?: boolean; | |||
visibility?: Visibility; | |||
disabled?: boolean; | |||
loading?: boolean; | |||
} | |||
export default function VisibilitySelector(props: VisibilitySelectorProps) { | |||
const { className, canTurnToPrivate, visibility, showDetails, disabled, loading = false } = props; | |||
const { className, canTurnToPrivate, visibility, disabled, loading = false } = props; | |||
return ( | |||
<div className={classNames(className)}> | |||
{Object.values(Visibility).map((v) => ( | |||
@@ -46,10 +45,7 @@ export default function VisibilitySelector(props: VisibilitySelectorProps) { | |||
onCheck={props.onChange} | |||
disabled={disabled || (v === Visibility.Private && !canTurnToPrivate) || loading} | |||
> | |||
<div> | |||
{translate('visibility', v)} | |||
{showDetails && <Note as="p">{translate('visibility', v, 'description.long')}</Note>} | |||
</div> | |||
<div>{translate('visibility', v)}</div> | |||
</RadioButton> | |||
))} | |||
</div> |
@@ -1,47 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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 { | |||
addSideBarClass, | |||
addWhitePageClass, | |||
removeSideBarClass, | |||
removeWhitePageClass, | |||
} from '../pages'; | |||
describe('class adders', () => { | |||
it.each([ | |||
[addSideBarClass, 'sidebar-page'], | |||
[addWhitePageClass, 'white-page'], | |||
])('%s should add the class', (fct, cls) => { | |||
const toggle = jest.spyOn(document.body.classList, 'toggle'); | |||
fct(); | |||
expect(toggle).toHaveBeenCalledWith(cls, true); | |||
}); | |||
}); | |||
describe('class removers', () => { | |||
it.each([ | |||
[removeSideBarClass, 'sidebar-page'], | |||
[removeWhitePageClass, 'white-page'], | |||
])('%s should add the class', (fct, cls) => { | |||
const toggle = jest.spyOn(document.body.classList, 'toggle'); | |||
fct(); | |||
expect(toggle).toHaveBeenCalledWith(cls, false); | |||
}); | |||
}); |
@@ -1,44 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 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. | |||
*/ | |||
const CLASS_SIDEBAR_PAGE = 'sidebar-page'; | |||
const CLASS_WHITE_PAGE = 'white-page'; | |||
export function addSideBarClass() { | |||
toggleBodyClass(CLASS_SIDEBAR_PAGE, true); | |||
} | |||
export function addWhitePageClass() { | |||
toggleBodyClass(CLASS_WHITE_PAGE, true); | |||
} | |||
export function removeSideBarClass() { | |||
toggleBodyClass(CLASS_SIDEBAR_PAGE, false); | |||
} | |||
export function removeWhitePageClass() { | |||
toggleBodyClass(CLASS_WHITE_PAGE, false); | |||
} | |||
function toggleBodyClass(className: string, force: boolean) { | |||
document.body.classList.toggle(className, force); | |||
if (document.documentElement) { | |||
document.documentElement.classList.toggle(className, force); | |||
} | |||
} |