From 7420cd299e01387079cf57ca99df70e300ad7b2d Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 16 Dec 2022 22:28:17 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=9F=20=F0=9F=8E=A8=20Show=20Source-def?= =?UTF-8?q?ined=20`cursor`=20and=20`primary=20key`=20fields=20on=20new=20S?= =?UTF-8?q?tream=20Details=20panel=20(#20366)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add storybook for CheckBox component add disabled state style * just checking how to extend current implementation of storybook * remove experimental changes * replace styled components with css modules add disabled state style add small size style add storybook * update test snapshots * fix checkbox cursor in disabled state * fix overflow issue with table header * create separate Cursor cell component * create separate PK cell component * update links * update translations * update stream details table: optionally show cursor and PK fields and disable them if they are source-defined * add "not-allowed" cursor to disabled radio button --- .../connection/CatalogTree/CatalogSection.tsx | 2 + .../StreamDetailsPanel/StreamDetailsPanel.tsx | 6 ++- .../CursorCell/CursorCell.module.scss | 4 ++ .../CursorCell/CursorCell.tsx | 44 ++++++++++++++++ .../StreamFieldsTable/CursorCell/index.tsx | 1 + .../StreamFieldsTable/PKCell/PKCell.tsx | 37 +++++++++++++ .../StreamFieldsTable/PKCell/index.tsx | 1 + .../StreamFieldsTable.module.scss | 7 +-- .../StreamFieldsTable/StreamFieldsTable.tsx | 52 +++++++++++++------ .../ui/CheckBox/CheckBox.module.scss | 3 +- .../ui/NextTable/NextTable.module.scss | 2 + .../components/ui/RadioButton/RadioButton.tsx | 2 +- airbyte-webapp/src/locales/en.json | 2 + airbyte-webapp/src/scss/_z-indices.scss | 1 + airbyte-webapp/src/utils/links.ts | 2 + 15 files changed, 140 insertions(+), 26 deletions(-) create mode 100644 airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.module.scss create mode 100644 airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.tsx create mode 100644 airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/index.tsx create mode 100644 airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/PKCell.tsx create mode 100644 airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/index.tsx diff --git a/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx b/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx index 0b8792a09d4da..c8d2793e85aee 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/CatalogSection.tsx @@ -203,6 +203,8 @@ const CatalogSectionInner: React.FC = ({ onSelectedChange={onSelectStream} shouldDefinePk={shouldDefinePk} shouldDefineCursor={shouldDefineCursor} + isCursorDefinitionSupported={cursorRequired} + isPKDefinitionSupported={pkRequired} stream={stream} /> ) : ( diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamDetailsPanel.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamDetailsPanel.tsx index aea07bbb83eb4..fb0ed0625471b 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamDetailsPanel.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamDetailsPanel.tsx @@ -17,6 +17,7 @@ interface StreamDetailsPanelProps extends StreamFieldsTableProps { } export const StreamDetailsPanel: React.FC = ({ + stream, config, disabled, onPkSelect, @@ -25,7 +26,8 @@ export const StreamDetailsPanel: React.FC = ({ onSelectedChange, shouldDefinePk, shouldDefineCursor, - stream, + isCursorDefinitionSupported, + isPKDefinitionSupported, syncSchemaFields, }) => { return ( @@ -47,6 +49,8 @@ export const StreamDetailsPanel: React.FC = ({ onPkSelect={onPkSelect} shouldDefinePk={shouldDefinePk} shouldDefineCursor={shouldDefineCursor} + isCursorDefinitionSupported={isCursorDefinitionSupported} + isPKDefinitionSupported={isPKDefinitionSupported} /> diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.module.scss b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.module.scss new file mode 100644 index 0000000000000..ce46b50cf07bf --- /dev/null +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.module.scss @@ -0,0 +1,4 @@ +.tooltip { + display: flex; + align-items: center; +} diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.tsx new file mode 100644 index 0000000000000..f71c9ce3e2708 --- /dev/null +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/CursorCell.tsx @@ -0,0 +1,44 @@ +import { CellContext } from "@tanstack/react-table"; +import React from "react"; +import { FormattedMessage } from "react-intl"; + +import { RadioButton } from "components/ui/RadioButton"; +import { Tooltip, TooltipLearnMoreLink } from "components/ui/Tooltip"; + +import { links } from "utils/links"; + +import { TableStream } from "../StreamFieldsTable"; +import styles from "./CursorCell.module.scss"; + +interface CursorCellProps extends CellContext { + isCursorDefinitionSupported: boolean; + isCursor: (path: string[]) => boolean; + onCursorSelect: (cursorPath: string[]) => void; +} + +export const CursorCell: React.FC = ({ + getValue, + row, + isCursorDefinitionSupported, + isCursor, + onCursorSelect, +}) => { + if (!isCursorDefinitionSupported) { + return null; + } + + const isCursorChecked = isCursor(row.original.path); + + const radioButton = ( + onCursorSelect(row.original.path)} disabled={!getValue()} /> + ); + + return !getValue() && isCursorChecked ? ( + + + + + ) : ( + radioButton + ); +}; diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/index.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/index.tsx new file mode 100644 index 0000000000000..840bb0efe4102 --- /dev/null +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/CursorCell/index.tsx @@ -0,0 +1 @@ +export { CursorCell } from "./CursorCell"; diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/PKCell.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/PKCell.tsx new file mode 100644 index 0000000000000..b24fecbce39c0 --- /dev/null +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/PKCell.tsx @@ -0,0 +1,37 @@ +import { CellContext } from "@tanstack/react-table"; +import React from "react"; +import { FormattedMessage } from "react-intl"; + +import { CheckBox } from "components/ui/CheckBox"; +import { Tooltip, TooltipLearnMoreLink } from "components/ui/Tooltip"; + +import { links } from "utils/links"; + +import { TableStream } from "../StreamFieldsTable"; + +interface PKCellProps extends CellContext { + isPKDefinitionSupported: boolean; + isPrimaryKey: (path: string[]) => boolean; + onPkSelect: (pkPath: string[]) => void; +} + +export const PKCell: React.FC = ({ getValue, row, isPKDefinitionSupported, isPrimaryKey, onPkSelect }) => { + if (!isPKDefinitionSupported) { + return null; + } + + const isPKChecked = isPrimaryKey(row.original.path); + + const checkbox = ( + onPkSelect(row.original.path)} disabled={!getValue()} /> + ); + + return !getValue() && isPKChecked ? ( + + + + + ) : ( + checkbox + ); +}; diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/index.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/index.tsx new file mode 100644 index 0000000000000..70fbec1da5444 --- /dev/null +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/PKCell/index.tsx @@ -0,0 +1 @@ +export { PKCell } from "./PKCell"; diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.module.scss b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.module.scss index 9a0f2a40bbbd5..67c68c04a842b 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.module.scss +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.module.scss @@ -79,15 +79,10 @@ $cell-left-padding: variables.$spacing-xl + variables.$spacing-sm; } } -.checkboxCell { +.radioBtnCell { display: flex; align-items: center; height: $cell-height; overflow: unset; padding-left: 0; } - -// need to fix styled-component z-index issue -.checkbox { - position: unset !important; -} diff --git a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.tsx b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.tsx index 86c92a6bc33a4..3f6f9f6a5f165 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/next/StreamDetailsPanel/StreamFieldsTable/StreamFieldsTable.tsx @@ -4,9 +4,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import { pathDisplayName } from "components/connection/CatalogTree/PathPopout"; import { ArrowRightIcon } from "components/icons/ArrowRightIcon"; -import { CheckBox } from "components/ui/CheckBox"; import { NextTable } from "components/ui/NextTable"; -import { RadioButton } from "components/ui/RadioButton"; import { SyncSchemaField, SyncSchemaFieldObject } from "core/domain/catalog"; import { AirbyteStreamConfiguration } from "core/request/AirbyteClient"; @@ -17,9 +15,11 @@ import { equal } from "utils/objects"; import { getDataType } from "utils/useTranslateDataType"; import { ConnectorHeaderGroupIcon } from "./ConnectorHeaderGroupIcon"; +import { CursorCell } from "./CursorCell"; +import { PKCell } from "./PKCell"; import styles from "./StreamFieldsTable.module.scss"; -interface TableStream { +export interface TableStream { path: string[]; dataType: string; cursorDefined?: boolean; @@ -32,6 +32,8 @@ export interface StreamFieldsTableProps { onPkSelect: (pkPath: string[]) => void; shouldDefinePk: boolean; shouldDefineCursor: boolean; + isCursorDefinitionSupported: boolean; + isPKDefinitionSupported: boolean; syncSchemaFields: SyncSchemaField[]; } @@ -41,6 +43,8 @@ export const StreamFieldsTable: React.FC = ({ onCursorSelect, shouldDefineCursor, shouldDefinePk, + isCursorDefinitionSupported, + isPKDefinitionSupported, syncSchemaFields, }) => { const { formatMessage } = useIntl(); @@ -97,33 +101,47 @@ export const StreamFieldsTable: React.FC = ({ columnHelper.accessor("cursorDefined", { id: "sourceCursorDefined", header: () => , - cell: ({ getValue, row }) => - getValue() && ( - onCursorSelect(row.original.path)} /> - ), + cell: (props) => ( + + ), meta: { thClassName: styles.headerCell, - tdClassName: styles.checkboxCell, + tdClassName: styles.radioBtnCell, }, }), columnHelper.accessor("primaryKeyDefined", { id: "sourcePrimaryKeyDefined", header: () => , - cell: ({ getValue, row }) => - getValue() && ( - onPkSelect(row.original.path)} - className={styles.checkbox} - /> - ), + cell: (props) => ( + + ), + meta: { thClassName: styles.headerCell, tdClassName: styles.textCell, }, }), ], - [columnHelper, formatMessage, isCursor, isPrimaryKey, onCursorSelect, onPkSelect] + [ + columnHelper, + formatMessage, + isCursor, + isPrimaryKey, + isCursorDefinitionSupported, + isPKDefinitionSupported, + onCursorSelect, + onPkSelect, + ] ); const destinationColumns = useMemo( diff --git a/airbyte-webapp/src/components/ui/CheckBox/CheckBox.module.scss b/airbyte-webapp/src/components/ui/CheckBox/CheckBox.module.scss index 07b0ac944b5e1..c3a67ea8d793f 100644 --- a/airbyte-webapp/src/components/ui/CheckBox/CheckBox.module.scss +++ b/airbyte-webapp/src/components/ui/CheckBox/CheckBox.module.scss @@ -19,8 +19,9 @@ $sm-size: 14px; display: none; } - .disabled { + &.disabled { border-color: colors.$grey-30; + cursor: not-allowed; } } diff --git a/airbyte-webapp/src/components/ui/NextTable/NextTable.module.scss b/airbyte-webapp/src/components/ui/NextTable/NextTable.module.scss index 0cd5356902665..25e49218fe986 100644 --- a/airbyte-webapp/src/components/ui/NextTable/NextTable.module.scss +++ b/airbyte-webapp/src/components/ui/NextTable/NextTable.module.scss @@ -1,5 +1,6 @@ @use "scss/colors"; @use "scss/variables" as vars; +@use "scss/z-indices"; // ------- -------- .table { @@ -12,6 +13,7 @@ .thead { position: sticky; top: 0; + z-index: z-indices.$tableScroll; } // ---------
--------- diff --git a/airbyte-webapp/src/components/ui/RadioButton/RadioButton.tsx b/airbyte-webapp/src/components/ui/RadioButton/RadioButton.tsx index f56b52b195cd1..85b1e717549a5 100644 --- a/airbyte-webapp/src/components/ui/RadioButton/RadioButton.tsx +++ b/airbyte-webapp/src/components/ui/RadioButton/RadioButton.tsx @@ -26,7 +26,7 @@ const RadioButtonContainer = styled.label<{ checked?: boolean; disabled?: boolea border-radius: 50%; display: inline-block; padding: 4px; - cursor: pointer; + cursor: ${({ disabled }) => (disabled ? "not-allowed" : "pointer")}; `; export const RadioButton: React.FC> = (props) => { diff --git a/airbyte-webapp/src/locales/en.json b/airbyte-webapp/src/locales/en.json index ccca86369833a..44d04d1da6fdb 100644 --- a/airbyte-webapp/src/locales/en.json +++ b/airbyte-webapp/src/locales/en.json @@ -223,6 +223,8 @@ "form.field.destinationName": "Destination name", "form.field.primaryKey": "Primary key", "form.field.cursorField": "Cursor field", + "form.field.sourceDefinedCursor": "Source-Defined Cursor", + "form.field.sourceDefinedPK": "Source-Defined Primary key", "preferences.headTitle": "Preferences", "preferences.title": "Specify your preferences", diff --git a/airbyte-webapp/src/scss/_z-indices.scss b/airbyte-webapp/src/scss/_z-indices.scss index fe178dd82c268..71ec0051a4ca0 100644 --- a/airbyte-webapp/src/scss/_z-indices.scss +++ b/airbyte-webapp/src/scss/_z-indices.scss @@ -8,3 +8,4 @@ $notification: 20; $schemaChangesBackdrop: 3; $schemaChangesBackdropContent: 4; $switchSliderBefore: 1; +$tableScroll: 1; diff --git a/airbyte-webapp/src/utils/links.ts b/airbyte-webapp/src/utils/links.ts index 369aea1bda525..e36d3f1a9559b 100644 --- a/airbyte-webapp/src/utils/links.ts +++ b/airbyte-webapp/src/utils/links.ts @@ -23,6 +23,8 @@ export const links = { statusLink: "https://status.airbyte.io/", tutorialsLink: "https://airbyte.com/tutorials", syncModeLink: `${BASE_DOCS_LINK}/understanding-airbyte/connections`, + sourceDefinedCursorLink: `${BASE_DOCS_LINK}/understanding-airbyte/connections/incremental-deduped-history/#source-defined-cursor`, + sourceDefinedPKLink: `${BASE_DOCS_LINK}/understanding-airbyte/connections/incremental-deduped-history/#source-defined-primary-key`, demoLink: "https://demo.airbyte.io", contactSales: "https://airbyte.com/talk-to-sales", webpageLink: "https://airbyte.com",