diff --git a/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx b/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx index 56612c8eaf93..01c12a7fed1e 100644 --- a/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx +++ b/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx @@ -103,6 +103,7 @@ const CreateConnectionFormInner: React.FC = ({ schem initialValues={initialValues} validationSchema={connectionValidationSchema(mode)} onSubmit={onFormSubmit} + validateOnChange={false} > {({ values, isSubmitting, isValid, dirty }) => (
diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx index fb4d5654f631..6daba67181b9 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx @@ -45,17 +45,12 @@ export const ConnectionItemPageInner: React.FC = () => { > }> - } /> + } /> } /> - } - /> + } /> : - } + element={isConnectionDeleted ? : } /> } /> diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx index c30abf287aa2..d5544c366499 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx @@ -150,6 +150,7 @@ export const ConnectionReplicationTab: React.FC = () => { validationSchema={connectionValidationSchema(mode)} onSubmit={onFormSubmit} enableReinitialize + validateOnChange={false} > {({ values, isSubmitting, isValid, dirty, resetForm }) => ( diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.test.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.test.tsx index 665b728cecff..79f0f5b8e56e 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.test.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.test.tsx @@ -1,4 +1,4 @@ -import { render, mockConnection } from "test-utils/testutils"; +import { mockConnection, render } from "test-utils/testutils"; import { ConnectionSettingsTab } from "./ConnectionSettingsTab"; @@ -23,13 +23,10 @@ jest.mock("hooks/services/Analytics/useAnalyticsService", () => { return analyticsService; }); -// Mocking the DeleteBlock component is a bit ugly, but it's simpler and less -// brittle than mocking the providers it depends on; at least it's a direct, -// visible dependency of the component under test here. -// -// This mock is intentionally trivial; if anything to do with this component is -// to be tested, we'll have to bite the bullet and render it properly, within -// the necessary providers. +jest.mock("hooks/services/ConnectionEdit/ConnectionEditService", () => ({ + useConnectionEditService: () => ({ connection: mockConnection }), +})); + jest.mock("components/DeleteBlock", () => () => { const MockDeleteBlock = () =>
Does not actually delete anything
; return ; @@ -40,11 +37,11 @@ describe("", () => { let container: HTMLElement; setMockIsAdvancedMode(false); - ({ container } = await render()); + ({ container } = await render()); expect(container.textContent).not.toContain("Connection State"); setMockIsAdvancedMode(true); - ({ container } = await render()); + ({ container } = await render()); expect(container.textContent).toContain("Connection State"); }); }); diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx index 0fbe9c03c2a0..b28518c7cfad 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx @@ -2,19 +2,16 @@ import React from "react"; import DeleteBlock from "components/DeleteBlock"; -import { WebBackendConnectionRead } from "core/request/AirbyteClient"; import { PageTrackingCodes, useTrackPage } from "hooks/services/Analytics"; +import { useConnectionEditService } from "hooks/services/ConnectionEdit/ConnectionEditService"; import { useAdvancedModeSetting } from "hooks/services/useAdvancedModeSetting"; import { useDeleteConnection } from "hooks/services/useConnectionHook"; import styles from "./ConnectionSettingsTab.module.scss"; import { StateBlock } from "./StateBlock"; -interface ConnectionSettingsTabProps { - connection: WebBackendConnectionRead; -} - -export const ConnectionSettingsTab: React.FC = ({ connection }) => { +export const ConnectionSettingsTab: React.FC = () => { + const { connection } = useConnectionEditService(); const { mutateAsync: deleteConnection } = useDeleteConnection(); const [isAdvancedMode] = useAdvancedModeSetting(); diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionStatusTab.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionStatusTab.tsx index 0efa2a215992..ad492856ea66 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionStatusTab.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionStatusTab.tsx @@ -13,10 +13,11 @@ import { Tooltip } from "components/ui/Tooltip"; import { Action, Namespace } from "core/analytics"; import { getFrequencyFromScheduleData } from "core/analytics/utils"; -import { ConnectionStatus, JobWithAttemptsRead, WebBackendConnectionRead } from "core/request/AirbyteClient"; +import { ConnectionStatus, JobWithAttemptsRead } from "core/request/AirbyteClient"; import Status from "core/statuses"; import { useTrackPage, PageTrackingCodes, useAnalyticsService } from "hooks/services/Analytics"; import { useConfirmationModalService } from "hooks/services/ConfirmationModal"; +import { useConnectionEditService } from "hooks/services/ConnectionEdit/ConnectionEditService"; import { FeatureItem, useFeature } from "hooks/services/Feature"; import { useResetConnection, useSyncConnection } from "hooks/services/useConnectionHook"; import { useCancelJob, useListJobs } from "services/job/JobService"; @@ -37,10 +38,6 @@ interface ActiveJob { isCanceling: boolean; } -interface ConnectionStatusTabProps { - connection: WebBackendConnectionRead; -} - const getJobRunningOrPending = (jobs: JobWithAttemptsRead[]) => { return jobs.find((jobWithAttempts) => { const jobStatus = jobWithAttempts?.job?.status; @@ -48,7 +45,8 @@ const getJobRunningOrPending = (jobs: JobWithAttemptsRead[]) => { }); }; -export const ConnectionStatusTab: React.FC = ({ connection }) => { +export const ConnectionStatusTab: React.FC = () => { + const { connection } = useConnectionEditService(); useTrackPage(PageTrackingCodes.CONNECTIONS_ITEM_STATUS); const [activeJob, setActiveJob] = useState(); const [jobPageSize, setJobPageSize] = useState(JOB_PAGE_SIZE_INCREMENT); diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab.module.scss b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab.module.scss new file mode 100644 index 000000000000..6903e64a247b --- /dev/null +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab.module.scss @@ -0,0 +1,14 @@ +.content { + max-width: 1073px; + margin: 0 auto; + padding-bottom: 10px; +} + +.customCard { + max-width: 500px; + margin: 0 auto; + min-height: 100px; + display: flex; + justify-content: center; + align-items: center; +} diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab.tsx index 170ef75a7e9c..41752ba8ffe9 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab.tsx @@ -2,23 +2,16 @@ import { Field, FieldArray } from "formik"; import React, { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { useToggle } from "react-use"; -import styled from "styled-components"; import { Card } from "components/ui/Card"; import { Text } from "components/ui/Text"; -import { buildConnectionUpdate, NormalizationType } from "core/domain/connection"; -import { - ConnectionStatus, - OperationCreate, - OperationRead, - OperatorType, - WebBackendConnectionRead, -} from "core/request/AirbyteClient"; +import { NormalizationType } from "core/domain/connection"; +import { OperationCreate, OperationRead, OperatorType } from "core/request/AirbyteClient"; import { useTrackPage, PageTrackingCodes } from "hooks/services/Analytics"; -import { ConnectionFormMode } from "hooks/services/ConnectionForm/ConnectionFormService"; +import { useConnectionEditService } from "hooks/services/ConnectionEdit/ConnectionEditService"; +import { useConnectionFormService } from "hooks/services/ConnectionForm/ConnectionFormService"; import { FeatureItem, useFeature } from "hooks/services/Feature"; -import { useUpdateConnection } from "hooks/services/useConnectionHook"; import { useCurrentWorkspace } from "hooks/services/useWorkspace"; import { useGetDestinationDefinitionSpecification } from "services/connector/DestinationDefinitionSpecificationService"; import { FormikOnSubmit } from "types/formik"; @@ -31,32 +24,14 @@ import { } from "views/Connection/ConnectionForm/formConfig"; import { FormCard } from "views/Connection/FormCard"; -interface ConnectionTransformationTabProps { - connection: WebBackendConnectionRead; -} - -const Content = styled.div` - max-width: 1073px; - margin: 0 auto; - padding-bottom: 10px; -`; - -const NoSupportedTransformationCard = styled(Card)` - max-width: 500px; - margin: 0 auto; - min-height: 100px; - display: flex; - justify-content: center; - align-items: center; -`; +import styles from "./ConnectionTransformationTab.module.scss"; const CustomTransformationsCard: React.FC<{ operations?: OperationCreate[]; onSubmit: FormikOnSubmit<{ transformations?: OperationRead[] }>; - mode: ConnectionFormMode; -}> = ({ operations, onSubmit, mode }) => { +}> = ({ operations, onSubmit }) => { const [editingTransformation, toggleEditingTransformation] = useToggle(false); - + const { mode } = useConnectionFormService(); const initialValues = useMemo( () => ({ transformations: getInitialTransformations(operations || []), @@ -75,7 +50,6 @@ const CustomTransformationsCard: React.FC<{ onSubmit, }} submitDisabled={editingTransformation} - mode={mode} > {(formProps) => ( @@ -94,8 +68,8 @@ const CustomTransformationsCard: React.FC<{ const NormalizationCard: React.FC<{ operations?: OperationRead[]; onSubmit: FormikOnSubmit<{ normalization?: NormalizationType }>; - mode: ConnectionFormMode; -}> = ({ operations, onSubmit, mode }) => { +}> = ({ operations, onSubmit }) => { + const { mode } = useConnectionFormService(); const initialValues = useMemo( () => ({ normalization: getInitialNormalization(operations, true), @@ -111,24 +85,22 @@ const NormalizationCard: React.FC<{ }} title={} collapsible - mode={mode} > ); }; -export const ConnectionTransformationTab: React.FC = ({ connection }) => { +export const ConnectionTransformationTab: React.FC = () => { + const { connection, updateConnection } = useConnectionEditService(); + const { mode } = useConnectionFormService(); const definition = useGetDestinationDefinitionSpecification(connection.destination.destinationDefinitionId); - const { mutateAsync: updateConnection } = useUpdateConnection(); const workspace = useCurrentWorkspace(); useTrackPage(PageTrackingCodes.CONNECTIONS_ITEM_TRANSFORMATION); const { supportsNormalization } = definition; const supportsDbt = useFeature(FeatureItem.AllowCustomDBT) && definition.supportsDbt; - const mode = connection.status === ConnectionStatus.deprecated ? "readonly" : "edit"; - const onSubmit: FormikOnSubmit<{ transformations?: OperationRead[]; normalization?: NormalizationType }> = async ( values, { resetForm } @@ -143,11 +115,7 @@ export const ConnectionTransformationTab: React.FC op.operatorConfiguration.operatorType === OperatorType.dbt) ); - await updateConnection( - buildConnectionUpdate(connection, { - operations, - }) - ); + await updateConnection({ connectionId: connection.connectionId, operations }); const nextFormValues: typeof values = {}; if (values.transformations) { @@ -159,25 +127,21 @@ export const ConnectionTransformationTab: React.FC +
- {supportsNormalization && ( - - )} - {supportsDbt && ( - - )} + {supportsNormalization && } + {supportsDbt && } {!supportsNormalization && !supportsDbt && ( - + - + )}
- +
); }; diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/components/NormalizationField.module.scss b/airbyte-webapp/src/views/Connection/ConnectionForm/components/NormalizationField.module.scss new file mode 100644 index 000000000000..044bcdd2bf93 --- /dev/null +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/components/NormalizationField.module.scss @@ -0,0 +1,5 @@ +@use "../../../../scss/variables"; + +.normalizationField { + margin: variables.$spacing-lg 0; +} diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/components/NormalizationField.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/components/NormalizationField.tsx index 158c7811df18..b7173eb33fb0 100644 --- a/airbyte-webapp/src/views/Connection/ConnectionForm/components/NormalizationField.tsx +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/components/NormalizationField.tsx @@ -1,25 +1,22 @@ import { FieldProps } from "formik"; import React from "react"; import { FormattedMessage } from "react-intl"; -import styled from "styled-components"; import { LabeledRadioButton, Link } from "components"; import { NormalizationType } from "core/domain/connection/operation"; -import { ConnectionFormMode } from "hooks/services/ConnectionForm/ConnectionFormService"; +import { useConnectionFormService } from "hooks/services/ConnectionForm/ConnectionFormService"; import { links } from "utils/links"; -const Normalization = styled.div` - margin: 16px 0; -`; +import styles from "./NormalizationField.module.scss"; -type NormalizationBlockProps = FieldProps & { - mode: ConnectionFormMode; -}; +type NormalizationBlockProps = FieldProps; + +export const NormalizationField: React.FC = ({ form, field }) => { + const { mode } = useConnectionFormService(); -const NormalizationField: React.FC = ({ form, field, mode }) => { return ( - +
= ({ form, field, mo ) } /> - +
); }; - -export { NormalizationField }; diff --git a/airbyte-webapp/src/views/Connection/FormCard.module.scss b/airbyte-webapp/src/views/Connection/FormCard.module.scss new file mode 100644 index 000000000000..bcb8d01884c5 --- /dev/null +++ b/airbyte-webapp/src/views/Connection/FormCard.module.scss @@ -0,0 +1,5 @@ +@use "../../scss/variables"; + +.formCard { + padding: 22px 27px variables.$spacing-xl 24px; +} diff --git a/airbyte-webapp/src/views/Connection/FormCard.tsx b/airbyte-webapp/src/views/Connection/FormCard.tsx index 9de05d1d3a9a..1df3f5c02954 100644 --- a/airbyte-webapp/src/views/Connection/FormCard.tsx +++ b/airbyte-webapp/src/views/Connection/FormCard.tsx @@ -2,23 +2,19 @@ import { Form, Formik, FormikConfig, FormikHelpers } from "formik"; import React from "react"; import { useIntl } from "react-intl"; import { useMutation } from "react-query"; -import styled from "styled-components"; import { FormChangeTracker } from "components/FormChangeTracker"; -import { ConnectionFormMode } from "hooks/services/ConnectionForm/ConnectionFormService"; +import { useConnectionFormService } from "hooks/services/ConnectionForm/ConnectionFormService"; import { generateMessageFromError } from "utils/errorStatusMessage"; import { CollapsibleCardProps, CollapsibleCard } from "views/Connection/CollapsibleCard"; import EditControls from "views/Connection/ConnectionForm/components/EditControls"; -const FormContainer = styled(Form)` - padding: 22px 27px 15px 24px; -`; +import styles from "./FormCard.module.scss"; interface FormCardProps extends CollapsibleCardProps { bottomSeparator?: boolean; form: FormikConfig; - mode?: ConnectionFormMode; submitDisabled?: boolean; } @@ -26,11 +22,11 @@ export const FormCard = ({ children, form, bottomSeparator = true, - mode, submitDisabled, ...props }: React.PropsWithChildren>) => { const { formatMessage } = useIntl(); + const { mode } = useConnectionFormService(); const { mutateAsync, error, reset, isSuccess } = useMutation< void, @@ -46,7 +42,7 @@ export const FormCard = ({ mutateAsync({ values, formikHelpers })}> {({ resetForm, isSubmitting, dirty, isValid }) => ( - + {children}
@@ -67,7 +63,7 @@ export const FormCard = ({ /> )}
-
+
)}