11'use client' ;
2+ import { Divider } from '@tremor/react' ;
23import {
34 Dispatch ,
45 SetStateAction ,
@@ -19,7 +20,7 @@ import { Icon } from '@/lib/Icon';
1920import { Label } from '@/lib/Label' ;
2021import { RowWithCheckbox } from '@/lib/Layout' ;
2122import { fetchAllTypeConversions } from '../handlers' ;
22- import { engineOptionStyles } from './styles' ;
23+ import { columnBoxDividerStyle , engineOptionStyles } from './styles' ;
2324interface CustomColumnTypeProps {
2425 columns : ColumnsItem [ ] ;
2526 tableRow : TableMapRow ;
@@ -41,6 +42,20 @@ export default function CustomColumnType({
4142 Record < string , { value : string ; label : string } [ ] >
4243 > ( { } ) ;
4344
45+ const selectedColumns = useMemo ( ( ) => {
46+ return columns . filter ( ( col ) => ! tableRow . exclude . has ( col . name ) ) ;
47+ } , [ columns , tableRow . exclude ] ) ;
48+
49+ const columnsWithDstTypes = useMemo ( ( ) => {
50+ const columnsWithDstTypes = selectedColumns . filter (
51+ ( col ) => destinationTypeMapping [ col . name ] !== undefined
52+ ) ;
53+ if ( columnsWithDstTypes . length == 0 ) {
54+ setUseCustom ( false ) ;
55+ }
56+ return columnsWithDstTypes ;
57+ } , [ selectedColumns , destinationTypeMapping ] ) ;
58+
4459 const customColumnTypeList = useMemo ( ( ) => {
4560 const currentRow = rows . find ( ( r ) => r . source === tableRow . source ) ;
4661 if ( ! currentRow ) return [ ] ;
@@ -53,14 +68,10 @@ export default function CustomColumnType({
5368 } ) ) ;
5469 } , [ rows , tableRow . source ] ) ;
5570
56- const availableColumns = columns
57- . filter (
58- ( column ) =>
59- ! customColumnTypeList . some (
60- ( mapping ) => mapping . columnName === column . name
61- )
62- )
63- . filter ( ( column ) => destinationTypeMapping [ column . name ] !== undefined ) ;
71+ const remainingColumnsWithDstTypes = columnsWithDstTypes . filter (
72+ ( col ) =>
73+ ! customColumnTypeList . some ( ( mapping ) => mapping . columnName === col . name )
74+ ) ;
6475
6576 const destinationTypeOptions = useCallback (
6677 ( col : string ) : { value : string ; label : string } [ ] => {
@@ -71,9 +82,7 @@ export default function CustomColumnType({
7182
7283 useEffect ( ( ) => {
7384 const fetchTypeMappings = async ( ) => {
74- if ( ! useCustom ) return ;
75-
76- const columnNameToQvalueKind = columns . map ( ( col ) => [
85+ const columnNameToQvalueKind = selectedColumns . map ( ( col ) => [
7786 col . name ,
7887 col . qkind ,
7988 ] ) as [ string , string ] [ ] ;
@@ -103,12 +112,9 @@ export default function CustomColumnType({
103112 } ;
104113
105114 fetchTypeMappings ( ) ;
106- // TODO: there is a bug where `columns` is getting re-rendered excessively
107- // in the parent. Once fixed, add back `columns` to the dependency array.
108- // eslint-disable-next-line react-hooks/exhaustive-deps
109- } , [ useCustom , peerType ] ) ;
115+ } , [ peerType , selectedColumns ] ) ;
110116
111- const handleUseCustom = useCallback (
117+ const handleUseCustomDstType = useCallback (
112118 ( state : boolean ) => {
113119 setUseCustom ( state ) ;
114120 if ( ! state ) {
@@ -129,7 +135,7 @@ export default function CustomColumnType({
129135 ) ;
130136 }
131137 } ,
132- [ tableRow . source , setRows ]
138+ [ tableRow . source ]
133139 ) ;
134140
135141 const handleCreateColumn = useCallback (
@@ -204,133 +210,144 @@ export default function CustomColumnType({
204210 ) ;
205211
206212 return (
207- < div
208- style = { {
209- display : 'flex' ,
210- flexDirection : 'column' ,
211- alignContent : 'center' ,
212- rowGap : '0.5rem' ,
213- } }
214- >
215- < RowWithCheckbox
216- label = {
217- < Label as = 'label' style = { { fontSize : 13 } } >
218- Use custom destination column type
219- </ Label >
220- }
221- action = {
222- < Checkbox
223- style = { { marginLeft : 0 } }
224- checked = { useCustom }
225- onCheckedChange = { handleUseCustom }
226- />
227- }
228- />
229- { useCustom && (
230- < div
213+ columnsWithDstTypes . length > 0 && (
214+ < div
215+ style = { {
216+ display : 'flex' ,
217+ flexDirection : 'column' ,
218+ alignContent : 'center' ,
219+ rowGap : '0.5rem' ,
220+ } }
221+ >
222+ < Divider
231223 style = { {
232- display : 'flex' ,
233- flexDirection : 'column' ,
234- gap : '0.5rem' ,
224+ ...columnBoxDividerStyle ,
225+ marginTop : '0.5rem' ,
235226 } }
236- >
237- { customColumnTypeList . length > 0 && (
238- < div
239- style = { {
240- display : 'flex' ,
241- gap : '0.5rem' ,
242- flexDirection : 'column' ,
243- } }
244- >
245- { customColumnTypeList . map ( ( mapping ) => (
246- < div
247- key = { mapping . columnName }
248- style = { {
249- display : 'flex' ,
250- alignItems : 'center' ,
251- gap : '0.5rem' ,
252- } }
253- >
254- < div style = { { width : '30%' } } >
255- < ReactSelect
256- value = { {
257- value : mapping . columnName ,
258- label : mapping . columnName ,
259- } }
260- theme = { SelectTheme }
261- styles = { engineOptionStyles }
262- />
263- </ div >
264- < span > →</ span >
265- < div style = { { width : '30%' } } >
266- < ReactSelect
267- value = { {
268- value : mapping . destinationType ,
269- label : mapping . destinationType ,
270- } }
271- onChange = { ( val ) =>
272- val ?. value && handleUpdateColumn ( mapping , val . value )
273- }
274- theme = { SelectTheme }
275- styles = { engineOptionStyles }
276- options = { destinationTypeOptions ( mapping . columnName ) }
277- />
278- </ div >
279- < Button
280- variant = 'normalBorderless'
281- onClick = { ( ) => handleUpdateColumn ( mapping , '' ) }
227+ />
228+ < RowWithCheckbox
229+ label = {
230+ < Label as = 'label' style = { { fontSize : 13 } } >
231+ Use custom destination column type
232+ </ Label >
233+ }
234+ action = {
235+ < Checkbox
236+ style = { { marginLeft : 0 } }
237+ checked = { useCustom }
238+ onCheckedChange = { handleUseCustomDstType }
239+ />
240+ }
241+ />
242+ { useCustom && (
243+ < div
244+ style = { {
245+ display : 'flex' ,
246+ flexDirection : 'column' ,
247+ gap : '0.5rem' ,
248+ } }
249+ >
250+ { customColumnTypeList . length > 0 && (
251+ < div
252+ style = { {
253+ display : 'flex' ,
254+ gap : '0.5rem' ,
255+ flexDirection : 'column' ,
256+ } }
257+ >
258+ { customColumnTypeList . map ( ( mapping ) => (
259+ < div
260+ key = { mapping . columnName }
261+ style = { {
262+ display : 'flex' ,
263+ alignItems : 'center' ,
264+ gap : '0.5rem' ,
265+ } }
282266 >
283- < Icon name = 'close' />
284- </ Button >
285- </ div >
286- ) ) }
287- </ div >
288- ) }
289-
290- { availableColumns . length > 0 && (
291- < div
292- style = { { display : 'flex' , gap : '0.5rem' , alignItems : 'center' } }
293- >
294- < div style = { { width : '30%' } } >
295- < ReactSelect
296- placeholder = 'Column'
297- value = {
298- selectedColumnName
299- ? { value : selectedColumnName , label : selectedColumnName }
300- : null
301- }
302- onChange = { ( val ) =>
303- val ?. value && setSelectedColumnName ( val . value )
304- }
305- options = { availableColumns . map ( ( col ) => ( {
306- value : col . name ,
307- label : col . name ,
308- } ) ) }
309- theme = { SelectTheme }
310- styles = { engineOptionStyles }
311- />
267+ < div style = { { width : '30%' } } >
268+ < ReactSelect
269+ value = { {
270+ value : mapping . columnName ,
271+ label : mapping . columnName ,
272+ } }
273+ theme = { SelectTheme }
274+ styles = { engineOptionStyles }
275+ />
276+ </ div >
277+ < span > →</ span >
278+ < div style = { { width : '30%' } } >
279+ < ReactSelect
280+ value = { {
281+ value : mapping . destinationType ,
282+ label : mapping . destinationType ,
283+ } }
284+ onChange = { ( val ) =>
285+ val ?. value && handleUpdateColumn ( mapping , val . value )
286+ }
287+ theme = { SelectTheme }
288+ styles = { engineOptionStyles }
289+ options = { destinationTypeOptions ( mapping . columnName ) }
290+ />
291+ </ div >
292+ < Button
293+ variant = 'normalBorderless'
294+ onClick = { ( ) => handleUpdateColumn ( mapping , '' ) }
295+ >
296+ < Icon name = 'close' />
297+ </ Button >
298+ </ div >
299+ ) ) }
312300 </ div >
313- < span > →</ span >
314- < div style = { { width : '30%' } } >
315- < ReactSelect
316- placeholder = 'Destination type'
317- value = { null }
318- onChange = { ( val ) =>
319- val ?. value && handleCreateColumn ( val . value )
320- }
321- options = {
322- selectedColumnName
323- ? destinationTypeOptions ( selectedColumnName )
324- : [ ]
325- }
326- theme = { SelectTheme }
327- styles = { engineOptionStyles }
328- />
301+ ) }
302+
303+ { remainingColumnsWithDstTypes . length > 0 && (
304+ < div
305+ style = { { display : 'flex' , gap : '0.5rem' , alignItems : 'center' } }
306+ >
307+ < div style = { { width : '30%' } } >
308+ < ReactSelect
309+ placeholder = 'Column'
310+ value = {
311+ selectedColumnName
312+ ? {
313+ value : selectedColumnName ,
314+ label : selectedColumnName ,
315+ }
316+ : null
317+ }
318+ onChange = { ( val ) =>
319+ val ?. value && setSelectedColumnName ( val . value )
320+ }
321+ options = { remainingColumnsWithDstTypes . map ( ( col ) => ( {
322+ value : col . name ,
323+ label : col . name ,
324+ } ) ) }
325+ theme = { SelectTheme }
326+ styles = { engineOptionStyles }
327+ />
328+ </ div >
329+ < span > →</ span >
330+ < div style = { { width : '30%' } } >
331+ < ReactSelect
332+ placeholder = 'Destination type'
333+ value = { null }
334+ onChange = { ( val ) =>
335+ val ?. value && handleCreateColumn ( val . value )
336+ }
337+ options = {
338+ selectedColumnName
339+ ? destinationTypeOptions ( selectedColumnName )
340+ : [ ]
341+ }
342+ theme = { SelectTheme }
343+ styles = { engineOptionStyles }
344+ />
345+ </ div >
329346 </ div >
330- </ div >
331- ) }
332- </ div >
333- ) }
334- </ div >
347+ ) }
348+ </ div >
349+ ) }
350+ </ div >
351+ )
335352 ) ;
336353}
0 commit comments