From: Kevin Silva Date: Fri, 28 Jul 2023 08:42:59 +0000 (+0200) Subject: SONAR-19068 - UI glitch when announcement message is set X-Git-Tag: 10.2.0.77647~281 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3994545c5d4313228716935ec752c0eb1253a077;p=sonarqube.git SONAR-19068 - UI glitch when announcement message is set --- diff --git a/server/sonar-web/design-system/src/components/Banner.tsx b/server/sonar-web/design-system/src/components/Banner.tsx new file mode 100644 index 00000000000..90a6cf70576 --- /dev/null +++ b/server/sonar-web/design-system/src/components/Banner.tsx @@ -0,0 +1,124 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 styled from '@emotion/styled'; +import { ReactNode } from 'react'; +import tw from 'twin.macro'; +import { + LAYOUT_BANNER_HEIGHT, + LAYOUT_VIEWPORT_MIN_WIDTH, + themeColor, + themeContrast, +} from '../helpers'; +import { translate } from '../helpers/l10n'; +import { ThemeColors } from '../types'; +import { InteractiveIconBase } from './InteractiveIcon'; +import { CloseIcon, FlagErrorIcon, FlagInfoIcon, FlagSuccessIcon, FlagWarningIcon } from './icons'; + +export type Variant = 'error' | 'warning' | 'success' | 'info'; + +interface Props { + children: ReactNode; + onDismiss?: VoidFunction; + variant: Variant; +} + +function getVariantInfo(variant: Variant) { + const variantList = { + error: { + icon: , + fontColor: 'errorText', + backGroundColor: 'errorBackground', + }, + warning: { + icon: , + fontColor: 'warningText', + backGroundColor: 'warningBackground', + }, + success: { + icon: , + fontColor: 'successText', + backGroundColor: 'successBackground', + }, + info: { + icon: , + fontColor: 'infoText', + backGroundColor: 'infoBackground', + }, + } as const; + + return variantList[variant]; +} + +export function Banner({ children, onDismiss, variant }: Props) { + const variantInfo = getVariantInfo(variant); + + return ( +
+ + + {variantInfo.icon} + {children} + {onDismiss && ( + + )} + + +
+ ); +} + +const BannerWrapper = styled.div<{ + backGroundColor: ThemeColors; + fontColor: ThemeColors; +}>` + min-width: ${LAYOUT_VIEWPORT_MIN_WIDTH}px; + max-width: 100%; + height: inherit; + background-color: ${({ backGroundColor }) => themeColor(backGroundColor)}; + color: ${({ fontColor }) => themeColor(fontColor)}; + ${tw`sw-z-global-navbar sw-fixed sw-w-full`} + ${tw`sw-sticky sw-top-0`} +`; + +const BannerInner = styled.div` + width: 100%; + height: inherit; + + ${tw`sw-box-border`} + ${tw`sw-flex sw-items-center sw-gap-3`} + ${tw`sw-px-4`} + ${tw`sw-body-sm`} +`; + +const BannerCloseIcon = styled(InteractiveIconBase)` + --background: ${themeColor('bannerIcon')}; + --backgroundHover: ${themeColor('bannerIconHover')}; + --color: ${themeContrast('bannerIcon')}; + --colorHover: ${themeContrast('bannerIconHover')}; + --focus: ${themeColor('bannerIconFocus', 0.2)}; +`; diff --git a/server/sonar-web/design-system/src/components/MainAppBar.tsx b/server/sonar-web/design-system/src/components/MainAppBar.tsx index 0712a133143..8a770e6134f 100644 --- a/server/sonar-web/design-system/src/components/MainAppBar.tsx +++ b/server/sonar-web/design-system/src/components/MainAppBar.tsx @@ -31,13 +31,11 @@ import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; import { BaseLink } from './Link'; const MainAppBarDiv = styled.div` - ${tw`sw-sticky sw-top-0`} ${tw`sw-flex`}; ${tw`sw-items-center`}; ${tw`sw-px-6`}; ${tw`sw-w-full`}; ${tw`sw-box-border`}; - ${tw`sw-z-global-navbar`}; background: ${themeColor('mainBar')}; border-bottom: ${themeBorder('default')}; diff --git a/server/sonar-web/design-system/src/components/__tests__/Banner-test.tsx b/server/sonar-web/design-system/src/components/__tests__/Banner-test.tsx new file mode 100644 index 00000000000..f07e4d6daf4 --- /dev/null +++ b/server/sonar-web/design-system/src/components/__tests__/Banner-test.tsx @@ -0,0 +1,50 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { render } from '../../helpers/testUtils'; +import { FCProps } from '../../types/misc'; +import { Banner } from '../Banner'; +import { Note } from '../Text'; + +it('should render with close button', async () => { + const onDismiss = jest.fn(); + const { user } = setupWithProps({ onDismiss }); + expect( + screen.getByRole('button', { + name: 'dismiss', + }) + ).toBeVisible(); + + await user.click( + screen.getByRole('button', { + name: 'dismiss', + }) + ); + + expect(onDismiss).toHaveBeenCalledTimes(1); +}); + +function setupWithProps(props: Partial> = {}) { + return render( + + {props.children ?? 'Test Message'} + + ); +} diff --git a/server/sonar-web/design-system/src/components/index.ts b/server/sonar-web/design-system/src/components/index.ts index 7ae0b61692b..0e4783df607 100644 --- a/server/sonar-web/design-system/src/components/index.ts +++ b/server/sonar-web/design-system/src/components/index.ts @@ -21,6 +21,7 @@ export * from './Accordion'; export * from './Avatar'; export { Badge } from './Badge'; +export * from './Banner'; export { BarChart } from './BarChart'; export { Breadcrumbs } from './Breadcrumbs'; export * from './BubbleChart'; diff --git a/server/sonar-web/design-system/src/theme/light.ts b/server/sonar-web/design-system/src/theme/light.ts index c2d3738838d..b303f3f8655 100644 --- a/server/sonar-web/design-system/src/theme/light.ts +++ b/server/sonar-web/design-system/src/theme/light.ts @@ -163,12 +163,15 @@ export const lightTheme = { warningBorder: COLORS.yellow[400], warningBackground: COLORS.yellow[50], + warningText: COLORS.yellow[900], successBorder: COLORS.green[400], successBackground: COLORS.green[50], + successText: COLORS.green[900], infoBorder: COLORS.blue[400], infoBackground: COLORS.blue[50], + infoText: COLORS.blue[900], // banner message bannerMessage: danger.lightest, diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx index 2d99e1311e4..f4924fa10b7 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx @@ -76,10 +76,12 @@ export default function GlobalContainer() { - - - - +
+ + + + +