diff --git a/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx b/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx index fd49a7b6f82aeb..7d75f818ea6145 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx @@ -166,7 +166,12 @@ const CatalogSectionInner: React.FC = ({ ); const destName = prefix + (streamNode.stream?.name ?? ""); - const configErrors = getIn(errors, `schema.streams[${streamNode.id}].config`); + const configErrors = getIn( + errors, + isNewStreamsTableEnabled + ? `syncCatalog.streams[${streamNode.id}].config` + : `schema.streams[${streamNode.id}].config` + ); const hasError = configErrors && Object.keys(configErrors).length > 0; const pkType = getPathType(pkRequired, shouldDefinePk); const cursorType = getPathType(cursorRequired, shouldDefineCursor); @@ -194,6 +199,7 @@ const CatalogSectionInner: React.FC = ({ onExpand={onExpand} changedSelected={changedSelected} hasError={hasError} + configErrors={configErrors} disabled={disabled} /> {isRowExpanded && diff --git a/airbyte-webapp/src/components/connection/CatalogTree/StreamHeader.tsx b/airbyte-webapp/src/components/connection/CatalogTree/StreamHeader.tsx index ea1f29071cbe9c..df29630e74689c 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/StreamHeader.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/StreamHeader.tsx @@ -43,6 +43,7 @@ export interface StreamHeaderProps { onExpand: () => void; changedSelected: boolean; hasError: boolean; + configErrors?: Record; disabled?: boolean; } diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.module.scss b/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.module.scss index a7eacc81334289..ab30731b2e7e68 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.module.scss +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.module.scss @@ -35,10 +35,6 @@ @include header-background(colors.$blue-30, colors.$blue-40); } - &.error { - border: 1px solid colors.$red; - } - &.disabled { background-color: colors.$grey-50; } diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.tsx index 4a90a28098398f..38a43e5a7d06d2 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/CatalogTreeTableRow.tsx @@ -34,9 +34,9 @@ export const CatalogTreeTableRow: React.FC = ({ fields, onExpand, disabled, + configErrors, }) => { const { primaryKey, cursorField, syncMode, destinationSyncMode } = stream.config ?? {}; - const { defaultCursorField } = stream.stream ?? {}; const syncSchema = useMemo( () => ({ @@ -103,6 +103,7 @@ export const CatalogTreeTableRow: React.FC = ({ path={cursorType === "sourceDefined" ? defaultCursorField : cursorField} onPathChange={onCursorChange} variant={pillButtonVariant} + hasError={!!configErrors?.cursorField} /> )} @@ -115,6 +116,7 @@ export const CatalogTreeTableRow: React.FC = ({ isMulti onPathChange={onPrimaryKeyChange} variant={pillButtonVariant} + hasError={!!configErrors?.primaryKey} /> )} diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamPathSelect.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamPathSelect.tsx index c4e7df8e776821..c89e68cf645835 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamPathSelect.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamPathSelect.tsx @@ -19,6 +19,7 @@ interface StreamPathSelectBaseProps { placeholder?: React.ReactNode; variant?: PillButtonVariant; disabled?: boolean; + hasError?: boolean; } interface StreamPathSelectMultiProps { @@ -69,6 +70,7 @@ export const StreamPathSelect: React.FC = (props) => { props.onPathChange(finalValues); }} className={styles.streamPathSelect} + hasError={props?.hasError} /> ); }; diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.test.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.test.tsx index e1a5c4710ac44d..191eefe324022d 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.test.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.test.tsx @@ -143,11 +143,4 @@ describe("useCatalogTreeTableRowProps", () => { expect(result.current.streamHeaderContentStyle).toEqual("streamHeaderContent changed"); expect(result.current.pillButtonVariant).toEqual("blue"); }); - it("should return error styles for a row that has an error", () => { - testSetup(mockInitialValues, false, "error"); - - const { result } = renderHook(() => useCatalogTreeTableRowProps(mockStream)); - - expect(result.current.streamHeaderContentStyle).toEqual("streamHeaderContent error"); - }); }); diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.tsx index 4a881040ea07ef..4f9e07c7a688b7 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/useCatalogTreeTableRowProps.tsx @@ -1,6 +1,5 @@ /* eslint-disable css-modules/no-unused-class */ import classNames from "classnames"; -import { useField } from "formik"; import isEqual from "lodash/isEqual"; import { useMemo } from "react"; @@ -11,16 +10,12 @@ import { useBulkEditSelect } from "hooks/services/BulkEdit/BulkEditService"; import { useConnectionFormService } from "hooks/services/ConnectionForm/ConnectionFormService"; import styles from "./CatalogTreeTableRow.module.scss"; + type StatusToDisplay = "disabled" | "added" | "removed" | "changed" | "unchanged"; export const useCatalogTreeTableRowProps = (stream: SyncSchemaStream) => { - const { initialValues } = useConnectionFormService(); const [isSelected] = useBulkEditSelect(stream.id); - - const [, { error }] = useField(`schema.streams[${stream.id}].config`); - - // in case error is an empty string - const hasError = error !== undefined; + const { initialValues } = useConnectionFormService(); const isStreamEnabled = stream.config?.selected; @@ -67,7 +62,6 @@ export const useCatalogTreeTableRowProps = (stream: SyncSchemaStream) => { [styles.removed]: statusToDisplay === "removed" && !isSelected, [styles.changed]: statusToDisplay === "changed" || isSelected, [styles.disabled]: statusToDisplay === "disabled", - [styles.error]: hasError, }); return { diff --git a/airbyte-webapp/src/components/ui/PillSelect/PillButton.tsx b/airbyte-webapp/src/components/ui/PillSelect/PillButton.tsx index 39c52db1e1828e..81a8c6c1af25b7 100644 --- a/airbyte-webapp/src/components/ui/PillSelect/PillButton.tsx +++ b/airbyte-webapp/src/components/ui/PillSelect/PillButton.tsx @@ -20,19 +20,27 @@ const STYLES_BY_VARIANT: Readonly> = { interface PillButtonProps extends React.ButtonHTMLAttributes { active?: boolean; variant?: PillButtonVariant; + hasError?: boolean; } -export const PillButton: React.FC = ({ children, active, variant = "grey", ...buttonProps }) => { +export const PillButton: React.FC = ({ + children, + active, + variant = "grey", + hasError = false, + ...buttonProps +}) => { const buttonClassName = classNames( styles.button, { [styles.active]: active, [styles.disabled]: buttonProps.disabled, }, - STYLES_BY_VARIANT[variant], + STYLES_BY_VARIANT[hasError ? "strong-red" : variant], buttonProps.className ); const arrayChildren = Children.toArray(children); + return (