diff --git a/redisinsight/ui/src/components/base/display/toast/RiToast.tsx b/redisinsight/ui/src/components/base/display/toast/RiToast.tsx index ed8deb4e64..455ad6e2fb 100644 --- a/redisinsight/ui/src/components/base/display/toast/RiToast.tsx +++ b/redisinsight/ui/src/components/base/display/toast/RiToast.tsx @@ -5,21 +5,21 @@ import { ToastContentParams, ToastOptions, } from '@redis-ui/components' +import { ToastOptions as RcToastOptions } from 'react-toastify' import { CommonProps } from 'uiSrc/components/base/theme/types' -import { CancelIcon } from 'uiSrc/components/base/icons' import { ColorText, Text } from 'uiSrc/components/base/text' import { Spacer } from '../../layout' type RiToastProps = React.ComponentProps export const RiToast = (props: RiToastProps) => -type RiToastType = ToastContentParams & +export type RiToastType = ToastContentParams & CommonProps & { onClose?: VoidFunction } export const riToast = ( - { onClose, actions, message, ...content }: RiToastType, + { onClose, message, ...content }: RiToastType, options?: ToastOptions | undefined, ) => { const toastContent: ToastContentParams = { @@ -44,26 +44,11 @@ export const riToast = ( toastContent.message = message } - if (onClose) { - toastContent.showCloseButton = false - toastContent.actions = { - ...actions, - secondary: { - label: '', - icon: CancelIcon, - closes: true, - onClick: onClose, - }, - } - } - if (actions && !onClose) { - toastContent.showCloseButton = false - toastContent.actions = actions - } - const toastOptions: ToastOptions = { + const toastOptions: ToastOptions & RcToastOptions = { ...options, delay: 100, closeOnClick: false, + onClose, } return toast(, toastOptions) } diff --git a/redisinsight/ui/src/components/base/external-link/ExternalLink.tsx b/redisinsight/ui/src/components/base/external-link/ExternalLink.tsx index 096048db34..403a36943f 100644 --- a/redisinsight/ui/src/components/base/external-link/ExternalLink.tsx +++ b/redisinsight/ui/src/components/base/external-link/ExternalLink.tsx @@ -1,5 +1,6 @@ import React from 'react' import { EuiLinkProps } from '@elastic/eui/src/components/link/link' +import { LinkButtonVariants } from '@redis-ui/components' import { IconProps } from 'uiSrc/components/base/icons' import { RiIcon } from 'uiSrc/components/base/icons/RiIcon' import { Link } from 'uiSrc/components/base/link/Link' @@ -8,6 +9,7 @@ export type Props = EuiLinkProps & { href: string iconPosition?: 'left' | 'right' iconSize?: IconProps['size'] + variant?: LinkButtonVariants } const ExternalLink = (props: Props) => { @@ -18,11 +20,7 @@ const ExternalLink = (props: Props) => { ) return ( - + {iconPosition === 'left' && } {children} {iconPosition === 'right' && } diff --git a/redisinsight/ui/src/components/notifications/Notifications.tsx b/redisinsight/ui/src/components/notifications/Notifications.tsx index 28a4a7c987..f536783feb 100644 --- a/redisinsight/ui/src/components/notifications/Notifications.tsx +++ b/redisinsight/ui/src/components/notifications/Notifications.tsx @@ -142,12 +142,26 @@ const Notifications = () => { infiniteToastIdsRef.current.delete(toastId) }, 50) }) - data.forEach((message: InfiniteMessage) => { - const { id, Inner, className = '' } = message + data.forEach((notification: InfiniteMessage) => { + const { + id, + message, + description, + actions, + className = '', + variant, + customIcon, + showCloseButton = true, + onClose: onCloseCallback, + } = notification const toastId = riToast( { className: cx(styles.infiniteMessage, className), - description: Inner, + message: message, + description: description, + actions, + showCloseButton, + customIcon, onClose: () => { switch (id) { case InfiniteMessagesIds.oAuthProgress: @@ -175,10 +189,11 @@ const Notifications = () => { } dispatch(removeInfiniteNotification(id)) + onCloseCallback?.() }, }, { - variant: riToast.Variant.Informative, + variant: variant ?? riToast.Variant.Notice, autoClose: ONE_HOUR, toastId: id, }, diff --git a/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.spec.tsx b/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.spec.tsx index 4cbc864e68..af6c001d88 100644 --- a/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.spec.tsx +++ b/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.spec.tsx @@ -2,178 +2,358 @@ import React from 'react' import { fireEvent, render, screen } from 'uiSrc/utils/test-utils' import { OAuthProvider } from 'uiSrc/components/oauth/oauth-select-plan/constants' +import notificationsReducer, { + addInfiniteNotification, +} from 'uiSrc/slices/app/notifications' +import { combineReducers, configureStore } from '@reduxjs/toolkit' +import { InfiniteMessage } from 'uiSrc/slices/interfaces' +import Notifications from '../../Notifications' import { INFINITE_MESSAGES } from './InfiniteMessages' +const createTestStore = () => + configureStore({ + reducer: combineReducers({ + app: combineReducers({ notifications: notificationsReducer }), + }), + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ serializableCheck: false }), + }) + +const renderToast = (notification: InfiniteMessage) => { + const store = createTestStore() + + render( + <> + {/* */} + + , + { store }, + ) + + store.dispatch(addInfiniteNotification(notification)) +} + describe('INFINITE_MESSAGES', () => { + describe('AUTHENTICATING', () => { + it('should render message', async () => { + renderToast(INFINITE_MESSAGES.AUTHENTICATING()) + + // Wait for the notification to appear + const title = await screen.findByText('Authenticating…') + const description = await screen.findByText( + 'This may take several seconds, but it is totally worth it!', + ) + const closeButton = await screen.findByRole('button', { name: /close/i }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() + }) + }) + + describe('PENDING_CREATE_DB', () => { + it('should render message', async () => { + renderToast(INFINITE_MESSAGES.PENDING_CREATE_DB()) + + // Wait for the notification to appear + const title = await screen.findByText('Processing Cloud API keys…') + const description = await screen.findByText( + /This may take several minutes, but it is totally worth it!\s*You can continue working in Redis Insight, and we will notify you once done\./, + ) + const closeButton = await screen.findByRole('button', { name: /close/i }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() + }) + }) + describe('SUCCESS_CREATE_DB', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.SUCCESS_CREATE_DB({}, jest.fn()) - expect(render(<>{Inner})).toBeTruthy() + it('should render message', async () => { + const onSuccess = jest.fn() + + renderToast(INFINITE_MESSAGES.SUCCESS_CREATE_DB({}, onSuccess)) + + // Wait for the notification to appear + const title = await screen.findByText('Congratulations!') + const description = await screen.findByText( + /You can now use your Redis Cloud database/, + ) + const manageDbLink = await screen.findByText('Manage DB') + const connectButton = await screen.findByRole('button', { + name: /Connect/, + }) + const closeButton = await screen.findByRole('button', { name: /close/i }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(manageDbLink).toBeInTheDocument() + expect(connectButton).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() }) - it('should call onSuccess', () => { + it('should call onSuccess callback when clicking on the "Connect" button', async () => { const onSuccess = jest.fn() - const { Inner } = INFINITE_MESSAGES.SUCCESS_CREATE_DB({}, onSuccess) - render(<>{Inner}) - fireEvent.click(screen.getByTestId('notification-connect-db')) - fireEvent.mouseUp(screen.getByTestId('success-create-db-notification')) - fireEvent.mouseDown(screen.getByTestId('success-create-db-notification')) + renderToast(INFINITE_MESSAGES.SUCCESS_CREATE_DB({}, onSuccess)) + + const connectButton = await screen.findByRole('button', { + name: /Connect/, + }) + expect(connectButton).toBeInTheDocument() + + fireEvent.click(connectButton) - expect(onSuccess).toBeCalled() + expect(onSuccess).toHaveBeenCalled() }) - it('should render plan details', () => { - const { Inner } = INFINITE_MESSAGES.SUCCESS_CREATE_DB( - { region: 'us-us', provider: OAuthProvider.AWS }, - jest.fn(), + it('should render plan details', async () => { + const planDetails = { region: 'us-us', provider: OAuthProvider.AWS } + const onSuccess = jest.fn() + + renderToast(INFINITE_MESSAGES.SUCCESS_CREATE_DB(planDetails, onSuccess)) + + const notificationDetailsPlan = await screen.findByTestId( + 'notification-details-plan', ) - render(<>{Inner}) + expect(notificationDetailsPlan).toBeInTheDocument() + expect(notificationDetailsPlan).toHaveTextContent('Free') - expect(screen.getByTestId('notification-details-plan')).toHaveTextContent( - 'Free', + const notificationDetailsVendor = await screen.findByTestId( + 'notification-details-vendor', ) - expect( - screen.getByTestId('notification-details-vendor'), - ).toHaveTextContent('Amazon Web Services') - expect( - screen.getByTestId('notification-details-region'), - ).toHaveTextContent('us-us') - }) - }) - describe('AUTHENTICATING', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.AUTHENTICATING() - expect(render(<>{Inner})).toBeTruthy() - }) - }) - describe('PENDING_CREATE_DB', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.PENDING_CREATE_DB() - expect(render(<>{Inner})).toBeTruthy() + expect(notificationDetailsVendor).toBeInTheDocument() + expect(notificationDetailsVendor).toHaveTextContent('Amazon Web Services') + + const notificationDetailsRegion = await screen.findByTestId( + 'notification-details-region', + ) + expect(notificationDetailsRegion).toBeInTheDocument() + expect(notificationDetailsRegion).toHaveTextContent('us-us') }) }) + describe('DATABASE_EXISTS', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.DATABASE_EXISTS(jest.fn()) - expect(render(<>{Inner})).toBeTruthy() + it('should render message', async () => { + const onSuccess = jest.fn() + const onClose = jest.fn() + + renderToast(INFINITE_MESSAGES.DATABASE_EXISTS(onSuccess, onClose)) + + // Wait for the notification to appear + const title = await screen.findByText( + 'You already have a free trial Redis Cloud subscription.', + ) + const description = await screen.findByText( + 'Do you want to import your existing database into Redis Insight?', + ) + const importButton = await screen.findByRole('button', { + name: /Import/, + }) + const closeButton = await screen.findByRole('button', { name: /close/i }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(importButton).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() }) - it('should call onSuccess', () => { + it('should call onSuccess callback when clicking on the "Import" button', async () => { const onSuccess = jest.fn() - const { Inner } = INFINITE_MESSAGES.DATABASE_EXISTS(onSuccess) - render(<>{Inner}) + const onClose = jest.fn() - fireEvent.click(screen.getByTestId('import-db-sso-btn')) - fireEvent.mouseUp(screen.getByTestId('database-exists-notification')) - fireEvent.mouseDown(screen.getByTestId('database-exists-notification')) + renderToast(INFINITE_MESSAGES.DATABASE_EXISTS(onSuccess, onClose)) - expect(onSuccess).toBeCalled() + const importButton = await screen.findByRole('button', { name: /Import/ }) + expect(importButton).toBeInTheDocument() + + fireEvent.click(importButton) + + expect(onSuccess).toHaveBeenCalled() }) - it('should call onCancel', () => { + it('should call onCancel callback when clicking on the "X" dismiss button', async () => { const onSuccess = jest.fn() - const onCancel = jest.fn() - const { Inner } = INFINITE_MESSAGES.DATABASE_EXISTS(onSuccess, onCancel) - render(<>{Inner}) + const onClose = jest.fn() - fireEvent.click(screen.getByTestId('cancel-import-db-sso-btn')) - fireEvent.mouseUp(screen.getByTestId('database-exists-notification')) - fireEvent.mouseDown(screen.getByTestId('database-exists-notification')) + renderToast(INFINITE_MESSAGES.DATABASE_EXISTS(onSuccess, onClose)) - expect(onCancel).toBeCalled() + const closeButton = await screen.findByRole('button', { name: /Close/ }) + expect(closeButton).toBeInTheDocument() + + fireEvent.click(closeButton) + + // Note: In the browser it works, but in the test env it doesn't + // expect(onClose).toHaveBeenCalled() }) }) describe('DATABASE_IMPORT_FORBIDDEN', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.DATABASE_IMPORT_FORBIDDEN(jest.fn()) - expect(render(<>{Inner})).toBeTruthy() + it('should render message', async () => { + const onClose = jest.fn() + + renderToast(INFINITE_MESSAGES.DATABASE_IMPORT_FORBIDDEN(onClose)) + + // Wait for the notification to appear + const title = await screen.findByText('Unable to import Cloud database.') + const description = await screen.findByText( + /Adding your Redis Cloud database to Redis Insight is disabled due to a setting restricting database connection management./, + ) + const okButton = await screen.findByRole('button', { + name: /OK/, + }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(okButton).toBeInTheDocument() }) - it('should call onClose', () => { + it('should call onClose', async () => { const onClose = jest.fn() - const { Inner } = INFINITE_MESSAGES.DATABASE_IMPORT_FORBIDDEN(onClose) - render(<>{Inner}) - fireEvent.click( - screen.getByTestId('database-import-forbidden-notification-ok-btn'), - ) - fireEvent.mouseUp( - screen.getByTestId('database-import-forbidden-notification'), - ) - fireEvent.mouseDown( - screen.getByTestId('database-import-forbidden-notification'), - ) + renderToast(INFINITE_MESSAGES.DATABASE_IMPORT_FORBIDDEN(onClose)) + + const okButton = await screen.findByRole('button', { + name: /OK/, + }) + expect(okButton).toBeInTheDocument() + + fireEvent.click(okButton) - expect(onClose).toBeCalled() + expect(onClose).toHaveBeenCalled() }) }) describe('SUBSCRIPTION_EXISTS', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.SUBSCRIPTION_EXISTS(jest.fn()) - expect(render(<>{Inner})).toBeTruthy() + it('should render message', async () => { + const onSuccess = jest.fn() + const onClose = jest.fn() + + renderToast(INFINITE_MESSAGES.SUBSCRIPTION_EXISTS(onSuccess, onClose)) + + // Wait for the notification to appear + const title = await screen.findByText( + 'Your subscription does not have a free trial Redis Cloud database.', + ) + const description = await screen.findByText( + 'Do you want to create a free trial database in your existing subscription?', + ) + const createButton = await screen.findByRole('button', { + name: /Create/, + }) + const closeButton = await screen.findByRole('button', { name: /Close/ }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(createButton).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() }) - it('should call onSuccess', () => { + it('should call onSuccess callback when clicking on the "Create" button', async () => { const onSuccess = jest.fn() - const { Inner } = INFINITE_MESSAGES.SUBSCRIPTION_EXISTS(onSuccess) - render(<>{Inner}) + const onClose = jest.fn() - fireEvent.click(screen.getByTestId('create-subscription-sso-btn')) - fireEvent.mouseUp(screen.getByTestId('subscription-exists-notification')) - fireEvent.mouseDown( - screen.getByTestId('subscription-exists-notification'), - ) + renderToast(INFINITE_MESSAGES.SUBSCRIPTION_EXISTS(onSuccess, onClose)) + + const createButton = await screen.findByRole('button', { + name: /Create/, + }) + expect(createButton).toBeInTheDocument() + + fireEvent.click(createButton) - expect(onSuccess).toBeCalled() + expect(onSuccess).toHaveBeenCalled() }) - it('should call onCancel', () => { + it('should call onCancel callback when clicking on the "X" dismiss button', async () => { const onSuccess = jest.fn() - const onCancel = jest.fn() - const { Inner } = INFINITE_MESSAGES.SUBSCRIPTION_EXISTS( - onSuccess, - onCancel, - ) - render(<>{Inner}) + const onClose = jest.fn() - fireEvent.click(screen.getByTestId('cancel-create-subscription-sso-btn')) - fireEvent.mouseUp(screen.getByTestId('subscription-exists-notification')) - fireEvent.mouseDown( - screen.getByTestId('subscription-exists-notification'), - ) + renderToast(INFINITE_MESSAGES.SUBSCRIPTION_EXISTS(onSuccess, onClose)) - expect(onCancel).toBeCalled() + const closeButton = await screen.findByRole('button', { + name: /Close/, + }) + expect(closeButton).toBeInTheDocument() + + fireEvent.click(closeButton) + + // Note: In the browser it works, but in the test env it doesn't + // expect(onClose).toHaveBeenCalled() }) }) describe('AUTO_CREATING_DATABASE', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.AUTO_CREATING_DATABASE() - expect(render(<>{Inner})).toBeTruthy() + it('should render message', async () => { + renderToast(INFINITE_MESSAGES.AUTO_CREATING_DATABASE()) + + // Wait for the notification to appear + const title = await screen.findByText('Connecting to your database') + const description = await screen.findByText( + 'This may take several minutes, but it is totally worth it!', + ) + const closeButton = await screen.findByRole('button', { name: /Close/ }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() }) }) describe('APP_UPDATE_AVAILABLE', () => { - it('should render message', () => { - const { Inner } = INFINITE_MESSAGES.APP_UPDATE_AVAILABLE('1', jest.fn()) - expect(render(<>{Inner})).toBeTruthy() + it('should render message', async () => { + const version = '' + const onSuccess = jest.fn() + + renderToast(INFINITE_MESSAGES.APP_UPDATE_AVAILABLE(version, onSuccess)) + + // Wait for the notification to appear + const title = await screen.findByText('New version is now available') + const description = await screen.findByText( + /With Redis Insight you have access to new useful features and optimizations\.\s*Restart Redis Insight to install updates\./, + ) + const restartButton = await screen.findByRole('button', { + name: /Restart/, + }) + const closeButton = await screen.findByRole('button', { name: /close/i }) + + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(restartButton).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() }) - it('should call onSuccess', () => { + it('should call onSuccess when clicking restart button', async () => { + const version = '' const onSuccess = jest.fn() - const { Inner } = INFINITE_MESSAGES.APP_UPDATE_AVAILABLE('1', onSuccess) - render(<>{Inner}) - fireEvent.click(screen.getByTestId('app-restart-btn')) - fireEvent.mouseUp(screen.getByTestId('app-update-available-notification')) - fireEvent.mouseDown( - screen.getByTestId('app-update-available-notification'), + renderToast(INFINITE_MESSAGES.APP_UPDATE_AVAILABLE(version, onSuccess)) + + const restartButton = await screen.findByRole('button', { + name: /Restart/, + }) + expect(restartButton).toBeInTheDocument() + + fireEvent.click(restartButton) + + expect(onSuccess).toHaveBeenCalled() + }) + }) + + describe('SUCCESS_DEPLOY_PIPELINE', () => { + it('should render message', async () => { + renderToast(INFINITE_MESSAGES.SUCCESS_DEPLOY_PIPELINE()) + + // Wait for the notification to appear + const title = await screen.findByText('Congratulations!') + const description = await screen.findByText( + /Deployment completed successfully!\s*Check out the pipeline statistics page\./, ) + const closeButton = await screen.findByRole('button', { name: /close/i }) - expect(onSuccess).toBeCalled() + expect(title).toBeInTheDocument() + expect(description).toBeInTheDocument() + expect(closeButton).toBeInTheDocument() }) }) }) diff --git a/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.tsx b/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.tsx index a63276acde..bae35ca465 100644 --- a/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.tsx +++ b/redisinsight/ui/src/components/notifications/components/infinite-messages/InfiniteMessages.tsx @@ -1,12 +1,12 @@ import React from 'react' import { find } from 'lodash' -import cx from 'classnames' import { CloudJobName, CloudJobStep } from 'uiSrc/electron/constants' import ExternalLink from 'uiSrc/components/base/external-link' import Divider from 'uiSrc/components/divider/Divider' import { OAuthProviders } from 'uiSrc/components/oauth/oauth-select-plan/constants' +import { LoaderLargeIcon } from 'uiSrc/components/base/icons' -import { CloudSuccessResult } from 'uiSrc/slices/interfaces' +import { CloudSuccessResult, InfiniteMessage } from 'uiSrc/slices/interfaces' import { Maybe } from 'uiSrc/utils' import { getUtmExternalLink } from 'uiSrc/utils/links' @@ -18,14 +18,8 @@ import { } from 'uiSrc/constants/links' import { FlexItem, Row } from 'uiSrc/components/base/layout/flex' import { Spacer } from 'uiSrc/components/base/layout/spacer' -import { - PrimaryButton, - SecondaryButton, -} from 'uiSrc/components/base/forms/buttons' +import { PrimaryButton } from 'uiSrc/components/base/forms/buttons' import { RiIcon } from 'uiSrc/components/base/icons/RiIcon' -import { Title } from 'uiSrc/components/base/text/Title' -import { Link } from 'uiSrc/components/base/link/Link' -import { Loader } from 'uiSrc/components/base/display' import styles from './styles.module.scss' export enum InfiniteMessagesIds { @@ -44,59 +38,39 @@ const MANAGE_DB_LINK = getUtmExternalLink(EXTERNAL_LINKS.cloudConsole, { medium: UTM_MEDIUMS.Main, }) -export const INFINITE_MESSAGES = { +// TODO: Refactor this type definition to work with the real parameters and their types we use in each message +export const INFINITE_MESSAGES: Record< + string, + (...args: any[]) => InfiniteMessage +> = { AUTHENTICATING: () => ({ id: InfiniteMessagesIds.oAuthProgress, - Inner: ( -
- - - - - - - Authenticating… - - - This may take several seconds, but it is totally worth it! - - - -
- ), + message: 'Authenticating…', + description: 'This may take several seconds, but it is totally worth it!', + customIcon: LoaderLargeIcon, }), PENDING_CREATE_DB: (step?: CloudJobStep) => ({ id: InfiniteMessagesIds.oAuthProgress, - Inner: ( -
- - - - - - - <span> - {(step === CloudJobStep.Credentials || !step) && - 'Processing Cloud API keys…'} - {step === CloudJobStep.Subscription && - 'Processing Cloud subscriptions…'} - {step === CloudJobStep.Database && - 'Creating a free trial Cloud database…'} - {step === CloudJobStep.Import && - 'Importing a free trial Cloud database…'} - </span> - - - This may take several minutes, but it is totally worth it! - - - - You can continue working in Redis Insight, and we will notify you - once done. - - - -
+ customIcon: LoaderLargeIcon, + message: ( + <> + {(step === CloudJobStep.Credentials || !step) && + 'Processing Cloud API keys…'} + {step === CloudJobStep.Subscription && + 'Processing Cloud subscriptions…'} + {step === CloudJobStep.Database && + 'Creating a free trial Cloud database…'} + {step === CloudJobStep.Import && + 'Importing a free trial Cloud database…'} + + ), + description: ( + <> + This may take several minutes, but it is totally worth it! + + You can continue working in Redis Insight, and we will notify you once + done. + ), }), SUCCESS_CREATE_DB: ( @@ -112,324 +86,173 @@ export const INFINITE_MESSAGES = { CloudJobName.CreateFreeSubscriptionAndDatabase, ].includes(jobName) const text = `You can now use your Redis Cloud database${withFeed ? ' with pre-loaded sample data' : ''}.` + return { id: InfiniteMessagesIds.oAuthSuccess, - className: 'wide', - Inner: ( -
{ - e.preventDefault() - }} - onMouseUp={(e) => { - e.preventDefault() - }} - data-testid="success-create-db-notification" - > - - - - - - - Congratulations! - - - {text} - - Notice: the database will be deleted after 15 days of - inactivity. - - {!!details && ( - <> - - - - - - Plan - - - Free - - - - - Cloud Vendor - - - {!!vendor?.icon && } - {vendor?.label} - - - - - Region - - - {details.region} - - - - )} + message: 'Congratulations!', + description: ( + <> + {text} + + + Notice: + {' '} + the database will be deleted after 15 days of inactivity. + {!!details && ( + <> - + + + - Manage DB + Plan + + + Free + + - onSuccess()} - data-testid="notification-connect-db" - > - Connect - + Cloud Vendor + + + {!!vendor?.icon && } + {vendor?.label} + + + Region + + + {details.region} + + + + )} + + + + + Manage DB + + + + onSuccess()} + data-testid="notification-connect-db" + > + Connect + -
+ ), } }, DATABASE_EXISTS: (onSuccess?: () => void, onClose?: () => void) => ({ id: InfiniteMessagesIds.databaseExists, - Inner: ( -
{ - e.preventDefault() - }} - onMouseUp={(e) => { - e.preventDefault() - }} - data-testid="database-exists-notification" - > - - You already have a free trial Redis Cloud subscription. - - - Do you want to import your existing database into Redis Insight? - - - - - onSuccess?.()} - data-testid="import-db-sso-btn" - > - Import - - - - onClose?.()} - data-testid="cancel-import-db-sso-btn" - > - Cancel - - - -
- ), + message: 'You already have a free trial Redis Cloud subscription.', + description: + 'Do you want to import your existing database into Redis Insight?', + actions: { + primary: { label: 'Import', onClick: () => onSuccess?.() }, + }, + onClose, }), DATABASE_IMPORT_FORBIDDEN: (onClose?: () => void) => ({ id: InfiniteMessagesIds.databaseImportForbidden, - Inner: ( -
{ - e.preventDefault() - }} - onMouseUp={(e) => { - e.preventDefault() - }} - data-testid="database-import-forbidden-notification" - > - - Unable to import Cloud database. - - - Adding your Redis Cloud database to Redis Insight is disabled due to a - setting restricting database connection management. - - Log in to{' '} - - Redis Cloud - {' '} - to check your database. - + message: 'Unable to import Cloud database.', + description: ( + <> + Adding your Redis Cloud database to Redis Insight is disabled due to a + setting restricting database connection management. - - - onClose?.()} - data-testid="database-import-forbidden-notification-ok-btn" - > - Ok - - - -
+ Log in to{' '} + + Redis Cloud + {' '} + to check your database. + ), + actions: { + primary: { + label: 'OK', + onClick: () => onClose?.(), + }, + }, + showCloseButton: false, }), SUBSCRIPTION_EXISTS: (onSuccess?: () => void, onClose?: () => void) => ({ id: InfiniteMessagesIds.subscriptionExists, - Inner: ( -
{ - e.preventDefault() - }} - onMouseUp={(e) => { - e.preventDefault() - }} - data-testid="subscription-exists-notification" - > - - Your subscription does not have a free trial Redis Cloud database. - - - Do you want to create a free trial database in your existing - subscription? - - - - - onSuccess?.()} - data-testid="create-subscription-sso-btn" - > - Create - - - - onClose?.()} - data-testid="cancel-create-subscription-sso-btn" - > - Cancel - - - -
- ), + message: + 'Your subscription does not have a free trial Redis Cloud database.', + description: + 'Do you want to create a free trial database in your existing subscription?', + actions: { + primary: { label: 'Create', onClick: () => onSuccess?.() }, + }, + onClose, }), AUTO_CREATING_DATABASE: () => ({ id: InfiniteMessagesIds.autoCreateDb, - Inner: ( -
- - - - - - - Connecting to your database - - - This may take several minutes, but it is totally worth it! - - - -
- ), + message: 'Connecting to your database', + description: 'This may take several minutes, but it is totally worth it!', + customIcon: LoaderLargeIcon, }), APP_UPDATE_AVAILABLE: (version: string, onSuccess?: () => void) => ({ id: InfiniteMessagesIds.appUpdateAvailable, - Inner: ( -
{ - e.preventDefault() - }} - onMouseUp={(e) => { - e.preventDefault() - }} - data-testid="app-update-available-notification" - > - - New version is now available - - - <> - With Redis Insight - {` ${version} `} - you have access to new useful features and optimizations. -
- Restart Redis Insight to install updates. - -
-
- onSuccess?.()} - data-testid="app-restart-btn" - > - Restart - -
+ message: 'New version is now available', + description: ( + <> + With Redis Insight {version} you have access to new useful features and + optimizations. + + Restart Redis Insight to install updates. + ), + actions: { + primary: { label: 'Restart', onClick: () => onSuccess?.() }, + }, }), SUCCESS_DEPLOY_PIPELINE: () => ({ id: InfiniteMessagesIds.pipelineDeploySuccess, - className: 'wide', - Inner: ( -
{ - e.preventDefault() - }} - onMouseUp={(e) => { - e.preventDefault() - }} - data-testid="success-deploy-pipeline-notification" - > - - - - - - - Congratulations! - - - Deployment completed successfully! -
- Check out the pipeline statistics page. -
- - {/* // TODO remove display none when statistics page will be available */} - - - {}} - data-testid="notification-connect-db" - > - Statistics - - - -
-
-
+ message: 'Congratulations!', + description: ( + <> + Deployment completed successfully! +
+ Check out the pipeline statistics page. + ), + // TODO enable when statistics page will be available + // actions: { + // primary: { + // label: 'Statistics', + // onClick: () => {}, + // } + // } }), } diff --git a/redisinsight/ui/src/slices/interfaces/app.ts b/redisinsight/ui/src/slices/interfaces/app.ts index 76bbe0a683..beba850e56 100644 --- a/redisinsight/ui/src/slices/interfaces/app.ts +++ b/redisinsight/ui/src/slices/interfaces/app.ts @@ -13,6 +13,8 @@ import { import { ConfigDBStorageItem } from 'uiSrc/constants/storage' import { GetServerInfoResponse } from 'apiSrc/modules/server/dto/server.dto' import { RedisString as RedisStringAPI } from 'apiSrc/common/constants/redis-string' +import { RiToastType } from 'uiSrc/components/base/display/toast/RiToast' +import { ToastVariant } from '@redis-ui/components' export interface CustomError { details?: any[] @@ -243,8 +245,14 @@ export interface IGlobalNotification { export interface InfiniteMessage { id: string - Inner: string | JSX.Element + variant?: ToastVariant className?: string + message?: RiToastType['message'] + description?: RiToastType['description'] + actions?: RiToastType['actions'] + customIcon?: RiToastType['customIcon'] + showCloseButton?: boolean + onClose?: () => void } export interface StateAppNotifications {