From: Ismail Cherri Date: Thu, 25 Apr 2024 15:36:02 +0000 (+0200) Subject: SONAR-22049 Align FlagMessage X-Git-Tag: 10.6.0.92116~164 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=80e8eb730b5d437a0c0a38087bba9399fe39fb5b;p=sonarqube.git SONAR-22049 Align FlagMessage --- diff --git a/server/sonar-web/design-system/src/components/FlagMessage.tsx b/server/sonar-web/design-system/src/components/FlagMessage.tsx deleted file mode 100644 index 47fb9b9fa58..00000000000 --- a/server/sonar-web/design-system/src/components/FlagMessage.tsx +++ /dev/null @@ -1,156 +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 styled from '@emotion/styled'; -import classNames from 'classnames'; -import * as React from 'react'; -import { useIntl } from 'react-intl'; -import tw from 'twin.macro'; -import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; -import { ThemeColors } from '../types/theme'; -import { InteractiveIcon } from './InteractiveIcon'; -import { CloseIcon, FlagErrorIcon, FlagInfoIcon, FlagSuccessIcon, FlagWarningIcon } from './icons'; - -export type Variant = 'error' | 'warning' | 'success' | 'info'; - -interface Props { - variant: Variant; -} - -function getVariantInfo(variant: Variant) { - const variantList = { - error: { - icon: , - borderColor: 'errorBorder', - backGroundColor: 'errorBackground', - }, - warning: { - icon: , - borderColor: 'warningBorder', - backGroundColor: 'warningBackground', - }, - success: { - icon: , - borderColor: 'successBorder', - backGroundColor: 'successBackground', - }, - info: { - icon: , - borderColor: 'infoBorder', - backGroundColor: 'infoBackground', - }, - } as const; - - return variantList[variant]; -} - -export function FlagMessage(props: Props & React.HTMLAttributes) { - const { className, variant, ...domProps } = props; - const variantInfo = getVariantInfo(variant); - - return ( - - {props.children && ( -
-
{variantInfo.icon}
-
{props.children}
-
- )} -
- ); -} - -FlagMessage.displayName = 'FlagMessage'; // so that tests don't see the obfuscated production name - -interface DismissableFlagMessageProps extends Props { - onDismiss: () => void; -} - -export function DismissableFlagMessage( - props: DismissableFlagMessageProps & React.HTMLAttributes, -) { - const { onDismiss, children, ...flagMessageProps } = props; - const intl = useIntl(); - return ( - - {children} - - - ); -} - -DismissableFlagMessage.displayName = 'DismissableFlagMessage'; // so that tests don't see the obfuscated production name - -export const StyledFlag = styled.div<{ - backGroundColor: ThemeColors; - borderColor: ThemeColors; -}>` - ${tw`sw-inline-flex`} - ${tw`sw-min-h-10`} - ${tw`sw-rounded-1`} - ${tw`sw-box-border`} - border: ${({ borderColor }) => themeBorder('default', borderColor)}; - background-color: ${themeColor('flagMessageBackground')}; - - :empty { - display: none; - } - - & > .flag-inner { - ${tw`sw-flex sw-items-stretch`} - ${tw`sw-box-border`} - } - - & .flag-icon { - ${tw`sw-flex sw-justify-center sw-items-center`} - ${tw`sw-rounded-l-1`} - ${tw`sw-px-3`} - background-color: ${({ backGroundColor }) => themeColor(backGroundColor)}; - } - - & .flag-content { - ${tw`sw-flex sw-flex-auto sw-items-center`} - ${tw`sw-overflow-auto`} - ${tw`sw-text-left`} - ${tw`sw-px-3 sw-py-2`} - ${tw`sw-body-sm`} - color: ${themeContrast('flagMessageBackground')}; - } -`; - -export const DismissIcon = styled(InteractiveIcon)` - --background: ${themeColor('productNews')}; - --backgroundHover: ${themeColor('productNewsHover')}; - --color: ${themeContrast('productNews')}; - --colorHover: ${themeContrast('productNewsHover')}; - --focus: ${themeColor('interactiveIconFocus', 0.2)}; - - height: 28px; -`; diff --git a/server/sonar-web/design-system/src/components/__tests__/FlagMessage-test.tsx b/server/sonar-web/design-system/src/components/__tests__/FlagMessage-test.tsx deleted file mode 100644 index 2b2afc1ee11..00000000000 --- a/server/sonar-web/design-system/src/components/__tests__/FlagMessage-test.tsx +++ /dev/null @@ -1,69 +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 { screen } from '@testing-library/react'; -import { IntlShape } from 'react-intl'; -import { render } from '../../helpers/testUtils'; -import { FCProps } from '../../types/misc'; -import { DismissableFlagMessage, FlagMessage, Variant } from '../FlagMessage'; - -jest.mock( - 'react-intl', - () => - ({ - ...jest.requireActual('react-intl'), - useIntl: () => ({ - formatMessage: ({ id }: { id: string }, values = {}) => - [id, ...Object.values(values)].join('.'), - }), - }) as IntlShape, -); - -it.each([ - ['error', '1px solid rgb(249,112,102)'], - ['warning', '1px solid rgb(248,205,92)'], - ['success', '1px solid rgb(50,213,131)'], - ['info', '1px solid rgb(110,185,228)'], -])('should render properly for "%s" variant', (variant: Variant, color) => { - renderFlagMessage({ variant }); - - const item = screen.getByRole('status'); - expect(item).toBeInTheDocument(); - expect(item).toHaveStyle({ border: color }); -}); - -it('should render Dismissable flag message properly', () => { - const dismissFunc = jest.fn(); - render(); - const item = screen.getByRole('status'); - expect(item).toBeInTheDocument(); - expect(item).toHaveStyle({ border: '1px solid rgb(249,112,102)' }); - const dismissButton = screen.getByRole('button'); - expect(dismissButton).toBeInTheDocument(); - dismissButton.click(); - expect(dismissFunc).toHaveBeenCalled(); -}); - -function renderFlagMessage(props: Partial> = {}) { - return render( - - This is an error! - , - ); -} diff --git a/server/sonar-web/design-system/src/components/index.ts b/server/sonar-web/design-system/src/components/index.ts index 35e06bdc597..e94ac812c9e 100644 --- a/server/sonar-web/design-system/src/components/index.ts +++ b/server/sonar-web/design-system/src/components/index.ts @@ -39,7 +39,6 @@ export * from './FacetBox'; export * from './FacetItem'; export { FailedQGConditionLink } from './FailedQGConditionLink'; export * from './FavoriteButton'; -export { DismissableFlagMessage, FlagMessage } from './FlagMessage'; export * from './FlowStep'; export * from './HighlightRing'; export * from './HighlightedSection'; diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/FlagMessage.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/FlagMessage.tsx new file mode 100644 index 00000000000..6b05991c12b --- /dev/null +++ b/server/sonar-web/design-system/src/sonar-aligned/components/FlagMessage.tsx @@ -0,0 +1,162 @@ +/* + * 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 styled from '@emotion/styled'; +import classNames from 'classnames'; +import * as React from 'react'; +import { useIntl } from 'react-intl'; +import tw from 'twin.macro'; +import { ThemeColors } from '~types/theme'; +import { InteractiveIcon } from '../../components/InteractiveIcon'; +import { + CloseIcon, + FlagErrorIcon, + FlagInfoIcon, + FlagSuccessIcon, + FlagWarningIcon, +} from '../../components/icons'; +import { themeBorder, themeColor, themeContrast } from '../../helpers/theme'; + +export type Variant = 'error' | 'warning' | 'success' | 'info'; + +interface Props { + variant: Variant; +} + +function getVariantInfo(variant: Variant) { + const variantList = { + error: { + icon: , + borderColor: 'errorBorder', + backGroundColor: 'errorBackground', + }, + warning: { + icon: , + borderColor: 'warningBorder', + backGroundColor: 'warningBackground', + }, + success: { + icon: , + borderColor: 'successBorder', + backGroundColor: 'successBackground', + }, + info: { + icon: , + borderColor: 'infoBorder', + backGroundColor: 'infoBackground', + }, + } as const; + + return variantList[variant]; +} + +export function FlagMessage(props: Props & React.HTMLAttributes) { + const { className, variant, ...domProps } = props; + const variantInfo = getVariantInfo(variant); + + return ( + + {props.children && ( +
+
{variantInfo.icon}
+
{props.children}
+
+ )} +
+ ); +} + +FlagMessage.displayName = 'FlagMessage'; // so that tests don't see the obfuscated production name + +interface DismissableFlagMessageProps extends Props { + onDismiss: () => void; +} + +export function DismissableFlagMessage( + props: DismissableFlagMessageProps & React.HTMLAttributes, +) { + const { onDismiss, children, ...flagMessageProps } = props; + const intl = useIntl(); + return ( + + {children} + + + ); +} + +DismissableFlagMessage.displayName = 'DismissableFlagMessage'; // so that tests don't see the obfuscated production name + +export const StyledFlag = styled.div<{ + backGroundColor: ThemeColors; + borderColor: ThemeColors; +}>` + ${tw`sw-inline-flex`} + ${tw`sw-min-h-10`} + ${tw`sw-rounded-1`} + ${tw`sw-box-border`} + border: ${({ borderColor }) => themeBorder('default', borderColor)}; + background-color: ${themeColor('flagMessageBackground')}; + + :empty { + display: none; + } + + & > .flag-inner { + ${tw`sw-flex sw-items-stretch`} + ${tw`sw-box-border`} + } + + & .flag-icon { + ${tw`sw-flex sw-justify-center sw-items-center`} + ${tw`sw-rounded-l-1`} + ${tw`sw-px-3`} + background-color: ${({ backGroundColor }) => themeColor(backGroundColor)}; + } + + & .flag-content { + ${tw`sw-flex sw-flex-auto sw-items-center`} + ${tw`sw-overflow-auto`} + ${tw`sw-text-left`} + ${tw`sw-px-3 sw-py-2`} + ${tw`sw-body-sm`} + color: ${themeContrast('flagMessageBackground')}; + } +`; + +export const DismissIcon = styled(InteractiveIcon)` + --background: ${themeColor('productNews')}; + --backgroundHover: ${themeColor('productNewsHover')}; + --color: ${themeContrast('productNews')}; + --colorHover: ${themeContrast('productNewsHover')}; + --focus: ${themeColor('interactiveIconFocus', 0.2)}; + + height: 28px; +`; diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/__tests__/FlagMessage-test.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/__tests__/FlagMessage-test.tsx new file mode 100644 index 00000000000..6772436944f --- /dev/null +++ b/server/sonar-web/design-system/src/sonar-aligned/components/__tests__/FlagMessage-test.tsx @@ -0,0 +1,69 @@ +/* + * 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 { screen } from '@testing-library/react'; +import { IntlShape } from 'react-intl'; +import { FCProps } from '~types/misc'; +import { render } from '../../../helpers/testUtils'; +import { DismissableFlagMessage, FlagMessage, Variant } from '../FlagMessage'; + +jest.mock( + 'react-intl', + () => + ({ + ...jest.requireActual('react-intl'), + useIntl: () => ({ + formatMessage: ({ id }: { id: string }, values = {}) => + [id, ...Object.values(values)].join('.'), + }), + }) as IntlShape, +); + +it.each([ + ['error', '1px solid rgb(249,112,102)'], + ['warning', '1px solid rgb(248,205,92)'], + ['success', '1px solid rgb(50,213,131)'], + ['info', '1px solid rgb(110,185,228)'], +])('should render properly for "%s" variant', (variant: Variant, color) => { + renderFlagMessage({ variant }); + + const item = screen.getByRole('status'); + expect(item).toBeInTheDocument(); + expect(item).toHaveStyle({ border: color }); +}); + +it('should render Dismissable flag message properly', () => { + const dismissFunc = jest.fn(); + render(); + const item = screen.getByRole('status'); + expect(item).toBeInTheDocument(); + expect(item).toHaveStyle({ border: '1px solid rgb(249,112,102)' }); + const dismissButton = screen.getByRole('button'); + expect(dismissButton).toBeInTheDocument(); + dismissButton.click(); + expect(dismissFunc).toHaveBeenCalled(); +}); + +function renderFlagMessage(props: Partial> = {}) { + return render( + + This is an error! + , + ); +} diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/index.ts b/server/sonar-web/design-system/src/sonar-aligned/components/index.ts index 459ba9d1655..9ffeb585803 100644 --- a/server/sonar-web/design-system/src/sonar-aligned/components/index.ts +++ b/server/sonar-web/design-system/src/sonar-aligned/components/index.ts @@ -19,6 +19,7 @@ */ export * from './Card'; +export { DismissableFlagMessage, FlagMessage } from './FlagMessage'; export * from './MetricsRatingBadge'; export * from './Table'; export * from './buttons';