From 45f39fab8d8deab23251af9f9858bdf13f051258 Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Fri, 6 Dec 2024 12:55:00 +0100 Subject: SONAR-23751 Notifications checkbox -> switch + Design changes --- .../main/js/apps/account/__tests__/Account-it.tsx | 8 +- .../apps/account/notifications/Notifications.tsx | 12 +- .../account/notifications/ProjectNotifications.tsx | 2 +- .../js/apps/account/notifications/Projects.tsx | 31 +++-- .../notifications/ProjectNotifications.tsx | 16 ++- .../components/notifications/NotificationsList.tsx | 148 +++++++++++++-------- .../main/js/design-system/components/Switch.tsx | 10 +- .../main/resources/org/sonar/l10n/core.properties | 5 +- 8 files changed, 141 insertions(+), 91 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx b/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx index c58397fa3ea..8471107398a 100644 --- a/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx +++ b/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx @@ -476,8 +476,8 @@ describe('notifications page', () => { searchInput: byRole('searchbox', { name: 'search.placeholder' }), sonarQubeProject: byRole('link', { name: 'SonarQube' }), checkbox: (type: NotificationProjectType) => - byRole('checkbox', { - name: `notification.dispatcher.description_x.notification.dispatcher.${type}.project`, + byRole('switch', { + name: `notification.dispatcher.${type}.project`, }), }; @@ -485,8 +485,8 @@ describe('notifications page', () => { title: byRole('heading', { name: 'my_profile.overall_notifications.title' }), noNotificationForProject: byText('my_account.no_project_notifications'), checkbox: (type: NotificationGlobalType) => - byRole('checkbox', { - name: `notification.dispatcher.description_x.notification.dispatcher.${type}`, + byRole('switch', { + name: `notification.dispatcher.${type}`, }), }; diff --git a/server/sonar-web/src/main/js/apps/account/notifications/Notifications.tsx b/server/sonar-web/src/main/js/apps/account/notifications/Notifications.tsx index 866120cf614..a9cb966ed47 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/Notifications.tsx +++ b/server/sonar-web/src/main/js/apps/account/notifications/Notifications.tsx @@ -18,9 +18,9 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Heading, Spinner } from '@sonarsource/echoes-react'; +import { Heading, Spinner, Text } from '@sonarsource/echoes-react'; import { Helmet } from 'react-helmet-async'; -import { FlagMessage, GreySeparator } from '~design-system'; +import { GreySeparator } from '~design-system'; import { translate } from '../../../helpers/l10n'; import { useNotificationsQuery } from '../../../queries/notifications'; import GlobalNotifications from './GlobalNotifications'; @@ -45,18 +45,16 @@ export default function Notifications() { {translate('my_account.notifications')} - - {translate('notification.dispatcher.information')} - + {translate('notification.dispatcher.information')} {notifications && ( <> - + - + diff --git a/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.tsx b/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.tsx index f4462f3bcac..5e98e23be38 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.tsx +++ b/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.tsx @@ -34,7 +34,7 @@ export default function ProjectNotifications({ project }: Readonly) { {project.projectName} - + ); } diff --git a/server/sonar-web/src/main/js/apps/account/notifications/Projects.tsx b/server/sonar-web/src/main/js/apps/account/notifications/Projects.tsx index 47b5d19ba8a..c19a5f63ce8 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/Projects.tsx +++ b/server/sonar-web/src/main/js/apps/account/notifications/Projects.tsx @@ -104,11 +104,23 @@ export default class Projects extends React.PureComponent { {translate('my_profile.per_project_notifications.title')} - +
+ {allProjects.length > 0 && ( +
+ +
+ )} + + +
{this.state.showModal && ( @@ -124,15 +136,6 @@ export default class Projects extends React.PureComponent { {translate('my_account.no_project_notifications')} )} - {allProjects.length > 0 && ( -
- -
- )} - {filteredProjects.map((project) => ( ))} diff --git a/server/sonar-web/src/main/js/apps/projectInformation/notifications/ProjectNotifications.tsx b/server/sonar-web/src/main/js/apps/projectInformation/notifications/ProjectNotifications.tsx index 72e0d01af3c..0287d76ceb4 100644 --- a/server/sonar-web/src/main/js/apps/projectInformation/notifications/ProjectNotifications.tsx +++ b/server/sonar-web/src/main/js/apps/projectInformation/notifications/ProjectNotifications.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { FlagMessage, SubTitle } from '~design-system'; +import { Heading, Text } from '@sonarsource/echoes-react'; import NotificationsList from '../../../components/notifications/NotificationsList'; import { translate } from '../../../helpers/l10n'; import { Component } from '../../../types/types'; @@ -32,13 +32,17 @@ export default function ProjectNotifications(props: Props) { return (
- {translate('project.info.notifications')} + + {translate('project.info.notifications')} + - - {translate('notification.dispatcher.information')} - + {translate('notification.dispatcher.information')} - + ); } diff --git a/server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx b/server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx index 661f8335893..2d30e75e98e 100644 --- a/server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx +++ b/server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx @@ -18,12 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Checkbox, Spinner } from '@sonarsource/echoes-react'; +import { Checkbox, Label, Spinner, Text } from '@sonarsource/echoes-react'; import classNames from 'classnames'; import { useCallback } from 'react'; -import { FormattedMessage } from 'react-intl'; -import { CellComponent, Table, TableRowInteractive } from '~design-system'; -import { hasMessage, translate, translateWithParameters } from '../../helpers/l10n'; +import { FormattedMessage, useIntl } from 'react-intl'; +import { CellComponent, Switch, Table, TableRowInteractive } from '~design-system'; +import { hasMessage, translate } from '../../helpers/l10n'; import { useAddNotificationMutation, useNotificationsQuery, @@ -32,7 +32,8 @@ import { interface Props { className?: string; - project?: string; + projectKey?: string; + projectName?: string; } function getDispatcherLabel(dispatcher: string, project?: string) { @@ -43,20 +44,25 @@ function getDispatcherLabel(dispatcher: string, project?: string) { return shouldUseProjectMessage ? translate(...projectMessageKey) : translate(...globalMessageKey); } -export default function NotificationsList({ project, className = '' }: Readonly) { +export default function NotificationsList({ + projectKey, + projectName, + className = '', +}: Readonly) { + const intl = useIntl(); const { data, isLoading } = useNotificationsQuery(); const { mutate: add, isPending: isPendingAdd } = useAddNotificationMutation(); const { mutate: remove, isPending: isPendingRemove } = useRemoveNotificationMutation(); - const types = (project ? data?.perProjectTypes : data?.globalTypes) || []; + const types = (projectKey ? data?.perProjectTypes : data?.globalTypes) || []; const channels = data?.channels || []; const checkboxId = useCallback( (type: string, channel: string) => { - return project === undefined + return projectKey === undefined ? `global-notification-${type}-${channel}` - : `project-notification-${project}-${type}-${channel}`; + : `project-notification-${projectKey}-${type}-${channel}`; }, - [project], + [projectKey], ); const isEnabled = useCallback( @@ -65,67 +71,101 @@ export default function NotificationsList({ project, className = '' }: Readonly< (notification) => notification.type === type && notification.channel === channel && - notification.project === project, + notification.project === projectKey, ), - [data?.notifications, project], + [data?.notifications, projectKey], ); const handleCheck = useCallback( (type: string, channel: string, checked: boolean) => { if (checked) { - add({ type, channel, project }); + add({ type, channel, project: projectKey }); } else { - remove({ type, channel, project }); + remove({ type, channel, project: projectKey }); } }, - [add, project, remove], + [add, projectKey, remove], ); + if (channels.length !== 1) { + return ( + + + + + {channels.map((channel) => ( + + ))} + + } + > + {types.map((type) => ( + + + {getDispatcherLabel(type, projectKey)} + + + {channels.map((channel) => ( + +
+ handleCheck(type, channel, checked as boolean)} + /> +
+
+ ))} +
+ ))} +
{translate('notification.for')} + , + }} + /> +
+
+ ); + } + return ( - - - - {channels.map((channel) => ( - - ))} - +
    {types.map((type) => ( - - - {getDispatcherLabel(type, project)} - - - {channels.map((channel) => ( - -
    - handleCheck(type, channel, checked as boolean)} - /> -
    -
    - ))} -
    +
  • + +
  • ))} -
{translate('notification.for')} - }} - /> -
+
); } diff --git a/server/sonar-web/src/main/js/design-system/components/Switch.tsx b/server/sonar-web/src/main/js/design-system/components/Switch.tsx index 23a4b968e4b..0c684bd061d 100644 --- a/server/sonar-web/src/main/js/design-system/components/Switch.tsx +++ b/server/sonar-web/src/main/js/design-system/components/Switch.tsx @@ -26,7 +26,9 @@ import { CheckIcon } from './icons'; interface Props { ariaDescribedby?: string; + ariaLabel?: string; disabled?: boolean; + id?: string; name?: string; onChange?: (value: boolean) => void; value: boolean | string; @@ -37,12 +39,12 @@ const getValue = (value: boolean | string) => { }; function SwitchWithRef(props: Readonly, ref: ForwardedRef) { - const { ariaDescribedby, disabled, name, onChange } = props; - const value = getValue(props.value); + const { ariaDescribedby, ariaLabel, disabled, name, value: propsValue, onChange, id } = props; + const value = getValue(propsValue); const handleClick = () => { if (!disabled && onChange) { - const value = getValue(props.value); + const value = getValue(propsValue); onChange(!value); } }; @@ -52,8 +54,10 @@ function SwitchWithRef(props: Readonly, ref: ForwardedRefLearn more in SonarQube documentation #------------------------------------------------------------------------------ @@ -3067,7 +3068,7 @@ my_profile.password.title=Enter a new password my_profile.password.old=Old Password my_profile.password.changed=The password has been changed! my_profile.notifications.submit=Save changes -my_profile.overall_notifications.title=Overall notifications +my_profile.overall_notifications.title=General notifications my_profile.per_project_notifications.title=Notifications per project my_profile.per_project_notifications.add=Add a project my_profile.per_project_notifications.edit=Set notifications -- cgit v1.2.3