diff --git a/ui/app/mirrors/create/cdc/columnbox.tsx b/ui/app/mirrors/create/cdc/columnbox.tsx index d444b96877..aca0be7bca 100644 --- a/ui/app/mirrors/create/cdc/columnbox.tsx +++ b/ui/app/mirrors/create/cdc/columnbox.tsx @@ -1,10 +1,12 @@ 'use client'; import { TableMapRow } from '@/app/dto/MirrorsDTO'; +import { ColumnSetting } from '@/grpc_generated/flow'; import { ColumnsItem } from '@/grpc_generated/route'; import { Checkbox } from '@/lib/Checkbox'; import { Label } from '@/lib/Label'; import { RowWithCheckbox } from '@/lib/Layout'; -import { Dispatch, SetStateAction } from 'react'; +import { Dispatch, Fragment, SetStateAction, useMemo } from 'react'; +import InfoPopover from '@/components/InfoPopover'; interface ColumnProps { columns: ColumnsItem[]; @@ -12,7 +14,7 @@ interface ColumnProps { rows: TableMapRow[]; setRows: Dispatch>; disabled?: boolean; - showOrdering: boolean; + showNullable: boolean; } export default function ColumnBox({ columns, @@ -20,69 +22,160 @@ export default function ColumnBox({ rows, setRows, disabled, + showNullable, }: ColumnProps) { - const handleColumnExclusion = (column: string, include: boolean) => { - const source = tableRow.source; - const currRows = [...rows]; - const rowIndex = currRows.findIndex((row) => row.source === source); + // Helper to update a specific row + const updateRow = (updater: (row: TableMapRow) => TableMapRow) => { + const rowIndex = rows.findIndex((row) => row.source === tableRow.source); if (rowIndex !== -1) { - const sourceRow = currRows[rowIndex], - newExclude = new Set(sourceRow.exclude); + const updatedRows = [...rows]; + updatedRows[rowIndex] = updater(updatedRows[rowIndex]); + setRows(updatedRows); + } + }; + + const handleColumnExclusion = (column: string, include: boolean) => { + updateRow((row) => { + const newExclude = new Set(row.exclude); if (include) { newExclude.delete(column); } else { newExclude.add(column); } - currRows[rowIndex] = { - ...sourceRow, - exclude: newExclude, - }; - setRows(currRows); - } + return { ...row, exclude: newExclude }; + }); }; - return columns.map((column) => { - const partOfOrderingKey = rows - .find((row) => row.source == tableRow.source) - ?.columns.some( - (col) => - col.sourceName === column.name && - (col.ordering > 0 || col.partitioning > 0) + const handleNullableEnabledChange = (columnName: string, enabled: boolean) => { + updateRow((row) => { + const existingColumn = row.columns.find( + (col) => col.sourceName === columnName ); - return ( - - {column.name} -

+ col.sourceName === columnName + ? { ...col, nullableEnabled: enabled } + : col + ) + : // Create new ColumnSetting + [ + ...row.columns, + { + sourceName: columnName, + destinationName: '', + destinationType: '', + ordering: 0, + partitioning: 0, + nullableEnabled: enabled, + }, + ]; + + return { ...row, columns: updatedColumns }; + }); + }; + + const nullableEnabledMap = useMemo(() => { + const map = new Map(); + tableRow.columns.forEach((col) => { + map.set(col.sourceName, col.nullableEnabled ?? false); + }); + return map; + }, [tableRow.columns]); + + const getNullableEnabled = (columnName: string): boolean => { + return nullableEnabledMap.get(columnName) ?? false; + }; + + return ( +

+
Name
+
Type
+ {showNullable && ( +
+ Nullable + +
+ )} + + {columns.map((column) => { + const partOfOrderingKey = rows + .find((row) => row.source == tableRow.source) + ?.columns.some( + (col) => + col.sourceName === column.name && + (col.ordering > 0 || col.partitioning > 0) + ); + + const isIncluded = !tableRow.exclude.has(column.name); + const nullableEnabled = getNullableEnabled(column.name); + + return ( + + + {column.name} + + } + action={ + + handleColumnExclusion(column.name, state) + } + /> + } + /> + +
{column.type} -

- - } - action={ - - handleColumnExclusion(column.name, state) - } - /> - } - /> - ); - }); +
+ + {showNullable && ( + + handleNullableEnabledChange(column.name, state) + } + /> + )} +
+ ); + })} +
+ ); } diff --git a/ui/app/mirrors/create/cdc/customColumnType.tsx b/ui/app/mirrors/create/cdc/customColumnType.tsx index b0aea24549..c33c2d5d93 100644 --- a/ui/app/mirrors/create/cdc/customColumnType.tsx +++ b/ui/app/mirrors/create/cdc/customColumnType.tsx @@ -141,10 +141,10 @@ export default function CustomColumnType({ prev.map((row) => { if (row.source !== tableRow.source) return row; - const columnExistsInRow = row.columns.some( + const existingColumn = row.columns.find( (col) => col.sourceName === selectedColumnName ); - if (!columnExistsInRow) { + if (!existingColumn) { return { ...row, columns: [ diff --git a/ui/app/mirrors/create/cdc/schemabox.tsx b/ui/app/mirrors/create/cdc/schemabox.tsx index 2bfcca3901..d4bb23c5aa 100644 --- a/ui/app/mirrors/create/cdc/schemabox.tsx +++ b/ui/app/mirrors/create/cdc/schemabox.tsx @@ -231,6 +231,7 @@ export default function SchemaBox({ row.partitionByExpr = existingRow.partitionByExpr; row.exclude = new Set(existingRow.exclude ?? []); row.destination = existingRow.destinationTableIdentifier; + row.columns = existingRow.columns ?? []; addTableColumns(row.source); } } @@ -529,7 +530,7 @@ export default function SchemaBox({ rows={rows} setRows={setRows} disabled={row.editingDisabled} - showOrdering={ + showNullable={ peerType?.toString() === DBType[DBType.CLICKHOUSE].toString() } diff --git a/ui/app/mirrors/create/cdc/sortingkey.tsx b/ui/app/mirrors/create/cdc/sortingkey.tsx index cf631e9123..4d4f00525c 100644 --- a/ui/app/mirrors/create/cdc/sortingkey.tsx +++ b/ui/app/mirrors/create/cdc/sortingkey.tsx @@ -49,6 +49,10 @@ function UpdatedRows( const rowIndex = rows.findIndex((row) => row.source === tableRow.source); if (rowIndex !== -1) { const newRows = [...rows]; + // Check if there's an existing ColumnSetting to preserve nullableEnabled + const existingSetting = rows[rowIndex].columns.find( + (setting) => setting.sourceName === colName + ); const columns = rows[rowIndex].columns.map(update); if (!columns.find((setting) => setting.sourceName === colName)) { columns.push( @@ -58,7 +62,7 @@ function UpdatedRows( destinationType: '', ordering: 0, partitioning: 0, - nullableEnabled: false, + nullableEnabled: existingSetting?.nullableEnabled ?? false, }) ); }