Skip to content

Commit

Permalink
Add confirmation modal when navigating from modified source or destin…
Browse files Browse the repository at this point in the history
…ation settings pages (#12186)

Add routes to destinations and source settings pages
Ensure ServiceForm is reset with updated values on successful save
  • Loading branch information
edmundito authored Apr 21, 2022
1 parent 8cf4569 commit 56af26c
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 76 deletions.
8 changes: 4 additions & 4 deletions airbyte-webapp/src/components/ConnectorBlocks/ItemTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const DestinationsPage: React.FC = () => {
<Route path={RoutePaths.DestinationNew} element={<CreateDestinationPage />} />
<Route path={RoutePaths.ConnectionNew} element={<CreationFormPage />} />
<Route
path=":id"
path=":id/*"
element={
<ResourceNotFoundErrorBoundary errorComponent={<StartOverErrorView />}>
<DestinationItemPage />
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -21,9 +22,8 @@ import DestinationSettings from "./components/DestinationSettings";
import DestinationConnectionTable from "./components/DestinationConnectionTable";

const DestinationItemPage: React.FC = () => {
const { params, push } = useRouter<unknown, { id: string }>();
const [currentStep, setCurrentStep] = useState<string>(StepsTypes.OVERVIEW);
const onSelectStep = (id: string) => setCurrentStep(id);
const { params, push } = useRouter<unknown, { id: string; "*": string }>();
const currentStep = useMemo<string>(() => (params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]), [params]);

const { sources } = useSourceList();

Expand All @@ -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: <FormattedMessage id="admin.destinations" />,
Expand Down Expand Up @@ -75,33 +80,6 @@ const DestinationItemPage: React.FC = () => {
push(path, { state });
};

const renderContent = () => {
if (currentStep === StepsTypes.SETTINGS) {
return (
<DestinationSettings currentDestination={destination} connectionsWithDestination={connectionsWithDestination} />
);
}

return (
<>
<TableItemTitle
type="source"
dropDownData={sourcesDropDownData}
onSelect={onSelect}
entityName={destination.name}
entity={destination.destinationName}
entityIcon={destinationDefinition.icon ? getIcon(destinationDefinition.icon) : null}
releaseStage={destinationDefinition.releaseStage}
/>
{connectionsWithDestination.length ? (
<DestinationConnectionTable connections={connectionsWithDestination} />
) : (
<Placeholder resource={ResourceTypes.Sources} />
)}
</>
);
};

return (
<MainPageWithScroll
headTitle={<HeadTitle titles={[{ id: "admin.destinations" }, { title: destination.name }]} />}
Expand All @@ -113,7 +91,40 @@ const DestinationItemPage: React.FC = () => {
/>
}
>
<Suspense fallback={<LoadingPage />}>{renderContent()}</Suspense>
<Suspense fallback={<LoadingPage />}>
<Routes>
<Route
path="/settings"
element={
<DestinationSettings
currentDestination={destination}
connectionsWithDestination={connectionsWithDestination}
/>
}
/>
<Route
index
element={
<>
<TableItemTitle
type="source"
dropDownData={sourcesDropDownData}
onSelect={onSelect}
entityName={destination.name}
entity={destination.destinationName}
entityIcon={destinationDefinition.icon ? getIcon(destinationDefinition.icon) : null}
releaseStage={destinationDefinition.releaseStage}
/>
{connectionsWithDestination.length ? (
<DestinationConnectionTable connections={connectionsWithDestination} />
) : (
<Placeholder resource={ResourceTypes.Sources} />
)}
</>
}
/>
</Routes>
</Suspense>
</MainPageWithScroll>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const DestinationConnectionTable: React.FC<IProps> = ({ connections }) => {
[connections, syncManualConnection]
);

const clickRow = (source: ITableDataItem) => push(`../../${RoutePaths.Connections}/${source.connectionId}`);
const clickRow = (source: ITableDataItem) => push(`../../../${RoutePaths.Connections}/${source.connectionId}`);

return (
<ConnectionTable
Expand Down
2 changes: 1 addition & 1 deletion airbyte-webapp/src/pages/SourcesPage/SourcesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const SourcesPage: React.FC = () => (
<Route path={RoutePaths.SourceNew} element={<CreateSourcePage />} />
<Route path={RoutePaths.ConnectionNew} element={<CreationFormPage />} />
<Route
path=":id"
path=":id/*"
element={
<ResourceNotFoundErrorBoundary errorComponent={<StartOverErrorView />}>
<SourceItemPage />
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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<string>(StepsTypes.OVERVIEW);
const onSelectStep = (id: string) => setCurrentStep(id);
const { query, params, push } = useRouter<{ id: string }, { id: string; "*": string }>();
const currentStep = useMemo<string>(() => (params["*"] === "" ? StepsTypes.OVERVIEW : params["*"]), [params]);

const { destinations } = useDestinationList();

Expand Down Expand Up @@ -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 =
Expand All @@ -75,31 +80,6 @@ const SourceItemPage: React.FC = () => {
push(path, { state });
};

const renderContent = () => {
if (currentStep === StepsTypes.SETTINGS) {
return <SourceSettings currentSource={source} connectionsWithSource={connectionsWithSource} />;
}

return (
<>
<TableItemTitle
type="destination"
dropDownData={destinationsDropDownData}
onSelect={onSelect}
entity={source.sourceName}
entityName={source.name}
entityIcon={sourceDefinition ? getIcon(sourceDefinition.icon) : null}
releaseStage={sourceDefinition.releaseStage}
/>
{connectionsWithSource.length ? (
<SourceConnectionTable connections={connectionsWithSource} />
) : (
<Placeholder resource={ResourceTypes.Destinations} />
)}
</>
);
};

return (
<MainPageWithScroll
headTitle={<HeadTitle titles={[{ id: "admin.sources" }, { title: source.name }]} />}
Expand All @@ -111,7 +91,35 @@ const SourceItemPage: React.FC = () => {
/>
}
>
<Suspense fallback={<LoadingPage />}>{renderContent()}</Suspense>
<Suspense fallback={<LoadingPage />}>
<Routes>
<Route
path="/settings"
element={<SourceSettings currentSource={source} connectionsWithSource={connectionsWithSource} />}
/>
<Route
index
element={
<>
<TableItemTitle
type="destination"
dropDownData={destinationsDropDownData}
onSelect={onSelect}
entity={source.sourceName}
entityName={source.name}
entityIcon={sourceDefinition ? getIcon(sourceDefinition.icon) : null}
releaseStage={sourceDefinition.releaseStage}
/>
{connectionsWithSource.length ? (
<SourceConnectionTable connections={connectionsWithSource} />
) : (
<Placeholder resource={ResourceTypes.Destinations} />
)}
</>
}
></Route>
</Routes>
</Suspense>
</MainPageWithScroll>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const SourceConnectionTable: React.FC<IProps> = ({ connections }) => {
[connections, syncManualConnection]
);

const clickRow = (source: ITableDataItem) => push(`../../${RoutePaths.Connections}/${source.connectionId}`);
const clickRow = (source: ITableDataItem) => push(`../../../${RoutePaths.Connections}/${source.connectionId}`);

return (
<ConnectionTable
Expand Down
25 changes: 19 additions & 6 deletions airbyte-webapp/src/views/Connector/ServiceForm/ServiceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { Formik, getIn, setIn, useFormikContext } from "formik";
import { JSONSchema7 } from "json-schema";
import { useToggle } from "react-use";

import { FormChangeTracker } from "components/FormChangeTracker";

import RequestConnectorModal from "views/Connector/RequestConnectorModal";
import { FormBaseItem } from "core/form/types";
import { ConnectorDefinition, ConnectorDefinitionSpecification, Scheduler } from "core/domain/connector";
import { isDefined } from "utils/common";
import { useFormChangeTrackerService, useUniqueFormId } from "hooks/services/FormChangeTracker";

import { ConnectionConfiguration } from "../../../core/domain/connection";
import {
Expand Down Expand Up @@ -36,7 +39,7 @@ const PatchInitialValuesWithWidgetConfig: React.FC<{
schema: JSONSchema7;
}> = ({ schema }) => {
const { widgetsInfo } = useServiceForm();
const { values, setFieldValue } = useFormikContext<ServiceFormValues>();
const { values, resetForm } = useFormikContext<ServiceFormValues>();

const valueRef = useRef<ConnectionConfiguration>();
valueRef.current = values.connectionConfiguration;
Expand All @@ -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]);
Expand Down Expand Up @@ -99,6 +107,9 @@ export type ServiceFormProps = {
};

const ServiceForm: React.FC<ServiceFormProps> = (props) => {
const formId = useUniqueFormId();
const { clearFormChange } = useFormChangeTrackerService();

const [isOpenRequestModal, toggleOpenRequestModal] = useToggle(false);
const [initialRequestName, setInitialRequestName] = useState<string>();
const {
Expand Down Expand Up @@ -178,12 +189,13 @@ const ServiceForm: React.FC<ServiceFormProps> = (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 (
Expand All @@ -194,7 +206,7 @@ const ServiceForm: React.FC<ServiceFormProps> = (props) => {
validationSchema={validationSchema}
onSubmit={onFormSubmit}
>
{() => (
{({ dirty }) => (
<ServiceFormContextProvider
widgetsInfo={uiWidgetsInfo}
getValues={getValues}
Expand All @@ -207,6 +219,7 @@ const ServiceForm: React.FC<ServiceFormProps> = (props) => {
>
{!props.isEditMode && <SetDefaultName />}
<FormikPatch />
<FormChangeTracker changed={dirty} formId={formId} />
<PatchInitialValuesWithWidgetConfig schema={jsonSchema} />
<FormRoot
{...props}
Expand Down

0 comments on commit 56af26c

Please sign in to comment.