From 67100efa0eb35159ed4c42b7d4e859a2249a7575 Mon Sep 17 00:00:00 2001 From: Teal Larson Date: Tue, 2 May 2023 12:21:40 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=9F=20=F0=9F=A7=B9=20Source=20and=20De?= =?UTF-8?q?stination=20Pages=20get=20+=20share=20their=20data=20the=20same?= =?UTF-8?q?=20way=20(#6222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Chandler Prall --- .../DestinationItemPage.tsx | 21 +++--- .../destination/DestinationOverviewPage.tsx | 5 +- .../DestinationSettingsPage.tsx | 35 ++++++---- airbyte-webapp/src/pages/destination/types.ts | 5 -- .../useGetDestinationFromParams.tsx | 23 +++++++ airbyte-webapp/src/pages/routePaths.tsx | 4 +- .../source/SourceItemPage/SourceItemPage.tsx | 68 ++++++++++--------- .../SourceOverviewPage/SourceOverviewPage.tsx | 11 ++- .../sourceOverviewContext.ts | 25 ------- .../useGetSourceFromParams.tsx | 22 ++++++ .../SourceSettingsPage/SourceSettingsPage.tsx | 67 +++++++++--------- 11 files changed, 161 insertions(+), 125 deletions(-) delete mode 100644 airbyte-webapp/src/pages/destination/types.ts create mode 100644 airbyte-webapp/src/pages/destination/useGetDestinationFromParams.tsx delete mode 100644 airbyte-webapp/src/pages/source/SourceOverviewPage/sourceOverviewContext.ts create mode 100644 airbyte-webapp/src/pages/source/SourceOverviewPage/useGetSourceFromParams.tsx diff --git a/airbyte-webapp/src/pages/destination/DestinationItemPage/DestinationItemPage.tsx b/airbyte-webapp/src/pages/destination/DestinationItemPage/DestinationItemPage.tsx index f4e4907823b..f6b097cb1a1 100644 --- a/airbyte-webapp/src/pages/destination/DestinationItemPage/DestinationItemPage.tsx +++ b/airbyte-webapp/src/pages/destination/DestinationItemPage/DestinationItemPage.tsx @@ -1,6 +1,6 @@ -import React, { Suspense, useMemo } from "react"; +import React, { Suspense } from "react"; import { useIntl } from "react-intl"; -import { Outlet, useNavigate, useParams } from "react-router-dom"; +import { Outlet, useNavigate } from "react-router-dom"; import { LoadingPage } from "components"; import { ApiErrorBoundary } from "components/common/ApiErrorBoundary"; @@ -13,22 +13,24 @@ import { PageHeader } from "components/ui/PageHeader"; import { useTrackPage, PageTrackingCodes } from "hooks/services/Analytics"; import { useAppMonitoringService } from "hooks/services/AppMonitoringService"; import { useExperiment } from "hooks/services/Experiment"; -import { useGetDestination } from "hooks/services/useDestinationHook"; import { ResourceNotFoundErrorBoundary } from "views/common/ResourceNotFoundErrorBoundary"; import { StartOverErrorView } from "views/common/StartOverErrorView"; import { ConnectorDocumentationWrapper } from "views/Connector/ConnectorDocumentationLayout"; +import { useGetDestinationFromParams, useGetDestinationTabFromParams } from "../useGetDestinationFromParams"; + export const DestinationItemPage: React.FC = () => { useTrackPage(PageTrackingCodes.DESTINATION_ITEM); - const params = useParams() as { "*": StepsTypes | ""; id: string }; - const navigate = useNavigate(); + const destination = useGetDestinationFromParams(); + const { formatMessage } = useIntl(); const isNewConnectionFlowEnabled = useExperiment("connection.updatedConnectionFlow", false); - const currentStep = useMemo(() => (params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]), [params]); - const { trackError } = useAppMonitoringService(); + const currentStep = useGetDestinationTabFromParams(); - const destination = useGetDestination(params.id); + const { trackError } = useAppMonitoringService(); + // can be removed after flag enabled for all users + const navigate = useNavigate(); const onSelectStep = (id: string) => { const path = id === StepsTypes.OVERVIEW ? "." : id.toLowerCase(); navigate(path); @@ -41,6 +43,7 @@ export const DestinationItemPage: React.FC = () => { }, { label: destination.name }, ]; + // to here return ( } trackError={trackError}> @@ -56,7 +59,7 @@ export const DestinationItemPage: React.FC = () => { }> - + diff --git a/airbyte-webapp/src/pages/destination/DestinationOverviewPage.tsx b/airbyte-webapp/src/pages/destination/DestinationOverviewPage.tsx index 9556e5607e5..2e4cdc7c783 100644 --- a/airbyte-webapp/src/pages/destination/DestinationOverviewPage.tsx +++ b/airbyte-webapp/src/pages/destination/DestinationOverviewPage.tsx @@ -1,6 +1,5 @@ import { useMemo } from "react"; import { useNavigate } from "react-router-dom"; -import { useOutletContext } from "react-router-dom"; import { ConnectorIcon } from "components/common/ConnectorIcon"; import { TableItemTitle } from "components/ConnectorBlocks"; @@ -13,12 +12,12 @@ import { useSourceList } from "hooks/services/useSourceHook"; import { RoutePaths } from "pages/routePaths"; import { useDestinationDefinition } from "services/connector/DestinationDefinitionService"; -import { DestinationOutletContext } from "./types"; +import { useGetDestinationFromParams } from "./useGetDestinationFromParams"; export const DestinationOverviewPage = () => { const navigate = useNavigate(); - const { destination } = useOutletContext(); + const destination = useGetDestinationFromParams(); const destinationDefinition = useDestinationDefinition(destination.destinationDefinitionId); // We load only connections attached to this destination to be shown in the connections grid const { connections } = useConnectionList({ destinationId: [destination.destinationId] }); diff --git a/airbyte-webapp/src/pages/destination/DestinationSettingsPage/DestinationSettingsPage.tsx b/airbyte-webapp/src/pages/destination/DestinationSettingsPage/DestinationSettingsPage.tsx index ef34bb38441..6d1cb452c5b 100644 --- a/airbyte-webapp/src/pages/destination/DestinationSettingsPage/DestinationSettingsPage.tsx +++ b/airbyte-webapp/src/pages/destination/DestinationSettingsPage/DestinationSettingsPage.tsx @@ -1,6 +1,8 @@ import React, { useCallback, useMemo } from "react"; import { FormattedMessage } from "react-intl"; -import { useOutletContext } from "react-router-dom"; + +import { Box } from "components/ui/Box"; +import { Text } from "components/ui/Text"; import { useTrackPage, PageTrackingCodes } from "hooks/services/Analytics"; import { useFormChangeTrackerService, useUniqueFormId } from "hooks/services/FormChangeTracker"; @@ -17,16 +19,17 @@ import { ConnectorCard } from "views/Connector/ConnectorCard"; import { ConnectorCardValues } from "views/Connector/ConnectorForm/types"; import styles from "./DestinationSettings.module.scss"; -import { DestinationOutletContext } from "../types"; +import { useGetDestinationFromParams } from "../useGetDestinationFromParams"; export const DestinationSettingsPage: React.FC = () => { - const { destination } = useOutletContext(); + const destination = useGetDestinationFromParams(); + const { connections: connectionsWithDestination } = useConnectionList({ destinationId: [destination.destinationId] }); + const destinationDefinition = useDestinationDefinition(destination.destinationDefinitionId); const destinationSpecification = useGetDestinationDefinitionSpecification( destination.destinationDefinitionId, destination.destinationId ); - const destinationDefinition = useDestinationDefinition(destination.destinationDefinitionId); const reloadDestination = useInvalidateDestination(destination.destinationId); const { mutateAsync: updateDestination } = useUpdateDestination(); const { mutateAsync: deleteDestination } = useDeleteDestination(); @@ -55,17 +58,19 @@ export const DestinationSettingsPage: React.FC = () => { return null; } return ( -

- - {connectionsWithDestination.map((connection) => ( - - - {`${connection.name}\n`} - - ))} -

+ + + + +
    + {connectionsWithDestination.map((connection) => ( +
  • {connection.name}
  • + ))} +
+
); }, [connectionsWithDestination]); diff --git a/airbyte-webapp/src/pages/destination/types.ts b/airbyte-webapp/src/pages/destination/types.ts deleted file mode 100644 index c84baf79e2d..00000000000 --- a/airbyte-webapp/src/pages/destination/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { DestinationRead } from "core/request/AirbyteClient"; - -export interface DestinationOutletContext { - destination: DestinationRead; -} diff --git a/airbyte-webapp/src/pages/destination/useGetDestinationFromParams.tsx b/airbyte-webapp/src/pages/destination/useGetDestinationFromParams.tsx new file mode 100644 index 00000000000..58cd8cdd97e --- /dev/null +++ b/airbyte-webapp/src/pages/destination/useGetDestinationFromParams.tsx @@ -0,0 +1,23 @@ +import { useMemo } from "react"; +import { useParams } from "react-router-dom"; + +import { StepsTypes } from "components/ConnectorBlocks"; + +import { useGetDestination } from "hooks/services/useDestinationHook"; + +export const useGetDestinationFromParams = () => { + const params = useParams<{ "*": StepsTypes | "" | undefined; destinationId: string }>(); + if (!params.destinationId) { + throw new Error("Destination id is missing"); + } + + return useGetDestination(params.destinationId); +}; + +export const useGetDestinationTabFromParams = () => { + const params = useParams<{ "*": StepsTypes | "" | undefined; destinationId: string }>(); + + return useMemo(() => { + return params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]; + }, [params]); +}; diff --git a/airbyte-webapp/src/pages/routePaths.tsx b/airbyte-webapp/src/pages/routePaths.tsx index cddfb797c9f..3047e4fb74d 100644 --- a/airbyte-webapp/src/pages/routePaths.tsx +++ b/airbyte-webapp/src/pages/routePaths.tsx @@ -20,13 +20,13 @@ export enum RoutePaths { } export enum DestinationPaths { - Root = ":id/*", // currently our tabs rely on this * wildcard to detect which tab is currently active + Root = ":destinationId/*", // currently our tabs rely on this * wildcard to detect which tab is currently active Settings = "settings", NewDestination = "new-destination", } export enum SourcePaths { - Root = ":id/*", // currently our tabs rely on this * wildcard to detect which tab is currently active + Root = ":sourceId/*", // currently our tabs rely on this * wildcard to detect which tab is currently active Settings = "settings", NewSource = "new-source", } diff --git a/airbyte-webapp/src/pages/source/SourceItemPage/SourceItemPage.tsx b/airbyte-webapp/src/pages/source/SourceItemPage/SourceItemPage.tsx index 9a413bf9b5f..a7d9cd2eba6 100644 --- a/airbyte-webapp/src/pages/source/SourceItemPage/SourceItemPage.tsx +++ b/airbyte-webapp/src/pages/source/SourceItemPage/SourceItemPage.tsx @@ -1,6 +1,6 @@ -import React, { Suspense, useMemo } from "react"; +import React, { Suspense } from "react"; import { useIntl } from "react-intl"; -import { Outlet, useNavigate, useParams } from "react-router-dom"; +import { Outlet, useNavigate } from "react-router-dom"; import { ApiErrorBoundary } from "components/common/ApiErrorBoundary"; import { HeadTitle } from "components/common/HeadTitle"; @@ -11,53 +11,59 @@ import { Breadcrumbs } from "components/ui/Breadcrumbs"; import { PageHeader } from "components/ui/PageHeader"; import { useTrackPage, PageTrackingCodes } from "hooks/services/Analytics"; +import { useAppMonitoringService } from "hooks/services/AppMonitoringService"; import { useExperiment } from "hooks/services/Experiment"; +import { ResourceNotFoundErrorBoundary } from "views/common/ResourceNotFoundErrorBoundary"; +import { StartOverErrorView } from "views/common/StartOverErrorView"; import { ConnectorDocumentationWrapper } from "views/Connector/ConnectorDocumentationLayout"; -import { useSetupSourceOverviewContext } from "../SourceOverviewPage/sourceOverviewContext"; +import { useGetSourceFromParams, useGetSourceTabFromParams } from "../SourceOverviewPage/useGetSourceFromParams"; export const SourceItemPage: React.FC = () => { useTrackPage(PageTrackingCodes.SOURCE_ITEM); - const params = useParams<{ "*": StepsTypes | "" | undefined; id: string }>(); + const source = useGetSourceFromParams(); + + // from here to the below comment can be removed when flag for new connection flow is on const navigate = useNavigate(); const { formatMessage } = useIntl(); - const isNewConnectionFlowEnabled = useExperiment("connection.updatedConnectionFlow", false); - - const currentStep = useMemo( - () => (params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]), - [params] - ); - const { source, sourceDefinition, connections } = useSetupSourceOverviewContext(params.id ?? ""); + const onSelectStep = (id: string) => { + const path = id === StepsTypes.OVERVIEW ? "." : id.toLowerCase(); + navigate(path); + }; const breadcrumbsData = [ { - label: formatMessage({ id: "sidebar.sources" }), + label: formatMessage({ id: "admin.sources" }), to: "..", }, { label: source.name }, ]; + // to here - const onSelectStep = (id: string) => { - const path = id === StepsTypes.OVERVIEW ? "." : id.toLowerCase(); - navigate(path); - }; + const isNewConnectionFlowEnabled = useExperiment("connection.updatedConnectionFlow", false); + + const currentStep = useGetSourceTabFromParams(); + + const { trackError } = useAppMonitoringService(); return ( - - - } - middleComponent={ - !isNewConnectionFlowEnabled && - } - /> - {isNewConnectionFlowEnabled && } - }> - - - - - + } trackError={trackError}> + + + } + middleComponent={ + !isNewConnectionFlowEnabled && + } + /> + {isNewConnectionFlowEnabled && } + }> + + + + + + ); }; diff --git a/airbyte-webapp/src/pages/source/SourceOverviewPage/SourceOverviewPage.tsx b/airbyte-webapp/src/pages/source/SourceOverviewPage/SourceOverviewPage.tsx index 00a8ba21bbb..9a3a610ac3e 100644 --- a/airbyte-webapp/src/pages/source/SourceOverviewPage/SourceOverviewPage.tsx +++ b/airbyte-webapp/src/pages/source/SourceOverviewPage/SourceOverviewPage.tsx @@ -6,14 +6,21 @@ import { TableItemTitle } from "components/ConnectorBlocks"; import Placeholder, { ResourceTypes } from "components/Placeholder"; import { DropdownMenuOptionType } from "components/ui/DropdownMenu"; +import { useConnectionList } from "hooks/services/useConnectionHook"; import { useDestinationList } from "hooks/services/useDestinationHook"; import { RoutePaths } from "pages/routePaths"; +import { useSourceDefinition } from "services/connector/SourceDefinitionService"; + +import { useGetSourceFromParams } from "./useGetSourceFromParams"; -import { useSourceOverviewContext } from "./sourceOverviewContext"; const SourceConnectionTable = React.lazy(() => import("./SourceConnectionTable")); export const SourceOverviewPage = () => { - const { source, sourceDefinition, connections } = useSourceOverviewContext(); + const source = useGetSourceFromParams(); + + const sourceDefinition = useSourceDefinition(source.sourceDefinitionId); + const { connections } = useConnectionList({ sourceId: [source.sourceId] }); + // We load all destinations so the add destination button has a pre-filled list of options. const { destinations } = useDestinationList(); diff --git a/airbyte-webapp/src/pages/source/SourceOverviewPage/sourceOverviewContext.ts b/airbyte-webapp/src/pages/source/SourceOverviewPage/sourceOverviewContext.ts deleted file mode 100644 index 5f9627ddbf0..00000000000 --- a/airbyte-webapp/src/pages/source/SourceOverviewPage/sourceOverviewContext.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { useOutletContext } from "react-router-dom"; - -import { SourceDefinitionRead, SourceRead, WebBackendConnectionListItem } from "core/request/AirbyteClient"; -import { useConnectionList } from "hooks/services/useConnectionHook"; -import { useGetSource } from "hooks/services/useSourceHook"; -import { useSourceDefinition } from "services/connector/SourceDefinitionService"; - -interface SourceOverviewContext { - source: SourceRead; - sourceDefinition: SourceDefinitionRead; - connections: WebBackendConnectionListItem[]; -} - -export const useSourceOverviewContext = () => { - return useOutletContext(); -}; - -export const useSetupSourceOverviewContext = (id: string): SourceOverviewContext => { - const source = useGetSource(id); - const sourceDefinition = useSourceDefinition(source.sourceDefinitionId); - // We load only connections attached to this source to be shown in the connections grid - const { connections } = useConnectionList({ sourceId: [source.sourceId] }); - - return { source, sourceDefinition, connections }; -}; diff --git a/airbyte-webapp/src/pages/source/SourceOverviewPage/useGetSourceFromParams.tsx b/airbyte-webapp/src/pages/source/SourceOverviewPage/useGetSourceFromParams.tsx new file mode 100644 index 00000000000..deb4096ffa3 --- /dev/null +++ b/airbyte-webapp/src/pages/source/SourceOverviewPage/useGetSourceFromParams.tsx @@ -0,0 +1,22 @@ +import { useMemo } from "react"; +import { useParams } from "react-router-dom"; + +import { StepsTypes } from "components/ConnectorBlocks"; + +import { useGetSource } from "hooks/services/useSourceHook"; + +export const useGetSourceFromParams = () => { + const params = useParams<{ "*": StepsTypes | "" | undefined; sourceId: string }>(); + if (!params.sourceId) { + throw new Error("Source id is missing"); + } + return useGetSource(params.sourceId); +}; + +export const useGetSourceTabFromParams = () => { + const params = useParams<{ "*": StepsTypes | "" | undefined; sourceId: string }>(); + + return useMemo(() => { + return params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]; + }, [params]); +}; diff --git a/airbyte-webapp/src/pages/source/SourceSettingsPage/SourceSettingsPage.tsx b/airbyte-webapp/src/pages/source/SourceSettingsPage/SourceSettingsPage.tsx index e183c5ad197..4ff08b09a13 100644 --- a/airbyte-webapp/src/pages/source/SourceSettingsPage/SourceSettingsPage.tsx +++ b/airbyte-webapp/src/pages/source/SourceSettingsPage/SourceSettingsPage.tsx @@ -1,43 +1,37 @@ -import React, { useCallback, useEffect, useMemo } from "react"; +import React, { useCallback, useMemo } from "react"; import { FormattedMessage } from "react-intl"; -import { ConnectionConfiguration } from "core/domain/connection"; +import { Box } from "components/ui/Box"; +import { Text } from "components/ui/Text"; + import { useTrackPage, PageTrackingCodes } from "hooks/services/Analytics"; import { useFormChangeTrackerService, useUniqueFormId } from "hooks/services/FormChangeTracker"; +import { useConnectionList } from "hooks/services/useConnectionHook"; import { useDeleteSource, useInvalidateSource, useUpdateSource } from "hooks/services/useSourceHook"; import { useDeleteModal } from "hooks/useDeleteModal"; +import { useSourceDefinition } from "services/connector/SourceDefinitionService"; import { useGetSourceDefinitionSpecification } from "services/connector/SourceDefinitionSpecificationService"; import { ConnectorCard } from "views/Connector/ConnectorCard"; -import { useDocumentationPanelContext } from "views/Connector/ConnectorDocumentationLayout/DocumentationPanelContext"; +import { ConnectorCardValues } from "views/Connector/ConnectorForm"; import styles from "./SourceSettingsPage.module.scss"; -import { useSourceOverviewContext } from "../SourceOverviewPage/sourceOverviewContext"; +import { useGetSourceFromParams } from "../SourceOverviewPage/useGetSourceFromParams"; export const SourceSettingsPage: React.FC = () => { + const source = useGetSourceFromParams(); + const { connections: connectionsWithSource } = useConnectionList({ sourceId: [source.sourceId] }); + const sourceDefinition = useSourceDefinition(source.sourceDefinitionId); + const sourceDefinitionSpecification = useGetSourceDefinitionSpecification(source.sourceDefinitionId, source.sourceId); + + const reloadSource = useInvalidateSource(source.sourceId); const { mutateAsync: updateSource } = useUpdateSource(); const { mutateAsync: deleteSource } = useDeleteSource(); - const { setDocumentationPanelOpen } = useDocumentationPanelContext(); const formId = useUniqueFormId(); const { clearFormChange } = useFormChangeTrackerService(); - const { source, sourceDefinition, connections } = useSourceOverviewContext(); - useTrackPage(PageTrackingCodes.SOURCE_ITEM_SETTINGS); - useEffect(() => { - return () => { - setDocumentationPanelOpen(false); - }; - }, [setDocumentationPanelOpen]); - const sourceDefinitionSpecification = useGetSourceDefinitionSpecification(source.sourceDefinitionId, source.sourceId); - - const reloadSource = useInvalidateSource(source.sourceId); - - const onSubmit = async (values: { - name: string; - serviceType: string; - connectionConfiguration?: ConnectionConfiguration; - }) => { + const onSubmit = async (values: ConnectorCardValues) => { await updateSource({ values, sourceId: source.sourceId, @@ -46,24 +40,31 @@ export const SourceSettingsPage: React.FC = () => { const onDelete = useCallback(async () => { clearFormChange(formId); - await deleteSource({ connectionsWithSource: connections, source }); - }, [clearFormChange, connections, source, deleteSource, formId]); + await deleteSource({ connectionsWithSource, source }); + }, [clearFormChange, formId, deleteSource, connectionsWithSource, source]); const modalAdditionalContent = useMemo(() => { - if (connections.length === 0) { + if (connectionsWithSource.length === 0) { return null; } + return ( -

- - {connections.map((connection) => ( - - - {`${connection.name}\n`} - - ))} -

+ + + + + +
    + {connectionsWithSource.map((connection) => ( +
  • {`${connection.name}`}
  • + ))} +
+
); - }, [connections]); + }, [connectionsWithSource]); const onDeleteClick = useDeleteModal("source", onDelete, modalAdditionalContent);