From 56af26cbfb045b0ab6fad4cb095c7400ae523337 Mon Sep 17 00:00:00 2001 From: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com> Date: Thu, 21 Apr 2022 14:11:45 -0400 Subject: [PATCH] Add confirmation modal when navigating from modified source or destination settings pages (#12186) Add routes to destinations and source settings pages Ensure ServiceForm is reset with updated values on successful save --- .../components/ConnectorBlocks/ItemTabs.tsx | 8 +- .../pages/DestinationPage/DestinationPage.tsx | 2 +- .../DestinationItemPage.tsx | 75 +++++++++++-------- .../components/DestinationConnectionTable.tsx | 2 +- .../src/pages/SourcesPage/SourcesPage.tsx | 2 +- .../pages/SourceItemPage/SourceItemPage.tsx | 68 +++++++++-------- .../components/SourceConnectionTable.tsx | 2 +- .../Connector/ServiceForm/ServiceForm.tsx | 25 +++++-- 8 files changed, 108 insertions(+), 76 deletions(-) diff --git a/airbyte-webapp/src/components/ConnectorBlocks/ItemTabs.tsx b/airbyte-webapp/src/components/ConnectorBlocks/ItemTabs.tsx index 41f6a5e96132..11049091ba7b 100644 --- a/airbyte-webapp/src/components/ConnectorBlocks/ItemTabs.tsx +++ b/airbyte-webapp/src/components/ConnectorBlocks/ItemTabs.tsx @@ -4,14 +4,14 @@ import { FormattedMessage } from "react-intl"; import StepsMenu from "components/StepsMenu"; export enum StepsTypes { - OVERVIEW = "Overview", - SETTINGS = "Settings", + OVERVIEW = "overview", + SETTINGS = "settings", } -type IProps = { +interface IProps { currentStep: string; setCurrentStep: (step: string) => void; -}; +} const steps = [ { diff --git a/airbyte-webapp/src/pages/DestinationPage/DestinationPage.tsx b/airbyte-webapp/src/pages/DestinationPage/DestinationPage.tsx index 8642eb3405e7..47c756200191 100644 --- a/airbyte-webapp/src/pages/DestinationPage/DestinationPage.tsx +++ b/airbyte-webapp/src/pages/DestinationPage/DestinationPage.tsx @@ -16,7 +16,7 @@ const DestinationsPage: React.FC = () => { } /> } /> }> diff --git a/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/DestinationItemPage.tsx b/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/DestinationItemPage.tsx index d503ef97ee65..4b46f9c4e75c 100644 --- a/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/DestinationItemPage.tsx +++ b/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/DestinationItemPage.tsx @@ -1,5 +1,6 @@ -import React, { Suspense, useMemo, useState } from "react"; +import React, { Suspense, useMemo } from "react"; import { FormattedMessage } from "react-intl"; +import { Route, Routes } from "react-router-dom"; import Placeholder, { ResourceTypes } from "components/Placeholder"; import Breadcrumbs from "components/Breadcrumbs"; @@ -21,9 +22,8 @@ import DestinationSettings from "./components/DestinationSettings"; import DestinationConnectionTable from "./components/DestinationConnectionTable"; const DestinationItemPage: React.FC = () => { - const { params, push } = useRouter(); - const [currentStep, setCurrentStep] = useState(StepsTypes.OVERVIEW); - const onSelectStep = (id: string) => setCurrentStep(id); + const { params, push } = useRouter(); + const currentStep = useMemo(() => (params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]), [params]); const { sources } = useSourceList(); @@ -37,6 +37,11 @@ const DestinationItemPage: React.FC = () => { const onClickBack = () => push(".."); + const onSelectStep = (id: string) => { + const path = id === StepsTypes.OVERVIEW ? "/" : `/${id.toLowerCase()}`; + push(`/destination/${destination.destinationId}${path}`); + }; + const breadcrumbsData = [ { name: , @@ -75,33 +80,6 @@ const DestinationItemPage: React.FC = () => { push(path, { state }); }; - const renderContent = () => { - if (currentStep === StepsTypes.SETTINGS) { - return ( - - ); - } - - return ( - <> - - {connectionsWithDestination.length ? ( - - ) : ( - - )} - - ); - }; - return ( } @@ -113,7 +91,40 @@ const DestinationItemPage: React.FC = () => { /> } > - }>{renderContent()} + }> + + + } + /> + + + {connectionsWithDestination.length ? ( + + ) : ( + + )} + + } + /> + + ); }; diff --git a/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/components/DestinationConnectionTable.tsx b/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/components/DestinationConnectionTable.tsx index 8f0205639c1c..8d29eece9a03 100644 --- a/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/components/DestinationConnectionTable.tsx +++ b/airbyte-webapp/src/pages/DestinationPage/pages/DestinationItemPage/components/DestinationConnectionTable.tsx @@ -45,7 +45,7 @@ const DestinationConnectionTable: React.FC = ({ connections }) => { [connections, syncManualConnection] ); - const clickRow = (source: ITableDataItem) => push(`../../${RoutePaths.Connections}/${source.connectionId}`); + const clickRow = (source: ITableDataItem) => push(`../../../${RoutePaths.Connections}/${source.connectionId}`); return ( ( } /> } /> }> diff --git a/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/SourceItemPage.tsx b/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/SourceItemPage.tsx index 52a299973f1e..767cca109381 100644 --- a/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/SourceItemPage.tsx +++ b/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/SourceItemPage.tsx @@ -1,5 +1,6 @@ -import React, { Suspense, useMemo, useState } from "react"; +import React, { Suspense, useMemo } from "react"; import { FormattedMessage } from "react-intl"; +import { Route, Routes } from "react-router-dom"; import { DropDownRow } from "components"; import PageTitle from "components/PageTitle"; @@ -24,9 +25,8 @@ import SourceSettings from "./components/SourceSettings"; import SourceConnectionTable from "./components/SourceConnectionTable"; const SourceItemPage: React.FC = () => { - const { query, push } = useRouter<{ id: string }>(); - const [currentStep, setCurrentStep] = useState(StepsTypes.OVERVIEW); - const onSelectStep = (id: string) => setCurrentStep(id); + const { query, params, push } = useRouter<{ id: string }, { id: string; "*": string }>(); + const currentStep = useMemo(() => (params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]), [params]); const { destinations } = useDestinationList(); @@ -62,6 +62,11 @@ const SourceItemPage: React.FC = () => { [destinations, destinationDefinitions] ); + const onSelectStep = (id: string) => { + const path = id === StepsTypes.OVERVIEW ? "/" : `/${id.toLowerCase()}`; + push(`/source/${source.sourceId}${path}`); + }; + const onSelect = (data: DropDownRow.IDataItem) => { const path = `../${RoutePaths.ConnectionNew}`; const state = @@ -75,31 +80,6 @@ const SourceItemPage: React.FC = () => { push(path, { state }); }; - const renderContent = () => { - if (currentStep === StepsTypes.SETTINGS) { - return ; - } - - return ( - <> - - {connectionsWithSource.length ? ( - - ) : ( - - )} - - ); - }; - return ( } @@ -111,7 +91,35 @@ const SourceItemPage: React.FC = () => { /> } > - }>{renderContent()} + }> + + } + /> + + + {connectionsWithSource.length ? ( + + ) : ( + + )} + + } + > + + ); }; diff --git a/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/components/SourceConnectionTable.tsx b/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/components/SourceConnectionTable.tsx index 8531befbdeef..8b2be3641546 100644 --- a/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/components/SourceConnectionTable.tsx +++ b/airbyte-webapp/src/pages/SourcesPage/pages/SourceItemPage/components/SourceConnectionTable.tsx @@ -46,7 +46,7 @@ const SourceConnectionTable: React.FC = ({ connections }) => { [connections, syncManualConnection] ); - const clickRow = (source: ITableDataItem) => push(`../../${RoutePaths.Connections}/${source.connectionId}`); + const clickRow = (source: ITableDataItem) => push(`../../../${RoutePaths.Connections}/${source.connectionId}`); return ( = ({ schema }) => { const { widgetsInfo } = useServiceForm(); - const { values, setFieldValue } = useFormikContext(); + const { values, resetForm } = useFormikContext(); const valueRef = useRef(); valueRef.current = values.connectionConfiguration; @@ -53,7 +56,12 @@ const PatchInitialValuesWithWidgetConfig: React.FC<{ .filter(([k, v]) => isDefined(v.default) && !isDefined(getIn(constPatchedValues, k))) .reduce((acc, [k, v]) => setIn(acc, k, v.default), constPatchedValues); - setFieldValue("connectionConfiguration", defaultPatchedValues); + resetForm({ + values: { + ...values, + connectionConfiguration: defaultPatchedValues, + }, + }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [schema]); @@ -99,6 +107,9 @@ export type ServiceFormProps = { }; const ServiceForm: React.FC = (props) => { + const formId = useUniqueFormId(); + const { clearFormChange } = useFormChangeTrackerService(); + const [isOpenRequestModal, toggleOpenRequestModal] = useToggle(false); const [initialRequestName, setInitialRequestName] = useState(); const { @@ -178,12 +189,13 @@ const ServiceForm: React.FC = (props) => { ); const onFormSubmit = useCallback( - async (values) => { + async (values: ServiceFormValues) => { const valuesToSend = getValues(values); + await onSubmit(valuesToSend); - return onSubmit(valuesToSend); + clearFormChange(formId); }, - [getValues, onSubmit] + [clearFormChange, formId, getValues, onSubmit] ); return ( @@ -194,7 +206,7 @@ const ServiceForm: React.FC = (props) => { validationSchema={validationSchema} onSubmit={onFormSubmit} > - {() => ( + {({ dirty }) => ( = (props) => { > {!props.isEditMode && } +