= ({ isSubmitting, errorMessage, addition
)}
{additionBottomControls || null}
-
diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/components/EditControls.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/components/EditControls.tsx
index a75012708327..c8366c3d3dc9 100644
--- a/airbyte-webapp/src/views/Connection/ConnectionForm/components/EditControls.tsx
+++ b/airbyte-webapp/src/views/Connection/ConnectionForm/components/EditControls.tsx
@@ -4,9 +4,10 @@ import styled from "styled-components";
import { Button, LoadingButton } from "components";
-interface IProps {
+interface EditControlProps {
isSubmitting: boolean;
dirty: boolean;
+ submitDisabled?: boolean;
resetForm: () => void;
successMessage?: React.ReactNode;
errorMessage?: React.ReactNode;
@@ -49,9 +50,10 @@ const Line = styled.div`
margin: 16px -27px 0 -24px;
`;
-const EditControls: React.FC = ({
+const EditControls: React.FC = ({
isSubmitting,
dirty,
+ submitDisabled,
resetForm,
successMessage,
errorMessage,
@@ -79,18 +81,13 @@ const EditControls: React.FC = ({
{showStatusMessage()}
-
+
{editSchemeMode ? (
diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/components/OperationsSection.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/components/OperationsSection.tsx
index 39ffd363e369..769b35f16aac 100644
--- a/airbyte-webapp/src/views/Connection/ConnectionForm/components/OperationsSection.tsx
+++ b/airbyte-webapp/src/views/Connection/ConnectionForm/components/OperationsSection.tsx
@@ -16,9 +16,17 @@ const SectionTitle = styled.div`
line-height: 17px;
`;
-export const OperationsSection: React.FC<{
+interface OperationsSectionProps {
destDefinition: DestinationDefinitionSpecificationRead;
-}> = ({ destDefinition }) => {
+ onStartEditTransformation?: () => void;
+ onEndEditTransformation?: () => void;
+}
+
+export const OperationsSection: React.FC = ({
+ destDefinition,
+ onStartEditTransformation,
+ onEndEditTransformation,
+}) => {
const formatMessage = useIntl().formatMessage;
const { hasFeature } = useFeatureService();
@@ -42,7 +50,14 @@ export const OperationsSection: React.FC<{
{supportsNormalization && }
{supportsTransformations && (
- {(formProps) => }
+ {(formProps) => (
+
+ )}
)}
>
diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/components/TransformationField.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/components/TransformationField.tsx
index 076ee9db1e0b..1567f2781b2d 100644
--- a/airbyte-webapp/src/views/Connection/ConnectionForm/components/TransformationField.tsx
+++ b/airbyte-webapp/src/views/Connection/ConnectionForm/components/TransformationField.tsx
@@ -10,14 +10,26 @@ import TransformationForm from "views/Connection/TransformationForm";
import { ConnectionFormMode } from "../ConnectionForm";
-const TransformationField: React.FC<
- ArrayHelpers & {
- form: FormikProps<{ transformations: OperationRead[] }>;
- defaultTransformation: OperationCreate;
- mode?: ConnectionFormMode;
- }
-> = ({ remove, push, replace, form, defaultTransformation, mode }) => {
+interface TransformationFieldProps extends ArrayHelpers {
+ form: FormikProps<{ transformations: OperationRead[] }>;
+ defaultTransformation: OperationCreate;
+ mode?: ConnectionFormMode;
+ onStartEdit?: () => void;
+ onEndEdit?: () => void;
+}
+
+const TransformationField: React.FC = ({
+ remove,
+ push,
+ replace,
+ form,
+ defaultTransformation,
+ mode,
+ onStartEdit,
+ onEndEdit,
+}) => {
const [editableItemIdx, setEditableItem] = useState(null);
+
return (
}
onRemove={remove}
- onStartEdit={(idx) => setEditableItem(idx)}
+ onStartEdit={(idx) => {
+ setEditableItem(idx);
+ onStartEdit?.();
+ }}
mode={mode}
>
{(editableItem) => (
setEditableItem(null)}
+ onCancel={() => {
+ setEditableItem(null);
+ onEndEdit?.();
+ }}
onDone={(transformation) => {
if (isDefined(editableItemIdx)) {
editableItemIdx >= form.values.transformations.length
? push(transformation)
: replace(editableItemIdx, transformation);
setEditableItem(null);
+ onEndEdit?.();
}
}}
/>
diff --git a/airbyte-webapp/src/views/Connection/FormCard.tsx b/airbyte-webapp/src/views/Connection/FormCard.tsx
index 2cab6d8f45d6..ec18e057c23f 100644
--- a/airbyte-webapp/src/views/Connection/FormCard.tsx
+++ b/airbyte-webapp/src/views/Connection/FormCard.tsx
@@ -20,6 +20,7 @@ interface FormCardProps extends CollapsibleCardProps {
bottomSeparator?: boolean;
form: FormikConfig;
mode?: ConnectionFormMode;
+ submitDisabled?: boolean;
}
export function FormCard({
@@ -27,6 +28,7 @@ export function FormCard({
form,
bottomSeparator = true,
mode,
+ submitDisabled,
...props
}: React.PropsWithChildren>) {
const { formatMessage } = useIntl();
@@ -54,6 +56,7 @@ export function FormCard({
withLine={bottomSeparator}
isSubmitting={isSubmitting}
dirty={dirty}
+ submitDisabled={!isValid || submitDisabled}
resetForm={() => {
resetForm();
reset();
diff --git a/airbyte-webapp/src/views/Connection/TransformationForm/TransformationForm.tsx b/airbyte-webapp/src/views/Connection/TransformationForm/TransformationForm.tsx
index a97c060d4f3e..a6856085f051 100644
--- a/airbyte-webapp/src/views/Connection/TransformationForm/TransformationForm.tsx
+++ b/airbyte-webapp/src/views/Connection/TransformationForm/TransformationForm.tsx
@@ -1,6 +1,6 @@
import type { FormikErrors } from "formik/dist/types";
-import { getIn, useFormik, useFormikContext } from "formik";
+import { getIn, useFormik } from "formik";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import styled from "styled-components";
@@ -12,6 +12,7 @@ import { FormChangeTracker } from "components/FormChangeTracker";
import { OperationService } from "core/domain/connection";
import { OperationCreate, OperationRead } from "core/request/AirbyteClient";
import { useGetService } from "core/servicesProvider";
+import { useFormChangeTrackerService, useUniqueFormId } from "hooks/services/FormChangeTracker";
import { equal } from "utils/objects";
const Content = styled.div`
@@ -87,20 +88,27 @@ const TransformationForm: React.FC = ({
}) => {
const formatMessage = useIntl().formatMessage;
const operationService = useGetService("OperationService");
+ const { clearFormChange } = useFormChangeTrackerService();
+ const formId = useUniqueFormId();
const formik = useFormik({
initialValues: transformation,
validationSchema: validationSchema,
onSubmit: async (values) => {
await operationService.check(values);
+ clearFormChange(formId);
onDone(values);
},
});
- const { dirty } = useFormikContext();
+
+ const onFormCancel: React.MouseEventHandler = () => {
+ clearFormChange(formId);
+ onCancel?.();
+ };
return (
<>
-
+
-
+