diff --git a/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx index 3f2cbfadb03c..bff661856ad9 100644 --- a/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx +++ b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx @@ -5,6 +5,7 @@ import { DataGeographyDropdown } from "components/common/DataGeographyDropdown"; import { ControlLabels } from "components/LabeledControl"; import { Card } from "components/ui/Card"; import { Spinner } from "components/ui/Spinner"; +import { ToastType } from "components/ui/Toast"; import { Geography } from "core/request/AirbyteClient"; import { useConnectionEditService } from "hooks/services/ConnectionEdit/ConnectionEditService"; @@ -32,8 +33,8 @@ export const UpdateConnectionDataResidency: React.FC = () => { } catch (e) { registerNotification({ id: "connection.geographyUpdateError", - title: formatMessage({ id: "connection.geographyUpdateError" }), - isError: true, + text: formatMessage({ id: "connection.geographyUpdateError" }), + type: ToastType.ERROR, }); } setSelectedValue(undefined); diff --git a/airbyte-webapp/src/components/ui/Button/Button.module.scss b/airbyte-webapp/src/components/ui/Button/Button.module.scss index 1358b7fbc546..55dfdaa9362c 100644 --- a/airbyte-webapp/src/components/ui/Button/Button.module.scss +++ b/airbyte-webapp/src/components/ui/Button/Button.module.scss @@ -13,6 +13,7 @@ font-weight: 600; cursor: pointer; transition: 0.2s ease-in; + white-space: nowrap; &.full { width: 100%; diff --git a/airbyte-webapp/src/components/ui/Toast/ErrorSign.tsx b/airbyte-webapp/src/components/ui/Toast/ErrorSign.tsx deleted file mode 100644 index d0e0e7fb7842..000000000000 --- a/airbyte-webapp/src/components/ui/Toast/ErrorSign.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { faExclamation } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import React from "react"; -import styled from "styled-components"; - -const ErrorIcon = styled.div` - width: 28px; - min-width: 28px; - height: 28px; - border-radius: 50%; - margin-right: 11px; - display: flex; - justify-content: center; - align-items: center; - background: ${({ theme }) => theme.dangerColor}; - border: 1px solid ${({ theme }) => theme.mediumPrimaryColor20}; -`; - -const ExclamationLight = styled(FontAwesomeIcon)` - font-size: 16px; - color: ${({ theme }) => theme.whiteColor}; -`; - -export const ErrorSign: React.FC = () => ( - - - -); diff --git a/airbyte-webapp/src/components/ui/Toast/Toast.module.scss b/airbyte-webapp/src/components/ui/Toast/Toast.module.scss index 0bf06de4cd58..42d4ac5840fe 100644 --- a/airbyte-webapp/src/components/ui/Toast/Toast.module.scss +++ b/airbyte-webapp/src/components/ui/Toast/Toast.module.scss @@ -1,3 +1,98 @@ +@use "scss/colors"; +@use "scss/variables" as vars; +@use "scss/z-indices"; +@use "scss/mixins"; + +$toast-icon-size: 13px; +$toast-icon-container-size: 34px; +$toast-bottom-margin: 27px; + +@keyframes slide-up-animations { + 0% { + transform: translate(-50%, -100%); + bottom: -60px; + } + + 100% { + transform: translate(-50%, 0); + bottom: $toast-bottom-margin; + } +} + +@mixin type($name, $color, $background) { + &.#{$name} { + background-color: $background; + border: 1px solid $color; + + .iconContainer { + background-color: $color; + } + + .toastIcon { + color: $color; + } + } +} + +.toastContainer { + display: flex; + flex-direction: row; + align-items: flex-start; + gap: vars.$spacing-md; + max-width: vars.$width-max-notification; + position: fixed; + box-sizing: border-box; + bottom: $toast-bottom-margin; + left: 50%; + transform: translate(-50%, 0); + z-index: z-indices.$notification; + padding: vars.$spacing-md; + border-radius: vars.$border-radius-md; + animation: slide-up-animations 0.25s ease-out; + + @include mixins.shadow; + + @include type("info", colors.$blue-400, colors.$blue-50); + @include type("warning", colors.$yellow-500, colors.$yellow-50); + @include type("success", colors.$green-200, colors.$green-50); + @include type("error", colors.$red-300, colors.$red-50); +} + +.iconContainer { + width: $toast-icon-container-size; + height: $toast-icon-container-size; + max-height: $toast-icon-container-size; + min-width: $toast-icon-container-size; + padding: vars.$border-radius-md; + border-radius: vars.$border-radius-md; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; +} + +.toastIcon { + width: $toast-icon-size; + height: $toast-icon-size; + background: colors.$white; + border-radius: 50%; +} + +.textContainer { + align-self: center; +} + +.text { + line-height: 17px; + text-align: left; +} + +.actionButton { + margin-top: vars.$spacing-xs; +} + .closeButton { - margin-left: 10px; + svg { + color: colors.$dark-blue-900; + } } diff --git a/airbyte-webapp/src/components/ui/Toast/Toast.tsx b/airbyte-webapp/src/components/ui/Toast/Toast.tsx index c0eec9417009..ef018b6e1869 100644 --- a/airbyte-webapp/src/components/ui/Toast/Toast.tsx +++ b/airbyte-webapp/src/components/ui/Toast/Toast.tsx @@ -1,86 +1,64 @@ -import { faTimes } from "@fortawesome/free-solid-svg-icons"; +import { faCheck, faExclamation, faTimes } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import classNames from "classnames"; import React from "react"; -import styled, { keyframes } from "styled-components"; -import { H5 } from "components/base/Titles"; +import { CrossIcon } from "components/icons/CrossIcon"; +import { Text } from "components/ui/Text"; import { Button } from "../Button"; -import { ErrorSign } from "./ErrorSign"; import styles from "./Toast.module.scss"; -interface ToastProps { - title: string | React.ReactNode; - text?: string | React.ReactNode; - hasError?: boolean; - onClose?: () => void; +export const enum ToastType { + WARNING = "warning", + SUCCESS = "success", + ERROR = "error", + INFO = "info", } -export const SlideUpAnimation = keyframes` - 0% { - translate(-50%, -100%); - bottom: -49px; - } - 100% { - translate(-50%, 0); - bottom: 49px; - } -`; - -const Singleton = styled.div<{ hasError?: boolean }>` - position: fixed; - bottom: 49px; - left: 50%; - transform: translate(-50%, 0); - z-index: 20; - - padding: 25px 25px 22px; - - background: ${({ theme, hasError }) => (hasError ? theme.lightDangerColor : theme.lightPrimaryColor)}; - border: 1px solid ${({ theme }) => theme.greyColor20}; - box-shadow: 0 1px 2px ${({ theme }) => theme.shadowColor}; - border-radius: 8px; - - display: flex; - flex-direction: row; - align-items: center; - - animation: ${SlideUpAnimation} 0.25s linear; -`; - -const Title = styled(H5)<{ hasError?: boolean }>` - color: ${({ theme, hasError }) => (hasError ? theme.dangerColor : theme.primaryColor)}; - - font-style: normal; - font-weight: bold; - font-size: 15px; - line-height: 18px; -`; +export interface ToastProps { + text: string | React.ReactNode; + type?: ToastType; + onAction?: () => void; + actionBtnText?: string; + onClose?: () => void; +} -const Text = styled.div` - color: ${({ theme }) => theme.mediumPrimaryColor}; +const ICON_MAPPING = { + [ToastType.WARNING]: faExclamation, + [ToastType.ERROR]: faTimes, + [ToastType.SUCCESS]: faCheck, + [ToastType.INFO]: faExclamation, +}; - font-style: normal; - font-weight: normal; - font-size: 14px; - line-height: 17px; - margin-top: 5px; -`; +const STYLES_BY_TYPE: Readonly> = { + [ToastType.WARNING]: styles.warning, + [ToastType.ERROR]: styles.error, + [ToastType.SUCCESS]: styles.success, + [ToastType.INFO]: styles.info, +}; -export const Toast: React.FC = (props) => ( - - {props.hasError && } - - {props.title} - {props.text && {props.text}} +export const Toast: React.FC = ({ type = ToastType.INFO, onAction, actionBtnText, onClose, text }) => { + return ( + + + + + + {text && ( + + {text} + + )} + + {onAction && ( + + {actionBtnText} + + )} + {onClose && ( + } /> + )} - {props.onClose && ( - } - /> - )} - -); + ); +}; diff --git a/airbyte-webapp/src/components/ui/Toast/index.stories.tsx b/airbyte-webapp/src/components/ui/Toast/index.stories.tsx index 1bd4fe19c190..9caeb2fde2cd 100644 --- a/airbyte-webapp/src/components/ui/Toast/index.stories.tsx +++ b/airbyte-webapp/src/components/ui/Toast/index.stories.tsx @@ -1,13 +1,15 @@ import { ComponentStory, ComponentMeta } from "@storybook/react"; -import { Toast } from "./Toast"; +import { Toast, ToastType } from "./Toast"; export default { title: "UI/Toast", component: Toast, argTypes: { - title: { type: { name: "string", required: false } }, text: { type: { name: "string", required: false } }, + type: { type: { name: "string", required: false } }, + onAction: { table: { disable: true } }, + actionBtnText: { type: { name: "string", required: false } }, onClose: { table: { disable: true } }, }, } as ComponentMeta; @@ -19,17 +21,56 @@ Basic.args = { text: "This is a basic card", }; -export const WithTitle = Template.bind({}); -WithTitle.args = { - title: "With Title", - text: "This is a card with a title", +export const WithText = Template.bind({}); +WithText.args = { + text: "This is a card with a text", +}; + +export const WithLongText = Template.bind({}); +WithLongText.args = { + text: "This is a card with a long text, very very long text message. Just an example how ", }; export const WithCloseButton = Template.bind({}); WithCloseButton.args = { - title: "With Close button", text: "This is a card with a close button", onClose: () => { console.log("Closed!"); }, }; + +export const WithActionButton = Template.bind({}); +WithActionButton.args = { + text: "This is a card with an action button button", + onAction: () => console.log("Action btn clicked!"), + actionBtnText: "Click me!", +}; + +export const WithActionAndCloseButton = Template.bind({}); +WithActionAndCloseButton.args = { + text: "This is a card with an action button button", + onAction: () => console.log("Action btn clicked!"), + actionBtnText: "Click me!", + onClose: () => console.log("Closed!"), +}; + +export const WarningToast = Template.bind({}); +WarningToast.args = { + text: "This is a card with a close button", + onClose: () => console.log("Closed!"), + type: ToastType.WARNING, +}; + +export const ErrorToast = Template.bind({}); +ErrorToast.args = { + text: "This is a card with a close button", + onClose: () => console.log("Closed!"), + type: ToastType.ERROR, +}; + +export const SuccessToast = Template.bind({}); +SuccessToast.args = { + text: "This is a card with a close button", + onClose: () => console.log("Closed!"), + type: ToastType.SUCCESS, +}; diff --git a/airbyte-webapp/src/hooks/services/Health/HealthPollService.tsx b/airbyte-webapp/src/hooks/services/Health/HealthPollService.tsx index 28f5428e012e..000714fc210d 100644 --- a/airbyte-webapp/src/hooks/services/Health/HealthPollService.tsx +++ b/airbyte-webapp/src/hooks/services/Health/HealthPollService.tsx @@ -6,6 +6,9 @@ import { HealthService } from "core/health/HealthService"; import { useGetService } from "core/servicesProvider"; import { useNotificationService } from "hooks/services/Notification/NotificationService"; +import { ToastType } from "../../../components/ui/Toast"; +import { Notification } from "../Notification"; + const HEALTH_NOTIFICATION_ID = "health.error"; const HEALTHCHECK_MAX_COUNT = 3; @@ -17,10 +20,10 @@ function useApiHealthPoll(): void { const { registerNotification, unregisterNotificationById } = useNotificationService(); useEffect(() => { - const errorNotification = { + const errorNotification: Notification = { id: HEALTH_NOTIFICATION_ID, - title: formatMessage({ id: "notifications.error.health" }), - isError: true, + text: formatMessage({ id: "notifications.error.health" }), + type: ToastType.ERROR, }; const interval = setInterval(async () => { diff --git a/airbyte-webapp/src/hooks/services/Notification/NotificationService.tsx b/airbyte-webapp/src/hooks/services/Notification/NotificationService.tsx index c1ac44317ada..3ec22bf99413 100644 --- a/airbyte-webapp/src/hooks/services/Notification/NotificationService.tsx +++ b/airbyte-webapp/src/hooks/services/Notification/NotificationService.tsx @@ -33,9 +33,8 @@ const NotificationService = ({ children }: { children: React.ReactNode }) => { {firstNotification ? ( // Show only first notification void; } export interface NotificationServiceApi { diff --git a/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx b/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx index 8e52c24b194c..a7e415cca2e6 100644 --- a/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx +++ b/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx @@ -2,6 +2,8 @@ import { useCallback, useMemo, useRef } from "react"; import { useIntl } from "react-intl"; import { useAsyncFn, useEffectOnce, useEvent } from "react-use"; +import { ToastType } from "components/ui/Toast"; + import { useConfig } from "config"; import { ConnectorDefinitionSpecification, ConnectorSpecification } from "core/domain/connector"; import { DestinationAuthService } from "core/domain/connector/DestinationAuthService"; @@ -107,7 +109,7 @@ export function useConnectorAuth(): { notificationService.registerNotification({ id: "oauthConnector.credentialsMissing", // Since it's dev only we don't need i18n on this string - title: "OAuth is not enabled for this connector on this environment.", + text: "OAuth is not enabled for this connector on this environment.", }); } else { // Log error to our monitoring, this should never happen and means OAuth credentials @@ -119,8 +121,8 @@ export function useConnectorAuth(): { }); notificationService.registerNotification({ id: "oauthConnector.credentialsMissing", - title: formatMessage({ id: "connector.oauthCredentialsMissing" }), - isError: true, + text: formatMessage({ id: "connector.oauthCredentialsMissing" }), + type: ToastType.ERROR, }); } } diff --git a/airbyte-webapp/src/hooks/useLoadingState.tsx b/airbyte-webapp/src/hooks/useLoadingState.tsx index cb002923d061..1074019eda54 100644 --- a/airbyte-webapp/src/hooks/useLoadingState.tsx +++ b/airbyte-webapp/src/hooks/useLoadingState.tsx @@ -1,7 +1,8 @@ import { useState } from "react"; import { useIntl } from "react-intl"; -import { useNotificationService } from "./services/Notification"; +import { ToastType } from "../components/ui/Toast"; +import { Notification, useNotificationService } from "./services/Notification"; const useLoadingState = (): { isLoading: boolean; @@ -13,13 +14,11 @@ const useLoadingState = (): { const [isLoading, setIsLoading] = useState(false); const [showFeedback, setShowFeedback] = useState(false); - const errorNotificationId = "error.somethingWentWrong"; - const errorNotification = (message: string) => ({ - isError: true, - title: formatMessage({ id: `notifications.${errorNotificationId}` }), - text: message, - id: errorNotificationId, - }); + const errorNotification: Notification = { + id: "notifications.error.somethingWentWrong", + text: formatMessage({ id: `notifications.error.somethingWentWrong` }), + type: ToastType.ERROR, + }; const startAction = async ({ action, feedbackAction }: { action: () => void; feedbackAction?: () => void }) => { try { @@ -37,11 +36,9 @@ const useLoadingState = (): { feedbackAction(); } }, 2000); - } catch (error) { - const message = error?.message || formatMessage({ id: "notifications.error.noMessage" }); - + } catch { setIsLoading(false); - registerNotification(errorNotification(message)); + registerNotification(errorNotification); } }; diff --git a/airbyte-webapp/src/packages/cloud/views/FirebaseActionRoute.tsx b/airbyte-webapp/src/packages/cloud/views/FirebaseActionRoute.tsx index 244d7ea78c3f..a41f6c84db18 100644 --- a/airbyte-webapp/src/packages/cloud/views/FirebaseActionRoute.tsx +++ b/airbyte-webapp/src/packages/cloud/views/FirebaseActionRoute.tsx @@ -4,8 +4,9 @@ import { Navigate, useNavigate } from "react-router-dom"; import { useAsync } from "react-use"; import LoadingPage from "components/LoadingPage"; +import { ToastType } from "components/ui/Toast"; -import { useTrackPage, PageTrackingCodes } from "hooks/services/Analytics"; +import { PageTrackingCodes, useTrackPage } from "hooks/services/Analytics"; import { useNotificationService } from "hooks/services/Notification"; import { useQuery } from "hooks/useQuery"; import { useAuthService } from "packages/cloud/services/auth/AuthService"; @@ -38,8 +39,8 @@ export const VerifyEmailAction: React.FC = () => { // Show a notification that the mail got verified successfully registerNotification({ id: "auth/email-verified", - title: formatMessage({ id: "verifyEmail.notification" }), - isError: false, + text: formatMessage({ id: "verifyEmail.notification" }), + type: ToastType.SUCCESS, }); // Navigate the user to the homepage navigate("/"); diff --git a/airbyte-webapp/src/packages/cloud/views/auth/ConfirmPasswordResetPage/ConfirmPasswordResetPage.tsx b/airbyte-webapp/src/packages/cloud/views/auth/ConfirmPasswordResetPage/ConfirmPasswordResetPage.tsx index f383b991cecb..295990e98a69 100644 --- a/airbyte-webapp/src/packages/cloud/views/auth/ConfirmPasswordResetPage/ConfirmPasswordResetPage.tsx +++ b/airbyte-webapp/src/packages/cloud/views/auth/ConfirmPasswordResetPage/ConfirmPasswordResetPage.tsx @@ -7,6 +7,7 @@ import * as yup from "yup"; import { LabeledInput, Link } from "components"; import { Button } from "components/ui/Button"; +import { ToastType } from "components/ui/Toast"; import { useNotificationService } from "hooks/services/Notification/NotificationService"; import { useQuery } from "hooks/useQuery"; @@ -46,8 +47,8 @@ const ResetPasswordConfirmPage: React.FC = () => { await confirmPasswordReset(query.oobCode, newPassword); registerNotification({ id: "confirmResetPassword.success", - title: formatMessage({ id: "confirmResetPassword.success" }), - isError: false, + text: formatMessage({ id: "confirmResetPassword.success" }), + type: ToastType.SUCCESS, }); navigate(CloudRoutes.Login); } catch (err) { @@ -57,37 +58,37 @@ const ResetPasswordConfirmPage: React.FC = () => { case AuthErrorCodes.EXPIRED_OOB_CODE: registerNotification({ id: "confirmResetPassword.error.expiredActionCode", - title: formatMessage({ + text: formatMessage({ id: "confirmResetPassword.error.expiredActionCode", }), - isError: true, + type: ToastType.ERROR, }); break; case AuthErrorCodes.INVALID_OOB_CODE: registerNotification({ id: "confirmResetPassword.error.invalidActionCode", - title: formatMessage({ + text: formatMessage({ id: "confirmResetPassword.error.invalidActionCode", }), - isError: true, + type: ToastType.ERROR, }); break; case AuthErrorCodes.WEAK_PASSWORD: registerNotification({ id: "confirmResetPassword.error.weakPassword", - title: formatMessage({ + text: formatMessage({ id: "confirmResetPassword.error.weakPassword", }), - isError: true, + type: ToastType.WARNING, }); break; default: registerNotification({ id: "confirmResetPassword.error.default", - title: formatMessage({ + text: formatMessage({ id: "confirmResetPassword.error.default", }), - isError: true, + type: ToastType.ERROR, }); } } diff --git a/airbyte-webapp/src/packages/cloud/views/auth/ResetPasswordPage/ResetPasswordPage.tsx b/airbyte-webapp/src/packages/cloud/views/auth/ResetPasswordPage/ResetPasswordPage.tsx index 2e477ba4afb8..b63fdbe6ae6b 100644 --- a/airbyte-webapp/src/packages/cloud/views/auth/ResetPasswordPage/ResetPasswordPage.tsx +++ b/airbyte-webapp/src/packages/cloud/views/auth/ResetPasswordPage/ResetPasswordPage.tsx @@ -6,6 +6,7 @@ import * as yup from "yup"; import { LabeledInput, Link } from "components"; import { HeadTitle } from "components/common/HeadTitle"; import { Button } from "components/ui/Button"; +import { ToastType } from "components/ui/Toast"; import { PageTrackingCodes, useTrackPage } from "hooks/services/Analytics"; import { useNotificationService } from "hooks/services/Notification/NotificationService"; @@ -42,8 +43,8 @@ const ResetPasswordPage: React.FC = () => { await requirePasswordReset(email); registerNotification({ id: "resetPassword.emailSent", - title: formatMessage({ id: "login.resetPassword.emailSent" }), - isError: false, + text: formatMessage({ id: "login.resetPassword.emailSent" }), + type: ToastType.SUCCESS, }); } catch (err) { err.message.includes("user-not-found") diff --git a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/EmailVerificationHint.tsx b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/EmailVerificationHint.tsx index 68ed96d4b74f..b0cd3aca2156 100644 --- a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/EmailVerificationHint.tsx +++ b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/EmailVerificationHint.tsx @@ -5,6 +5,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import styled from "styled-components"; import { InfoBox } from "components/ui/InfoBox"; +import { ToastType } from "components/ui/Toast"; import { useNotificationService } from "hooks/services/Notification"; import { useAuthService } from "packages/cloud/services/auth/AuthService"; @@ -16,7 +17,6 @@ interface Props { const ResendEmailLink = styled.button` appearance: none; background: none; - padding: none; border: none; font-size: inherit; text-decoration: underline; @@ -48,28 +48,28 @@ export const EmailVerificationHint: React.FC = ({ className }) => { case AuthErrorCodes.NETWORK_REQUEST_FAILED: registerNotification({ id: error.code, - title: formatMessage({ + text: formatMessage({ id: FirebaseAuthMessageId.NetworkFailure, }), - isError: true, + type: ToastType.ERROR, }); break; case AuthErrorCodes.TOO_MANY_ATTEMPTS_TRY_LATER: registerNotification({ id: error.code, - title: formatMessage({ + text: formatMessage({ id: FirebaseAuthMessageId.TooManyRequests, }), - isError: true, + type: ToastType.WARNING, }); break; default: registerNotification({ id: error.code, - title: formatMessage({ + text: formatMessage({ id: FirebaseAuthMessageId.DefaultError, }), - isError: true, + type: ToastType.ERROR, }); } } diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx index 82ea74f3acac..e32c31e126b3 100644 --- a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx @@ -12,6 +12,7 @@ import { Button } from "components/ui/Button"; import { DropDown } from "components/ui/DropDown"; import { Input } from "components/ui/Input"; import { Modal } from "components/ui/Modal"; +import { ToastType } from "components/ui/Toast"; import { Action, Namespace } from "core/analytics"; import { useAnalyticsService } from "hooks/services/Analytics"; @@ -88,8 +89,9 @@ export const InviteUsersModal: React.FC<{ { onSuccess: () => { registerNotification({ - title: formatMessage({ id: "addUsers.success.title" }), + text: formatMessage({ id: "addUsers.success.title" }), id: "invite-users-success", + type: ToastType.SUCCESS, }); props.onClose(); }, diff --git a/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx index a72be59554d0..5ce15d43b9c7 100644 --- a/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx +++ b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx @@ -6,6 +6,7 @@ import { ControlLabels } from "components"; import { DataGeographyDropdown } from "components/common/DataGeographyDropdown"; import { Button } from "components/ui/Button"; import { Text } from "components/ui/Text"; +import { ToastType } from "components/ui/Toast"; import { Geography } from "core/request/AirbyteClient"; import { PageTrackingCodes, useTrackPage } from "hooks/services/Analytics"; @@ -44,8 +45,8 @@ export const DataResidencyView: React.FC = () => { } catch (e) { registerNotification({ id: "workspaceSettings.defaultGeographyError", - title: formatMessage({ id: "settings.defaultDataResidencyUpdateError" }), - isError: true, + text: formatMessage({ id: "settings.defaultDataResidencyUpdateError" }), + type: ToastType.ERROR, }); } }; diff --git a/airbyte-webapp/src/pages/SettingsPage/pages/ConfigurationsPage/components/LogsContent.tsx b/airbyte-webapp/src/pages/SettingsPage/pages/ConfigurationsPage/components/LogsContent.tsx index 3de89859cfb6..47a3001ef5a7 100644 --- a/airbyte-webapp/src/pages/SettingsPage/pages/ConfigurationsPage/components/LogsContent.tsx +++ b/airbyte-webapp/src/pages/SettingsPage/pages/ConfigurationsPage/components/LogsContent.tsx @@ -4,6 +4,7 @@ import { useAsyncFn } from "react-use"; import styled from "styled-components"; import { Button } from "components/ui/Button"; +import { ToastType } from "components/ui/Toast"; import { LogType } from "core/domain/logs/types"; import { useNotificationService } from "hooks/services/Notification"; @@ -33,8 +34,8 @@ const LogsContent: React.FC = () => { registerNotification({ id: "admin.logs.error", - title: formatMessage({ id: "admin.logs.error" }), - isError: true, + text: formatMessage({ id: "admin.logs.error" }), + type: ToastType.ERROR, }); } }; diff --git a/airbyte-webapp/src/pages/SettingsPage/pages/NotificationPage/components/WebHookForm.tsx b/airbyte-webapp/src/pages/SettingsPage/pages/NotificationPage/components/WebHookForm.tsx index ca50fc542bbc..de597f65ea17 100644 --- a/airbyte-webapp/src/pages/SettingsPage/pages/NotificationPage/components/WebHookForm.tsx +++ b/airbyte-webapp/src/pages/SettingsPage/pages/NotificationPage/components/WebHookForm.tsx @@ -9,11 +9,12 @@ import * as yup from "yup"; import { Label, LabeledSwitch } from "components"; import { DocsIcon } from "components/icons/DocsIcon"; import { PlayIcon } from "components/icons/PlayIcon"; -import { Row, Cell } from "components/SimpleTableComponents"; +import { Cell, Row } from "components/SimpleTableComponents"; import { Button } from "components/ui/Button"; import { Heading } from "components/ui/Heading"; import { Input } from "components/ui/Input"; import { Text } from "components/ui/Text"; +import { ToastType } from "components/ui/Toast"; import { Tooltip } from "components/ui/Tooltip"; import useWorkspace, { WebhookPayload } from "hooks/services/useWorkspace"; @@ -59,16 +60,16 @@ export const WebHookForm: React.FC = ({ webhook }) => { case true: { registerNotification({ id: "settings.webhook.test.passed", - title: formatMessage({ id: "settings.webhook.test.passed" }), - isError: false, + text: formatMessage({ id: "settings.webhook.test.passed" }), + type: ToastType.SUCCESS, }); break; } case false: { registerNotification({ id: "settings.webhook.test.failed", - title: formatMessage({ id: "settings.webhook.test.failed" }), - isError: true, + text: formatMessage({ id: "settings.webhook.test.failed" }), + type: ToastType.ERROR, }); break; } @@ -83,8 +84,8 @@ export const WebHookForm: React.FC = ({ webhook }) => { case false: { registerNotification({ id: "settings.webhook.save.failed", - title: formatMessage({ id: "settings.webhook.save.failed" }), - isError: true, + text: formatMessage({ id: "settings.webhook.save.failed" }), + type: ToastType.ERROR, }); break; } diff --git a/airbyte-webapp/src/scss/_variables.scss b/airbyte-webapp/src/scss/_variables.scss index 4b747c904771..e0ac714ca4ab 100644 --- a/airbyte-webapp/src/scss/_variables.scss +++ b/airbyte-webapp/src/scss/_variables.scss @@ -24,6 +24,7 @@ $main-page-content-min-width: 960px; $width-size-menu: 93px; $width-wide-menu: 200px; +$width-max-notification: 600px; $width-modal-sm: 492px; $width-modal-md: 585px; diff --git a/airbyte-webapp/src/scss/_z-indices.scss b/airbyte-webapp/src/scss/_z-indices.scss index dcf0df9ac865..04b4b250ca99 100644 --- a/airbyte-webapp/src/scss/_z-indices.scss +++ b/airbyte-webapp/src/scss/_z-indices.scss @@ -4,3 +4,4 @@ $modal: 9999 + 1; $sidebar: 9999; $panelSplitter: 0; $dropdownMenu: 2; +$notification: 20;