From 1ddd4d7d7d77bfe5ade819622d700bb6b9f52f3a Mon Sep 17 00:00:00 2001 From: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:33:19 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=9F=20=F0=9F=8E=89=20Add=20optional=20?= =?UTF-8?q?invite=20user=20hint=20to=20connector=20create=20pages=20(#1579?= =?UTF-8?q?9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add InviteUsersModalService and migrate UserSettingsView to use it * Add InviteUsersHint component and show in create source/destination pages * Update InviteUsersHint to use Text component and spacing variables * Add experiments for showing invite user hint Move cloud settings paths to its own file * Update Invite hint to lazy load with suspense * Fix invite user modal experiment names and add unit test * Rename CloudInviteUsersHint component file * Add notification when users are invited * Fix copy and remove plural form of invite success dialog * Show invite users hint in connector create form page * Fix stylelint issue in InviteUsersHint * Fix access management path in InviteUsersHint * Fix button text in UserSettingsView * Fix linkToUsersPage type in experiments iface * Cleanup code * Cleanup scss path in InviteUsersHint.module * update InviteUsersHint layout to be consistent with or without button --- .../CloudInviteUsersHint.tsx | 15 ++++ .../components/CloudInviteUsersHint/index.ts | 1 + .../hooks/services/Experiment/experiments.ts | 2 + .../src/hooks/services/Notification/index.tsx | 1 + .../src/hooks/services/Notification/types.ts | 6 +- .../src/packages/cloud/locales/en.json | 7 +- .../users/InviteUsersModalService.tsx | 39 ++++++++++ .../views/settings/CloudSettingsPage.tsx | 13 +--- .../cloud/views/settings/routePaths.ts | 12 +++ .../InviteUsersHint.module.scss | 14 ++++ .../InviteUsersHint/InviteUsersHint.test.tsx | 77 +++++++++++++++++++ .../users/InviteUsersHint/InviteUsersHint.tsx | 67 ++++++++++++++++ .../views/users/InviteUsersHint/index.ts | 1 + .../views/users/InviteUsersHint/types.ts | 3 + .../InviteUsersModal/InviteUsersModal.tsx | 10 ++- .../UsersSettingsView/UsersSettingsView.tsx | 65 +++++++++------- .../CreationFormPage/CreationFormPage.tsx | 3 + .../CreateDestinationPage.tsx | 2 + .../CreateSourcePage/CreateSourcePage.tsx | 2 + 19 files changed, 298 insertions(+), 42 deletions(-) create mode 100644 airbyte-webapp/src/components/CloudInviteUsersHint/CloudInviteUsersHint.tsx create mode 100644 airbyte-webapp/src/components/CloudInviteUsersHint/index.ts create mode 100644 airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx create mode 100644 airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts create mode 100644 airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.module.scss create mode 100644 airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.test.tsx create mode 100644 airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx create mode 100644 airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/index.ts create mode 100644 airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/types.ts diff --git a/airbyte-webapp/src/components/CloudInviteUsersHint/CloudInviteUsersHint.tsx b/airbyte-webapp/src/components/CloudInviteUsersHint/CloudInviteUsersHint.tsx new file mode 100644 index 000000000000..9f5b5b885c4a --- /dev/null +++ b/airbyte-webapp/src/components/CloudInviteUsersHint/CloudInviteUsersHint.tsx @@ -0,0 +1,15 @@ +import { lazy, Suspense } from "react"; + +import { InviteUsersHintProps } from "packages/cloud/views/users/InviteUsersHint/types"; +import { isCloudApp } from "utils/app"; + +const LazyInviteUsersHint = lazy(() => + import("packages/cloud/views/users/InviteUsersHint").then(({ InviteUsersHint }) => ({ default: InviteUsersHint })) +); + +export const CloudInviteUsersHint: React.VFC = (props) => + isCloudApp() ? ( + + + + ) : null; diff --git a/airbyte-webapp/src/components/CloudInviteUsersHint/index.ts b/airbyte-webapp/src/components/CloudInviteUsersHint/index.ts new file mode 100644 index 000000000000..bfe0be13e8d1 --- /dev/null +++ b/airbyte-webapp/src/components/CloudInviteUsersHint/index.ts @@ -0,0 +1 @@ +export * from "./CloudInviteUsersHint"; diff --git a/airbyte-webapp/src/hooks/services/Experiment/experiments.ts b/airbyte-webapp/src/hooks/services/Experiment/experiments.ts index 1323d1a874f7..a06231626681 100644 --- a/airbyte-webapp/src/hooks/services/Experiment/experiments.ts +++ b/airbyte-webapp/src/hooks/services/Experiment/experiments.ts @@ -5,6 +5,8 @@ export interface Experiments { "onboarding.hideOnboarding": boolean; + "connector.inviteUsersHint.visible": boolean; + "connector.inviteUsersHint.linkToUsersPage": boolean; "connector.orderOverwrite": Record; "connector.frequentlyUsedDestinationIds": string[]; "connector.startWithDestinationId": string; diff --git a/airbyte-webapp/src/hooks/services/Notification/index.tsx b/airbyte-webapp/src/hooks/services/Notification/index.tsx index 07b31c844d5f..94de118c512a 100644 --- a/airbyte-webapp/src/hooks/services/Notification/index.tsx +++ b/airbyte-webapp/src/hooks/services/Notification/index.tsx @@ -1,4 +1,5 @@ import NotificationService, { useNotificationService } from "./NotificationService"; +export * from "./types"; export default NotificationService; export { NotificationService, useNotificationService }; diff --git a/airbyte-webapp/src/hooks/services/Notification/types.ts b/airbyte-webapp/src/hooks/services/Notification/types.ts index 23419bef17c0..5a136fd49df5 100644 --- a/airbyte-webapp/src/hooks/services/Notification/types.ts +++ b/airbyte-webapp/src/hooks/services/Notification/types.ts @@ -1,7 +1,9 @@ +import React from "react"; + export interface Notification { id: string | number; - title: string; - text?: string; + title: React.ReactNode; + text?: React.ReactNode; isError?: boolean; nonClosable?: boolean; onClose?: () => void; diff --git a/airbyte-webapp/src/packages/cloud/locales/en.json b/airbyte-webapp/src/packages/cloud/locales/en.json index e2703274dcde..2e762fb5820e 100644 --- a/airbyte-webapp/src/packages/cloud/locales/en.json +++ b/airbyte-webapp/src/packages/cloud/locales/en.json @@ -118,6 +118,8 @@ "settings.accessManagement.roleEditors": "Editors can edit connections", "settings.accessManagement.roleAdmin": "Admin can also manage users", + "addUsers.success.title": "Invitations sent!", + "credits.date": "Date", "credits.amount": "Credits", @@ -149,5 +151,8 @@ "verifyEmail.notification": "You successfully verified your email. Thank you.", - "webapp.cannotReachServer": "Cannot reach server." + "webapp.cannotReachServer": "Cannot reach server.", + + "inviteUsersHint.message": "Need help from a teammate to set up the {connector}?", + "inviteUsersHint.cta": "Invite users" } diff --git a/airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx b/airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx new file mode 100644 index 000000000000..46f2e3e3f7b2 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx @@ -0,0 +1,39 @@ +import { createContext, useContext, useMemo } from "react"; +import { useToggle } from "react-use"; + +import { InviteUsersModal } from "packages/cloud/views/users/InviteUsersModal"; + +interface InviteUsersModalServiceContext { + isInviteUsersModalOpen: boolean; + toggleInviteUsersModalOpen: (open?: boolean) => void; +} + +const inviteUsersModalServiceContext = createContext(null); +const { Provider } = inviteUsersModalServiceContext; + +export const useInviteUsersModalService = () => { + const ctx = useContext(inviteUsersModalServiceContext); + if (!ctx) { + throw new Error("useInviteUsersModalService should be use within InviteUsersModalServiceProvider"); + } + return ctx; +}; + +export const InviteUsersModalServiceProvider: React.FC = ({ children }) => { + const [isOpen, toggleIsOpen] = useToggle(false); + + const contextValue = useMemo( + () => ({ + isInviteUsersModalOpen: isOpen, + toggleInviteUsersModalOpen: toggleIsOpen, + }), + [isOpen, toggleIsOpen] + ); + + return ( + + {children} + {isOpen && } + + ); +}; diff --git a/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx b/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx index 2ec80029d6f9..86b89add3811 100644 --- a/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx +++ b/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx @@ -12,19 +12,10 @@ import { } from "pages/SettingsPage/pages/ConnectorsPage"; // import ConfigurationsPage from "pages/SettingsPage/pages/ConfigurationsPage"; import NotificationPage from "pages/SettingsPage/pages/NotificationPage"; -import { PageConfig, SettingsRoute } from "pages/SettingsPage/SettingsPage"; +import { PageConfig } from "pages/SettingsPage/SettingsPage"; import { isOsanoActive, showOsanoDrawer } from "utils/dataPrivacy"; -const CloudSettingsRoutes = { - Configuration: SettingsRoute.Configuration, - Notifications: SettingsRoute.Notifications, - Account: SettingsRoute.Account, - Source: SettingsRoute.Source, - Destination: SettingsRoute.Destination, - - Workspace: "workspaces", - AccessManagement: "access-management", -} as const; +import { CloudSettingsRoutes } from "./routePaths"; export const CloudSettingsPage: React.FC = () => { // TODO: uncomment when supported in cloud diff --git a/airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts b/airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts new file mode 100644 index 000000000000..c82011c13398 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts @@ -0,0 +1,12 @@ +import { SettingsRoute } from "pages/SettingsPage/SettingsPage"; + +export const CloudSettingsRoutes = { + Configuration: SettingsRoute.Configuration, + Notifications: SettingsRoute.Notifications, + Account: SettingsRoute.Account, + Source: SettingsRoute.Source, + Destination: SettingsRoute.Destination, + + Workspace: "workspaces", + AccessManagement: "access-management", +} as const; diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.module.scss b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.module.scss new file mode 100644 index 000000000000..314275886b69 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.module.scss @@ -0,0 +1,14 @@ +@use "scss/variables"; + +.container { + text-align: center; + margin-top: variables.$spacing-lg; + + &.withLink { + padding: variables.$spacing-md; + } +} + +.ctaButton { + margin-left: variables.$spacing-sm; +} diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.test.tsx b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.test.tsx new file mode 100644 index 000000000000..1cef3cba4429 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.test.tsx @@ -0,0 +1,77 @@ +import { fireEvent, render } from "@testing-library/react"; +import React from "react"; +import { TestWrapper } from "test-utils/testutils"; + +import { Experiments } from "hooks/services/Experiment/experiments"; +import * as ExperimentService from "hooks/services/Experiment/ExperimentService"; +import { RoutePaths } from "pages/routePaths"; + +import { CloudSettingsRoutes } from "../../settings/routePaths"; + +const mockToggleInviteUsersModalOpen = jest.fn(); +jest.doMock("packages/cloud/services/users/InviteUsersModalService", () => ({ + InviteUsersModalServiceProvider: ({ children }: { children: React.ReactNode }): JSX.Element => <>{children}, + useInviteUsersModalService: () => ({ + toggleInviteUsersModalOpen: mockToggleInviteUsersModalOpen, + }), +})); + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { InviteUsersHint } = require("./InviteUsersHint"); + +const createUseExperimentMock = + (options: { visible?: boolean; linkToUsersPage?: boolean }) => (key: keyof Experiments) => { + switch (key) { + case "connector.inviteUsersHint.visible": + return options.visible ?? false; + case "connector.inviteUsersHint.linkToUsersPage": + return options.linkToUsersPage ?? false; + default: + throw new Error(`${key} is not mocked`); + } + }; + +describe("InviteUsersHint", () => { + beforeEach(() => { + mockToggleInviteUsersModalOpen.mockReset(); + }); + + it("does not render by default", () => { + const { queryByTestId } = render(, { wrapper: TestWrapper }); + expect(queryByTestId("inviteUsersHint")).not.toBeInTheDocument(); + }); + + it("renders when `connector.inviteUserHint.visible` is set to `true`", () => { + jest.spyOn(ExperimentService, "useExperiment").mockImplementation(createUseExperimentMock({ visible: true })); + + const { getByTestId } = render(, { wrapper: TestWrapper }); + const element = getByTestId("inviteUsersHint"); + expect(element).toBeInTheDocument(); + }); + + it("opens modal when clicking on CTA by default", () => { + jest.spyOn(ExperimentService, "useExperiment").mockImplementation(createUseExperimentMock({ visible: true })); + + const { getByTestId } = render(, { wrapper: TestWrapper }); + const element = getByTestId("inviteUsersHint-cta"); + + expect(element).not.toHaveAttribute("href"); + + fireEvent.click(element); + expect(mockToggleInviteUsersModalOpen).toHaveBeenCalledTimes(1); + }); + + it("opens link to access-management settings when clicking on CTA and `connector.inviteUsersHint.linkToUsersPage` is `true`", () => { + jest + .spyOn(ExperimentService, "useExperiment") + .mockImplementation(createUseExperimentMock({ visible: true, linkToUsersPage: true })); + + const { getByTestId } = render(, { wrapper: TestWrapper }); + const element = getByTestId("inviteUsersHint-cta"); + + expect(element).toHaveAttribute("href", `../${RoutePaths.Settings}/${CloudSettingsRoutes.AccessManagement}`); + + fireEvent.click(element); + expect(mockToggleInviteUsersModalOpen).not.toHaveBeenCalled(); + }); +}); diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx new file mode 100644 index 000000000000..606f45481dc3 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx @@ -0,0 +1,67 @@ +import classNames from "classnames"; +import { FormattedMessage, useIntl } from "react-intl"; + +import { Button } from "components/ui/Button"; +import { Text } from "components/ui/Text"; + +import { useExperiment } from "hooks/services/Experiment"; +import { + InviteUsersModalServiceProvider, + useInviteUsersModalService, +} from "packages/cloud/services/users/InviteUsersModalService"; +import { CloudSettingsRoutes } from "packages/cloud/views/settings/routePaths"; +import { RoutePaths } from "pages/routePaths"; + +import styles from "./InviteUsersHint.module.scss"; +import { InviteUsersHintProps } from "./types"; + +const ACCESS_MANAGEMENT_PATH = `../${RoutePaths.Settings}/${CloudSettingsRoutes.AccessManagement}`; + +const InviteUsersHintContent: React.VFC = ({ connectorType }) => { + const { formatMessage } = useIntl(); + const { toggleInviteUsersModalOpen } = useInviteUsersModalService(); + const linkToUsersPage = useExperiment("connector.inviteUsersHint.linkToUsersPage", false); + + const inviteUsersCta = linkToUsersPage ? ( + + + + ) : ( + + ); + + return ( + + {" "} + {inviteUsersCta} + + ); +}; + +export const InviteUsersHint: React.VFC = (props) => { + const isVisible = useExperiment("connector.inviteUsersHint.visible", false); + + return isVisible ? ( + + + + ) : null; +}; diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/index.ts b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/index.ts new file mode 100644 index 000000000000..6bffca09a935 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/index.ts @@ -0,0 +1 @@ +export * from "./InviteUsersHint"; diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/types.ts b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/types.ts new file mode 100644 index 000000000000..2a80eac9d00c --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/types.ts @@ -0,0 +1,3 @@ +export interface InviteUsersHintProps { + connectorType: "source" | "destination"; +} 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 a958a032b432..eb78eef6c241 100644 --- a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx @@ -13,6 +13,7 @@ import { DropDown } from "components/ui/DropDown"; import { Input } from "components/ui/Input"; import { Modal } from "components/ui/Modal"; +import { useNotificationService } from "hooks/services/Notification"; import { useCurrentWorkspace } from "hooks/services/useWorkspace"; import { useUserHook } from "packages/cloud/services/users/UseUserHook"; @@ -59,6 +60,7 @@ export const InviteUsersModal: React.FC<{ const { formatMessage } = useIntl(); const { workspaceId } = useCurrentWorkspace(); const { inviteUserLogic } = useUserHook(); + const { registerNotification } = useNotificationService(); const { mutateAsync: invite } = inviteUserLogic; const isRoleVisible = false; // Temporarily hiding roles because there's only 'Admin' in cloud. @@ -81,7 +83,13 @@ export const InviteUsersModal: React.FC<{ await invite( { users: values.users, workspaceId }, { - onSuccess: () => props.onClose(), + onSuccess: () => { + registerNotification({ + title: formatMessage({ id: "addUsers.success.title" }), + id: "invite-users-success", + }); + props.onClose(); + }, } ); }} diff --git a/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx b/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx index 15f9ab29027d..c36f889e682c 100644 --- a/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx +++ b/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx @@ -1,25 +1,27 @@ import { faPlus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import React from "react"; +import React, { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { CellProps } from "react-table"; -import { useToggle } from "react-use"; -import { H5 } from "components/base/Titles"; import { Button } from "components/ui/Button"; import { Table } from "components/ui/Table"; +import { Text } from "components/ui/Text"; import { useTrackPage, PageTrackingCodes } from "hooks/services/Analytics"; import { useConfirmationModalService } from "hooks/services/ConfirmationModal"; import { useCurrentWorkspace } from "hooks/services/useWorkspace"; import { User } from "packages/cloud/lib/domain/users"; import { useAuthService } from "packages/cloud/services/auth/AuthService"; +import { + InviteUsersModalServiceProvider, + useInviteUsersModalService, +} from "packages/cloud/services/users/InviteUsersModalService"; import { useListUsers, useUserHook } from "packages/cloud/services/users/UseUserHook"; -import { InviteUsersModal } from "packages/cloud/views/users/InviteUsersModal"; import styles from "./UsersSettingsView.module.scss"; -const RemoveUserSection: React.FC<{ workspaceId: string; email: string }> = ({ workspaceId, email }) => { +const RemoveUserSection: React.VFC<{ workspaceId: string; email: string }> = ({ workspaceId, email }) => { const { openConfirmationModal, closeConfirmationModal } = useConfirmationModalService(); const { removeUserLogic } = useUserHook(); const { isLoading, mutate: removeUser } = removeUserLogic; @@ -44,17 +46,32 @@ const RemoveUserSection: React.FC<{ workspaceId: string; email: string }> = ({ w ); }; -export const UsersSettingsView: React.FC = () => { - useTrackPage(PageTrackingCodes.SETTINGS_ACCESS_MANAGEMENT); +const Header: React.VFC = () => { + const { toggleInviteUsersModalOpen } = useInviteUsersModalService(); + return ( +
+ + + + +
+ ); +}; - const [modalIsOpen, toggleModal] = useToggle(false); +export const UsersTable: React.FC = () => { const { workspaceId } = useCurrentWorkspace(); - const users = useListUsers(); - const { user } = useAuthService(); - const columns = React.useMemo( + const columns = useMemo( () => [ { Header: , @@ -96,22 +113,16 @@ export const UsersSettingsView: React.FC = () => { [workspaceId, user] ); + return ; +}; + +export const UsersSettingsView: React.VFC = () => { + useTrackPage(PageTrackingCodes.SETTINGS_ACCESS_MANAGEMENT); + return ( - <> -
-
- -
- -
-
- {modalIsOpen && } - + +
+ + ); }; diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/CreationFormPage/CreationFormPage.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/CreationFormPage/CreationFormPage.tsx index 3bce72196493..e97420b17c60 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/CreationFormPage/CreationFormPage.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/CreationFormPage/CreationFormPage.tsx @@ -3,6 +3,7 @@ import { FormattedMessage } from "react-intl"; import { useLocation, useNavigate } from "react-router-dom"; import { LoadingPage } from "components"; +import { CloudInviteUsersHint } from "components/CloudInviteUsersHint"; import ConnectionBlock from "components/ConnectionBlock"; import { FormPageContent } from "components/ConnectorBlocks"; import { CreateConnectionForm } from "components/CreateConnection/CreateConnectionForm"; @@ -144,6 +145,7 @@ export const CreationFormPage: React.FC = () => { } }} /> + ); } else if (currentEntityStep === EntityStepsTypes.DESTINATION) { @@ -158,6 +160,7 @@ export const CreationFormPage: React.FC = () => { setCurrentStep(StepsTypes.CREATE_CONNECTION); }} /> + ); } diff --git a/airbyte-webapp/src/pages/DestinationPage/pages/CreateDestinationPage/CreateDestinationPage.tsx b/airbyte-webapp/src/pages/DestinationPage/pages/CreateDestinationPage/CreateDestinationPage.tsx index e21148398bc8..f0e800a652d6 100644 --- a/airbyte-webapp/src/pages/DestinationPage/pages/CreateDestinationPage/CreateDestinationPage.tsx +++ b/airbyte-webapp/src/pages/DestinationPage/pages/CreateDestinationPage/CreateDestinationPage.tsx @@ -2,6 +2,7 @@ import React, { useState } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; +import { CloudInviteUsersHint } from "components/CloudInviteUsersHint"; import { FormPageContent } from "components/ConnectorBlocks"; import HeadTitle from "components/HeadTitle"; import { PageHeader } from "components/ui/PageHeader"; @@ -50,6 +51,7 @@ export const CreateDestinationPage: React.FC = () => { destinationDefinitions={destinationDefinitions} hasSuccess={successRequest} /> + diff --git a/airbyte-webapp/src/pages/SourcesPage/pages/CreateSourcePage/CreateSourcePage.tsx b/airbyte-webapp/src/pages/SourcesPage/pages/CreateSourcePage/CreateSourcePage.tsx index 3f6c6e9e7a79..a5fc4ddf9947 100644 --- a/airbyte-webapp/src/pages/SourcesPage/pages/CreateSourcePage/CreateSourcePage.tsx +++ b/airbyte-webapp/src/pages/SourcesPage/pages/CreateSourcePage/CreateSourcePage.tsx @@ -2,6 +2,7 @@ import React, { useState } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; +import { CloudInviteUsersHint } from "components/CloudInviteUsersHint"; import { FormPageContent } from "components/ConnectorBlocks"; import HeadTitle from "components/HeadTitle"; import { PageHeader } from "components/ui/PageHeader"; @@ -47,6 +48,7 @@ const CreateSourcePage: React.FC = () => { } /> +