From 1940bbca1f5a3a7acf08247edcfa24560ee1f76c Mon Sep 17 00:00:00 2001 From: Betthauser Date: Tue, 7 May 2024 14:42:23 -0700 Subject: [PATCH 01/49] feat(client): add import dropdown options and modal --- .../components/notebook/NotebookAddCell.tsx | 156 +++++++++++++++--- 1 file changed, 137 insertions(+), 19 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index fe95418b5f..065c557947 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -1,7 +1,16 @@ import { useState, useEffect } from 'react'; import { observer } from 'mobx-react-lite'; import { computed } from 'mobx'; -import { styled, Button, Divider, Menu, MenuProps, Stack } from '@semoss/ui'; +import { + styled, + Button, + Divider, + Menu, + MenuProps, + Stack, + Typography, + Modal, +} from '@semoss/ui'; import { useBlocks } from '@/hooks'; import { @@ -92,6 +101,26 @@ const Transformations = Array.from(Object.values(TransformationCells)).map( }, ); +const DataImportDropdownOptions = [ + { + display: `From Data Catalog`, + defaultCellType: null, + }, + { + display: `From CSV`, + defaultCellType: null, + }, +]; + +// const DataImportDropdownOptions = Array.from(Object.values(TransformationCells)).map( +// (item) => { +// return { +// display: `Test ${item.name}`, +// defaultCellType: item.widget, +// }; +// }, +// ); + const AddCellOptions: Record = { code: { display: 'Cell', @@ -134,8 +163,8 @@ const AddCellOptions: Record = { 'import-data': { display: 'Import Data', icon: , - options: [], - disabled: true, + options: DataImportDropdownOptions, + disabled: false, }, text: { display: 'Text', @@ -149,10 +178,21 @@ export const NotebookAddCell = observer( (props: { query: QueryState; previousCellId?: string }): JSX.Element => { const [anchorEl, setAnchorEl] = useState(null); const [selectedAddCell, setSelectedAddCell] = useState(''); + const [importModalType, setImportModalType] = useState(''); + const [isOpenDataImportModal, setIsOpenDataImportModal] = + useState(false); + // const [isOpenImportDataOptions, setIsOpenImportDataOptions] = useState(false); const open = Boolean(anchorEl); const { query, previousCellId = '' } = props; const { state, notebook } = useBlocks(); + useEffect(() => { + console.log({ + anchorEl, + type: typeof anchorEl, + }); + }, [anchorEl]); + // const cellTypeOptions = computed(() => { // const options = { ...AddCellOptions }; // // transformation cell types can only be added if there exists a query-import cell before it @@ -234,6 +274,7 @@ export const NotebookAddCell = observer( {Object.entries(AddCellOptions).map((add, i) => { const value = add[1]; + console.log({ i, add }); return ( - {Array.from( - AddCellOptions[selectedAddCell]?.options || [], - ({ display, defaultCellType }, index) => { - return ( - { - appendCell(defaultCellType); - setAnchorEl(null); - }} - > - {display} - - ); - }, + {selectedAddCell === 'transformation' && + Array.from( + AddCellOptions[selectedAddCell]?.options || [], + ({ display, defaultCellType }, index) => { + return ( + { + appendCell(defaultCellType); + setAnchorEl(null); + }} + > + {display} + + ); + }, + )} + + {selectedAddCell === 'import-data' && ( + <> + + Import Data + + {Array.from( + AddCellOptions[selectedAddCell]?.options || [], + ({ display }, index) => { + return ( + { + // appendCell(defaultCellType); + setIsOpenDataImportModal(true); + setImportModalType(display); + setAnchorEl(null); + }} + > + {display} + + ); + }, + )} + )} + + {/* Import Data Modal */} + + {importModalType} + + + {`(modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content)`} + + + + + + + + + ); }, From fd15602ba7a26e2dbf80e064fa268e79d87a1f85 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 8 May 2024 14:21:17 -0700 Subject: [PATCH 02/49] feat(client): restructure new modal based on consolidated figma --- .../components/notebook/NotebookAddCell.tsx | 119 ++++++++++++------ 1 file changed, 81 insertions(+), 38 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 065c557947..3f03e5d04e 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -10,6 +10,7 @@ import { Stack, Typography, Modal, + Select, } from '@semoss/ui'; import { useBlocks } from '@/hooks'; @@ -31,6 +32,7 @@ import { KeyboardArrowUp, KeyboardArrowDown, TableRows, + Label, } from '@mui/icons-material'; import { DefaultCellDefinitions, @@ -40,6 +42,7 @@ import { } from '@/components/cell-defaults'; import { QueryImportCellConfig } from '../cell-defaults/query-import-cell'; import { CodeCellConfig } from '../cell-defaults/code-cell'; +import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; const StyledButton = styled(Button)(({ theme }) => ({ color: theme.palette.text.secondary, @@ -186,6 +189,9 @@ export const NotebookAddCell = observer( const { query, previousCellId = '' } = props; const { state, notebook } = useBlocks(); + const { control, handleSubmit, reset, watch, setValue, getValues } = + useForm(); + useEffect(() => { console.log({ anchorEl, @@ -268,6 +274,10 @@ export const NotebookAddCell = observer( } }; + const onSubmit = (submitData) => { + console.log({ submitData }); + }; + return ( @@ -337,7 +347,7 @@ export const NotebookAddCell = observer( {selectedAddCell === 'import-data' && ( <> - Import Data - + */} {Array.from( AddCellOptions[selectedAddCell]?.options || [], ({ display }, index) => { @@ -355,10 +365,17 @@ export const NotebookAddCell = observer( { - // appendCell(defaultCellType); setIsOpenDataImportModal(true); - setImportModalType(display); + if ( + display == + 'From Data Catalog' + ) { + setImportModalType(display); + } else { + // open seperate modal for From CSV? + } setAnchorEl(null); }} > @@ -373,43 +390,69 @@ export const NotebookAddCell = observer( {/* Import Data Modal */} - {importModalType} - - - {`(modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content modal content)`} - - - +
- - + + Import Data + ( + + )} + /> + + {`[modal content]`} + + + + + {/* + + + */} - +
); From f7a0179e784d1fe42a513572628868c157d16c01 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Tue, 14 May 2024 14:20:53 -0700 Subject: [PATCH 03/49] feat(client): populate database dropdown with user dbs from be --- .../components/notebook/NotebookAddCell.tsx | 100 ++++++++---------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 3f03e5d04e..b698631643 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -13,7 +13,7 @@ import { Select, } from '@semoss/ui'; -import { useBlocks } from '@/hooks'; +import { useBlocks, usePixel } from '@/hooks'; import { ActionMessages, CellStateConfig, @@ -44,6 +44,16 @@ import { QueryImportCellConfig } from '../cell-defaults/query-import-cell'; import { CodeCellConfig } from '../cell-defaults/code-cell'; import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; +const StyledModalTitle = styled(Typography)(({ theme }) => ({ + alignContent: 'center', + marginRight: '15px', +})); + +const StyledModalTitleWrapper = styled(Modal.Title)(({ theme }) => ({ + display: 'flex', + alignContent: 'center', +})); + const StyledButton = styled(Button)(({ theme }) => ({ color: theme.palette.text.secondary, backgroundColor: 'unset!important', @@ -182,22 +192,24 @@ export const NotebookAddCell = observer( const [anchorEl, setAnchorEl] = useState(null); const [selectedAddCell, setSelectedAddCell] = useState(''); const [importModalType, setImportModalType] = useState(''); - const [isOpenDataImportModal, setIsOpenDataImportModal] = + const [isDataImportModalOpen, setIsDataImportModalOpen] = useState(false); - // const [isOpenImportDataOptions, setIsOpenImportDataOptions] = useState(false); const open = Boolean(anchorEl); const { query, previousCellId = '' } = props; const { state, notebook } = useBlocks(); const { control, handleSubmit, reset, watch, setValue, getValues } = useForm(); + const [userDatabases, setUserDatabases] = useState(null); + + const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); useEffect(() => { - console.log({ - anchorEl, - type: typeof anchorEl, - }); - }, [anchorEl]); + if (getDatabases.status !== 'SUCCESS') { + return; + } + setUserDatabases(getDatabases.data); + }, [getDatabases.status, getDatabases.data]); // const cellTypeOptions = computed(() => { // const options = { ...AddCellOptions }; @@ -347,17 +359,6 @@ export const NotebookAddCell = observer( {selectedAddCell === 'import-data' && ( <> - {/* - Import Data - */} {Array.from( AddCellOptions[selectedAddCell]?.options || [], ({ display }, index) => { @@ -367,14 +368,14 @@ export const NotebookAddCell = observer( value={display} disabled={display == 'From CSV'} // temporary onClick={() => { - setIsOpenDataImportModal(true); + setIsDataImportModalOpen(true); if ( display == 'From Data Catalog' ) { setImportModalType(display); } else { - // open seperate modal for From CSV? + // open seperate modal / form for From CSV } setAnchorEl(null); }} @@ -389,40 +390,37 @@ export const NotebookAddCell = observer( {/* Import Data Modal */} - +
- - - Import Data + + + + Import Data + ( + render={({ field }) => ( )} /> - + {`[modal content]`} - {/* - - - */}
From 098a5754f1be9a7b7a995389ab56949fb314a963 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 15 May 2024 14:20:54 -0700 Subject: [PATCH 04/49] feat(client): structure useform for addable removable query elements and children --- .../components/notebook/NotebookAddCell.tsx | 245 +++++++++++++++--- 1 file changed, 205 insertions(+), 40 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index b698631643..252de3e460 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -33,6 +33,9 @@ import { KeyboardArrowDown, TableRows, Label, + JoinLeftRounded, + FilterListRounded, + ControlPointDuplicateRounded, } from '@mui/icons-material'; import { DefaultCellDefinitions, @@ -105,6 +108,21 @@ interface AddCellOption { disabled?: boolean; } +type QueryChildElement = { + childElementName: string; +}; + +type QueryStackElement = { + queryType: string; // Data, Join or Filter + queryChildren: QueryChildElement[]; +}; + +type FormValues = { + queryStackElements: QueryStackElement[]; + databaseSelect: string; + tableSelect: string; +}; + const Transformations = Array.from(Object.values(TransformationCells)).map( (item) => { return { @@ -199,11 +217,28 @@ export const NotebookAddCell = observer( const { state, notebook } = useBlocks(); const { control, handleSubmit, reset, watch, setValue, getValues } = - useForm(); + useForm({ + defaultValues: { + queryStackElements: [], + databaseSelect: '', + tableSelect: '', + }, + }); + const [userDatabases, setUserDatabases] = useState(null); + const [queryElementCounter, setQueryElementCounter] = useState(0); const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); + const { + fields: stackFields, + append: appendStack, + remove: removeStack, + } = useFieldArray({ + control, + name: 'queryStackElements', + }); + useEffect(() => { if (getDatabases.status !== 'SUCCESS') { return; @@ -391,57 +426,187 @@ export const NotebookAddCell = observer( {/* Import Data Modal */} -
- - - - Import Data - + + + + Import Data + + ( + + )} + /> + + + + Data ( )} /> - - {`[modal content]`} - - - - - + + {stackFields.map((stack, stackIndex) => ( + + {stack.queryType} + + + ))} + + + + + + + + + +
From 349b0602bc8b3819950e8297e67bcd67f1ac75c7 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Thu, 16 May 2024 14:26:10 -0700 Subject: [PATCH 05/49] feat(client): databases selectable and populating tables selectfrom be on change --- .../components/notebook/NotebookAddCell.tsx | 158 +++++++++++++----- 1 file changed, 118 insertions(+), 40 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 252de3e460..7ee2ec36b9 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -13,7 +13,7 @@ import { Select, } from '@semoss/ui'; -import { useBlocks, usePixel } from '@/hooks'; +import { useBlocks, usePixel, useRootStore } from '@/hooks'; import { ActionMessages, CellStateConfig, @@ -47,6 +47,8 @@ import { QueryImportCellConfig } from '../cell-defaults/query-import-cell'; import { CodeCellConfig } from '../cell-defaults/code-cell'; import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; +import { LoadingScreen } from '@/components/ui'; + const StyledModalTitle = styled(Typography)(({ theme }) => ({ alignContent: 'center', marginRight: '15px', @@ -209,10 +211,13 @@ export const NotebookAddCell = observer( (props: { query: QueryState; previousCellId?: string }): JSX.Element => { const [anchorEl, setAnchorEl] = useState(null); const [selectedAddCell, setSelectedAddCell] = useState(''); + const [importModalType, setImportModalType] = useState(''); + const [tableNames, setTableNames] = useState([]); const [isDataImportModalOpen, setIsDataImportModalOpen] = useState(false); const open = Boolean(anchorEl); + const { query, previousCellId = '' } = props; const { state, notebook } = useBlocks(); @@ -229,6 +234,12 @@ export const NotebookAddCell = observer( const [queryElementCounter, setQueryElementCounter] = useState(0); const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); + const [isDatabaseLoading, setIsDatabaseLoading] = + useState(false); + const [showEditColumns, setShowEditColumns] = useState(false); + const [showTablePreview, setShowTablePreview] = + useState(false); + const { configStore, monolithStore } = useRootStore(); const { fields: stackFields, @@ -325,6 +336,30 @@ export const NotebookAddCell = observer( console.log({ submitData }); }; + const retrieveDatabaseTables = async (databaseId) => { + setIsDatabaseLoading(true); + const pixelString = `META | GetDatabaseTableStructure ( database = [ \"${databaseId}\" ] ) ;`; + + monolithStore.runQuery(pixelString).then((response) => { + const type = response.pixelReturn[0].operationType; + const pixelResponse = response.pixelReturn[0].output; + + if (type.indexOf('ERROR') === -1) { + const tableNames = [ + ...pixelResponse.reduce((set, ele) => { + set.add(ele[0]); + return set; + }, new Set()), + ]; + setTableNames(tableNames); + } else { + console.error('Error retrieving database tables'); + } + + setIsDatabaseLoading(false); + }); + }; + return ( @@ -426,6 +461,9 @@ export const NotebookAddCell = observer( {/* Import Data Modal */} + {isDatabaseLoading && ( + + )}
( { - // field.onChange(e.target.value) - console.log({ e }); - }} - label={'Select Table...'} - // value={field.value || null} - size={'small'} - sx={{ - minWidth: '220px', - }} - > - - sample table 1 - - - sample table 2 - - - sample table 3 - - {/* {userDatabases?.map((ele) => ( - - {ele.app_name} + {!!tableNames.length && ( + + Data: + ( + + ))} + + )} + /> + + + + {showEditColumns && ( +
+ Edit Columns +
)} - /> -
+ + {showTablePreview && ( +
+ Preview +
+ )} + + )} {stackFields.map((stack, stackIndex) => ( {stack.queryType} @@ -514,7 +593,6 @@ export const NotebookAddCell = observer( color="error" size="small" onClick={() => { - // alert(`delete ${stackIndex}`); removeStack(stackIndex); }} > From dfdbc01bf01a1621ccbf479a88bdc57b69eb72e9 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Fri, 17 May 2024 22:29:38 -0700 Subject: [PATCH 06/49] feat(client): table preview retrieving and displaying correct vals from sample db id --- .../components/notebook/NotebookAddCell.tsx | 192 +++++++++++++++++- 1 file changed, 188 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 7ee2ec36b9..562c328acd 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -11,6 +11,7 @@ import { Typography, Modal, Select, + Table, } from '@semoss/ui'; import { useBlocks, usePixel, useRootStore } from '@/hooks'; @@ -48,6 +49,7 @@ import { CodeCellConfig } from '../cell-defaults/code-cell'; import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; import { LoadingScreen } from '@/components/ui'; +import { useBlocksPixel } from '@/hooks/useBlocksPixel'; const StyledModalTitle = styled(Typography)(({ theme }) => ({ alignContent: 'center', @@ -233,6 +235,16 @@ export const NotebookAddCell = observer( const [userDatabases, setUserDatabases] = useState(null); const [queryElementCounter, setQueryElementCounter] = useState(0); + const [databaseTableHeaders, setDatabaseTableHeaders] = useState([]); + const [databaseTableRawHeaders, setDatabaseTableRawHeaders] = useState( + [], + ); + const [databaseTableRows, setDatabaseTableRows] = useState([]); + + const [selectedDatabaseId, setSelectedDatabaseId] = useState(null); + const [selectedTable, setSelectedTable] = useState(null); + const [selectedColumnsSet, setSelectedColumnsSet] = useState(new Set()); + const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); const [isDatabaseLoading, setIsDatabaseLoading] = useState(false); @@ -250,6 +262,16 @@ export const NotebookAddCell = observer( name: 'queryStackElements', }); + useEffect( + () => console.log({ selectedColumnsSet }), + [selectedColumnsSet], + ); + useEffect( + () => console.log({ selectedDatabaseId }), + [selectedDatabaseId], + ); + useEffect(() => console.log({ selectedTable }), [selectedTable]); + useEffect(() => { if (getDatabases.status !== 'SUCCESS') { return; @@ -360,6 +382,96 @@ export const NotebookAddCell = observer( }); }; + const selectTableHandler = (tableName) => { + // get column names from GetDatabaseTableStructure + alert('get column names from GetDatabaseTableStructure'); + }; + + const retrieveTableRows = async () => { + // setIsDatabaseLoading(true); + // "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | Select ( STATION_SETTINGS__EMAIL , STATION_SETTINGS__ROLE , STATION_SETTINGS__STATION , STATION_SETTINGS__USER , STATION_SETTINGS__VISN ) .as ( [ EMAIL , ROLE , STATION , USER , VISN ] ) | Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME961853__Preview\" ] ) ] ) ;" + // "META | Frame ( ) | QueryAll ( ) | Limit ( 20 ) | Collect ( 500 ) ;" + // "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | Select ( STATION_SETTINGS__EMAIL , STATION_SETTINGS__ROLE , STATION_SETTINGS__STATION , STATION_SETTINGS__USER , STATION_SETTINGS__VISN ) .as ( [ EMAIL , ROLE , STATION , USER , VISN ] ) | Distinct ( false ) | QueryRowCount ( ) ;" + // `Database( database=["f9b656cc-06e7-4cce-bae8-b5f92075b6da"] )|Select(STATION_SETTINGS__EMAIL, STATION_SETTINGS__ROLE, STATION_SETTINGS__STATION, STATION_SETTINGS__USER, STATION_SETTINGS__VISN).as([EMAIL, ROLE, STATION, USER, VISN])|Distinct(false)|Limit(20) | Import(frame=[CreateFrame(frameType=[GRID], override=[true]).as(["consolidated_settings_FRAME961853__Preview"])]);META|Frame()|QueryAll()|Limit(20)|Collect(500);` + // const pixelString = `META | GetDatabaseTableStructure ( database = [ \"${databaseId}\" ] ) ;`; + // const pixelString = `Database( database=["f9b656cc-06e7-4cce-bae8-b5f92075b6da"] )|Select(STATION_SETTINGS__EMAIL, STATION_SETTINGS__ROLE, STATION_SETTINGS__STATION, STATION_SETTINGS__USER, STATION_SETTINGS__VISN).as([EMAIL, ROLE, STATION, USER, VISN]);` + // const pixelString2 = `META|Frame()|QueryAll()|Limit(20)|Collect(500);` + + // const pixelString = ``` + // Database( + // database = [ + // \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" + // ] + // ) | Select ( + // STATION_SETTINGS__EMAIL, + // STATION_SETTINGS__ROLE, + // STATION_SETTINGS__STATION, + // STATION_SETTINGS__USER, + // STATION_SETTINGS__VISN + // ).as( + // [ + // EMAIL, + // ROLE, + // STATION, + // USER, + // VISN + // ] + // ) | Distinct(false) | Limit(20) | Import ( + // frame = [ + // CreateFrame( + // frameType = [ + // GRID + // ], + // override = [ + // true + // ] ).as( + // [ + // \"consolidated_settings_FRAME961853__Preview\" + // ] + // ) + // ] + // ); META | Frame() | QueryAll() | Limit(20) | Collect(500); + // ``` + + // const pixelString = `Database(database=[\"${ selectedDatabaseId }\"])|Select(STATION_SETTINGS__EMAIL,STATION_SETTINGS__ROLE,STATION_SETTINGS__STATION,STATION_SETTINGS__USER,STATION_SETTINGS__VISN).as([EMAIL,ROLE,STATION,USER,VISN])|Distinct(false)|Limit(20)|Import(frame=[CreateFrame(frameType=[GRID],override=[true]).as([\"consolidated_settings_FRAME961853__Preview\"])]); META | Frame() | QueryAll() | Limit(20) | Collect(500);` + const pixelString = `Database(database=[\"f9b656cc-06e7-4cce-bae8-b5f92075b6da\"])|Select(STATION_SETTINGS__EMAIL,STATION_SETTINGS__ROLE,STATION_SETTINGS__STATION,STATION_SETTINGS__USER,STATION_SETTINGS__VISN).as([EMAIL,ROLE,STATION,USER,VISN])|Distinct(false)|Limit(20)|Import(frame=[CreateFrame(frameType=[GRID],override=[true]).as([\"consolidated_settings_FRAME961853__Preview\"])]); META | Frame() | QueryAll() | Limit(20) | Collect(500);`; + + await monolithStore.runQuery(pixelString).then((response) => { + const type = response.pixelReturn[0].operationType; + const pixelResponse1 = response; + const tableHeadersData = + response.pixelReturn[1].output.data.headers; + const tableRawHeadersData = + response.pixelReturn[1].output.data.rawHeaders; + const tableRowsData = + response.pixelReturn[1].output.data.values; + + console.log({ + tableHeadersData, + tableRawHeadersData, + tableRowsData, + }); + + setDatabaseTableHeaders(tableHeadersData); + setDatabaseTableRawHeaders(tableRawHeadersData); + setDatabaseTableRows(tableRowsData); + + // if (type.indexOf('ERROR') === -1) { + // const tableNames = [ + // ...pixelResponse.reduce((set, ele) => { + // set.add(ele[0]); + // return set; + // }, new Set()), + // ]; + // setTableNames(tableNames); + // } else { + // console.error('Error retrieving database tables'); + // } + + // setIsDatabaseLoading(false); + }); + }; + return ( @@ -484,6 +596,9 @@ export const NotebookAddCell = observer( + */} + { + console.log( + { + checkbox: + value, + }, + ); + const tableColumnsObjectDup = + { + ...tableColumnsObject, + }; + tableColumnsObjectDup[ + selectedTable + ][ + columnIdx + ].showInPreview = + !tableColumnsObjectDup[ + selectedTable + ][ + columnIdx + ] + .showInPreview; + setTableColumnsObject( + tableColumnsObjectDup, + ); + }} + /> + { + console.log( + { + textbox: + value, + }, + ); + const tableColumnsObjectDup = + { + ...tableColumnsObject, + }; + tableColumnsObjectDup[ + selectedTable + ][ + columnIdx + ].userAlias = + value; + setTableColumnsObject( + tableColumnsObjectDup, + ); + }} + > + {/* {tableColumnsObject[columnName].userAlias} */} + + + ); + }, + )} + + )} {showTablePreview && ( @@ -698,56 +812,38 @@ export const NotebookAddCell = observer( - {/* {getData.status === 'SUCCESS' && */} - {true && - databaseTableHeaders.map( - (h, hIdx) => ( - - {h} - - ), - )} - - - - {/* {isLoading && ( - - - - )} */} - {/* {isError && ( - - There was an issue generating a preview. - - )} */} - {/* {getData.status === 'SUCCESS' && */} - {true && - databaseTableRows.map( - (r, rIdx) => ( - ( + - {r.map( - ( - v, - vIdx, - ) => ( - - { - v - } - - ), - )} - + {h} + ), )} + + + + {databaseTableRows.map( + (r, rIdx) => ( + + {r.map( + ( + v, + vIdx, + ) => ( + + {v} + + ), + )} + + ), + )}
From e57d7fa45e730346058fc8b3b0f1b40b1f590104 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Tue, 21 May 2024 12:29:52 -0700 Subject: [PATCH 08/49] feat(client): preview and column editing fully working and tracked in useform --- .../components/notebook/NotebookAddCell.tsx | 348 +++++++++--------- 1 file changed, 164 insertions(+), 184 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index f0690853fe..b9f3282ff5 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -13,6 +13,7 @@ import { Select, Table, Checkbox, + TextField, } from '@semoss/ui'; import { useBlocks, usePixel, useRootStore } from '@/hooks'; @@ -44,14 +45,16 @@ import { DefaultCellDefinitions, DefaultCells, TransformationCells, - // ImportDataCells, // need options for Import Data dropdown options } from '@/components/cell-defaults'; import { QueryImportCellConfig } from '../cell-defaults/query-import-cell'; import { CodeCellConfig } from '../cell-defaults/code-cell'; import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; import { LoadingScreen } from '@/components/ui'; -import { useBlocksPixel } from '@/hooks/useBlocksPixel'; + +const StyledImportDataForm = styled('form')(({ theme }) => ({ + margin: '30px 41px', +})); const StyledModalTitle = styled(Typography)(({ theme }) => ({ alignContent: 'center', @@ -103,6 +106,14 @@ const StyledBorderDiv = styled('div')(({ theme }) => ({ borderRadius: '8px', })); +interface Column { + id: string; + tableName: string; + columnName: string; + userAlias: string; + checked: boolean; +} + interface AddCellOption { display: string; icon: React.ReactNode; @@ -127,6 +138,7 @@ type FormValues = { queryStackElements: QueryStackElement[]; databaseSelect: string; tableSelect: string; + columns: Column[]; }; const Transformations = Array.from(Object.values(TransformationCells)).map( @@ -149,15 +161,6 @@ const DataImportDropdownOptions = [ }, ]; -// const DataImportDropdownOptions = Array.from(Object.values(TransformationCells)).map( -// (item) => { -// return { -// display: `Test ${item.name}`, -// defaultCellType: item.widget, -// }; -// }, -// ); - const AddCellOptions: Record = { code: { display: 'Cell', @@ -247,7 +250,7 @@ export const NotebookAddCell = observer( const [selectedDatabaseId, setSelectedDatabaseId] = useState(null); const [selectedTable, setSelectedTable] = useState(null); - const [selectedColumnsSet, setSelectedColumnsSet] = useState(new Set()); + const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); const [isDatabaseLoading, setIsDatabaseLoading] = @@ -266,28 +269,30 @@ export const NotebookAddCell = observer( name: 'queryStackElements', }); - // useEffect( - // () => console.log({ selectedColumnsSet }), - // [selectedColumnsSet], - // ); - // useEffect( - // () => console.log({ selectedDatabaseId }), - // [selectedDatabaseId], - // ); - // useEffect(() => console.log({ selectedTable }), [selectedTable]); + const { fields, append, remove } = useFieldArray({ + control, + name: 'columns', + }); + + useEffect(() => { + remove(); + tableColumnsObject[selectedTable]?.forEach((tableObject, idx) => { + console.log({ tableObject }); + append({ + id: idx, + tableName: tableObject.tableName, + columnName: tableObject.columnName, + userAlias: tableObject.columnName, + checked: true, + }); + }); + }, [selectedTable]); useEffect(() => { if (getDatabases.status !== 'SUCCESS') { return; } setUserDatabases(getDatabases.data); - - // // add all table names to new array and set in state - // console.log({ userDatabases: getDatabases }); - // setDatabaseTableNames([]); - - // // add all table columns to arrays as values set at table names keys - // setTableColumnsObject({}); }, [getDatabases.status, getDatabases.data]); // const cellTypeOptions = computed(() => { @@ -365,7 +370,7 @@ export const NotebookAddCell = observer( } }; - const onSubmit = (submitData) => { + const onImportDataSubmit = (submitData) => { console.log({ submitData }); }; @@ -386,7 +391,7 @@ export const NotebookAddCell = observer( ]; const newTableColumnsObject = pixelResponse.reduce( - (acc, ele) => { + (acc, ele, idx) => { const tableName = ele[0]; const columnName = ele[1]; const columnType = ele[2]; @@ -404,11 +409,12 @@ export const NotebookAddCell = observer( columnName2, tableName2, userAlias: columnName, // user editable in Edit Columns - showInPreview: true, // user editable in Edit Columns + checked: true, }); return acc; }, + {}, ); setTableColumnsObject(newTableColumnsObject); @@ -443,8 +449,7 @@ export const NotebookAddCell = observer( const aliasString = tableColumnsObject[tableName] .map( - (ele) => - `${ele.columnName}`, // may need to switch to ele.columnName2 but they seem to be identical + (ele) => `${ele.columnName}`, // may need to switch to ele.columnName2 but they seem to be identical ) .join(', '); @@ -454,7 +459,6 @@ export const NotebookAddCell = observer( await monolithStore.runQuery(pixelString).then((response) => { const type = response.pixelReturn[0].operationType; - const pixelResponse1 = response; const tableHeadersData = response.pixelReturn[1].output.data.headers; const tableRawHeadersData = @@ -472,17 +476,9 @@ export const NotebookAddCell = observer( setDatabaseTableRawHeaders(tableRawHeadersData); setDatabaseTableRows(tableRowsData); - // if (type.indexOf('ERROR') === -1) { - // const tableNames = [ - // ...pixelResponse.reduce((set, ele) => { - // set.add(ele[0]); - // return set; - // }, new Set()), - // ]; - // setTableNames(tableNames); - // } else { - // console.error('Error retrieving database tables'); - // } + if (type.indexOf('ERROR') != -1) { + console.error('Error retrieving database tables'); + } setIsDatabaseLoading(false); }); @@ -591,17 +587,11 @@ export const NotebookAddCell = observer( {isDatabaseLoading && ( )} - - - + + Import Data {userDatabases?.map((ele) => ( - {/* */} {ele.app_name} ))} @@ -635,9 +628,7 @@ export const NotebookAddCell = observer( )} /> - + {!!tableNames.length && ( Edit Columns -
    - {databaseTableHeaders.map( - (columnName, columnIdx) => { - console.log({ - selectedTable, - }); - console.log({ - columnName, - }); - console.log({ - tableColumnsObject, - }); - return ( -
  • - {/* - */} - { - console.log( - { - checkbox: - value, - }, + {fields?.map((field, index) => ( +
    + ( + { + field.onChange( + e, + ); + const hiddenColumnIdsSetDup = + new Set( + [ + ...hiddenColumnIdsSet, + ], ); - const tableColumnsObjectDup = - { - ...tableColumnsObject, - }; - tableColumnsObjectDup[ - selectedTable - ][ - columnIdx - ].showInPreview = - !tableColumnsObjectDup[ - selectedTable - ][ - columnIdx - ] - .showInPreview; - setTableColumnsObject( - tableColumnsObjectDup, + if ( + field.value == + true + ) { + hiddenColumnIdsSetDup.add( + index, ); - }} - /> - { - console.log( - { - textbox: - value, - }, + } else { + hiddenColumnIdsSetDup.delete( + index, ); - const tableColumnsObjectDup = - { - ...tableColumnsObject, - }; - tableColumnsObjectDup[ - selectedTable - ][ - columnIdx - ].userAlias = - value; - setTableColumnsObject( - tableColumnsObjectDup, - ); - }} - > - {/* {tableColumnsObject[columnName].userAlias} */} - -
  • - ); - }, - )} -
+ } + setHiddenColumnIdsSet( + hiddenColumnIdsSetDup, + ); + }} + /> + )} + /> + ( + { + field.onChange( + e.target + .value, + ); + const newTableHeaders = + [ + ...databaseTableHeaders, + ]; + newTableHeaders[ + index + ] = + e.target.value; + setDatabaseTableHeaders( + newTableHeaders, + ); + }} + /> + )} + /> + + ))} )} @@ -812,15 +785,21 @@ export const NotebookAddCell = observer( - {databaseTableHeaders.map( - (h, hIdx) => ( + {databaseTableHeaders + .filter( + (v, colIdx) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map((h, hIdx) => ( {h} - ), - )} + ))} @@ -829,18 +808,31 @@ export const NotebookAddCell = observer( - {r.map( - ( - v, - vIdx, - ) => ( - - {v} - - ), - )} + {r + .filter( + ( + v, + colIdx, + ) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map( + ( + v, + vIdx, + ) => ( + + { + v + } + + ), + )} ), )} @@ -874,7 +866,7 @@ export const NotebookAddCell = observer( sx={{ display: 'flex', justifyContent: 'flex-start', - border: '1px solid goldenrod', + // border: '1px solid goldenrod', padding: '0px', }} > @@ -934,22 +926,10 @@ export const NotebookAddCell = observer( sx={{ display: 'flex', justifyContent: 'flex-end', - border: '1px solid pink', + // border: '1px solid pink', padding: '0px', }} > - + + {showTables && cell.parameters.databaseId ? ( + + ) : ( + <> + )} + + )} + + + + {isExpanded && ( + + + + + ), + }} + onChange={(e) => { + const value = e.target.value; + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.frameType', + value: value, + }, + }); + }} + > + {Object.values(FRAME_TYPES).map((frame, i) => ( + + {frame.display} + + ))} + + + ), + }} + onChange={(e) => { + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.frameVariableName', + value: e.target.value, + }, + }); + }} + /> + + )} + + + ); + }, +); diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DatabaseTables.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DatabaseTables.tsx new file mode 100644 index 0000000000..149c14d716 --- /dev/null +++ b/packages/client/src/components/cell-defaults/data-import-cell/DatabaseTables.tsx @@ -0,0 +1,143 @@ +import { useState, useMemo } from 'react'; +import { usePixel } from '@/hooks'; +import { + styled, + List, + Stack, + Card, + Divider, + LinearProgress, + Typography, + Collapse, +} from '@semoss/ui'; +import { + AccessTime, + DateRange, + FontDownload, + KeyboardArrowRight, + Numbers, + TableChartOutlined, +} from '@mui/icons-material'; + +const StyledHeader = styled(Stack)(() => ({ + cursor: 'pointer', +})); +const StyledTableScroll = styled(Stack)(({ theme }) => ({ + width: '100%', + overflow: 'auto', + padding: theme.spacing(0.5), +})); +const StyledCard = styled(Card)(({ theme }) => ({ + minWidth: theme.spacing(35), +})); +const StyledList = styled(List)(({ theme }) => ({ + maxHeight: theme.spacing(15), + overflow: 'auto', +})); + +export const DatabaseTables = (props: { databaseId: string }) => { + const [tables, setTables] = useState({}); + const [isLoading, setIsLoading] = useState(true); + + const databaseMetamodel = usePixel<{ + dataTypes: Record; + nodes: { propSet: string[]; conceptualName: string }[]; + }>( + `GetDatabaseMetamodel( database=["${props.databaseId}"], options=["dataTypes"]); `, + ); + + useMemo(() => { + if (databaseMetamodel.status !== 'SUCCESS') { + setIsLoading(true); + return; + } + const { nodes = [], dataTypes = {} } = databaseMetamodel.data; + const retrievedTables = {}; + nodes.forEach((n) => { + const tableName = n.conceptualName; + const filteredDataTypes = Object.keys(dataTypes).filter((colName) => + colName.includes(`${tableName}__`), + ); + retrievedTables[n.conceptualName] = { + columnNames: [...n.propSet], + columnTypes: filteredDataTypes.reduce((acc, colName) => { + acc[colName] = dataTypes[colName]; + return acc; + }, {}), + }; + }); + setTables(retrievedTables); + setIsLoading(false); + }, [databaseMetamodel.status, databaseMetamodel.data]); + + const getIconForDataType = (dataType: string) => { + switch (dataType) { + case 'INT': + case 'DOUBLE': + case 'DECIMAL': + case 'NUMBER': + return ; + case 'STRING': + case 'TEXT': + return ; + case 'DATE': + case 'DATETIME': + return ; + case 'TIME': + return ; + default: + return <>; + } + }; + + if (isLoading) { + return ; + } + + return ( +
+ {isLoading && } + + + {Array.from(Object.keys(tables), (tableName, index) => { + return ( + + + + + + + + + + {Array.from( + tables[tableName].columnNames, + (columnName, index) => { + return ( + + + {getIconForDataType( + tables[tableName] + .columnTypes[ + `${tableName}__${columnName}` + ], + )} + + + + ); + }, + )} + + + ); + })} + + +
+ ); +}; diff --git a/packages/client/src/components/cell-defaults/data-import-cell/config.ts b/packages/client/src/components/cell-defaults/data-import-cell/config.ts new file mode 100644 index 0000000000..6394cdeab6 --- /dev/null +++ b/packages/client/src/components/cell-defaults/data-import-cell/config.ts @@ -0,0 +1,17 @@ +import { CellConfig } from '@/stores'; +import { DataImportCell, DataImportCellDef } from './DataImportCell'; + +export const DataImportCellConfig: CellConfig = { + name: 'Data Import', + widget: 'data-import', + view: DataImportCell, + parameters: { + databaseId: '', + frameType: 'PY', + frameVariableName: '', + selectQuery: '', + }, + toPixel: ({ databaseId, frameType, frameVariableName, selectQuery }) => { + return `Database( database=["${databaseId}"] ) | Query("${selectQuery}") | Import(frame=[CreateFrame(frameType=[${frameType}], override=[true]).as(["${frameVariableName}"])]);`; + }, +}; diff --git a/packages/client/src/components/cell-defaults/data-import-cell/index.ts b/packages/client/src/components/cell-defaults/data-import-cell/index.ts new file mode 100644 index 0000000000..82983d57d9 --- /dev/null +++ b/packages/client/src/components/cell-defaults/data-import-cell/index.ts @@ -0,0 +1,2 @@ +export * from './config'; +export * from './DataImportCell'; diff --git a/packages/client/src/components/cell-defaults/index.ts b/packages/client/src/components/cell-defaults/index.ts index 36f89b0ce4..ec8646954a 100644 --- a/packages/client/src/components/cell-defaults/index.ts +++ b/packages/client/src/components/cell-defaults/index.ts @@ -2,6 +2,7 @@ import { CellRegistry } from '@/stores'; import { CodeCellConfig, CodeCellDef } from './code-cell'; import { QueryImportCellConfig, QueryImportCellDef } from './query-import-cell'; +import { DataImportCellConfig, DataImportCellDef } from './data-import-cell'; import { UppercaseTransformationCellConfig, UppercaseTransformationCellDef, @@ -46,6 +47,7 @@ import { export type DefaultCellDefinitions = | CodeCellDef | QueryImportCellDef + | DataImportCellDef | UppercaseTransformationCellDef | UpdateRowTransformationCellDef | ColumnTypeTransformationCellDef @@ -59,6 +61,7 @@ export type DefaultCellDefinitions = export const DefaultCells: CellRegistry = { [CodeCellConfig.widget]: CodeCellConfig, [QueryImportCellConfig.widget]: QueryImportCellConfig, + [DataImportCellConfig.widget]: DataImportCellConfig, [UppercaseTransformationCellConfig.widget]: UppercaseTransformationCellConfig, [UpdateRowTransformationCellConfig.widget]: diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index b9f3282ff5..c1ca500294 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { observer } from 'mobx-react-lite'; import { computed } from 'mobx'; import { @@ -47,6 +47,7 @@ import { TransformationCells, } from '@/components/cell-defaults'; import { QueryImportCellConfig } from '../cell-defaults/query-import-cell'; +import { DataImportCellConfig } from '../cell-defaults/data-import-cell'; import { CodeCellConfig } from '../cell-defaults/code-cell'; import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; @@ -252,7 +253,11 @@ export const NotebookAddCell = observer( const [selectedTable, setSelectedTable] = useState(null); const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); - const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); + const [importDataSQLString, setImportDataSQLString] = + useState(''); + const importDataSQLStringRef = useRef(''); + + const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open const [isDatabaseLoading, setIsDatabaseLoading] = useState(false); const [showEditColumns, setShowEditColumns] = useState(false); @@ -295,6 +300,11 @@ export const NotebookAddCell = observer( setUserDatabases(getDatabases.data); }, [getDatabases.status, getDatabases.data]); + const loadDatabaseStructure = () => { + // set loading to true + // fetch database structure + }; + // const cellTypeOptions = computed(() => { // const options = { ...AddCellOptions }; // // transformation cell types can only be added if there exists a query-import cell before it @@ -332,6 +342,15 @@ export const NotebookAddCell = observer( parameters: DefaultCells[widget].parameters, }; + if (widget === DataImportCellConfig.widget) { + config.parameters = { + ...DefaultCells[widget].parameters, + frameVariableName: `FRAME_${newCellId}`, + databaseId: selectedDatabaseId, + selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs + }; + } + if (widget === QueryImportCellConfig.widget) { config.parameters = { ...DefaultCells[widget].parameters, @@ -370,8 +389,32 @@ export const NotebookAddCell = observer( } }; + const constructSQLString = ({ submitData }) => { + console.log({ submitData }); + let newSQLString = 'SELECT '; + + newSQLString += submitData.columns + .filter((ele) => ele.checked) + .map((colObj) => { + if (colObj.columnName === colObj.userAlias) { + return colObj.columnName; + } else { + return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + } + }) + .join(', '); + + newSQLString += ` FROM ${submitData.tableSelect}`; + newSQLString += ';'; + + importDataSQLStringRef.current = newSQLString; + }; + const onImportDataSubmit = (submitData) => { console.log({ submitData }); + constructSQLString({ submitData }); + appendCell('data-import'); + setIsDataImportModalOpen(false); }; const retrieveDatabaseTables = async (databaseId) => { @@ -428,25 +471,17 @@ export const NotebookAddCell = observer( }; const selectTableHandler = (tableName) => { - // get column names from GetDatabaseTableStructure - // alert('get column names from GetDatabaseTableStructure'); setSelectedTable(tableName); retrieveTableRows(tableName); }; const retrieveTableRows = async (tableName) => { setIsDatabaseLoading(true); - - // create / format a select array for pixel with table and column names desired - // create / format a column alias array for pixel - can just be col names for now but will be user editable - // create a limit variable, can be static at 20 for now - const selectStringArray = tableColumnsObject[tableName].map( (ele) => `${ele.tableName}__${ele.columnName}`, ); const selectString = selectStringArray.join(', '); - const aliasString = tableColumnsObject[tableName] .map( (ele) => `${ele.columnName}`, // may need to switch to ele.columnName2 but they seem to be identical @@ -454,7 +489,6 @@ export const NotebookAddCell = observer( .join(', '); const limit = 20; // may want this to be a changeable useState variable - const pixelString = `Database(database=[\"${selectedDatabaseId}\"])|Select(${selectString}).as([${aliasString}])|Distinct(false)|Limit(${limit})|Import(frame=[CreateFrame(frameType=[GRID],override=[true]).as([\"consolidated_settings_FRAME961853__Preview\"])]); META | Frame() | QueryAll() | Limit(${limit}) | Collect(500);`; await monolithStore.runQuery(pixelString).then((response) => { @@ -561,6 +595,7 @@ export const NotebookAddCell = observer( value={display} disabled={display == 'From CSV'} // temporary onClick={() => { + loadDatabaseStructure(); setIsDataImportModalOpen(true); if ( display == From 5bb9aced62b58674bbc11dd364b3c2488e0c3880 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Thu, 23 May 2024 17:52:07 -0700 Subject: [PATCH 10/49] feat(client): style edits on import data modal form and cell --- .../data-import-cell/DataImportCell.tsx | 13 +- .../components/notebook/NotebookAddCell.tsx | 468 +++++++++++++++++- 2 files changed, 474 insertions(+), 7 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index fb83120856..43b5e6d371 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -10,6 +10,7 @@ import { TextField, Stack, InputAdornment, + Typography, } from '@semoss/ui'; import { @@ -268,11 +269,16 @@ export const DataImportCell: CellComponent = observer( direction="row" justifyContent={'space-between'} > + {/* + {cfgLibraryDatabases.display[cell.parameters.databaseId]} + */} = observer( language="sql" /** TODO: language support? can we tell this from the database type? */ options={{ scrollbar: { alwaysConsumeMouseWheel: false }, - readOnly: false, + // readOnly: false, + readOnly: true, minimap: { enabled: false }, automaticLayout: true, scrollBeyondLastLine: false, diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index c1ca500294..23d177db15 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -14,6 +14,7 @@ import { Table, Checkbox, TextField, + Grid, } from '@semoss/ui'; import { useBlocks, usePixel, useRootStore } from '@/hooks'; @@ -65,6 +66,16 @@ const StyledModalTitle = styled(Typography)(({ theme }) => ({ const StyledModalTitleWrapper = styled(Modal.Title)(({ theme }) => ({ display: 'flex', alignContent: 'center', + border: '1px solid blue', + padding: '0px', +})); + +const StyledModalTitleWrapper2 = styled(Modal.Title)(({ theme }) => ({ + display: 'flex', + alignContent: 'center', + border: '1px solid blue', + padding: '0px', + justifyContent: 'space-between', })); const StyledButton = styled(Button)(({ theme }) => ({ @@ -253,8 +264,6 @@ export const NotebookAddCell = observer( const [selectedTable, setSelectedTable] = useState(null); const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); - const [importDataSQLString, setImportDataSQLString] = - useState(''); const importDataSQLStringRef = useRef(''); const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open @@ -488,7 +497,7 @@ export const NotebookAddCell = observer( ) .join(', '); - const limit = 20; // may want this to be a changeable useState variable + const limit = 10; // may want this to be a changeable useState variable const pixelString = `Database(database=[\"${selectedDatabaseId}\"])|Select(${selectString}).as([${aliasString}])|Distinct(false)|Limit(${limit})|Import(frame=[CreateFrame(frameType=[GRID],override=[true]).as([\"consolidated_settings_FRAME961853__Preview\"])]); META | Frame() | QueryAll() | Limit(${limit}) | Collect(500);`; await monolithStore.runQuery(pixelString).then((response) => { @@ -617,8 +626,458 @@ export const NotebookAddCell = observer( )} + {/* New Import Data Modal */} + + +
+ + + Import Data + + ( + + )} + /> + + {!!tableNames.length && ( + + +
+ + Data + + ( + + )} + /> +
+
+ + +
+
+ + {showEditColumns && ( + <> + + Edit Columns + + {fields?.map((field, index) => ( +
+ ( + { + field.onChange( + e, + ); + const hiddenColumnIdsSetDup = + new Set( + [ + ...hiddenColumnIdsSet, + ], + ); + if ( + field.value == + true + ) { + hiddenColumnIdsSetDup.add( + index, + ); + } else { + hiddenColumnIdsSetDup.delete( + index, + ); + } + setHiddenColumnIdsSet( + hiddenColumnIdsSetDup, + ); + }} + /> + )} + /> + ( + { + field.onChange( + e.target + .value, + ); + const newTableHeaders = + [ + ...databaseTableHeaders, + ]; + newTableHeaders[ + index + ] = + e.target.value; + setDatabaseTableHeaders( + newTableHeaders, + ); + }} + /> + )} + /> +
+ ))} + + )} + + {showTablePreview && ( + + + Preview + +
+ {/* + + {databaseTableHeaders + .filter( + (v, colIdx) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map((h, hIdx) => ( + + {h} + + ))} + + */} + + + {databaseTableHeaders + .filter( + (v, colIdx) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map((h, hIdx) => ( + + + {h} + + + ))} + + {databaseTableRows.map( + (r, rIdx) => ( + + {r + .filter( + ( + v, + colIdx, + ) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map( + ( + v, + vIdx, + ) => ( + + { + v + } + + ), + )} + + ), + )} + +
+ + )} +
+ )} + + {/* stack for user-added joins filters and summaries */} + {stackFields.map((stack, stackIndex) => ( + + {stack.queryType} + + + ))} + + + + + + + + + + + +
+ + {/* Import Data Modal */} - + {/* */} + {isDatabaseLoading && ( )} @@ -976,6 +1435,7 @@ export const NotebookAddCell = observer( type="submit" variant="contained" color="primary" + disabled > Import From 2ba5de2072e4434e2cf3f58b636e41b9a16ce21d Mon Sep 17 00:00:00 2001 From: Betthauser Date: Tue, 28 May 2024 13:52:25 -0700 Subject: [PATCH 11/49] feat(client): basic styling and import data cell functionality complete --- .../components/notebook/NotebookAddCell.tsx | 122 ++++++++++++------ 1 file changed, 82 insertions(+), 40 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 23d177db15..9ce13d6b29 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -66,14 +66,13 @@ const StyledModalTitle = styled(Typography)(({ theme }) => ({ const StyledModalTitleWrapper = styled(Modal.Title)(({ theme }) => ({ display: 'flex', alignContent: 'center', - border: '1px solid blue', padding: '0px', + marginBottom: '15px', })); const StyledModalTitleWrapper2 = styled(Modal.Title)(({ theme }) => ({ display: 'flex', alignContent: 'center', - border: '1px solid blue', padding: '0px', justifyContent: 'space-between', })); @@ -226,6 +225,12 @@ const AddCellOptions: Record = { }, }; +const IMPORT_MODAL_WIDTHS = { + small: '500px', + medium: '750px', + large: '1000px', +}; + export const NotebookAddCell = observer( (props: { query: QueryState; previousCellId?: string }): JSX.Element => { const [anchorEl, setAnchorEl] = useState(null); @@ -263,6 +268,8 @@ export const NotebookAddCell = observer( const [selectedDatabaseId, setSelectedDatabaseId] = useState(null); const [selectedTable, setSelectedTable] = useState(null); const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); + const [importModalPixelWidth, setImportModalPixelWidth] = + useState(IMPORT_MODAL_WIDTHS.small); const importDataSQLStringRef = useRef(''); @@ -424,6 +431,21 @@ export const NotebookAddCell = observer( constructSQLString({ submitData }); appendCell('data-import'); setIsDataImportModalOpen(false); + closeImportModalHandler(); + }; + + const closeImportModalHandler = () => { + setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); + setHiddenColumnIdsSet(new Set()); + setIsDataImportModalOpen(false); + setDatabaseTableHeaders([]); + setSelectedDatabaseId(null); + setShowTablePreview(false); + setTableColumnsObject({}); + setDatabaseTableRows([]); + setSelectedTable(null); + setTableNames([]); + reset(); }; const retrieveDatabaseTables = async (databaseId) => { @@ -605,6 +627,9 @@ export const NotebookAddCell = observer( disabled={display == 'From CSV'} // temporary onClick={() => { loadDatabaseStructure(); + setImportModalPixelWidth( + IMPORT_MODAL_WIDTHS.small, + ); setIsDataImportModalOpen(true); if ( display == @@ -627,18 +652,9 @@ export const NotebookAddCell = observer( {/* New Import Data Modal */} - - -
+ + + Import Data @@ -662,6 +678,9 @@ export const NotebookAddCell = observer( setHiddenColumnIdsSet( new Set(), ); + setImportModalPixelWidth( + IMPORT_MODAL_WIDTHS.medium, + ); }} label={'Select Database...'} value={field.value || null} @@ -693,14 +712,14 @@ export const NotebookAddCell = observer(
@@ -721,6 +740,12 @@ export const NotebookAddCell = observer( setHiddenColumnIdsSet( new Set(), ); + setShowTablePreview( + true, + ); + setImportModalPixelWidth( + IMPORT_MODAL_WIDTHS.large, + ); }} label={ 'Select Table...' @@ -734,9 +759,6 @@ export const NotebookAddCell = observer( variant="outlined" sx={{ minWidth: '150px', - // backgroundColor: '#E2F2FF', - // border: '0px', - // outline: '0px', }} > {tableNames?.map( @@ -759,7 +781,6 @@ export const NotebookAddCell = observer( size="medium" sx={{ marginRight: '15px', - border: '1px solid red', }} onClick={() => { setShowEditColumns( @@ -787,8 +808,21 @@ export const NotebookAddCell = observer( {showEditColumns && ( - <> - + + Edit Columns {fields?.map((field, index) => ( @@ -867,7 +901,7 @@ export const NotebookAddCell = observer( />
))} - + )} {showTablePreview && ( @@ -881,7 +915,8 @@ export const NotebookAddCell = observer( variant="h6" sx={{ marginTop: '15px', - marginBottom: '25px', + marginLeft: '15px', + marginBottom: '20px', }} > Preview @@ -989,15 +1024,16 @@ export const NotebookAddCell = observer( sx={{ display: 'flex', justifyContent: 'flex-start', - // border: '1px solid goldenrod', padding: '0px', - marginTop: '10px', + marginTop: '15px', + marginBottom: '15px', }} > @@ -1360,22 +1402,23 @@ export const NotebookAddCell = observer( sx={{ display: 'flex', justifyContent: 'flex-start', - // border: '1px solid goldenrod', padding: '0px', }} > - - - {showEditColumns && ( - <> - - Edit Columns - - {fields?.map((field, index) => ( -
- ( - { - field.onChange( - e, - ); - const hiddenColumnIdsSetDup = - new Set( - [ - ...hiddenColumnIdsSet, - ], - ); - if ( - field.value == - true - ) { - hiddenColumnIdsSetDup.add( - index, - ); - } else { - hiddenColumnIdsSetDup.delete( - index, - ); - } - setHiddenColumnIdsSet( - hiddenColumnIdsSetDup, - ); - }} - /> - )} - /> - ( - { - field.onChange( - e.target - .value, - ); - const newTableHeaders = - [ - ...databaseTableHeaders, - ]; - newTableHeaders[ - index - ] = - e.target.value; - setDatabaseTableHeaders( - newTableHeaders, - ); - }} - /> - )} - /> -
- ))} - - )} - - {showTablePreview && ( - - - - - {databaseTableHeaders - .filter( - (v, colIdx) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map((h, hIdx) => ( - - {h} - - ))} - - - - {databaseTableRows.map( - (r, rIdx) => ( - - {r - .filter( - ( - v, - colIdx, - ) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map( - ( - v, - vIdx, - ) => ( - - { - v - } - - ), - )} - - ), - )} - -
-
- )} -
- )} - {stackFields.map((stack, stackIndex) => ( - - {stack.queryType} - - - ))} - - - - - - - - - - - -
); }, From de586972b1e386de48907234c3c1ba6cc5216924 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Thu, 30 May 2024 15:40:33 -0700 Subject: [PATCH 13/49] feat(client): add functinoality and styling to column edit interface --- .../components/notebook/NotebookAddCell.tsx | 522 +++++++++++++----- 1 file changed, 371 insertions(+), 151 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index cf588d824c..c0d03553d9 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -15,6 +15,7 @@ import { Checkbox, TextField, Grid, + IconButton, } from '@semoss/ui'; import { useBlocks, usePixel, useRootStore } from '@/hooks'; @@ -41,6 +42,7 @@ import { FilterListRounded, ControlPointDuplicateRounded, CheckBox, + IndeterminateCheckBox, } from '@mui/icons-material'; import { DefaultCellDefinitions, @@ -121,6 +123,7 @@ interface Column { id: string; tableName: string; columnName: string; + columnType: string; userAlias: string; checked: boolean; } @@ -231,6 +234,14 @@ const IMPORT_MODAL_WIDTHS = { large: '1000px', }; +const SQL_COLUMN_TYPES = [ + 'DATE', + 'NUMBER', + 'STRING', + 'TIMESTAMP', + // there may be more to add need a definitive list +]; + export const NotebookAddCell = observer( (props: { query: QueryState; previousCellId?: string }): JSX.Element => { const [anchorEl, setAnchorEl] = useState(null); @@ -279,6 +290,7 @@ export const NotebookAddCell = observer( const [showEditColumns, setShowEditColumns] = useState(false); const [showTablePreview, setShowTablePreview] = useState(false); + const [checkAllColumns, setCheckAllColumns] = useState(true); const { configStore, monolithStore } = useRootStore(); const { @@ -308,6 +320,7 @@ export const NotebookAddCell = observer( tableName: tableObject.tableName, columnName: tableObject.columnName, userAlias: tableObject.columnName, + columnType: tableObject.columnType, checked: true, }); }); @@ -686,7 +699,7 @@ export const NotebookAddCell = observer( IMPORT_MODAL_WIDTHS.medium, ); }} - label={'Select Database...'} + label={'Select Database'} value={field.value || null} size={'small'} sx={{ @@ -744,9 +757,14 @@ export const NotebookAddCell = observer( setHiddenColumnIdsSet( new Set(), ); - setShowTablePreview( - true, - ); + if ( + !showTablePreview && + !showEditColumns + ) { + setShowTablePreview( + true, + ); + } setImportModalPixelWidth( IMPORT_MODAL_WIDTHS.large, ); @@ -820,152 +838,376 @@ export const NotebookAddCell = observer( }} > Edit Columns - +
{/* table header with uncontrolled checkbox for all */} - + - - {/* check / uncheck all columns */} - - - - {/* */} - Fields - {/* */} - - - {/* */} - Alias - {/* */} - - - {/* */} - Field Type - {/* */} - - - - - {/* show checkboxes and text fields for all columns */} - {editableColumnFields?.map( - (field, index) => ( -
- ( - { - field.onChange( - e, - ); - const hiddenColumnIdsSetDup = - new Set( - [ - ...hiddenColumnIdsSet, - ], + + { + setCheckAllColumns( + !checkAllColumns, + ); + const hiddenColumnIdsSetDup = + new Set(); + if ( + checkAllColumns == + false + ) { + editableColumnFields.forEach( + ( + field, + index, + ) => { + // not working need to use setValue + field.checked = + true; + console.log( + { + index, + field, + }, ); - if ( - field.value == - true - ) { hiddenColumnIdsSetDup.add( index, ); - } else { + }, + ); + } else { + editableColumnFields.forEach( + ( + field, + index, + ) => { + // not working need to use setValue + field.checked = + false; + console.log( + { + index, + field, + }, + ); hiddenColumnIdsSetDup.delete( index, ); - } - setHiddenColumnIdsSet( - hiddenColumnIdsSetDup, - ); - }} - /> - )} - /> - ( - + + + + + + Fields + + + + + Alias + + + + + Field Type + + + + + {/* show checkboxes and text fields for all columns */} + {editableColumnFields?.map( + (field, index) => ( + + + { - field.onChange( - e - .target - .value, - ); - const newTableHeaders = - [ - ...databaseTableHeaders, - ]; - newTableHeaders[ - index - ] = - e.target.value; - setDatabaseTableHeaders( - newTableHeaders, - ); - }} + render={({ + field, + }) => ( + { + field.onChange( + e, + ); + const hiddenColumnIdsSetDup = + new Set( + [ + ...hiddenColumnIdsSet, + ], + ); + if ( + field.value == + true + ) { + hiddenColumnIdsSetDup.add( + index, + ); + } else { + hiddenColumnIdsSetDup.delete( + index, + ); + } + + console.log( + { + hiddenColumnIdsSetDup, + editableColumnFields, + }, + ); + + if ( + hiddenColumnIdsSetDup.size == + 0 + ) { + setCheckAllColumns( + true, + ); + } else { + setCheckAllColumns( + false, + ); + } + + setHiddenColumnIdsSet( + hiddenColumnIdsSetDup, + ); + }} + /> + )} /> - )} - /> -
- ), - )} + + + { + field.columnName + } + {field.columnName == + 'ID' && ( +
+ PK +
+ )} + {field.columnName.includes( + '_ID', + ) && ( +
+ FK +
+ )} +
+ + ( + { + field.onChange( + e + .target + .value, + ); + const newTableHeaders = + [ + ...databaseTableHeaders, + ]; + newTableHeaders[ + index + ] = + e.target.value; + setDatabaseTableHeaders( + newTableHeaders, + ); + }} + /> + )} + /> + + + ( + + )} + /> + + + ), + )} +
+ + + + )} @@ -987,23 +1229,6 @@ export const NotebookAddCell = observer( Preview - {/* - - {databaseTableHeaders - .filter( - (v, colIdx) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map((h, hIdx) => ( - - {h} - - ))} - - */} {databaseTableHeaders @@ -1161,11 +1386,6 @@ export const NotebookAddCell = observer( color="secondary" onClick={() => { closeImportModalHandler(); - // setIsDataImportModalOpen(false) - // setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); - // setShowTablePreview(false); - // setTableNames([]); - // reset(); }} > Cancel From d71d81665cb71f557e76aee820ea48db915441ea Mon Sep 17 00:00:00 2001 From: Betthauser Date: Fri, 31 May 2024 14:05:38 -0700 Subject: [PATCH 14/49] feat(client): add starter stack component for join builder --- .../components/notebook/NotebookAddCell.tsx | 821 +++++++++++++++++- 1 file changed, 783 insertions(+), 38 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index c0d03553d9..940b508765 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -43,6 +43,7 @@ import { ControlPointDuplicateRounded, CheckBox, IndeterminateCheckBox, + Close, } from '@mui/icons-material'; import { DefaultCellDefinitions, @@ -231,7 +232,7 @@ const AddCellOptions: Record = { const IMPORT_MODAL_WIDTHS = { small: '500px', medium: '750px', - large: '1000px', + large: '1150px', }; const SQL_COLUMN_TYPES = [ @@ -723,7 +724,8 @@ export const NotebookAddCell = observer( direction="column" sx={{ backgroundColor: '#FAFAFA', - padding: '16px 16px 24px 16px', + padding: '16px 16px 16px 16px', + marginBottom: '15px', }} > @@ -769,9 +771,7 @@ export const NotebookAddCell = observer( IMPORT_MODAL_WIDTHS.large, ); }} - label={ - 'Select Table...' - } + label={'Select Table'} value={field.value} size={'small'} color="primary" @@ -1291,45 +1291,790 @@ export const NotebookAddCell = observer( {/* stack for user-added joins filters and summaries */} {stackFields.map((stack, stackIndex) => ( - - {stack.queryType} - - - ))} + + +
+ + {stack.queryType} + + {/* ( */} + + {/* )} + /> */} + + + + {/* ( */} + + {/* )} + /> */} + + where + + {/* ( */} + + {/* )} + /> */} + + = + + {/* ( */} + + {/* )} + /> */} +
+
+ { + removeStack(stackIndex); + }} + > + + - - + +
+
+ + {/* {showEditColumns && ( */} + {false && ( + + + Edit Columns + + +
+ {/* table header with uncontrolled checkbox for all */} + + + + { + setCheckAllColumns( + !checkAllColumns, + ); + const hiddenColumnIdsSetDup = + new Set(); + if ( + checkAllColumns == + false + ) { + editableColumnFields.forEach( + ( + field, + index, + ) => { + // not working need to use setValue + field.checked = + true; + console.log( + { + index, + field, + }, + ); + hiddenColumnIdsSetDup.add( + index, + ); + }, + ); + } else { + editableColumnFields.forEach( + ( + field, + index, + ) => { + // not working need to use setValue + field.checked = + false; + console.log( + { + index, + field, + }, + ); + hiddenColumnIdsSetDup.delete( + index, + ); + }, + ); + } + setHiddenColumnIdsSet( + hiddenColumnIdsSetDup, + ); + }} + color={ + checkAllColumns + ? 'primary' + : 'secondary' + } + sx={{ + marginLeft: + '-10px', + }} + > + + + + + + Fields + + + + + Alias + + + + + Field Type + + + + + {/* show checkboxes and text fields for all columns */} + {editableColumnFields?.map( + (field, index) => ( + + + ( + { + field.onChange( + e, + ); + const hiddenColumnIdsSetDup = + new Set( + [ + ...hiddenColumnIdsSet, + ], + ); + if ( + field.value == + true + ) { + hiddenColumnIdsSetDup.add( + index, + ); + } else { + hiddenColumnIdsSetDup.delete( + index, + ); + } + + console.log( + { + hiddenColumnIdsSetDup, + editableColumnFields, + }, + ); + + if ( + hiddenColumnIdsSetDup.size == + 0 + ) { + setCheckAllColumns( + true, + ); + } else { + setCheckAllColumns( + false, + ); + } + + setHiddenColumnIdsSet( + hiddenColumnIdsSetDup, + ); + }} + /> + )} + /> + + + { + field.columnName + } + {field.columnName == + 'ID' && ( +
+ PK +
+ )} + {field.columnName.includes( + '_ID', + ) && ( +
+ FK +
+ )} +
+ + ( + { + field.onChange( + e + .target + .value, + ); + const newTableHeaders = + [ + ...databaseTableHeaders, + ]; + newTableHeaders[ + index + ] = + e.target.value; + setDatabaseTableHeaders( + newTableHeaders, + ); + }} + /> + )} + /> + + + ( + + )} + /> + +
+ ), + )} +
+
+ + + + + + )} + + {/* {showTablePreview && ( */} + {false && ( + + + Preview + + + + + {databaseTableHeaders + .filter( + (v, colIdx) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map((h, hIdx) => ( + + + {h} + + + ))} + + {databaseTableRows.map( + (r, rIdx) => ( + + {r + .filter( + ( + v, + colIdx, + ) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map( + ( + v, + vIdx, + ) => ( + + { + v + } + + ), + )} + + ), + )} + +
+
+ )} + + // + // {stack.queryType} + // + // + ))} + + + + */} + Date: Tue, 18 Jun 2024 18:03:32 -0700 Subject: [PATCH 19/49] feat(client): new useform and usefieldarray structure working redering tables and submitting --- .../components/notebook/NotebookAddCell.tsx | 756 ++++++++++-------- 1 file changed, 426 insertions(+), 330 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 8d34d0ae11..233c6648fb 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -5,18 +5,18 @@ import { styled, Button, Divider, - Menu, MenuProps, - Stack, Typography, + Menu, + Stack, Modal, - Select, - Table, Checkbox, TextField, - Grid, IconButton, Tooltip, + Select, + Table, + Grid, } from '@semoss/ui'; import { useBlocks, usePixel, useRootStore } from '@/hooks'; @@ -27,29 +27,29 @@ import { QueryState, } from '@/stores'; import { - AccountTree, - Add, + ArrowDownwardRounded, + ControlPointDuplicateRounded, + ChangeCircleOutlined, + IndeterminateCheckBox, AddCircleOutline, + AccountTree, Functions, - ChangeCircleOutlined, Storage, + Add, Code, ImportExport, - TextFields, - KeyboardArrowUp, KeyboardArrowDown, + FilterListRounded, + JoinLeftRounded, + KeyboardArrowUp, + TextFields, TableRows, Label, - JoinLeftRounded, - FilterListRounded, - ControlPointDuplicateRounded, CheckBox, - IndeterminateCheckBox, - Close, - JoinInner, - ArrowDownwardRounded, AddCircle, AddBox, + Close, + JoinInner, } from '@mui/icons-material'; import { DefaultCellDefinitions, @@ -186,19 +186,7 @@ const StyledBorderDiv = styled('div')(({ theme }) => ({ borderRadius: '8px', })); -interface Column { - id: string; - tableName: string; - columnName: string; - columnType: string; - userAlias: string; - checked: boolean; -} - -interface Table { - name: string; - columns: Column[]; -} +// old useForm types interface AddCellOption { display: string; @@ -228,6 +216,34 @@ type FormValues = { tables: Table[]; }; +// new useForm types + +interface Column { + id: number; + tableName: string; + columnName: string; + columnType: string; + userAlias: string; + checked: boolean; +} + +interface Table { + id: number; + name: string; + columns: Column[]; +} + +interface NewFormData { + databaseSelect: string; + tables: Table[]; +} + +// ### is this needed? +type NewFormValues = { + databaseSelect: string; + tables: Table[]; +}; + const Transformations = Array.from(Object.values(TransformationCells)).map( (item) => { return { @@ -330,6 +346,70 @@ export const NotebookAddCell = observer( }, }); + // ### newControl structure + const { + control: newControl, + handleSubmit: newHandleSubmit, + reset: newReset, + watch: newWatch, + setValue: newSetValue, + getValues: newGetValues, + } = useForm({ + defaultValues: { + databaseSelect: '', + tables: [ + // { + // id: 123456789, + // name: "test-table-name-2", + // columns: [ + // { + // id: 987654321, + // tableName: "test-table-name-1", + // columnName: "test-column-name-1", + // columnType: "string", + // userAlias: "test-column-alias-1", + // checked: false, + // },{ + // id: 987654322, + // tableName: "test-table-name-1", + // columnName: "test-column-name-2", + // columnType: "string", + // userAlias: "test-column-alias-2", + // checked: false, + // },{ + // id: 987654323, + // tableName: "test-table-name-1", + // columnName: "test-column-name-3", + // columnType: "string", + // userAlias: "test-column-alias-3", + // checked: false, + // }, + // ] + // },{ + // id: 123456790, + // name: "test-table-name-2", + // columns: [ + // { + // id: 987654321, + // tableName: "test-table-name-2", + // columnName: "test-column-name-1", + // columnType: "string", + // userAlias: "test-column-alias-1", + // checked: false, + // },{ + // id: 987654322, + // tableName: "test-table-name-2", + // columnName: "test-column-name-2", + // columnType: "string", + // userAlias: "test-column-alias-2", + // checked: false, + // }, + // ] + // }, + ], + }, + }); + const [userDatabases, setUserDatabases] = useState(null); const [queryElementCounter, setQueryElementCounter] = useState(0); @@ -353,7 +433,7 @@ export const NotebookAddCell = observer( const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open const [isDatabaseLoading, setIsDatabaseLoading] = useState(false); - const [showEditColumns, setShowEditColumns] = useState(false); + const [showEditColumns, setShowEditColumns] = useState(true); // ### change back to false const [showTablePreview, setShowTablePreview] = useState(false); const [checkAllColumns, setCheckAllColumns] = useState(true); @@ -370,6 +450,8 @@ export const NotebookAddCell = observer( const [tableEdgesObject, setTableEdgesObject] = useState(null); const [columnDataTypesDict, setColumnDataTypesDict] = useState(null); + // oldFieldArrays + const { fields: stackFields, append: appendStack, @@ -389,7 +471,7 @@ export const NotebookAddCell = observer( }); const { - fields: editableTableColumnFields, + fields: tableFields, append: appendEditableTableColumns, remove: removeEditableTableColumns, } = useFieldArray({ @@ -397,6 +479,18 @@ export const NotebookAddCell = observer( name: 'tables', }); + // ### only one field array is necessary? + // do each of these need a field array for the columns? + + const { + fields: newTableFields, + append: newTableAppend, + remove: newTableRemove, + } = useFieldArray({ + control: newControl, + name: 'tables', + }); + useEffect(() => { setSelectedLeftKey(null); setSelectedRightKey(null); @@ -622,11 +716,12 @@ export const NotebookAddCell = observer( alert('add all'); }; - const onImportDataSubmit = (submitData) => { - constructSQLString({ submitData }); - appendCell('data-import'); - setIsDataImportModalOpen(false); - closeImportModalHandler(); + const onImportDataSubmit = (data: NewFormData) => { + // constructSQLString({ submitData }); + // appendCell('data-import'); + // setIsDataImportModalOpen(false); + // closeImportModalHandler(); + console.log({ data }); }; const closeImportModalHandler = () => { @@ -649,6 +744,7 @@ export const NotebookAddCell = observer( // const pixelResponse = await runPixel(pixelString); monolithStore.runQuery(pixelString).then((pixelResponse) => { + console.log({ pixelResponse }); const responseTableStructure = pixelResponse.pixelReturn[0].output; const isResponseTableStructureGood = @@ -673,7 +769,7 @@ export const NotebookAddCell = observer( }, new Set()), ]; - const newTableColumnsObject = responseTableStructure.reduce( + const tableColumnsObject = responseTableStructure.reduce( (acc, ele, idx) => { const tableName = ele[0]; const columnName = ele[1]; @@ -699,8 +795,32 @@ export const NotebookAddCell = observer( }, {}, ); - setTableColumnsObject(newTableColumnsObject); - setTableNames(tableNames); + + const newTableColumnsObject: Table[] = Object.keys( + tableColumnsObject, + ).map((tableName, tableIdx) => ({ + id: tableIdx, + name: tableName, + columns: tableColumnsObject[tableName].map( + (colObj, colIdx) => ({ + id: colIdx, + tableName: tableName, + columnName: colObj.columnName, + columnType: colObj.columnType, + userAlias: colObj.userAlias, + checked: false, + }), + ), + })); + + newReset({ + databaseSelect: databaseId, + tables: newTableColumnsObject, + }); + console.log({ newTableColumnsObject }); + + // setTableColumnsObject(tableColumnsObject); + // setTableNames(tableNames); } else { console.error('Error retrieving database tables'); } @@ -963,7 +1083,8 @@ export const NotebookAddCell = observer( {/* New Import Data Modal */} - + {/* */} +
( { - field.onChange( - e - .target - .value, - ); - // unclear what desired effect is - }} - value={ - field.value || - null - } - size={ - 'small' - } - sx={{ - minWidth: - '220px', + {column.columnName.includes( + '_ID', + ) && ( +
- {SQL_COLUMN_TYPES.map( - ( - ele, - ) => ( - - { - ele - } - - ), - )} - + FK +
)} - /> - - - ), - )} - - - - ))} + + + ( + { + field.onChange( + e + .target + .value, + ); + // const newTableHeaders = + // [ + // ...databaseTableHeaders, + // ]; + // newTableHeaders[ + // index + // ] = + // e.target.value; + // setDatabaseTableHeaders( + // newTableHeaders, + // ); + }} + /> + )} + /> + + + ( + + )} + /> + + + ), + )} + + + + ), + )} {/* From df144cf3d5265c0cb5567c8d042f3947d1840094 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Mon, 24 Jun 2024 15:59:17 -0700 Subject: [PATCH 20/49] feat(client): restructure and clean up old elements vars etc for new designs --- .vscode/settings.json | 6 +- .../components/notebook/NotebookAddCell.tsx | 903 ++++++++---------- 2 files changed, 428 insertions(+), 481 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e37420baf7..90a9b54149 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,8 @@ "files.exclude": { "**/*.rollup.cache": true, "**/dist": true, - "**/target": true - } + "**/target": true, + }, + "editor.folding": true, + "editor.foldingStrategy": "indentation", } diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 233c6648fb..23a0ebe43f 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -66,6 +66,8 @@ import { LoadingScreen } from '@/components/ui'; import { runPixel } from '@/api'; import { TableContainer, alertTitleClasses } from '@mui/material'; +// region --- Styled Elements + const StyledImportDataForm = styled('form')(({ theme }) => ({ margin: '30px 41px', })); @@ -186,7 +188,9 @@ const StyledBorderDiv = styled('div')(({ theme }) => ({ borderRadius: '8px', })); -// old useForm types +// endregion + +// region --- Old Data Import useForm Types & Interfaces interface AddCellOption { display: string; @@ -216,7 +220,9 @@ type FormValues = { tables: Table[]; }; -// new useForm types +// endregion + +// region --- New Data Import useForm Types & Interfaces interface Column { id: number; @@ -244,6 +250,10 @@ type NewFormValues = { tables: Table[]; }; +// endregion + +// region --- Transformations / Options / Constants + const Transformations = Array.from(Object.values(TransformationCells)).map( (item) => { return { @@ -324,19 +334,20 @@ const IMPORT_MODAL_WIDTHS = { const SQL_COLUMN_TYPES = ['DATE', 'NUMBER', 'STRING', 'TIMESTAMP']; +// endregion + export const NotebookAddCell = observer( (props: { query: QueryState; previousCellId?: string }): JSX.Element => { const [anchorEl, setAnchorEl] = useState(null); const [selectedAddCell, setSelectedAddCell] = useState(''); - const [importModalType, setImportModalType] = useState(''); const [isDataImportModalOpen, setIsDataImportModalOpen] = useState(false); const open = Boolean(anchorEl); - const { query, previousCellId = '' } = props; const { state, notebook } = useBlocks(); + // Old useForm for Data Import --- remove const { control, handleSubmit, reset, watch, setValue, getValues } = useForm({ defaultValues: { @@ -346,96 +357,39 @@ export const NotebookAddCell = observer( }, }); - // ### newControl structure + // New useForm for Data Import const { control: newControl, handleSubmit: newHandleSubmit, reset: newReset, - watch: newWatch, - setValue: newSetValue, - getValues: newGetValues, - } = useForm({ - defaultValues: { - databaseSelect: '', - tables: [ - // { - // id: 123456789, - // name: "test-table-name-2", - // columns: [ - // { - // id: 987654321, - // tableName: "test-table-name-1", - // columnName: "test-column-name-1", - // columnType: "string", - // userAlias: "test-column-alias-1", - // checked: false, - // },{ - // id: 987654322, - // tableName: "test-table-name-1", - // columnName: "test-column-name-2", - // columnType: "string", - // userAlias: "test-column-alias-2", - // checked: false, - // },{ - // id: 987654323, - // tableName: "test-table-name-1", - // columnName: "test-column-name-3", - // columnType: "string", - // userAlias: "test-column-alias-3", - // checked: false, - // }, - // ] - // },{ - // id: 123456790, - // name: "test-table-name-2", - // columns: [ - // { - // id: 987654321, - // tableName: "test-table-name-2", - // columnName: "test-column-name-1", - // columnType: "string", - // userAlias: "test-column-alias-1", - // checked: false, - // },{ - // id: 987654322, - // tableName: "test-table-name-2", - // columnName: "test-column-name-2", - // columnType: "string", - // userAlias: "test-column-alias-2", - // checked: false, - // }, - // ] - // }, - ], - }, - }); + getValues: _newGetValues, + setValue: _newSetValue, + watch: _newWatch, + } = useForm(); + + // region --- useStates / useRefs const [userDatabases, setUserDatabases] = useState(null); const [queryElementCounter, setQueryElementCounter] = useState(0); - - const [databaseTableHeaders, setDatabaseTableHeaders] = useState([]); const [databaseTableRawHeaders, setDatabaseTableRawHeaders] = useState( [], ); - const [tableNames, setTableNames] = useState([]); - const [databaseTableRows, setDatabaseTableRows] = useState([]); - - const [tableColumnsObject, setTableColumnsObject] = useState({}); - - const [selectedDatabaseId, setSelectedDatabaseId] = useState(null); - const [selectedTable, setSelectedTable] = useState(null); - const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); const [importModalPixelWidth, setImportModalPixelWidth] = useState(IMPORT_MODAL_WIDTHS.small); - + const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); + const [databaseTableHeaders, setDatabaseTableHeaders] = useState([]); + const [selectedDatabaseId, setSelectedDatabaseId] = useState(null); + const [tableColumnsObject, setTableColumnsObject] = useState({}); + const [databaseTableRows, setDatabaseTableRows] = useState([]); + const [tableNames, setTableNames] = useState([]); + const [selectedTable, setSelectedTable] = useState(null); const importDataSQLStringRef = useRef(''); - const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open const [isDatabaseLoading, setIsDatabaseLoading] = useState(false); - const [showEditColumns, setShowEditColumns] = useState(true); // ### change back to false const [showTablePreview, setShowTablePreview] = useState(false); + const [showEditColumns, setShowEditColumns] = useState(true); // ### change back to false const [checkAllColumns, setCheckAllColumns] = useState(true); const { configStore, monolithStore } = useRootStore(); @@ -444,13 +398,14 @@ export const NotebookAddCell = observer( useState(null); const [selectedRightTable, setSelectedRightTable] = useState(null); - const [selectedLeftKey, setSelectedLeftKey] = useState(null); const [selectedRightKey, setSelectedRightKey] = useState(null); - - const [tableEdgesObject, setTableEdgesObject] = useState(null); const [columnDataTypesDict, setColumnDataTypesDict] = useState(null); + const [selectedLeftKey, setSelectedLeftKey] = useState(null); + const [tableEdgesObject, setTableEdgesObject] = useState(null); - // oldFieldArrays + // endregion + + // region --- Import Data Old useFieldArrays const { fields: stackFields, @@ -479,6 +434,10 @@ export const NotebookAddCell = observer( name: 'tables', }); + // endregion + + // region --- Import Data New useFieldArray + // ### only one field array is necessary? // do each of these need a field array for the columns? @@ -491,6 +450,10 @@ export const NotebookAddCell = observer( name: 'tables', }); + // endregion + + // region --- useEffects + useEffect(() => { setSelectedLeftKey(null); setSelectedRightKey(null); @@ -523,13 +486,12 @@ export const NotebookAddCell = observer( return; } setUserDatabases(getDatabases.data); + console.log({ userDatabases: getDatabases.data }); }, [getDatabases.status, getDatabases.data]); - // const loadDatabaseStructure = () => { - // // set loading to true - // // fetch database structure - // }; + // endregion + // might be deletable // const cellTypeOptions = computed(() => { // const options = { ...AddCellOptions }; // // transformation cell types can only be added if there exists a query-import cell before it @@ -555,9 +517,7 @@ export const NotebookAddCell = observer( // return Object.values(options); // }).get(); - /** - * Create a new cell - */ + /** Create a New Cell and Add to Notebook */ const appendCell = (widget: string) => { try { const newCellId = `${Math.floor(Math.random() * 100000)}`; @@ -614,108 +574,112 @@ export const NotebookAddCell = observer( } }; - const constructSQLString = ({ submitData }) => { - console.log({ submitData }); - let newSQLString = 'SELECT '; - - newSQLString += submitData.columns - .filter((ele) => ele.checked) - .map((colObj) => { - if (colObj.columnName === colObj.userAlias) { - return colObj.columnName; - } else { - return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - } - }) - .join(', '); - - newSQLString += ` FROM ${submitData.tableSelect}`; - newSQLString += ';'; - - if ( - selectedLeftTable && - selectedRightTable && - selectedLeftKey && - selectedRightKey - ) { - newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - } - - importDataSQLStringRef.current = newSQLString; - }; - - const constructDataBasePixel = ({ submitData }) => { - // mimic this pixel structure instead of constructing raw SQL ? - // or have join autoselect keys and add columns to edit - // that makes sense with new pixel structure - // show all tables and selectable rows in edit columns view - // find way of showing alerts for un joinable columns - // add form structure to json state (?) - // make basic non SQL view for notebook cell - // make edit window - - // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | - - // Select ( - // STATION_SETTINGS__ROLE , - // USER_SETTINGS__DATE_CREATED , - // VISN_SETTINGS__EMAIL , - // VISN_SETTINGS__USER , - // VISN_SETTINGS__VISN ) - // .as ( [ - // ROLE , - // DATE_CREATED , - // EMAIL , - // USER , - // VISN - // ] ) | - - // Join ( ( - // USER_SETTINGS , - // inner.join , - // STATION_SETTINGS - // ) , ( - // USER_SETTINGS , - // inner.join , - // VISN_SETTINGS - // ) ) | - - // Distinct ( false ) | - - // QueryRowCount ( ) ;", - console.log({ submitData }); - let newSQLString = 'SELECT '; - - newSQLString += submitData.columns - .filter((ele) => ele.checked) - .map((colObj) => { - if (colObj.columnName === colObj.userAlias) { - return colObj.columnName; - } else { - return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - } - }) - .join(', '); + /** Construct a Raw SQL String for Data Import --- remove */ + // const constructSQLString = ({ submitData }) => { + // console.log({ submitData }); + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } - newSQLString += ` FROM ${submitData.tableSelect}`; - newSQLString += ';'; + // importDataSQLStringRef.current = newSQLString; + // }; - if ( - selectedLeftTable && - selectedRightTable && - selectedLeftKey && - selectedRightKey - ) { - newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - } + /** Construct Submit Pixel for Data Import --- remove? */ + // const constructDataBasePixel = ({ submitData }) => { + // // mimic this pixel structure instead of constructing raw SQL ? + // // or have join autoselect keys and add columns to edit + // // that makes sense with new pixel structure + // // show all tables and selectable rows in edit columns view + // // find way of showing alerts for un joinable columns + // // add form structure to json state (?) + // // make basic non SQL view for notebook cell + // // make edit window + + // // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | + + // // Select ( + // // STATION_SETTINGS__ROLE , + // // USER_SETTINGS__DATE_CREATED , + // // VISN_SETTINGS__EMAIL , + // // VISN_SETTINGS__USER , + // // VISN_SETTINGS__VISN ) + // // .as ( [ + // // ROLE , + // // DATE_CREATED , + // // EMAIL , + // // USER , + // // VISN + // // ] ) | + + // // Join ( ( + // // USER_SETTINGS , + // // inner.join , + // // STATION_SETTINGS + // // ) , ( + // // USER_SETTINGS , + // // inner.join , + // // VISN_SETTINGS + // // ) ) | + + // // Distinct ( false ) | + + // // QueryRowCount ( ) ;", + // console.log({ submitData }); + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } - importDataSQLStringRef.current = newSQLString; - }; + // importDataSQLStringRef.current = newSQLString; + // }; + /** Add all the columns from a Table */ const addAllTableColumnsHandler = (event) => { alert('add all'); }; + /** New Submit for Import Data --- empty */ const onImportDataSubmit = (data: NewFormData) => { // constructSQLString({ submitData }); // appendCell('data-import'); @@ -724,6 +688,7 @@ export const NotebookAddCell = observer( console.log({ data }); }; + /** Close and Reset Import Data Form Modal */ const closeImportModalHandler = () => { setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); setHiddenColumnIdsSet(new Set()); @@ -738,6 +703,7 @@ export const NotebookAddCell = observer( reset(); }; + /** Get Database Information for Data Import Modal */ const retrieveDatabaseTablesAndEdges = async (databaseId) => { setIsDatabaseLoading(true); const pixelString = `META|GetDatabaseTableStructure(database=[ \"${databaseId}\" ]);META|GetDatabaseMetamodel( database=[ \"${databaseId}\" ], options=["dataTypes","positions"]);`; @@ -759,7 +725,7 @@ export const NotebookAddCell = observer( 'ERROR', ) === -1; - // populate database structure as before + // populate database structure if (isResponseTableStructureGood) { console.log({ responseTableStructure }); const tableNames = [ @@ -826,10 +792,6 @@ export const NotebookAddCell = observer( } // make and populate new edges dict - // ### NEED TO... - // store columns used for join - // these will get displayed in the Key1 and Key2 - if (isResponseTableEdgesStructureGood) { const newEdgesDict = responseTableEdgesStructure.edges.reduce((acc, ele) => { @@ -877,6 +839,7 @@ export const NotebookAddCell = observer( }); }; + /** Old Get All Database Tables for Import Data --- remove? */ // const retrieveDatabaseTables = async (databaseId) => { // setIsDatabaseLoading(true); // const pixelString = `META | GetDatabaseTableStructure ( database = [ \"${databaseId}\" ] ) ;`; @@ -930,11 +893,13 @@ export const NotebookAddCell = observer( // }); // }; + /** Old Select Tables for Import Data --- remove? */ const selectTableHandler = (tableName) => { setSelectedTable(tableName); retrieveTableRows(tableName); }; + /** Old Select Tables for Import Data --- unused / remove? */ const retrieveTableRows = async (tableName) => { setIsDatabaseLoading(true); const selectStringArray = tableColumnsObject[tableName].map( @@ -979,95 +944,65 @@ export const NotebookAddCell = observer( }; return ( - - - - {Object.entries(AddCellOptions).map((add, i) => { - const value = add[1]; - return ( - { - if (value.options) { - setAnchorEl(e.currentTarget); - setSelectedAddCell(add[0]); - } else { - appendCell(value.defaultCellType); + <> + {/* Dropdown for All Add Cell Option Sets */} + + + + + {Object.entries(AddCellOptions).map((add, i) => { + const value = add[1]; + return ( + { + if (value.options) { + setAnchorEl(e.currentTarget); + setSelectedAddCell(add[0]); + } else { + appendCell(value.defaultCellType); + } + }} + endIcon={ + Array.isArray(value.options) && + (selectedAddCell == add[0] && open ? ( + + ) : ( + + )) } - }} - endIcon={ - Array.isArray(value.options) && - (selectedAddCell == add[0] && open ? ( - - ) : ( - - )) - } - > - {value.display} - - ); - })} - - - { - setAnchorEl(null); - }} - > - {selectedAddCell === 'transformation' && - Array.from( - AddCellOptions[selectedAddCell]?.options || [], - ({ display, defaultCellType }, index) => { - return ( - { - appendCell(defaultCellType); - setAnchorEl(null); - }} - > - {display} - - ); - }, - )} - - {selectedAddCell === 'import-data' && ( - <> - {Array.from( + > + {value.display} + + ); + })} + + + { + setAnchorEl(null); + }} + > + {selectedAddCell === 'transformation' && + Array.from( AddCellOptions[selectedAddCell]?.options || [], - ({ display }, index) => { + ({ display, defaultCellType }, index) => { return ( { - // loadDatabaseStructure(); - setImportModalPixelWidth( - IMPORT_MODAL_WIDTHS.small, - ); - setIsDataImportModalOpen(true); - if ( - display == - 'From Data Catalog' - ) { - setImportModalType(display); - } else { - // open seperate modal / form for From CSV - } + appendCell(defaultCellType); setAnchorEl(null); }} > @@ -1076,14 +1011,53 @@ export const NotebookAddCell = observer( ); }, )} - - )} - - {/* New Import Data Modal */} + {selectedAddCell === 'import-data' && ( + <> + {Array.from( + AddCellOptions[selectedAddCell]?.options || + [], + ({ display }, index) => { + return ( + { + // loadDatabaseStructure(); + setImportModalPixelWidth( + IMPORT_MODAL_WIDTHS.small, + ); + setIsDataImportModalOpen( + true, + ); + if ( + display == + 'From Data Catalog' + ) { + setImportModalType( + display, + ); + } else { + // open seperate modal / form for From CSV + } + setAnchorEl(null); + }} + > + {display} + + ); + }, + )} + + )} + + + + {/* New Import Data Modal --- stand-alone component? */} + - {/* */}
- {userDatabases?.map((ele) => ( - - {ele.app_name} - - ))} + {userDatabases?.map( + (ele, dbIndex) => ( + + {ele.app_name} + + ), + )} )} /> @@ -1166,8 +1111,8 @@ export const NotebookAddCell = observer( - {/* {!!tableNames.length && ( */} - {true && ( + {!!tableNames.length && ( + // {true && ( ( - { + field.onChange( + e.target.value, + ); + selectTableHandler( + e.target.value, + ); + setHiddenColumnIdsSet( + new Set(), + ); + if ( + !showTablePreview && + !showEditColumns + ) { + setShowTablePreview( + true, ); - }} - label={'Select Table'} - value={field.value} - size={'small'} - color="primary" - disabled={ - !tableNames.length } - variant="outlined" - sx={{ - minWidth: '150px', - }} - > - {tableNames?.map( - (ele) => ( - - {ele} - - ), - )} - - )} - /> + setImportModalPixelWidth( + IMPORT_MODAL_WIDTHS.large, + ); + }} + label={'Select Table'} + value={field.value} + size={'small'} + color="primary" + disabled={ + !tableNames.length + } + variant="outlined" + sx={{ + minWidth: '150px', + }} + > + {tableNames?.map( + (ele) => ( + + {ele} + + ), + )} + + )} + /> */}
{/* */} + variant="outlined" + color="primary" + size="medium" + disabled={ + !selectedDatabaseId || + !selectedTable || + !( + tableEdgesObject[selectedTable] && + Object.values( + tableEdgesObject[selectedTable], + ).length + ) + } + onClick={() => { + setQueryElementCounter( + queryElementCounter + 1, + ); + console.log({ + selectedDatabaseId, + selectedTable, + }); + setImportModalPixelWidth( + IMPORT_MODAL_WIDTHS.large, + ); + appendStack({ + queryType: `Join`, + queryChildren: [ + ], + }); + }} + startIcon={} + > + Join + */} From 387db8ee72fde40fa9d1196c348bf9d8e8c06587 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Thu, 27 Jun 2024 21:44:25 -0700 Subject: [PATCH 23/49] feat(client): add partial logic for tracking table and joins edges logged --- .../components/notebook/NotebookAddCell.tsx | 64 ++++++++++++++++--- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 4a749eed81..131633b6f7 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -435,16 +435,10 @@ export const NotebookAddCell = observer( const [checkedColumnsSet, setCheckedColumnsSet] = useState(new Set()); const [hiddenTablesSet, setHiddenTablesSet] = useState({}); const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } + const [tableEdges, setTableEdges] = useState({}); // + const [initialTableSelected, setInitialTableSelected] = useState(null); - // newCheckHandler must... - // must hide any unjoined tables - // must check for repeat column names / aliases - // add to column aliases set - - // check / uncheck column - // check for table edges - // hide unjoinable tables - // update alias counts + // track to manage joinable tables // endregion @@ -532,6 +526,16 @@ export const NotebookAddCell = observer( console.log({ userDatabases: getDatabases.data }); }, [getDatabases.status, getDatabases.data]); + useEffect(() => { + if (initialTableSelected == null) { + // TODO: unhide all tables + alert('unhide all tables'); + } else { + // TODO: hide all unjoinable tables + alert('hide all unjoinable tables'); + } + }, [initialTableSelected]); + // endregion // region --- cellTypeOptions unused / remove? @@ -880,6 +884,34 @@ export const NotebookAddCell = observer( console.error('Error retrieving database edges'); } + // store edges in useState + const edges = pixelResponse.pixelReturn[1].output.edges; + const newTableEdges = {}; + edges.forEach((edge) => { + // add edge from source direction + if (newTableEdges[edge.source]) { + newTableEdges[edge.source][edge.target] = edge.relation; + // debugger; + } else { + newTableEdges[edge.source] = { + [edge.target]: edge.relation, + }; + // debugger; + } + // add edge from target direction + if (newTableEdges[edge.target]) { + newTableEdges[edge.target][edge.source] = edge.relation; + // debugger; + } else { + newTableEdges[edge.target] = { + [edge.source]: edge.relation, + }; + // debugger; + } + }); + console.log({ newTableEdges }); + setTableEdges(newTableEdges); + setIsDatabaseLoading(false); }); }; @@ -1036,8 +1068,20 @@ export const NotebookAddCell = observer( /** Checkbox Handler */ const checkBoxHandler = (tableIndex, columnIndex) => { const columnObject = watchedTables[tableIndex].columns[columnIndex]; - console.log({ columnObject }); updateAliasCountObj(columnObject.checked, columnObject.userAlias); + if (columnObject.checked && initialTableSelected == null) { + setInitialTableSelected(watchedTables[tableIndex].name); + alert(watchedTables[tableIndex].name); + console.log({ tableIndex, watchedTables }); + } else if ( + columnObject.checked == false + // && + // ### start here + // check for checked columns in same table as init column + // check for any other checked columns in other tables + ) { + setInitialTableSelected(null); + } // add checked column to set // check for joinable tables From bf9adccb84670306ad29a2d58b4dccc50266a2cc Mon Sep 17 00:00:00 2001 From: Betthauser Date: Fri, 28 Jun 2024 14:08:47 -0700 Subject: [PATCH 24/49] feat(client): tables rendering based on available joins working needs debugging --- .../components/notebook/NotebookAddCell.tsx | 589 +++++++++--------- 1 file changed, 303 insertions(+), 286 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 131633b6f7..35c6fe76db 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -438,6 +438,9 @@ export const NotebookAddCell = observer( const [tableEdges, setTableEdges] = useState({}); // const [initialTableSelected, setInitialTableSelected] = useState(null); + const [checkedColumnsCount, setCheckedColumnsCount] = useState(0); + const [shownTables, setShownTables] = useState(new Set()); + // track to manage joinable tables // endregion @@ -523,18 +526,17 @@ export const NotebookAddCell = observer( return; } setUserDatabases(getDatabases.data); - console.log({ userDatabases: getDatabases.data }); }, [getDatabases.status, getDatabases.data]); - useEffect(() => { - if (initialTableSelected == null) { - // TODO: unhide all tables - alert('unhide all tables'); - } else { - // TODO: hide all unjoinable tables - alert('hide all unjoinable tables'); - } - }, [initialTableSelected]); + // useEffect(() => { + // if (initialTableSelected == null) { + // // TODO: unhide all tables + // alert('unhide all tables'); + // } else { + // // TODO: hide all unjoinable tables + // alert('hide all unjoinable tables'); + // } + // }, [initialTableSelected]); // endregion @@ -726,6 +728,7 @@ export const NotebookAddCell = observer( /** Add all the columns from a Table */ const addAllTableColumnsHandler = (event) => { alert('add all'); + // TODO: check all columns from table }; /** New Submit for Import Data --- empty */ @@ -774,10 +777,12 @@ export const NotebookAddCell = observer( 'ERROR', ) === -1; + let newTableNames = []; + // populate database structure if (isResponseTableStructureGood) { console.log({ responseTableStructure }); - const tableNames = [ + newTableNames = [ ...responseTableStructure.reduce((set, ele) => { set.add(ele[0]); return set; @@ -832,14 +837,14 @@ export const NotebookAddCell = observer( databaseSelect: databaseId, tables: newTableColumnsObject, }); - console.log({ newTableColumnsObject }); - - // setTableColumnsObject(tableColumnsObject); - // setTableNames(tableNames); } else { console.error('Error retrieving database tables'); } + // set visible tables set to all tables + setTableNames(newTableNames); + setShownTables(new Set(newTableNames)); + // make and populate new edges dict if (isResponseTableEdgesStructureGood) { const newEdgesDict = @@ -891,27 +896,21 @@ export const NotebookAddCell = observer( // add edge from source direction if (newTableEdges[edge.source]) { newTableEdges[edge.source][edge.target] = edge.relation; - // debugger; } else { newTableEdges[edge.source] = { [edge.target]: edge.relation, }; - // debugger; } // add edge from target direction if (newTableEdges[edge.target]) { newTableEdges[edge.target][edge.source] = edge.relation; - // debugger; } else { newTableEdges[edge.target] = { [edge.source]: edge.relation, }; - // debugger; } }); - console.log({ newTableEdges }); setTableEdges(newTableEdges); - setIsDatabaseLoading(false); }); }; @@ -1060,34 +1059,46 @@ export const NotebookAddCell = observer( } } - console.log({ isBeingAdded }); - console.log({ newAliasesCountObj }); setAliasesCountObj(newAliasesCountObj); }; + /** Find Joinable Tables */ + const findAllJoinableTables = (rootTableName) => { + const joinableTables = tableEdges[rootTableName] + ? Object.keys(tableEdges[rootTableName]) + : []; + console.log({ + rootTableName, + tableEdges, + joinableTables, + 'tableEdges[rootTableName]': tableEdges[rootTableName], + }); + const newShownTables = new Set([...joinableTables, rootTableName]); + // debugger; + setShownTables(newShownTables); + }; + /** Checkbox Handler */ const checkBoxHandler = (tableIndex, columnIndex) => { + // debugger; const columnObject = watchedTables[tableIndex].columns[columnIndex]; - updateAliasCountObj(columnObject.checked, columnObject.userAlias); - if (columnObject.checked && initialTableSelected == null) { - setInitialTableSelected(watchedTables[tableIndex].name); - alert(watchedTables[tableIndex].name); - console.log({ tableIndex, watchedTables }); - } else if ( - columnObject.checked == false - // && - // ### start here - // check for checked columns in same table as init column - // check for any other checked columns in other tables - ) { - setInitialTableSelected(null); + updateAliasCountObj(columnObject?.checked, columnObject.userAlias); + if (columnObject?.checked) { + // debugger; + if (checkedColumnsCount == 0) { + // debugger; + findAllJoinableTables(watchedTables[tableIndex].name); + } + setCheckedColumnsCount(checkedColumnsCount + 1); + } else if (columnObject?.checked == false) { + // debugger; + if (checkedColumnsCount == 1) { + // debugger; + setShownTables(new Set(tableNames)); + } + setCheckedColumnsCount(checkedColumnsCount - 1); } - - // add checked column to set - // check for joinable tables - // hide all other tables - - // check for repeat aliases in checked columns + // debugger; }; return ( @@ -1337,278 +1348,284 @@ export const NotebookAddCell = observer( Available Tables / Columns - {newTableFields.map( - (table, tableIndex) => ( - - - - + shownTables.has(t.name), + ) + .map( + (table, tableIndex) => ( + + + + + + + { + table.name } - placement="top" - > - - - {table.name} - - - - - - - - - - - - - Fields - - - - - Alias - - - - - Field - Type - - - + + +
+ + + + + + + + + + Fields + + + + + Alias + + + + + Field + Type + + + - {table.columns.map( - ( - column, - columnIndex, - ) => ( - - - ( - { - field.onChange( - e, - ); - checkBoxHandler( - tableIndex, - columnIndex, - ); - }} - /> - )} - /> - - - { + {table.columns.map( + ( + column, + columnIndex, + ) => ( + - PK - - )} - {column.columnName.includes( - '_ID', - ) && ( -
- FK -
- )} -
- - + > + ( - { - if ( - watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .checked - ) { - updateAliasCountObj( - true, - e - .target - .value, - field.value, - ); - } field.onChange( - e - .target - .value, + e, + ); + checkBoxHandler( + tableIndex, + columnIndex, ); }} /> )} /> - {watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .checked && - aliasesCountObj[ - watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .userAlias - ] > - 1 && ( - - - - )} - - - - - + + { + column.columnName } - render={({ - field, - }) => ( - - )} - /> - -
- ), - )} -
-
-
- ), - )} + /> + {watchedTables[ + tableIndex + ] + .columns[ + columnIndex + ] + .checked && + aliasesCountObj[ + watchedTables[ + tableIndex + ] + .columns[ + columnIndex + ] + .userAlias + ] > + 1 && ( + + + + )} + + + + + ( + + )} + /> + + + ), + )} + + + + ), + )} {/* From 81a95d9939dad5ca4dda516953736640300b240d Mon Sep 17 00:00:00 2001 From: Betthauser Date: Mon, 1 Jul 2024 09:30:29 -0700 Subject: [PATCH 25/49] feat(client): checkbox and table rendering bugs addressed with state management refactor --- .../components/notebook/NotebookAddCell.tsx | 512 +++++++++--------- 1 file changed, 260 insertions(+), 252 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 35c6fe76db..85ff8f0fa0 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -1027,6 +1027,8 @@ export const NotebookAddCell = observer( ) => { const newAliasesCountObj = { ...aliasesCountObj }; + console.log({ isBeingAdded, newAlias, oldAlias }); + if (isBeingAdded) { if (newAliasesCountObj[newAlias]) { newAliasesCountObj[newAlias] = @@ -1059,6 +1061,7 @@ export const NotebookAddCell = observer( } } + console.log({ newAliasesCountObj }); setAliasesCountObj(newAliasesCountObj); }; @@ -1082,6 +1085,7 @@ export const NotebookAddCell = observer( const checkBoxHandler = (tableIndex, columnIndex) => { // debugger; const columnObject = watchedTables[tableIndex].columns[columnIndex]; + console.log({ columnObject }); updateAliasCountObj(columnObject?.checked, columnObject.userAlias); if (columnObject?.checked) { // debugger; @@ -1348,284 +1352,288 @@ export const NotebookAddCell = observer( Available Tables / Columns - {newTableFields - .filter((t) => - shownTables.has(t.name), - ) - .map( - (table, tableIndex) => ( - - - - ( +
+ {/* using conditional rendering for each table but if bugs persists set state for showntables in checkbox handler */} + {shownTables.has( + table.name, + ) && ( + + + + + + + { + table.name } - placement="top" - > - - - { - table.name - } - - - - - - - - - - - - - Fields - - - - - Alias - - - - - Field - Type - - - - - {table.columns.map( - ( - column, - columnIndex, - ) => ( - - - ( - { - field.onChange( - e, - ); - checkBoxHandler( - tableIndex, - columnIndex, - ); - }} - /> - )} - /> - - - { - column.columnName + + +
+ + + + - PK - - )} - {column.columnName.includes( - '_ID', - ) && ( -
- FK -
- )} -
- - + color="primary" + > + + + + + + Fields + + + + + Alias + + + + + Field + Type + + +
+ + {table.columns.map( + ( + column, + columnIndex, + ) => ( + + ( - { - if ( - watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .checked - ) { - updateAliasCountObj( - true, - e - .target - .value, - field.value, - ); - } field.onChange( - e - .target - .value, + e, + ); + checkBoxHandler( + tableIndex, + columnIndex, ); }} /> )} /> - {watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .checked && - aliasesCountObj[ - watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .userAlias - ] > - 1 && ( - - - - )} - - - - - + + { + column.columnName } - render={({ - field, - }) => ( - - )} - /> - - - ), - )} -
-
-
- ), - )} + /> + {watchedTables[ + tableIndex + ] + .columns[ + columnIndex + ] + .checked && + aliasesCountObj[ + watchedTables[ + tableIndex + ] + .columns[ + columnIndex + ] + .userAlias + ] > + 1 && ( + + + + )} + + + + + ( + + )} + /> + + + ), + )} + + + + )} +
+ ), + )} {/* From 23e2abf97a8d624690de150090fc868de4888194 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Mon, 1 Jul 2024 14:42:41 -0700 Subject: [PATCH 26/49] feat(client): automatic join logic built out adding stack partially working --- .../components/notebook/NotebookAddCell.tsx | 198 +++++++++++------- 1 file changed, 123 insertions(+), 75 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 85ff8f0fa0..df99e69bc6 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -352,7 +352,7 @@ const AddCellOptions: Record = { }; const IMPORT_MODAL_WIDTHS = { - small: '500px', + small: '600px', medium: '1150px', large: '1150px', }; @@ -436,7 +436,7 @@ export const NotebookAddCell = observer( const [hiddenTablesSet, setHiddenTablesSet] = useState({}); const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } const [tableEdges, setTableEdges] = useState({}); // - const [initialTableSelected, setInitialTableSelected] = useState(null); + const [rootTable, setRootTable] = useState(null); const [checkedColumnsCount, setCheckedColumnsCount] = useState(0); const [shownTables, setShownTables] = useState(new Set()); @@ -528,15 +528,10 @@ export const NotebookAddCell = observer( setUserDatabases(getDatabases.data); }, [getDatabases.status, getDatabases.data]); - // useEffect(() => { - // if (initialTableSelected == null) { - // // TODO: unhide all tables - // alert('unhide all tables'); - // } else { - // // TODO: hide all unjoinable tables - // alert('hide all unjoinable tables'); - // } - // }, [initialTableSelected]); + useEffect(() => { + // if any change occurs with checkboxes reassess all joins to display + setJoinsStackHandler(); + }, [checkedColumnsCount]); // endregion @@ -1083,26 +1078,99 @@ export const NotebookAddCell = observer( /** Checkbox Handler */ const checkBoxHandler = (tableIndex, columnIndex) => { - // debugger; const columnObject = watchedTables[tableIndex].columns[columnIndex]; console.log({ columnObject }); updateAliasCountObj(columnObject?.checked, columnObject.userAlias); if (columnObject?.checked) { - // debugger; if (checkedColumnsCount == 0) { - // debugger; findAllJoinableTables(watchedTables[tableIndex].name); + setRootTable(watchedTables[tableIndex].name); } setCheckedColumnsCount(checkedColumnsCount + 1); } else if (columnObject?.checked == false) { - // debugger; if (checkedColumnsCount == 1) { - // debugger; setShownTables(new Set(tableNames)); + setRootTable(null); } setCheckedColumnsCount(checkedColumnsCount - 1); } - // debugger; + }; + + const checkTableForSelectedColumns = (tableName) => { + for (let i = 0; i < watchedTables.length; i++) { + const currTable = watchedTables[i]; + if (currTable.name == tableName) { + const currTableColumns = currTable.columns; + for (let j = 0; j < currTableColumns.length; j++) { + const currColumn = currTableColumns[j]; + if (currColumn.checked == true) return true; + } + } + } + return false; + }; + + const setJoinsStackHandler = () => { + if (checkedColumnsCount < 2) { + // do nothing + } else { + const leftTable = rootTable; + const rightTables = Object.entries(tableEdgesObject[rootTable]); + + rightTables.forEach((entry, joinIdx) => { + const rightTable = entry[0]; + const leftKey = entry[1]['sourceColumn']; + const rightKey = entry[1]['targetColumn']; + console.log({ + joinIdx, + leftTable, + rightTable, + leftKey, + rightKey, + }); + + const leftTableContainsCheckedColumns = + checkTableForSelectedColumns(leftTable); + const rightTableContainsCheckedColumns = + checkTableForSelectedColumns(rightTable); + + if ( + leftTableContainsCheckedColumns && + rightTableContainsCheckedColumns + ) { + // alert(`${leftTable} :: ${rightTable} || ${leftKey} :: ${rightKey}`); + alert('join being added'); + setQueryElementCounter(queryElementCounter + 1); + appendStack({ + queryType: `Join`, + queryChildren: [], + }); + } + // check leftTable and rightTable for checks + }); + + console.log({ leftTable, rightTables, tableEdges }); + + removeStack(); + // remove all join stacks? + // left table will always be the root table + // get right tables from tableEdges + // check right tables for checked columns + // if 1+ are found add append join stack + // if 0 are found remove specific join stack? + + // Array.from(shownTables).forEach((shownTable: string, shownTableIndex, foo) => { + // console.log({ shownTableIndex, shownTable, foo }); + // if (shownTableIndex == 0) { + // const leftTable = shownTable; + // const rightTables = Object.entries(tableEdgesObject[leftTable]); + // for (const [rightTable, keysObject] of rightTables) { + // console.log({ leftTable, rightTable, joinColumn: keysObject["sourceColumn"] }) + // } + // } + // }); + } + console.log({ tableEdges, shownTables, tableEdgesObject }); }; return ( @@ -2284,7 +2352,6 @@ export const NotebookAddCell = observer( ); }} // label={'Right Table'} - label={'Join Table'} value={selectedRightTable} size={'small'} color="primary" @@ -2483,7 +2550,7 @@ export const NotebookAddCell = observer(
- + */}
@@ -2975,26 +3042,6 @@ export const NotebookAddCell = observer( )} - // - // {stack.queryType} - // - // ))} - {/* */} +
-
+ {/*
- - {/* - */} -
+
*/} {/* {showEditColumns && ( */} @@ -3084,6 +2855,7 @@ export const NotebookAddCell = observer( queryType: `Join`, queryChildren: [], }); + console.log({ stackFields }); }} startIcon={} > From f5b92f2db89b07bdae61d0ac186ee256c75c32f7 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 3 Jul 2024 11:14:33 -0700 Subject: [PATCH 28/49] feat(client): joins bug fixed added new remove logic --- .../components/notebook/NotebookAddCell.tsx | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index d219ea0c56..dcc42cfad5 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -1179,26 +1179,48 @@ export const NotebookAddCell = observer( const rightTableContainsCheckedColumns = checkTableForSelectedColumns(rightTable); + const defaultJoinType = 'Inner Join'; + const joinsSetString = `${leftTable}:${rightTable}`; - console.log({ joinsSetString, joinsSet }); if ( leftTableContainsCheckedColumns && rightTableContainsCheckedColumns && joinsSet.has(joinsSetString) == false ) { - // setQueryElementCounter(queryElementCounter + 1); - // appendStack({ - // queryType: `Join`, - // queryChildren: [], - // }); appendJoinElement({ leftTable: leftTable, rightTable: rightTable, - joinType: 'Inner Join', + joinType: defaultJoinType, leftKey: leftKey, rightKey: rightKey, }); addToJoinsSetHelper(joinsSetString); + } else if ( + leftTableContainsCheckedColumns == false || + (rightTableContainsCheckedColumns == false && + joinsSet.has(joinsSetString)) + ) { + // one or both tables contains no checked columns + // but the join has been previously added to the join set and stack + // so remove it from both + + joinsSet.delete(joinsSetString); + // find the index of the target join element to remove + + joinElements.some((ele, idx) => { + if ( + leftTable == ele.leftTable && + rightTable == ele.rightTable && + defaultJoinType == ele.joinType && + leftKey == ele.leftKey && + rightKey == ele.rightKey + ) { + removeJoinElement(idx); + return true; + } else { + return false; + } + }); } }); } @@ -2824,7 +2846,7 @@ export const NotebookAddCell = observer( marginBottom: '15px', }} > - + */} - -
)} @@ -2356,7 +1986,6 @@ export const NotebookAddCell = observer( )} {/* stack for user-added joins filters and summaries */} - {/* {stackFields.map((stack, stackIndex) => ( */} {joinElements.map((join, stackIndex) => ( - {/* - */} - {/* - where - */} - where @@ -2466,7 +2072,7 @@ export const NotebookAddCell = observer( {/* {showEditColumns && ( */} - {false && ( + {/* {false && ( - {/* table header with uncontrolled checkbox for all */} @@ -2593,7 +2198,6 @@ export const NotebookAddCell = observer( - {/* show checkboxes and text fields for all columns */} {editableColumnFields?.map( (field, index) => ( - )} + )} */} {/* {showPreview && ( */} - {false && ( + {/* {false && (
- )} + )} */}
))} @@ -2936,43 +2540,6 @@ export const NotebookAddCell = observer( marginBottom: '15px', }} > - {/* */} From 52070836e6691e57326e0e932d48a456b3a0e23f Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 10 Jul 2024 11:24:32 -0700 Subject: [PATCH 32/49] feat(client): style joins stack elements to match figma --- .../src/components/notebook/NotebookAddCell.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 529cc3d2f6..58ff3b730d 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -149,7 +149,7 @@ const StyledTableTitleBlueBubble = styled(Typography)(({ theme }) => ({ marginTop: '0px', marginLeft: '0px', marginBottom: '15px', - backgroundColor: '#E2F2FF', // primary 4 + backgroundColor: theme.palette.primary.selected, width: 'fit-content', padding: '7.5px 17.5px', borderRadius: '10px', @@ -214,18 +214,19 @@ const StyledBorderDiv = styled('div')(({ theme }) => ({ })); const StyledJoinDiv = styled('div')(({ theme }) => ({ - border: '1px solid #aaa', + border: 'none', padding: '4px 12px', borderRadius: '12px', - fontSize: '16px', - color: '#aaa', + fontSize: '14px', + color: 'black', cursor: 'default', + backgroundColor: theme.palette.primary.selected, })); const StyledJoinTypography = styled(Typography)(({ theme }) => ({ - marginLeft: '7.5px', - marginRight: '7.5px', - color: 'gray', + marginLeft: '12.5px', + marginRight: '12.5px', + color: theme.palette.secondary.dark, cursor: 'default', })); From d18da3f7fe3de0e9f190818f7de30e6bb4e44665 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Thu, 11 Jul 2024 14:20:29 -0700 Subject: [PATCH 33/49] feat(client): add test params for styled cell view with pixel toggle --- .../data-import-cell/DataImportCell.tsx | 88 +++++++++++++------ .../cell-defaults/data-import-cell/config.ts | 4 + .../components/notebook/NotebookAddCell.tsx | 3 +- .../src/components/notebook/NotebookCell.tsx | 12 ++- 4 files changed, 78 insertions(+), 29 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index 5855d1f73e..7a0d59d530 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -51,6 +51,16 @@ const FRAME_TYPES = { }, }; +const StyledBlueDiv = styled('div')(({ theme }) => ({ + padding: '5px 10px', + borderRadius: '12px', + backgroundColor: '#F1E9FB', + // maxWidth: '150px', + fontSize: '13px', + textAlign: 'center', + width: 'fit-content', +})); + const StyledContent = styled('div')(({ theme }) => ({ position: 'relative', width: '100%', @@ -95,6 +105,11 @@ export interface DataImportCellDef extends CellDef<'data-import'> { /** Select query rendered in the cell */ selectQuery: string; + + /** Select query rendered in the cell */ + // parameters: { + foo: string; + // } }; } @@ -107,6 +122,7 @@ export const DataImportCell: CellComponent = observer( const { state } = useBlocks(); const [showTables, setShowTables] = useState(false); + const [showStyledView, setShowStyledView] = useState(true); const [cfgLibraryDatabases, setCfgLibraryDatabases] = useState({ loading: true, @@ -317,7 +333,7 @@ export const DataImportCell: CellComponent = observer( ), )} - */} + - {showTables && cell.parameters.databaseId ? ( + {/* {showTables && cell.parameters.databaseId ? ( ) : ( <> - )} + )} */} )} - - - + {showStyledView ? ( +
+ {/* cell.parameters.joins.map */} + {/* cell.parameters.filters.map */} + Bubble View +
+ ) : ( + + + + )} {isExpanded && ( = observer( ))} = { frameType: 'PY', frameVariableName: '', selectQuery: '', + foo: 'baz', }, toPixel: ({ databaseId, frameType, frameVariableName, selectQuery }) => { // this only runs when the cell runs @@ -30,6 +31,9 @@ export const DataImportCellConfig: CellConfig = { // const combinedPixelString = selectQuery.slice(0, -1) + pixelImportString + pixelMetaString; const combinedPixelString = selectQuery.slice(0, -1) + pixelImportString; + + console.log({ combinedPixelString }); + return combinedPixelString; // const firstPixel = `${splitPixelString[0]};`; diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 58ff3b730d..15f09b8a19 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -88,6 +88,7 @@ const StyledModalTitleWrapper = styled(Modal.Title)(({ theme }) => ({ padding: '0px', marginBottom: '15px', justifyContent: 'space-between', + marginTop: '25px', })); const StyledModalTitleWrapper2 = styled(Modal.Title)(({ theme }) => ({ @@ -635,6 +636,7 @@ export const NotebookAddCell = observer( // selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs // selectQuery: pixelStringRef.current, // construct query based on useForm inputs selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs + foo: 'moo', }; } @@ -1479,7 +1481,6 @@ export const NotebookAddCell = observer( - {/* Import Data from Database Selector */}
{cell.config.name} + {/* {cell.config.parameters.foo} */} @@ -713,7 +714,15 @@ export const NotebookCell = observer( )} - {rendered} + {/* { cell.widget == 'data-import' ? +
data import bubbles
+ : */} + + {rendered} + + {/* } */} {cell.isExecuted && ( <> @@ -722,6 +731,7 @@ export const NotebookCell = observer( Date: Fri, 12 Jul 2024 13:55:32 -0700 Subject: [PATCH 34/49] feat(client): styled cell diplay working for joins and tables with added params --- .../data-import-cell/DataImportCell.tsx | 223 +++++++++++++++++- .../cell-defaults/data-import-cell/config.ts | 12 +- .../components/notebook/NotebookAddCell.tsx | 35 +++ .../src/components/notebook/NotebookCell.tsx | 7 +- 4 files changed, 263 insertions(+), 14 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index 7a0d59d530..2b31861e38 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -11,6 +11,9 @@ import { Stack, InputAdornment, Typography, + Tooltip, + Modal, + IconButton, } from '@semoss/ui'; import { @@ -18,6 +21,8 @@ import { CropFree, KeyboardArrowDown, DriveFileRenameOutlineRounded, + CalendarViewMonth, + JoinInner, } from '@mui/icons-material'; import { editor } from 'monaco-editor'; import { DatabaseTables } from './DatabaseTables'; @@ -51,11 +56,73 @@ const FRAME_TYPES = { }, }; +const StyledJoinDiv = styled('div')(({ theme }) => ({ + border: 'none', + padding: '0px 12px', + borderRadius: '12px', + fontSize: '12.5px', + color: 'black', + cursor: 'default', + // backgroundColor: theme.palette.primary.selected, + backgroundColor: '#F1E9FB', + fontWeight: '400', +})); + +const StyledJoinTypography = styled(Typography)(({ theme }) => ({ + marginLeft: '12.5px', + marginRight: '12.5px', + color: theme.palette.secondary.dark, + cursor: 'default', +})); + +const StyledModalTitleWrapper2 = styled(Modal.Title)(({ theme }) => ({ + display: 'flex', + alignContent: 'center', + padding: '0px', + // justifyContent: 'space-between', +})); + +const TableIconButton = styled(Tooltip)(({ theme }) => ({ + marginLeft: '-3px', + marginRight: '7px', + color: theme.palette.primary.main, +})); + +const StyledTableTitleBlueBubble = styled(Typography)(({ theme }) => ({ + marginTop: '0px', + // marginBottom: '15px', + // marginLeft: '15px', + marginRight: '15px', + backgroundColor: theme.palette.primary.selected, + width: 'fit-content', + padding: '7.5px 17.5px', + borderRadius: '10px', + display: 'inline-flex', + alignItems: 'center', + cursor: 'default', + fontSize: '12.5px', +})); + +const StyledJoinElementBlueBubble = styled(Typography)(({ theme }) => ({ + marginTop: '0px', + marginBottom: '15px', + // marginLeft: '15px', + marginRight: '15px', + backgroundColor: theme.palette.primary.selected, + width: 'fit-content', + padding: '10px 20px', + borderRadius: '10px', + // display: 'block', + // alignItems: 'center', + cursor: 'default', + fontSize: '12.5px', +})); + const StyledBlueDiv = styled('div')(({ theme }) => ({ padding: '5px 10px', borderRadius: '12px', - backgroundColor: '#F1E9FB', - // maxWidth: '150px', + // backgroundColor: '#F1E9FB', // light purple + backgroundColor: theme.palette.primary.selected, fontSize: '13px', textAlign: 'center', width: 'fit-content', @@ -91,6 +158,24 @@ const StyledTextField = styled(TextField)(({ theme }) => ({ const StyledContainer = styled('div')(({ theme }) => ({})); +interface JoinObject { + // table1: string; + // table2: string; + // key1: string; + // key2: string; + // joinType: string; + id: string; + joinType: string; + leftKey: string; + leftTable: string; + rightKey: string; + rightTable: string; +} + +interface FilterObject { + // structure for filters tbd +} + export interface DataImportCellDef extends CellDef<'data-import'> { widget: 'data-import'; parameters: { @@ -110,6 +195,13 @@ export interface DataImportCellDef extends CellDef<'data-import'> { // parameters: { foo: string; // } + + tableNames: string[]; + + joins: JoinObject[]; + + // filters will be added later + // filters: FilterObject[]; }; } @@ -363,11 +455,127 @@ export const DataImportCell: CellComponent = observer( )} {showStyledView ? ( -
- {/* cell.parameters.joins.map */} - {/* cell.parameters.filters.map */} - Bubble View -
+ <> +
+ {/* + Data from: + */} + {cell.parameters.tableNames && + cell.parameters.tableNames.map( + (tableName) => ( + + + + + {/* */} + {tableName} + {/* */} + + ), + )} +
+ + {/* stack for user-added joins filters and summaries */} + {isExpanded && + cell.parameters.joins && + cell.parameters.joins.map( + (join, stackIndex) => ( + + +
+ + + {join.leftTable} + + + + + + + + + + + + {join.rightTable} + + + + + where + + + + + {join.leftKey} + + + + + = + + + + + {join.rightKey} + + +
+ {/*
+ { + removeStack(stackIndex); + }} + > + + +
*/} +
+
+ ), + )} + ) : ( = observer( alignItems={'center'} justifyContent={'flex-end'} borderColor={'red'} + paddingTop={'25px'} > = { frameVariableName: '', selectQuery: '', foo: 'baz', + joins: [], + tableNames: [], + // filters: [], }, - toPixel: ({ databaseId, frameType, frameVariableName, selectQuery }) => { + toPixel: ({ + databaseId, + frameType, + frameVariableName, + selectQuery, + foo, + joins, + }) => { // this only runs when the cell runs // it will check the frame type and variable name which the user could change // so NotebookAddCell should track the static first part of the pixel with db id / cols and add Meta | Frame() etc without the import and var name diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 15f09b8a19..5533a29d7c 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -470,6 +470,7 @@ export const NotebookAddCell = observer( const [checkedColumnsCount, setCheckedColumnsCount] = useState(0); const [shownTables, setShownTables] = useState(new Set()); + const [selectedTableNames, setSelectedTableNames] = useState(new Set()); const [joinsSet, setJoinsSet] = useState(new Set()); // Set({ "USERS_TABLE:VISNS_TABLE" }) const [pixelString, setPixelString] = useState(''); @@ -536,6 +537,10 @@ export const NotebookAddCell = observer( // region --- useEffects + useEffect(() => { + console.log({ joinElements }); + }, [joinElements]); + useEffect(() => { setSelectedLeftKey(null); setSelectedRightKey(null); @@ -575,6 +580,8 @@ export const NotebookAddCell = observer( useEffect(() => { // if any change occurs with checkboxes reassess all joins to display setJoinsStackHandler(); + updateSelectedTables(); + console.log({ selectedTableNames }); }, [checkedColumnsCount]); useEffect(() => { @@ -637,6 +644,8 @@ export const NotebookAddCell = observer( // selectQuery: pixelStringRef.current, // construct query based on useForm inputs selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs foo: 'moo', + joins: joinElements, + tableNames: Array.from(selectedTableNames), }; } @@ -968,6 +977,31 @@ export const NotebookAddCell = observer( }); }; + const updateSelectedTables = () => { + // const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = []; + const pixelColumnAliases = []; + // const pixelJoins = []; + + watchedTables?.forEach((tableObject) => { + const currTableName = tableObject.name; + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + setSelectedTableNames(pixelTables); + }; + /** Old Get All Database Tables for Import Data --- remove? */ const retrieveDatabaseTables = async (databaseId) => { setIsDatabaseLoading(true); @@ -1357,6 +1391,7 @@ export const NotebookAddCell = observer( const joinsSetCopy = new Set(joinsSet); joinsSetCopy.add(newJoinSet); setJoinsSet(joinsSetCopy); + console.log({ joinsSetCopy }); }; return ( diff --git a/packages/client/src/components/notebook/NotebookCell.tsx b/packages/client/src/components/notebook/NotebookCell.tsx index b2e903e5d0..8c14065eaa 100644 --- a/packages/client/src/components/notebook/NotebookCell.tsx +++ b/packages/client/src/components/notebook/NotebookCell.tsx @@ -717,11 +717,7 @@ export const NotebookCell = observer( {/* { cell.widget == 'data-import' ?
data import bubbles
: */} - - {rendered} - + {rendered} {/* } */} {cell.isExecuted && ( @@ -731,7 +727,6 @@ export const NotebookCell = observer( Date: Mon, 15 Jul 2024 14:49:14 -0700 Subject: [PATCH 35/49] feat(client): style cell view and start edit modal --- .../data-import-cell/DataImportCell.tsx | 148 +++++++++++------- 1 file changed, 95 insertions(+), 53 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index 2b31861e38..0d88f4e83e 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -23,6 +23,7 @@ import { DriveFileRenameOutlineRounded, CalendarViewMonth, JoinInner, + Edit, } from '@mui/icons-material'; import { editor } from 'monaco-editor'; import { DatabaseTables } from './DatabaseTables'; @@ -56,16 +57,37 @@ const FRAME_TYPES = { }, }; -const StyledJoinDiv = styled('div')(({ theme }) => ({ +const BlueStyledJoinDiv = styled('div')(({ theme }) => ({ border: 'none', padding: '0px 12px', borderRadius: '12px', fontSize: '12.5px', color: 'black', cursor: 'default', - // backgroundColor: theme.palette.primary.selected, + backgroundColor: theme.palette.primary.selected, + fontWeight: '500', +})); + +const GreenStyledJoinDiv = styled('div')(({ theme }) => ({ + border: 'none', + padding: '0px 12px', + borderRadius: '12px', + fontSize: '12.5px', + color: 'black', + cursor: 'default', + backgroundColor: '#DEF4F3', + fontWeight: '500', +})); + +const PurpleStyledJoinDiv = styled('div')(({ theme }) => ({ + border: 'none', + padding: '0px 12px', + borderRadius: '12px', + fontSize: '12.5px', + color: '#BAB4C2', + cursor: 'default', backgroundColor: '#F1E9FB', - fontWeight: '400', + fontWeight: '500', })); const StyledJoinTypography = styled(Typography)(({ theme }) => ({ @@ -86,14 +108,16 @@ const TableIconButton = styled(Tooltip)(({ theme }) => ({ marginLeft: '-3px', marginRight: '7px', color: theme.palette.primary.main, + // color: 'black', })); -const StyledTableTitleBlueBubble = styled(Typography)(({ theme }) => ({ +const StyledTableTitleBubble = styled('div')(({ theme }) => ({ marginTop: '0px', // marginBottom: '15px', // marginLeft: '15px', marginRight: '15px', - backgroundColor: theme.palette.primary.selected, + // backgroundColor: theme.palette.primary.selected, + backgroundColor: '#F1E9FB', width: 'fit-content', padding: '7.5px 17.5px', borderRadius: '10px', @@ -101,6 +125,7 @@ const StyledTableTitleBlueBubble = styled(Typography)(({ theme }) => ({ alignItems: 'center', cursor: 'default', fontSize: '12.5px', + fontWeight: '400', })); const StyledJoinElementBlueBubble = styled(Typography)(({ theme }) => ({ @@ -372,6 +397,15 @@ export const DataImportCell: CellComponent = observer( }); }; + const openEditModal = () => { + alert('openEditModal'); + console.log({ + databaseId: cell.parameters.databaseId, + tableNames: cell.parameters.tableNames, + joins: cell.parameters.joins, + }); + }; + return ( @@ -381,15 +415,10 @@ export const DataImportCell: CellComponent = observer( direction="row" justifyContent={'space-between'} > - {/* - {cfgLibraryDatabases.display[cell.parameters.databaseId]} - */} = observer( ), )} - {/* */} - {/* {showTables && cell.parameters.databaseId ? ( - - ) : ( - <> - )} */} )} {showStyledView ? ( @@ -470,20 +483,39 @@ export const DataImportCell: CellComponent = observer( {cell.parameters.tableNames && cell.parameters.tableNames.map( (tableName) => ( - + // + // + // + // + // {tableName} + // + // + - - - - {/* */} - {tableName} - {/* */} - + {/* <> */} + + + {tableName} + + {/* */} + ), )}
@@ -512,9 +544,9 @@ export const DataImportCell: CellComponent = observer( }} > - + {join.leftTable} - + = observer( - + {join.rightTable} - + - where + ON - + {join.leftKey} - + @@ -555,9 +587,9 @@ export const DataImportCell: CellComponent = observer( - + {join.rightKey} - + {/*
@@ -608,9 +640,19 @@ export const DataImportCell: CellComponent = observer( direction="row" alignItems={'center'} justifyContent={'flex-end'} - borderColor={'red'} - paddingTop={'25px'} + paddingTop={'0px'} > + + Date: Tue, 16 Jul 2024 15:02:24 -0700 Subject: [PATCH 36/49] feat(client): all data integrated to cell params passing to new edit modal component --- .../data-import-cell/DataImportCell.tsx | 32 +- .../cell-defaults/data-import-cell/config.ts | 6 +- .../notebook/DataImportFormModal.tsx | 2720 +++++++++++++++++ .../components/notebook/NotebookAddCell.tsx | 68 +- 4 files changed, 2799 insertions(+), 27 deletions(-) create mode 100644 packages/client/src/components/notebook/DataImportFormModal.tsx diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index 0d88f4e83e..be3332d518 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -31,6 +31,8 @@ import { DatabaseTables } from './DatabaseTables'; import { ActionMessages, CellComponent, CellDef } from '@/stores'; import { useBlocks, usePixel } from '@/hooks'; +import { DataImportFormModal } from '../../notebook/DataImportFormModal'; + const EDITOR_LINE_HEIGHT = 19; const EDITOR_MAX_HEIGHT = 500; // ~25 lines @@ -216,17 +218,18 @@ export interface DataImportCellDef extends CellDef<'data-import'> { /** Select query rendered in the cell */ selectQuery: string; - /** Select query rendered in the cell */ - // parameters: { - foo: string; - // } + // foo: string; tableNames: string[]; joins: JoinObject[]; - // filters will be added later + selectedColumns: string[]; + + columnAliases: string[]; + // filters: FilterObject[]; + // summaries: FilterObject[]; }; } @@ -241,6 +244,9 @@ export const DataImportCell: CellComponent = observer( const [showTables, setShowTables] = useState(false); const [showStyledView, setShowStyledView] = useState(true); + const [isDataImportModalOpen, setIsDataImportModalOpen] = + useState(false); + const [cfgLibraryDatabases, setCfgLibraryDatabases] = useState({ loading: true, ids: [], @@ -398,12 +404,12 @@ export const DataImportCell: CellComponent = observer( }; const openEditModal = () => { - alert('openEditModal'); console.log({ databaseId: cell.parameters.databaseId, tableNames: cell.parameters.tableNames, joins: cell.parameters.joins, }); + setIsDataImportModalOpen(true); }; return ( @@ -716,6 +722,20 @@ export const DataImportCell: CellComponent = observer( )} + ); }, diff --git a/packages/client/src/components/cell-defaults/data-import-cell/config.ts b/packages/client/src/components/cell-defaults/data-import-cell/config.ts index 1a26e835c5..c78b06969c 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/config.ts +++ b/packages/client/src/components/cell-defaults/data-import-cell/config.ts @@ -10,9 +10,10 @@ export const DataImportCellConfig: CellConfig = { frameType: 'PY', frameVariableName: '', selectQuery: '', - foo: 'baz', joins: [], tableNames: [], + selectedColumns: [], + columnAliases: [], // filters: [], }, toPixel: ({ @@ -20,8 +21,9 @@ export const DataImportCellConfig: CellConfig = { frameType, frameVariableName, selectQuery, - foo, joins, + selectedColumns, + columnAliases, }) => { // this only runs when the cell runs // it will check the frame type and variable name which the user could change diff --git a/packages/client/src/components/notebook/DataImportFormModal.tsx b/packages/client/src/components/notebook/DataImportFormModal.tsx new file mode 100644 index 0000000000..dc8f0e5af6 --- /dev/null +++ b/packages/client/src/components/notebook/DataImportFormModal.tsx @@ -0,0 +1,2720 @@ +import { useState, useEffect, useRef } from 'react'; +import { observer } from 'mobx-react-lite'; +import { computed } from 'mobx'; +import { + styled, + Button, + Divider, + MenuProps, + Typography, + Menu, + Stack, + Modal, + Checkbox, + TextField, + IconButton, + Tooltip, + Select, + Table, + Grid, +} from '@semoss/ui'; + +import { useBlocks, usePixel, useRootStore } from '@/hooks'; +import { + ActionMessages, + CellStateConfig, + NewCellAction, + QueryState, +} from '@/stores'; +import { + ArrowDownwardRounded, + ControlPointDuplicateRounded, + ChangeCircleOutlined, + IndeterminateCheckBox, + AddCircleOutline, + AccountTree, + Functions, + Storage, + Add, + Code, + ImportExport, + KeyboardArrowDown, + FilterListRounded, + JoinLeftRounded, + KeyboardArrowUp, + TextFields, + TableRows, + Label, + CheckBox, + AddCircle, + AddBox, + Close, + JoinInner, + Warning, + WarningAmber, + TableView, + TableChart, + CalendarViewMonth, +} from '@mui/icons-material'; +import { + DefaultCellDefinitions, + DefaultCells, + TransformationCells, +} from '@/components/cell-defaults'; +import { QueryImportCellConfig } from '../cell-defaults/query-import-cell'; +import { DataImportCellConfig } from '../cell-defaults/data-import-cell'; +import { CodeCellConfig } from '../cell-defaults/code-cell'; +import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; + +import { LoadingScreen } from '@/components/ui'; + +import { runPixel } from '@/api'; +import { TableContainer, alertTitleClasses } from '@mui/material'; + +// region --- Styled Elements + +const StyledImportDataForm = styled('form')(({ theme }) => ({ + margin: '30px 41px', +})); + +const StyledModalTitle = styled(Typography)(({ theme }) => ({ + alignContent: 'center', + marginRight: '15px', +})); + +const StyledModalTitleWrapper = styled(Modal.Title)(({ theme }) => ({ + display: 'flex', + alignContent: 'center', + padding: '0px', + marginBottom: '15px', + justifyContent: 'space-between', + marginTop: '25px', +})); + +const StyledModalTitleWrapper2 = styled(Modal.Title)(({ theme }) => ({ + display: 'flex', + alignContent: 'center', + padding: '0px', + justifyContent: 'space-between', +})); + +const StyledButton = styled(Button)(({ theme }) => ({ + color: theme.palette.text.secondary, + backgroundColor: 'unset!important', +})); + +const StyledDivider = styled(Divider)(({ theme }) => ({ + flexGrow: 1, +})); + +const ScrollTableSetContainer = styled(TableContainer)(({ theme }) => ({ + maxHeight: '350px', + overflowY: 'scroll', +})); + +const StyledTableSetWrapper = styled('div')(({ theme }) => ({ + backgroundColor: '#fff', + marginBottom: '20px', +})); + +const StyledTableTitle = styled(Typography)(({ theme }) => ({ + marginTop: '15px', + marginLeft: '15px', + marginBottom: '20px', +})); + +const StyledTableTitleGreenBubble = styled(Typography)(({ theme }) => ({ + marginTop: '20px', + marginLeft: '15px', + marginBottom: '20px', + backgroundColor: '#E7F4E5x`', // primary 4 + width: 'fit-content', + padding: '7.5px 17.5px', + borderRadius: '10px', +})); + +const FlexWrapper = styled('div')(({ theme }) => ({ + display: 'flex', + padding: '0px', + marginTop: '15px', +})); + +const FlexTableCell = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + // padding: '0px', + // marginTop: '15px', +})); + +const StyledTableTitleBlueBubble = styled(Typography)(({ theme }) => ({ + marginTop: '0px', + marginLeft: '0px', + marginBottom: '15px', + backgroundColor: theme.palette.primary.selected, + width: 'fit-content', + padding: '7.5px 17.5px', + borderRadius: '10px', + display: 'flex', + alignItems: 'center', +})); + +const SingleTableWrapper = styled('div')(({ theme }) => ({ + marginBottom: '60px', + marginLeft: '12.5px', + marginRight: '12.5px', +})); + +const CheckAllIconButton = styled(IconButton)(({ theme }) => ({ + marginLeft: '-10px', +})); + +const AliasWarningIcon = styled(Tooltip)(({ theme }) => ({ + color: 'goldenrod', + marginLeft: '10px', +})); + +const TableIconButton = styled(Tooltip)(({ theme }) => ({ + marginLeft: '-3px', + marginRight: '7px', + color: theme.palette.primary.main, +})); + +const ColumnNameText = styled(Typography)(({ theme }) => ({ + fontWeight: 'bold', +})); + +const StyledMenu = styled((props: MenuProps) => ( + +))(({ theme }) => ({ + '& .MuiPaper-root': { + marginTop: theme.spacing(1), + }, + '.MuiList-root': { + padding: 0, + }, +})); + +const StyledMenuItem = styled(Menu.Item)(() => ({ + textTransform: 'capitalize', +})); + +const StyledBorderDiv = styled('div')(({ theme }) => ({ + border: `1px solid ${theme.palette.secondary.main}`, + padding: '8px 16px', + borderRadius: '8px', +})); + +const StyledJoinDiv = styled('div')(({ theme }) => ({ + border: 'none', + padding: '4px 12px', + borderRadius: '12px', + fontSize: '14px', + color: 'black', + cursor: 'default', + backgroundColor: theme.palette.primary.selected, +})); + +const StyledJoinTypography = styled(Typography)(({ theme }) => ({ + marginLeft: '12.5px', + marginRight: '12.5px', + color: theme.palette.secondary.dark, + cursor: 'default', +})); + +// endregion + +// region --- Old Data Import useForm Types & Interfaces + +interface AddCellOption { + display: string; + icon: React.ReactNode; + defaultCellType?: DefaultCellDefinitions['widget']; + options?: { + display: string; + defaultCellType: DefaultCellDefinitions['widget']; + }[]; + disabled?: boolean; +} + +type QueryChildElement = { + childElementName: string; +}; + +type QueryStackElement = { + queryType: string; // Data, Join or Filter + queryChildren: QueryChildElement[]; +}; + +type JoinElement = { + leftTable: string; + rightTable: string; + joinType: string; + leftKey: string; + rightKey: string; +}; + +type FormValues = { + queryStackElements: QueryStackElement[]; + joinElements: JoinElement[]; + databaseSelect: string; + tableSelect: string; + columns: Column[]; + tables: Table[]; +}; + +// endregion + +// region --- New Data Import useForm Types & Interfaces + +interface Column { + id: number; + tableName: string; + columnName: string; + columnType: string; + userAlias: string; + checked: boolean; +} + +interface Table { + id: number; + name: string; + columns: Column[]; +} + +interface NewFormData { + databaseSelect: string; + tables: Table[]; +} + +// ### is this needed? +type NewFormValues = { + databaseSelect: string; + tables: Table[]; + joins: JoinElement[]; + // filters: FilterElement[]; + // summaries: SummaryElement[]; + // calculations: CalculationElement[]; +}; + +// endregion + +// region --- Transformations / Options / Constants + +// const Transformations = Array.from(Object.values(TransformationCells)).map( +// (item) => { +// return { +// display: item.name, +// defaultCellType: item.widget, +// }; +// }, +// ); + +// const DataImportDropdownOptions = [ +// { +// display: `From Data Catalog`, +// defaultCellType: null, +// }, +// { +// display: `From CSV`, +// defaultCellType: null, +// }, +// ]; + +// const AddCellOptions: Record = { +// code: { +// display: 'Cell', +// defaultCellType: 'code', +// icon: , +// }, +// 'query-import': { +// display: 'Query Import', +// defaultCellType: 'query-import', +// // no DB MUI icon using the icon path from main menu +// icon: ( +// +// +// +// +// +// +// +// +// +// +// ), +// }, +// transformation: { +// display: 'Transformation', +// icon: , +// options: Transformations, +// }, +// 'import-data': { +// display: 'Import Data', +// icon: , +// options: DataImportDropdownOptions, +// disabled: false, +// }, +// text: { +// display: 'Text', +// icon: , +// disabled: true, +// }, +// }; + +// const IMPORT_MODAL_WIDTHS = { +// small: '600px', +// medium: '1150px', +// large: '1150px', +// }; + +// const SQL_COLUMN_TYPES = ['DATE', 'NUMBER', 'STRING', 'TIMESTAMP']; + +// endregion + +export const DataImportFormModal = observer( + (props: { + // query: QueryState; + previousCellId?: string; + isDataImportModalOpen: boolean; + setIsDataImportModalOpen; + cell; + }): JSX.Element => { + const { + previousCellId, + isDataImportModalOpen, + setIsDataImportModalOpen, + cell, + } = props; + // const [anchorEl, setAnchorEl] = useState(null); + // const [selectedAddCell, setSelectedAddCell] = useState(''); + // const [importModalType, setImportModalType] = useState(''); + // const [isDataImportModalOpen, setIsDataImportModalOpen] = + // useState(false); + // const open = Boolean(anchorEl); + // const { query, previousCellId = '' } = props; + // const { state, notebook } = useBlocks(); + + // Old useForm for Data Import --- remove + // const { control, handleSubmit, reset, watch, setValue, getValues } = + useForm({ + defaultValues: { + queryStackElements: [], + databaseSelect: '', + tableSelect: '', + }, + }); + + // New useForm for Data Import + // const { + // control: newControl, + // handleSubmit: newHandleSubmit, + // reset: newReset, + // getValues: _newGetValues, + // setValue: _newSetValue, + // watch: dataImportwatch, + // } = useForm(); + + // const watchedTables = dataImportwatch('tables'); + + // region --- useStates / useRefs + + // const [userDatabases, setUserDatabases] = useState(null); + // const [queryElementCounter, setQueryElementCounter] = useState(0); + // const [databaseTableRawHeaders, setDatabaseTableRawHeaders] = useState( + // [], + // ); + // const [importModalPixelWidth, setImportModalPixelWidth] = + // useState(IMPORT_MODAL_WIDTHS.small); + // const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); + // const [databaseTableHeaders, setDatabaseTableHeaders] = useState([]); + // const [selectedDatabaseId, setSelectedDatabaseId] = useState(null); + // const [tableColumnsObject, setTableColumnsObject] = useState({}); + // const [databaseTableRows, setDatabaseTableRows] = useState([]); + // const [tableNames, setTableNames] = useState([]); + // const [selectedTable, setSelectedTable] = useState(null); + // const importDataSQLStringRef = useRef(''); + // const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open + // const [isDatabaseLoading, setIsDatabaseLoading] = + // useState(false); + // const [showPreview, setShowTablePreview] = useState(false); + // const [showEditColumns, setShowEditColumns] = useState(true); // ### change back to false + // const [checkAllColumns, setCheckAllColumns] = useState(true); + // const { configStore, monolithStore } = useRootStore(); + + // // State Vars for Old useForm --- all uneeded / deletable + // const [selectedLeftTable, setSelectedLeftTable] = + // useState(null); + // const [selectedRightTable, setSelectedRightTable] = + // useState(null); + // const [selectedRightKey, setSelectedRightKey] = useState(null); + // const [columnDataTypesDict, setColumnDataTypesDict] = useState(null); + // const [selectedLeftKey, setSelectedLeftKey] = useState(null); + // const [tableEdgesObject, setTableEdgesObject] = useState(null); + + // // State Vars for new useForm Structure + // // checkedColumnsSet + // const [checkedColumnsSet, setCheckedColumnsSet] = useState(new Set()); + // const [hiddenTablesSet, setHiddenTablesSet] = useState({}); + // const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } + // const [tableEdges, setTableEdges] = useState({}); // + // const [rootTable, setRootTable] = useState(null); + + // const [checkedColumnsCount, setCheckedColumnsCount] = useState(0); + // const [shownTables, setShownTables] = useState(new Set()); + // const [selectedTableNames, setSelectedTableNames] = useState(new Set()); + // const [joinsSet, setJoinsSet] = useState(new Set()); // Set({ "USERS_TABLE:VISNS_TABLE" }) + + // const [pixelString, setPixelString] = useState(''); + // const pixelStringRef = useRef(''); + // const pixelStringRefPart1 = useRef(''); + + // endregion + + // region --- Import Data Old useFieldArrays + + // const { + // fields: stackFields, + // append: appendStack, + // remove: removeStack, + // } = useFieldArray({ + // control, + // name: 'queryStackElements', + // }); + + // const { + // fields: editableColumnFields, + // append: appendEditableColumns, + // remove: removeEditableColumns, + // } = useFieldArray({ + // control, + // name: 'columns', + // }); + + // const { + // fields: tableFields, + // append: appendEditableTableColumns, + // remove: removeEditableTableColumns, + // } = useFieldArray({ + // control, + // name: 'tables', + // }); + + // endregion + + // region --- Import Data New useFieldArray + + // ### only one field array is necessary? + // do each of these need a field array for the columns? + + // const { + // fields: newTableFields, + // append: newTableAppend, + // remove: newTableRemove, + // } = useFieldArray({ + // control: newControl, + // name: 'tables', + // }); + + // const { + // fields: joinElements, + // append: appendJoinElement, + // remove: removeJoinElement, + // } = useFieldArray({ + // control: newControl, + // name: 'joins', + // }); + + // endregion + + // region --- useEffects + + // useEffect(() => { + // console.log({ joinElements }); + // }, [joinElements]); + + // useEffect(() => { + // setSelectedLeftKey(null); + // setSelectedRightKey(null); + // removeEditableColumns(); + // removeStack(); + // }, [selectedDatabaseId, selectedTable]); + + // useEffect(() => { + // removeEditableColumns(); + // removeStack(); + // setShowTablePreview(false); + // setShowEditColumns(true); + // }, [selectedDatabaseId]); + + // useEffect(() => { + // removeEditableColumns(); + // tableColumnsObject[selectedTable]?.forEach((tableObject, idx) => { + // console.log({ tableObject }); + // appendEditableColumns({ + // id: idx, + // tableName: tableObject.tableName, + // columnName: tableObject.columnName, + // userAlias: tableObject.columnName, + // columnType: tableObject.columnType, + // checked: true, + // }); + // }); + // }, [selectedTable]); + + // useEffect(() => { + // if (getDatabases.status !== 'SUCCESS') { + // return; + // } + // setUserDatabases(getDatabases.data); + // }, [getDatabases.status, getDatabases.data]); + + // useEffect(() => { + // // if any change occurs with checkboxes reassess all joins to display + // setJoinsStackHandler(); + // updateSelectedTables(); + // console.log({ selectedTableNames }); + // }, [checkedColumnsCount]); + + // useEffect(() => { + // if (showPreview) { + // retrievePreviewData(); + // } + // }, [ + // aliasesCountObj, + // checkedColumnsCount, + // showPreview, + // selectedDatabaseId, + // ]); + + // endregion + + // region --- cellTypeOptions unused / remove? + // const cellTypeOptions = computed(() => { + // alert("test23") + // const options = { ...AddCellOptions }; + // // transformation cell types can only be added if there exists a query-import cell before it + // if (!previousCellId) { + // delete options['transformation']; + // } else { + // const previousCellIndex = query.list.indexOf(previousCellId); + // let hasFrameVariable = false; + // for (let index = 0; index <= previousCellIndex; index++) { + // if ( + // query.cells[query.list[index]].config.widget === + // 'query-import' + // ) { + // hasFrameVariable = true; + // break; + // } + // } + // if (!hasFrameVariable) { + // delete options['transformation']; + // } + // } + + // return Object.values(options); + // }).get(); + // endregion + + /** Create a New Cell and Add to Notebook */ + // const appendCell = (widget: string) => { + // try { + // const newCellId = `${Math.floor(Math.random() * 100000)}`; + + // const config: NewCellAction['payload']['config'] = { + // widget: DefaultCells[widget].widget, + // parameters: DefaultCells[widget].parameters, + // }; + + // if (widget === DataImportCellConfig.widget) { + // config.parameters = { + // ...DefaultCells[widget].parameters, + // frameVariableName: `FRAME_${newCellId}`, + // databaseId: selectedDatabaseId, + // // selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs + // // selectQuery: pixelStringRef.current, // construct query based on useForm inputs + // selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs + // foo: 'moo', + // joins: joinElements, + // tableNames: Array.from(selectedTableNames), + // }; + // } + + // if (widget === QueryImportCellConfig.widget) { + // config.parameters = { + // ...DefaultCells[widget].parameters, + // frameVariableName: `FRAME_${newCellId}`, + // }; + // } + + // if ( + // previousCellId && + // state.queries[query.id].cells[previousCellId].widget === + // widget && + // widget === CodeCellConfig.widget + // ) { + // const previousCellType = + // state.queries[query.id].cells[previousCellId].parameters + // ?.type ?? 'pixel'; + // config.parameters = { + // ...DefaultCells[widget].parameters, + // type: previousCellType, + // }; + // } + + // // copy and add the step + // state.dispatch({ + // message: ActionMessages.NEW_CELL, + // payload: { + // queryId: query.id, + // cellId: newCellId, + // previousCellId: previousCellId, + // config: config as Omit, + // }, + // }); + // notebook.selectCell(query.id, newCellId); + // } catch (e) { + // console.error(e); + // } + // }; + + /** Construct a Raw SQL String for Data Import --- remove */ + // const constructSQLString = ({ submitData }) => { + // console.log({ submitData }); + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } + + // importDataSQLStringRef.current = newSQLString; + // }; + + /** Construct Submit Pixel for Data Import --- remove? */ + // const constructDataBasePixel = ({ submitData }) => { + // // mimic this pixel structure instead of constructing raw SQL ? + // // or have join autoselect keys and add columns to edit + // // that makes sense with new pixel structure + // // show all tables and selectable rows in edit columns view + // // find way of showing alerts for un joinable columns + // // add form structure to json state (?) + // // make basic non SQL view for notebook cell + // // make edit window + + // // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | + + // // Select ( + // // STATION_SETTINGS__ROLE , + // // USER_SETTINGS__DATE_CREATED , + // // VISN_SETTINGS__EMAIL , + // // VISN_SETTINGS__USER , + // // VISN_SETTINGS__VISN ) + // // .as ( [ + // // ROLE , + // // DATE_CREATED , + // // EMAIL , + // // USER , + // // VISN + // // ] ) | + + // // Join ( ( + // // USER_SETTINGS , + // // inner.join , + // // STATION_SETTINGS + // // ) , ( + // // USER_SETTINGS , + // // inner.join , + // // VISN_SETTINGS + // // ) ) | + + // // Distinct ( false ) | + + // // QueryRowCount ( ) ;", + // console.log({ submitData }); + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } + + // importDataSQLStringRef.current = newSQLString; + // }; + + /** Add all the columns from a Table */ + // const addAllTableColumnsHandler = (event) => { + // alert('add all'); + // // TODO: check all columns from table + // }; + + /** New Submit for Import Data --- empty */ + // const onImportDataSubmit = (data: NewFormData) => { + // // constructSQLString({ submitData }); + // retrievePreviewData(); + // appendCell('data-import'); + // setIsDataImportModalOpen(false); + // // closeImportModalHandler(); + // }; + + /** Close and Reset Import Data Form Modal */ + // const closeImportModalHandler = () => { + // setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); + // setHiddenColumnIdsSet(new Set()); + // setIsDataImportModalOpen(false); + // setDatabaseTableHeaders([]); + // setSelectedDatabaseId(null); + // setShowTablePreview(false); + // setTableColumnsObject({}); + // setDatabaseTableRows([]); + // setSelectedTable(null); + // setTableNames([]); + // reset(); + // }; + + /** Get Database Information for Data Import Modal */ + // const retrieveDatabaseTablesAndEdges = async (databaseId) => { + // setIsDatabaseLoading(true); + // const pixelString = `META|GetDatabaseTableStructure(database=[ \"${databaseId}\" ]);META|GetDatabaseMetamodel( database=[ \"${databaseId}\" ], options=["dataTypes","positions"]);`; + + // // const pixelResponse = await runPixel(pixelString); + // monolithStore.runQuery(pixelString).then((pixelResponse) => { + // console.log({ pixelResponse }); + // const responseTableStructure = + // pixelResponse.pixelReturn[0].output; + // const isResponseTableStructureGood = + // pixelResponse.pixelReturn[0].operationType.indexOf( + // 'ERROR', + // ) === -1; + + // const responseTableEdgesStructure = + // pixelResponse.pixelReturn[1].output; + // const isResponseTableEdgesStructureGood = + // pixelResponse.pixelReturn[1].operationType.indexOf( + // 'ERROR', + // ) === -1; + + // let newTableNames = []; + + // // populate database structure + // if (isResponseTableStructureGood) { + // console.log({ responseTableStructure }); + // newTableNames = [ + // ...responseTableStructure.reduce((set, ele) => { + // set.add(ele[0]); + // return set; + // }, new Set()), + // ]; + + // const tableColumnsObject = responseTableStructure.reduce( + // (acc, ele, idx) => { + // const tableName = ele[0]; + // const columnName = ele[1]; + // const columnType = ele[2]; + // // other info seems to not be needed, unsure what flag is representing or if repeat names are aliases etc + // const columnBoolean = ele[3]; + // const columnName2 = ele[4]; + // const tableName2 = ele[4]; + + // if (!acc[tableName]) acc[tableName] = []; + // acc[tableName].push({ + // tableName, + // columnName, + // columnType, + // columnBoolean, + // columnName2, + // tableName2, + // userAlias: columnName, // user editable in Edit Columns + // checked: true, + // }); + + // return acc; + // }, + // {}, + // ); + + // const newTableColumnsObject: Table[] = Object.keys( + // tableColumnsObject, + // ).map((tableName, tableIdx) => ({ + // id: tableIdx, + // name: tableName, + // columns: tableColumnsObject[tableName].map( + // (colObj, colIdx) => ({ + // id: colIdx, + // tableName: tableName, + // columnName: colObj.columnName, + // columnType: colObj.columnType, + // userAlias: colObj.userAlias, + // checked: false, + // }), + // ), + // })); + + // newReset({ + // databaseSelect: databaseId, + // tables: newTableColumnsObject, + // }); + // } else { + // console.error('Error retrieving database tables'); + // } + + // // set visible tables set to all tables + // setTableNames(newTableNames); + // setShownTables(new Set(newTableNames)); + + // // make and populate new edges dict + // if (isResponseTableEdgesStructureGood) { + // const newEdgesDict = + // responseTableEdgesStructure.edges.reduce((acc, ele) => { + // const source = ele.source; + // const target = ele.target; + // const sourceColumn = ele.sourceColumn; + // const targetColumn = ele.targetColumn; + + // if (!acc[source]) { + // acc[source] = { + // [target]: { + // sourceColumn, + // targetColumn, + // }, + // }; + // } else { + // acc[source][target] = { + // sourceColumn, + // targetColumn, + // }; + // } + + // if (!acc[target]) { + // acc[target] = { + // [source]: { + // sourceColumn: targetColumn, + // targetColumn: sourceColumn, + // }, + // }; + // } else { + // acc[target][source] = { + // sourceColumn: targetColumn, + // targetColumn: sourceColumn, + // }; + // } + // return acc; + // }, {}); + + // setTableEdgesObject(newEdgesDict); + // } else { + // console.error('Error retrieving database edges'); + // } + + // // store edges in useState + // const edges = pixelResponse.pixelReturn[1].output.edges; + // const newTableEdges = {}; + // edges.forEach((edge) => { + // // add edge from source direction + // if (newTableEdges[edge.source]) { + // newTableEdges[edge.source][edge.target] = edge.relation; + // } else { + // newTableEdges[edge.source] = { + // [edge.target]: edge.relation, + // }; + // } + // // add edge from target direction + // if (newTableEdges[edge.target]) { + // newTableEdges[edge.target][edge.source] = edge.relation; + // } else { + // newTableEdges[edge.target] = { + // [edge.source]: edge.relation, + // }; + // } + // }); + // setTableEdges(newTableEdges); + // setIsDatabaseLoading(false); + // }); + // }; + + // const updateSelectedTables = () => { + // // const databaseId = selectedDatabaseId; + // const pixelTables = new Set(); + // const pixelColumnNames = []; + // const pixelColumnAliases = []; + // // const pixelJoins = []; + + // watchedTables?.forEach((tableObject) => { + // const currTableName = tableObject.name; + // const currTableColumns = tableObject.columns; + + // currTableColumns.forEach((columnObject) => { + // if (columnObject.checked) { + // pixelTables.add(columnObject.tableName); + // pixelColumnNames.push( + // `${columnObject.tableName}__${columnObject.columnName}`, + // ); + // pixelColumnAliases.push(columnObject.userAlias); + // } + // }); + // }); + + // setSelectedTableNames(pixelTables); + // }; + + /** Old Get All Database Tables for Import Data --- remove? */ + // const retrieveDatabaseTables = async (databaseId) => { + // setIsDatabaseLoading(true); + // const pixelString = `META | GetDatabaseTableStructure ( database = [ \"${databaseId}\" ] ) ;`; + + // monolithStore.runQuery(pixelString).then((response) => { + // const type = response.pixelReturn[0].operationType; + // const pixelResponse = response.pixelReturn[0].output; + + // if (type.indexOf('ERROR') === -1) { + // const tableNames = [ + // ...pixelResponse.reduce((set, ele) => { + // set.add(ele[0]); + // return set; + // }, new Set()), + // ]; + + // const newTableColumnsObject = pixelResponse.reduce( + // (acc, ele, idx) => { + // const tableName = ele[0]; + // const columnName = ele[1]; + // const columnType = ele[2]; + // // other info seems to not be needed, unsure what flag is representing or if repeat names are aliases etc + // const columnBoolean = ele[3]; + // const columnName2 = ele[4]; + // const tableName2 = ele[4]; + + // if (!acc[tableName]) acc[tableName] = []; + // acc[tableName].push({ + // tableName, + // columnName, + // columnType, + // columnBoolean, + // columnName2, + // tableName2, + // userAlias: columnName, // user editable in Edit Columns + // checked: true, + // }); + + // return acc; + // }, + // {}, + // ); + + // setTableColumnsObject(newTableColumnsObject); + // setTableNames(tableNames); + // } else { + // console.error('Error retrieving database tables'); + // } + + // setIsDatabaseLoading(false); + // }); + // }; + + /** Old Select Tables for Import Data --- remove? */ + // const selectTableHandler = (tableName) => { + // setSelectedTable(tableName); + // retrieveTableRows(tableName); + // }; + + // const retrievePreviewData = async () => { + // setIsDatabaseLoading(true); + + // // run database rows reactor + // const databaseId = selectedDatabaseId; + // const pixelTables = new Set(); + // const pixelColumnNames = []; + // const pixelColumnAliases = []; + // const pixelJoins = []; + + // watchedTables.forEach((tableObject) => { + // const currTableName = tableObject.name; + // const currTableColumns = tableObject.columns; + + // currTableColumns.forEach((columnObject) => { + // if (columnObject.checked) { + // pixelTables.add(columnObject.tableName); + // pixelColumnNames.push( + // `${columnObject.tableName}__${columnObject.columnName}`, + // ); + // pixelColumnAliases.push(columnObject.userAlias); + // } + // }); + // }); + + // console.log(joinsSet); + + // Array.from(joinsSet).forEach((joinEle: string) => { + // console.log({ joinEle }); + // const splitJoinsString = joinEle.split(':'); + // pixelJoins.push( + // `( ${splitJoinsString[0]} , inner.join , ${splitJoinsString[1]} )`, + // ); + // }); + + // console.log({ + // databaseId, + // pixelTables, + // pixelColumnNames, + // pixelColumnAliases, + // pixelJoins, + // joinsSet, + // }); + + // // when constructing final pixel string seperate all these with '|' + // let pixelStringPart1 = `Database ( database = [ \"${databaseId}\" ] )`; + // pixelStringPart1 += ` | Select ( ${pixelColumnNames.join(' , ')} )`; + // pixelStringPart1 += `.as ( [ ${pixelColumnAliases.join(' , ')} ] )`; + // if (pixelJoins.length > 0) { + // pixelStringPart1 += ` | Join ( ${pixelJoins.join(' , ')} ) `; + // } + // pixelStringPart1 += ` | Distinct ( false ) | Limit ( 20 )`; + + // // seperated Import out so frame can construct this independently from preview + // const pixelStringPart2 = ` | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; + // const pixelStringPart3 = ` ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + + // const combinedPixelString = + // pixelStringPart1 + pixelStringPart2 + ' ; ' + pixelStringPart3; + + // // const joinsPixelString = pixelJoins.length > 0 ? `Join ( ${pixelJoins.join(' , ')} ) ` : null; + // // const distinctPixelString = `Distinct ( false ) | Limit ( 20 )`; + // // const importPixelString = `Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; + // // // when constructing string seperate META with ';' + // // const metaPixelString = `META | Frame() | QueryAll() | Limit(50) | Collect(500)` + // // // add ';' at end of final pixel string + + // // const pixelStringObject = { + // // databasePixelString, + // // selectPixelString, + // // aliasPixelString, + // // joinsPixelString, + // // distinctPixelString, + // // limitPixelString, + // // importPixelString, + // // metaPixelString, + // // } + + // const combinedJoinString = + // pixelJoins.length > 0 + // ? `| Join ( ${pixelJoins.join(' , ')} ) ` + // : ''; + + // // const testReactorPixel = + // // 'Database ( database = [ "f9b656cc-06e7-4cce-bae8-b5f92075b6da" ] ) | Select ( STATION_SETTINGS__EMAIL , USER_SETTINGS__PHONE ) .as ( [ EMAIL , PHONE ] ) | Join ( ( USER_SETTINGS , inner.join , STATION_SETTINGS ) ) | Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ "consolidated_settings_FRAME932867__Preview" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);'; + // const reactorPixel = `Database ( database = [ \"${databaseId}\" ] ) | Select ( ${pixelColumnNames.join( + // ' , ', + // )} ) .as ( [ ${pixelColumnAliases.join( + // ' , ', + // // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | `; // end of reactor string is added in cell-defaults/data-import/config.ts to incorporate correct frame variable name + // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + // // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ); META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + // // ## TODO fix variable import pixel syntax, currently including db name for some reason + + // // these might not be needed with new part1 ref + // setPixelString(reactorPixel); + // pixelStringRef.current = reactorPixel; + + // // this ref is for the form submit + // pixelStringRefPart1.current = pixelStringPart1 + ';'; + + // await monolithStore.runQuery(reactorPixel).then((response) => { + // const type = response.pixelReturn[0]?.operationType; + // const tableHeadersData = + // response.pixelReturn[1]?.output?.data?.headers; + // const tableRawHeadersData = + // response.pixelReturn[1]?.output?.data?.rawHeaders; + // const tableRowsData = + // response.pixelReturn[1]?.output?.data?.values; + + // setDatabaseTableHeaders(tableHeadersData); + // setDatabaseTableRawHeaders(tableRawHeadersData); + // setDatabaseTableRows(tableRowsData); + + // if (type.indexOf('ERROR') != -1) { + // console.error('Error retrieving database tables'); + // } + + // setIsDatabaseLoading(false); + // }); + // }; + + /** Old Select Tables for Import Data --- unused / remove? */ + // const retrieveTableRows = async (tableName) => { + // setIsDatabaseLoading(true); + // const selectStringArray = tableColumnsObject[tableName].map( + // (ele) => `${ele.tableName}__${ele.columnName}`, + // ); + + // const selectString = selectStringArray.join(', '); + // const aliasString = tableColumnsObject[tableName] + // .map( + // (ele) => `${ele.columnName}`, // may need to switch to ele.columnName2 but they seem to be identical + // ) + // .join(', '); + + // const limit = 10; // may want this to be a changeable useState variable + // const pixelString = `Database(database=[\"${selectedDatabaseId}\"])|Select(${selectString}).as([${aliasString}])|Distinct(false)|Limit(${limit})|Import(frame=[CreateFrame(frameType=[GRID],override=[true]).as([\"consolidated_settings_FRAME961853__Preview\"])]); META | Frame() | QueryAll() | Limit(${limit}) | Collect(500);`; + + // await monolithStore.runQuery(pixelString).then((response) => { + // const type = response.pixelReturn[0].operationType; + // const tableHeadersData = + // response.pixelReturn[1].output.data.headers; + // const tableRawHeadersData = + // response.pixelReturn[1].output.data.rawHeaders; + // const tableRowsData = + // response.pixelReturn[1].output.data.values; + + // console.log({ + // tableHeadersData, + // tableRawHeadersData, + // tableRowsData, + // }); + + // setDatabaseTableHeaders(tableHeadersData); + // setDatabaseTableRawHeaders(tableRawHeadersData); + // setDatabaseTableRows(tableRowsData); + + // if (type.indexOf('ERROR') != -1) { + // console.error('Error retrieving database tables'); + // } + + // setIsDatabaseLoading(false); + // }); + // }; + + /** Helper Function Update Alias Tracker Object*/ + // const updateAliasCountObj = ( + // isBeingAdded, + // newAlias, + // oldAlias = null, + // ) => { + // const newAliasesCountObj = { ...aliasesCountObj }; + + // console.log({ isBeingAdded, newAlias, oldAlias }); + + // if (isBeingAdded) { + // if (newAliasesCountObj[newAlias]) { + // newAliasesCountObj[newAlias] = + // newAliasesCountObj[newAlias] + 1; + // } else { + // newAliasesCountObj[newAlias] = 1; + // } + // } else { + // if (newAliasesCountObj[newAlias]) { + // newAliasesCountObj[newAlias] = + // newAliasesCountObj[newAlias] - 1; + // } else { + // newAliasesCountObj[newAlias] = 0; + // } + // } + + // if (newAliasesCountObj[newAlias] < 1) { + // delete newAliasesCountObj[newAlias]; + // } + + // if (oldAlias) { + // if (newAliasesCountObj[oldAlias]) { + // newAliasesCountObj[oldAlias] = + // newAliasesCountObj[newAlias] - 1; + // } else { + // newAliasesCountObj[oldAlias] = 0; + // } + // if (newAliasesCountObj[oldAlias] < 1) { + // delete newAliasesCountObj[oldAlias]; + // } + // } + + // console.log({ newAliasesCountObj }); + // setAliasesCountObj(newAliasesCountObj); + // }; + + /** Find Joinable Tables */ + // const findAllJoinableTables = (rootTableName) => { + // const joinableTables = tableEdges[rootTableName] + // ? Object.keys(tableEdges[rootTableName]) + // : []; + // console.log({ + // rootTableName, + // tableEdges, + // joinableTables, + // 'tableEdges[rootTableName]': tableEdges[rootTableName], + // }); + // const newShownTables = new Set([...joinableTables, rootTableName]); + // // debugger; + // setShownTables(newShownTables); + // }; + + /** Checkbox Handler */ + // const checkBoxHandler = (tableIndex, columnIndex) => { + // const columnObject = watchedTables[tableIndex].columns[columnIndex]; + // console.log({ columnObject }); + // updateAliasCountObj(columnObject?.checked, columnObject.userAlias); + // if (columnObject?.checked) { + // if (checkedColumnsCount == 0) { + // findAllJoinableTables(watchedTables[tableIndex].name); + // setRootTable(watchedTables[tableIndex].name); + // } + // setCheckedColumnsCount(checkedColumnsCount + 1); + // } else if (columnObject?.checked == false) { + // if (checkedColumnsCount == 1) { + // setShownTables(new Set(tableNames)); + // setRootTable(null); + // } + // setCheckedColumnsCount(checkedColumnsCount - 1); + // } + // }; + + // const checkTableForSelectedColumns = (tableName) => { + // for (let i = 0; i < watchedTables.length; i++) { + // const currTable = watchedTables[i]; + // if (currTable.name == tableName) { + // const currTableColumns = currTable.columns; + // for (let j = 0; j < currTableColumns.length; j++) { + // const currColumn = currTableColumns[j]; + // if (currColumn.checked == true) return true; + // } + // } + // } + // return false; + // }; + + // const setJoinsStackHandler = () => { + // if (checkedColumnsCount < 2) { + // removeJoinElement(); + // setJoinsSet(new Set()); + // } else { + // const leftTable = rootTable; + // const rightTables = + // tableEdgesObject[rootTable] && + // tableEdgesObject && + // Object.entries(tableEdgesObject[rootTable]); + + // // addresses crash for dbs with only one table / no edges + // rightTables?.forEach((entry, joinIdx) => { + // const rightTable = entry[0]; + // const leftKey = entry[1]['sourceColumn']; + // const rightKey = entry[1]['targetColumn']; + + // const leftTableContainsCheckedColumns = + // checkTableForSelectedColumns(leftTable); + // const rightTableContainsCheckedColumns = + // checkTableForSelectedColumns(rightTable); + + // const defaultJoinType = 'Inner Join'; + + // const joinsSetString = `${leftTable}:${rightTable}`; + // if ( + // leftTableContainsCheckedColumns && + // rightTableContainsCheckedColumns && + // joinsSet.has(joinsSetString) == false + // ) { + // appendJoinElement({ + // leftTable: leftTable, + // rightTable: rightTable, + // joinType: defaultJoinType, + // leftKey: leftKey, + // rightKey: rightKey, + // }); + // addToJoinsSetHelper(joinsSetString); + // } else if ( + // leftTableContainsCheckedColumns == false || + // (rightTableContainsCheckedColumns == false && + // joinsSet.has(joinsSetString)) + // ) { + // joinsSet.delete(joinsSetString); + // joinElements.some((ele, idx) => { + // if ( + // leftTable == ele.leftTable && + // rightTable == ele.rightTable && + // defaultJoinType == ele.joinType && + // leftKey == ele.leftKey && + // rightKey == ele.rightKey + // ) { + // removeJoinElement(idx); + // return true; + // } else { + // return false; + // } + // }); + // } + // }); + // } + // }; + + // const addToJoinsSetHelper = (newJoinSet) => { + // const joinsSetCopy = new Set(joinsSet); + // joinsSetCopy.add(newJoinSet); + // setJoinsSet(joinsSetCopy); + // console.log({ joinsSetCopy }); + // }; + + return ( + + {cell.parameters.databaseId} +

TABLE NAMES

+ {cell.parameters.tableNames?.map((tableName, idx) => ( +
{tableName}
+ ))} +

JOINS

+ {cell.parameters.joins?.map((join, idx) => ( +
+ {join.leftTable} ({join.joinType}){join.rightTable} ON + {join.leftKey} ={join.rightKey} +
+ ))} +

SELECTED COLUMNS

+ {cell.parameters.selectedColumns?.map((column, idx) => ( +
{column}
+ ))} +

ALIASES

+ {cell.parameters.columnAliases?.map((alias, idx) => ( +
{alias}
+ ))} + {/* need the selected columns */} + {/* need the column aliases */} + {/* need the filters */} + {/* {cell.parameters.summaries} */} + +
+ ); + + return ( + <> + {/* Dropdown for All Add Cell Option Sets */} + + {/* + + + {AddCellOptions && + Object.entries(AddCellOptions).map((add, i) => { + const value = add[1]; + return ( + { + if (value.options) { + setAnchorEl(e.currentTarget); + setSelectedAddCell(add[0]); + } else { + appendCell( + value.defaultCellType, + ); + } + }} + endIcon={ + Array.isArray(value.options) && + (selectedAddCell == add[0] && + open ? ( + + ) : ( + + )) + } + > + {value.display} + + ); + })} + + + { + setAnchorEl(null); + }} + > + {selectedAddCell === 'transformation' && + Array.from( + AddCellOptions[selectedAddCell]?.options || [], + ({ display, defaultCellType }, index) => { + return ( + { + appendCell(defaultCellType); + setAnchorEl(null); + }} + > + {display} + + ); + }, + )} + + {selectedAddCell === 'import-data' && ( + <> + {Array.from( + AddCellOptions[selectedAddCell]?.options || + [], + ({ display }, index) => { + return ( + { + // loadDatabaseStructure(); + setImportModalPixelWidth( + IMPORT_MODAL_WIDTHS.small, + ); + setIsDataImportModalOpen( + true, + ); + if ( + display == + 'From Data Catalog' + ) { + setImportModalType( + display, + ); + } else { + // open seperate modal / form for From CSV + } + setAnchorEl(null); + }} + > + {display} + + ); + }, + )} + + )} + + */} + + {/* New Import Data Modal --- stand-alone component? */} + + ); + }, +); + +// {/* */} +// +// +// +// +//
+// +// Import Data from +// +// ( +// +// )} +// /> +//
+// +// +// +//
+// {selectedDatabaseId && ( +// +// +//
+// +// Data +// +//
+//
+// +// +//
+//
+ +// {showEditColumns && ( +// +// +// Available Tables / Columns +// +// +// {newTableFields.map( +// (table, tableIndex) => ( +//
+// {/* using conditional rendering for each table but if bugs persists set state for showntables in checkbox handler */} +// {shownTables.has( +// table.name, +// ) && ( +// +// +// +// +// +// +// { +// table.name +// } +// +// +// +// +// +// +// +// +// +// +// +// +// Fields +// +// +// +// +// Alias +// +// +// +// +// Field +// Type +// +// +// + +// {table.columns.map( +// ( +// column, +// columnIndex, +// ) => ( +// +// +// ( +// { +// field.onChange( +// e, +// ); +// checkBoxHandler( +// tableIndex, +// columnIndex, +// ); +// }} +// /> +// )} +// /> +// +// +// { +// column.columnName +// } +// {column.columnName == +// 'ID' && ( +//
+// PK +//
+// )} +// {column.columnName.includes( +// '_ID', +// ) && ( +//
+// FK +//
+// )} +//
+// +// +// ( +// { +// if ( +// watchedTables[ +// tableIndex +// ] +// .columns[ +// columnIndex +// ] +// .checked +// ) { +// updateAliasCountObj( +// true, +// e +// .target +// .value, +// field.value, +// ); +// } +// field.onChange( +// e +// .target +// .value, +// ); +// }} +// /> +// )} +// /> +// {watchedTables[ +// tableIndex +// ] +// .columns[ +// columnIndex +// ] +// .checked && +// aliasesCountObj[ +// watchedTables[ +// tableIndex +// ] +// .columns[ +// columnIndex +// ] +// .userAlias +// ] > +// 1 && ( +// +// +// +// )} +// +// + +// +// ( +// +// )} +// /> +// +//
+// ), +// )} +//
+//
+//
+// )} +//
+// ), +// )} +//
+//
+// )} + +// {showPreview && ( +// +// +// Preview +// +// +// +// +// +// {databaseTableHeaders +// .filter( +// ( +// v, +// colIdx, +// ) => { +// return !hiddenColumnIdsSet.has( +// colIdx, +// ); +// }, +// ) +// .map( +// ( +// h, +// hIdx, +// ) => ( +// +// +// { +// h +// } +// +// +// ), +// )} +// +// {databaseTableRows.map( +// (r, rIdx) => ( +// +// {r +// .filter( +// ( +// v, +// colIdx, +// ) => { +// return !hiddenColumnIdsSet.has( +// colIdx, +// ); +// }, +// ) +// .map( +// ( +// v, +// vIdx, +// ) => ( +// +// { +// v +// } +// +// ), +// )} +// +// ), +// )} +// +//
+//
+//
+// )} +//
+// )} + +// {/* stack for user-added joins filters and summaries */} +// {joinElements.map((join, stackIndex) => ( +// +// +//
+// +// Join +// + +// +// +// {join.leftTable} +// +// + +// +// +// +// +// + +// +// +// {join.rightTable} +// +// + +// +// where +// + +// +// +// {join.leftKey} +// +// + +// +// = +// + +// +// +// {join.rightKey} +// +// +//
+// {/*
+// { +// removeStack(stackIndex); +// }} +// > +// +// +//
*/} +//
+ +// {/* {showEditColumns && ( */} +// {/* {false && ( +// +// +// Edit Columns +// + +// +// +// +// +// { +// setCheckAllColumns( +// !checkAllColumns, +// ); +// const hiddenColumnIdsSetDup = +// new Set(); +// if ( +// checkAllColumns == +// false +// ) { +// editableColumnFields.forEach( +// ( +// field, +// index, +// ) => { +// // not working need to use setValue +// field.checked = +// true; +// console.log( +// { +// index, +// field, +// }, +// ); +// hiddenColumnIdsSetDup.add( +// index, +// ); +// }, +// ); +// } else { +// editableColumnFields.forEach( +// ( +// field, +// index, +// ) => { +// // not working need to use setValue +// field.checked = +// false; +// console.log( +// { +// index, +// field, +// }, +// ); +// hiddenColumnIdsSetDup.delete( +// index, +// ); +// }, +// ); +// } +// setHiddenColumnIdsSet( +// hiddenColumnIdsSetDup, +// ); +// }} +// color={ +// checkAllColumns +// ? 'primary' +// : 'secondary' +// } +// sx={{ +// marginLeft: +// '-10px', +// }} +// > +// +// +// +// +// +// Fields +// +// +// +// +// Alias +// +// +// +// +// Field Type +// +// +// + +// {editableColumnFields?.map( +// (field, index) => ( +// +// +// ( +// { +// field.onChange( +// e, +// ); +// const hiddenColumnIdsSetDup = +// new Set( +// [ +// ...hiddenColumnIdsSet, +// ], +// ); +// if ( +// field.value == +// true +// ) { +// hiddenColumnIdsSetDup.add( +// index, +// ); +// } else { +// hiddenColumnIdsSetDup.delete( +// index, +// ); +// } + +// console.log( +// { +// hiddenColumnIdsSetDup, +// editableColumnFields, +// }, +// ); + +// if ( +// hiddenColumnIdsSetDup.size == +// 0 +// ) { +// setCheckAllColumns( +// true, +// ); +// } else { +// setCheckAllColumns( +// false, +// ); +// } + +// setHiddenColumnIdsSet( +// hiddenColumnIdsSetDup, +// ); +// }} +// /> +// )} +// /> +// +// +// { +// field.columnName +// } +// {field.columnName == +// 'ID' && ( +//
+// PK +//
+// )} +// {field.columnName.includes( +// '_ID', +// ) && ( +//
+// FK +//
+// )} +//
+// +// ( +// { +// field.onChange( +// e +// .target +// .value, +// ); +// const newTableHeaders = +// [ +// ...databaseTableHeaders, +// ]; +// newTableHeaders[ +// index +// ] = +// e.target.value; +// setDatabaseTableHeaders( +// newTableHeaders, +// ); +// }} +// /> +// )} +// /> +// +// +// ( +// +// )} +// /> +// +//
+// ), +// )} +//
+//
+// +// +// +// +//
+// )} */} + +// {/* {showPreview && ( */} +// {/* {false && ( +// +// +// Preview +// +// +// +// +// {databaseTableHeaders +// .filter( +// (v, colIdx) => { +// return !hiddenColumnIdsSet.has( +// colIdx, +// ); +// }, +// ) +// .map((h, hIdx) => ( +// +// +// {h} +// +// +// ))} +// +// {databaseTableRows.map( +// (r, rIdx) => ( +// +// {r +// .filter( +// ( +// v, +// colIdx, +// ) => { +// return !hiddenColumnIdsSet.has( +// colIdx, +// ); +// }, +// ) +// .map( +// ( +// v, +// vIdx, +// ) => ( +// +// { +// v +// } +// +// ), +// )} +// +// ), +// )} +// +//
+//
+// )} */} +//
+// ))} + +// +// +// +// +// +// +// +// +// +// +//
+//
diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 5533a29d7c..71e1a0562d 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -643,9 +643,10 @@ export const NotebookAddCell = observer( // selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs // selectQuery: pixelStringRef.current, // construct query based on useForm inputs selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs - foo: 'moo', joins: joinElements, tableNames: Array.from(selectedTableNames), + selectedColumns: getSelectedColumnNames(), + columnAliases: getColumnAliases(), }; } @@ -1062,18 +1063,11 @@ export const NotebookAddCell = observer( retrieveTableRows(tableName); }; - const retrievePreviewData = async () => { - setIsDatabaseLoading(true); - - // run database rows reactor - const databaseId = selectedDatabaseId; + const getSelectedColumnNames = () => { const pixelTables = new Set(); const pixelColumnNames = []; - const pixelColumnAliases = []; - const pixelJoins = []; watchedTables.forEach((tableObject) => { - const currTableName = tableObject.name; const currTableColumns = tableObject.columns; currTableColumns.forEach((columnObject) => { @@ -1082,12 +1076,57 @@ export const NotebookAddCell = observer( pixelColumnNames.push( `${columnObject.tableName}__${columnObject.columnName}`, ); + } + }); + }); + + return pixelColumnNames; + }; + + const getColumnAliases = () => { + const pixelTables = new Set(); + const pixelColumnAliases = []; + + watchedTables.forEach((tableObject) => { + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); pixelColumnAliases.push(columnObject.userAlias); } }); }); - console.log(joinsSet); + return pixelColumnAliases; + }; + + const retrievePreviewData = async () => { + setIsDatabaseLoading(true); + + // run database rows reactor + const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = getSelectedColumnNames(); + const pixelColumnAliases = getColumnAliases(); + // const pixelColumnNames = []; + // const pixelColumnAliases = []; + const pixelJoins = []; + + // watchedTables.forEach((tableObject) => { + // const currTableName = tableObject.name; + // const currTableColumns = tableObject.columns; + + // currTableColumns.forEach((columnObject) => { + // if (columnObject.checked) { + // pixelTables.add(columnObject.tableName); + // pixelColumnNames.push( + // `${columnObject.tableName}__${columnObject.columnName}`, + // ); + // pixelColumnAliases.push(columnObject.userAlias); + // } + // }); + // }); Array.from(joinsSet).forEach((joinEle: string) => { console.log({ joinEle }); @@ -1097,15 +1136,6 @@ export const NotebookAddCell = observer( ); }); - console.log({ - databaseId, - pixelTables, - pixelColumnNames, - pixelColumnAliases, - pixelJoins, - joinsSet, - }); - // when constructing final pixel string seperate all these with '|' let pixelStringPart1 = `Database ( database = [ \"${databaseId}\" ] )`; pixelStringPart1 += ` | Select ( ${pixelColumnNames.join(' , ')} )`; From 10c68239f4b69f99c427a9d53fa4f2214df1fd51 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 17 Jul 2024 15:21:14 -0700 Subject: [PATCH 37/49] feat(client): fully style and transfer functionality to edit modal and passing cell data --- .../data-import-cell/DataImportCell.tsx | 31 +- .../notebook/DataImportFormModal.tsx | 4097 +++++++++-------- 2 files changed, 2100 insertions(+), 2028 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index be3332d518..f33406432c 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -722,20 +722,23 @@ export const DataImportCell: CellComponent = observer( )} - + {isDataImportModalOpen && ( + + )} ); }, diff --git a/packages/client/src/components/notebook/DataImportFormModal.tsx b/packages/client/src/components/notebook/DataImportFormModal.tsx index dc8f0e5af6..8c200c756b 100644 --- a/packages/client/src/components/notebook/DataImportFormModal.tsx +++ b/packages/client/src/components/notebook/DataImportFormModal.tsx @@ -382,143 +382,154 @@ type NewFormValues = { // }, // }; -// const IMPORT_MODAL_WIDTHS = { -// small: '600px', -// medium: '1150px', -// large: '1150px', -// }; +const IMPORT_MODAL_WIDTHS = { + small: '600px', + medium: '1150px', + large: '1150px', +}; -// const SQL_COLUMN_TYPES = ['DATE', 'NUMBER', 'STRING', 'TIMESTAMP']; +const SQL_COLUMN_TYPES = ['DATE', 'NUMBER', 'STRING', 'TIMESTAMP']; // endregion export const DataImportFormModal = observer( (props: { - // query: QueryState; + query?: QueryState; previousCellId?: string; - isDataImportModalOpen: boolean; - setIsDataImportModalOpen; - cell; + editMode?: boolean; + isDataImportModalOpen?: boolean; + setIsDataImportModalOpen?; + cell?; }): JSX.Element => { const { + query, previousCellId, isDataImportModalOpen, setIsDataImportModalOpen, + editMode, cell, } = props; - // const [anchorEl, setAnchorEl] = useState(null); - // const [selectedAddCell, setSelectedAddCell] = useState(''); - // const [importModalType, setImportModalType] = useState(''); + const [anchorEl, setAnchorEl] = useState(null); + const [selectedAddCell, setSelectedAddCell] = useState(''); + const [importModalType, setImportModalType] = useState(''); + + // needed for new cell? incoming as prop for edit? // const [isDataImportModalOpen, setIsDataImportModalOpen] = // useState(false); - // const open = Boolean(anchorEl); + const open = Boolean(anchorEl); + + // needed for new cell? incoming as prop for edit? // const { query, previousCellId = '' } = props; - // const { state, notebook } = useBlocks(); + const { state, notebook } = useBlocks(); // Old useForm for Data Import --- remove - // const { control, handleSubmit, reset, watch, setValue, getValues } = - useForm({ - defaultValues: { - queryStackElements: [], - databaseSelect: '', - tableSelect: '', - }, - }); + const { control, handleSubmit, reset, watch, setValue, getValues } = + useForm({ + defaultValues: { + queryStackElements: [], + databaseSelect: '', + tableSelect: '', + }, + }); // New useForm for Data Import - // const { - // control: newControl, - // handleSubmit: newHandleSubmit, - // reset: newReset, - // getValues: _newGetValues, - // setValue: _newSetValue, - // watch: dataImportwatch, - // } = useForm(); + const { + control: newControl, + handleSubmit: newHandleSubmit, + reset: newReset, + getValues: _newGetValues, + setValue: _newSetValue, + watch: dataImportwatch, + } = useForm(); - // const watchedTables = dataImportwatch('tables'); + const watchedTables = dataImportwatch('tables'); // region --- useStates / useRefs - // const [userDatabases, setUserDatabases] = useState(null); - // const [queryElementCounter, setQueryElementCounter] = useState(0); - // const [databaseTableRawHeaders, setDatabaseTableRawHeaders] = useState( - // [], - // ); - // const [importModalPixelWidth, setImportModalPixelWidth] = - // useState(IMPORT_MODAL_WIDTHS.small); - // const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); - // const [databaseTableHeaders, setDatabaseTableHeaders] = useState([]); - // const [selectedDatabaseId, setSelectedDatabaseId] = useState(null); - // const [tableColumnsObject, setTableColumnsObject] = useState({}); - // const [databaseTableRows, setDatabaseTableRows] = useState([]); - // const [tableNames, setTableNames] = useState([]); - // const [selectedTable, setSelectedTable] = useState(null); - // const importDataSQLStringRef = useRef(''); - // const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open - // const [isDatabaseLoading, setIsDatabaseLoading] = - // useState(false); - // const [showPreview, setShowTablePreview] = useState(false); - // const [showEditColumns, setShowEditColumns] = useState(true); // ### change back to false - // const [checkAllColumns, setCheckAllColumns] = useState(true); - // const { configStore, monolithStore } = useRootStore(); + const [userDatabases, setUserDatabases] = useState(null); + const [queryElementCounter, setQueryElementCounter] = useState(0); + const [databaseTableRawHeaders, setDatabaseTableRawHeaders] = useState( + [], + ); + const [importModalPixelWidth, setImportModalPixelWidth] = + useState(IMPORT_MODAL_WIDTHS.small); + const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); + const [databaseTableHeaders, setDatabaseTableHeaders] = useState([]); + const [selectedDatabaseId, setSelectedDatabaseId] = useState( + cell ? cell.parameters.databaseId : null, + ); + const [tableColumnsObject, setTableColumnsObject] = useState({}); + const [databaseTableRows, setDatabaseTableRows] = useState([]); + const [tableNames, setTableNames] = useState([]); + const [selectedTable, setSelectedTable] = useState(null); + const importDataSQLStringRef = useRef(''); + const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open + const [isDatabaseLoading, setIsDatabaseLoading] = + useState(false); + const [showPreview, setShowTablePreview] = useState(false); + const [showEditColumns, setShowEditColumns] = useState(true); // ### change back to false + const [checkAllColumns, setCheckAllColumns] = useState(true); + const { configStore, monolithStore } = useRootStore(); // // State Vars for Old useForm --- all uneeded / deletable - // const [selectedLeftTable, setSelectedLeftTable] = - // useState(null); - // const [selectedRightTable, setSelectedRightTable] = - // useState(null); - // const [selectedRightKey, setSelectedRightKey] = useState(null); - // const [columnDataTypesDict, setColumnDataTypesDict] = useState(null); - // const [selectedLeftKey, setSelectedLeftKey] = useState(null); - // const [tableEdgesObject, setTableEdgesObject] = useState(null); + const [selectedLeftTable, setSelectedLeftTable] = + useState(null); + const [selectedRightTable, setSelectedRightTable] = + useState(null); + const [selectedRightKey, setSelectedRightKey] = useState(null); + const [columnDataTypesDict, setColumnDataTypesDict] = useState(null); + const [selectedLeftKey, setSelectedLeftKey] = useState(null); + const [tableEdgesObject, setTableEdgesObject] = useState(null); // // State Vars for new useForm Structure // // checkedColumnsSet - // const [checkedColumnsSet, setCheckedColumnsSet] = useState(new Set()); - // const [hiddenTablesSet, setHiddenTablesSet] = useState({}); - // const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } - // const [tableEdges, setTableEdges] = useState({}); // - // const [rootTable, setRootTable] = useState(null); + const [checkedColumnsSet, setCheckedColumnsSet] = useState(new Set()); + const [hiddenTablesSet, setHiddenTablesSet] = useState({}); + const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } + const [tableEdges, setTableEdges] = useState({}); // + const [rootTable, setRootTable] = useState(null); + + const [checkedColumnsCount, setCheckedColumnsCount] = useState(0); + const [shownTables, setShownTables] = useState(new Set()); + const [selectedTableNames, setSelectedTableNames] = useState(new Set()); + const [joinsSet, setJoinsSet] = useState(new Set()); // Set({ "USERS_TABLE:VISNS_TABLE" }) - // const [checkedColumnsCount, setCheckedColumnsCount] = useState(0); - // const [shownTables, setShownTables] = useState(new Set()); - // const [selectedTableNames, setSelectedTableNames] = useState(new Set()); - // const [joinsSet, setJoinsSet] = useState(new Set()); // Set({ "USERS_TABLE:VISNS_TABLE" }) + const [pixelString, setPixelString] = useState(''); + const pixelStringRef = useRef(''); + const pixelStringRefPart1 = useRef(''); - // const [pixelString, setPixelString] = useState(''); - // const pixelStringRef = useRef(''); - // const pixelStringRefPart1 = useRef(''); + const [isInitLoadComplete, setIsInitLoadComplete] = useState(false); // endregion // region --- Import Data Old useFieldArrays - // const { - // fields: stackFields, - // append: appendStack, - // remove: removeStack, - // } = useFieldArray({ - // control, - // name: 'queryStackElements', - // }); - - // const { - // fields: editableColumnFields, - // append: appendEditableColumns, - // remove: removeEditableColumns, - // } = useFieldArray({ - // control, - // name: 'columns', - // }); - - // const { - // fields: tableFields, - // append: appendEditableTableColumns, - // remove: removeEditableTableColumns, - // } = useFieldArray({ - // control, - // name: 'tables', - // }); + const { + fields: stackFields, + append: appendStack, + remove: removeStack, + } = useFieldArray({ + control, + name: 'queryStackElements', + }); + + const { + fields: editableColumnFields, + append: appendEditableColumns, + remove: removeEditableColumns, + } = useFieldArray({ + control, + name: 'columns', + }); + + const { + fields: tableFields, + append: appendEditableTableColumns, + remove: removeEditableTableColumns, + } = useFieldArray({ + control, + name: 'tables', + }); // endregion @@ -527,85 +538,113 @@ export const DataImportFormModal = observer( // ### only one field array is necessary? // do each of these need a field array for the columns? - // const { - // fields: newTableFields, - // append: newTableAppend, - // remove: newTableRemove, - // } = useFieldArray({ - // control: newControl, - // name: 'tables', - // }); - - // const { - // fields: joinElements, - // append: appendJoinElement, - // remove: removeJoinElement, - // } = useFieldArray({ - // control: newControl, - // name: 'joins', - // }); + const { + fields: newTableFields, + append: newTableAppend, + remove: newTableRemove, + } = useFieldArray({ + control: newControl, + name: 'tables', + }); + + const { + fields: joinElements, + append: appendJoinElement, + remove: removeJoinElement, + } = useFieldArray({ + control: newControl, + name: 'joins', + }); // endregion // region --- useEffects - // useEffect(() => { - // console.log({ joinElements }); - // }, [joinElements]); - - // useEffect(() => { - // setSelectedLeftKey(null); - // setSelectedRightKey(null); - // removeEditableColumns(); - // removeStack(); - // }, [selectedDatabaseId, selectedTable]); - - // useEffect(() => { - // removeEditableColumns(); - // removeStack(); - // setShowTablePreview(false); - // setShowEditColumns(true); - // }, [selectedDatabaseId]); - - // useEffect(() => { - // removeEditableColumns(); - // tableColumnsObject[selectedTable]?.forEach((tableObject, idx) => { - // console.log({ tableObject }); - // appendEditableColumns({ - // id: idx, - // tableName: tableObject.tableName, - // columnName: tableObject.columnName, - // userAlias: tableObject.columnName, - // columnType: tableObject.columnType, - // checked: true, - // }); - // }); - // }, [selectedTable]); - - // useEffect(() => { - // if (getDatabases.status !== 'SUCCESS') { - // return; - // } - // setUserDatabases(getDatabases.data); - // }, [getDatabases.status, getDatabases.data]); - - // useEffect(() => { - // // if any change occurs with checkboxes reassess all joins to display - // setJoinsStackHandler(); - // updateSelectedTables(); - // console.log({ selectedTableNames }); - // }, [checkedColumnsCount]); - - // useEffect(() => { - // if (showPreview) { - // retrievePreviewData(); - // } - // }, [ - // aliasesCountObj, - // checkedColumnsCount, - // showPreview, - // selectedDatabaseId, - // ]); + useEffect(() => { + if (editMode) { + console.log('useEffect watchedTables'); + if (editMode && !checkedColumnsCount) { + retrieveDatabaseTablesAndEdges(cell.parameters.databaseId); + // alert("add selected columns into useForm") + // alert("add joins into useForm") + // alert("add filters into useForm") + // alert("add summaries into useForm") + } + } + }, []); + + useEffect(() => { + console.log({ joinElements }); + }, [joinElements]); + + useEffect(() => { + setSelectedLeftKey(null); + setSelectedRightKey(null); + removeEditableColumns(); + removeStack(); + }, [selectedDatabaseId, selectedTable]); + + useEffect(() => { + // alert("useEffect selectedDatabaseId") + // console.log(cell.parameters.databaseId) + // console.log(selectedDatabaseId); + + removeEditableColumns(); + removeStack(); + setShowTablePreview(false); + setShowEditColumns(true); + }, [selectedDatabaseId]); + + useEffect(() => { + // $$$ + if ( + editMode && + checkedColumnsCount == 0 && + cell.parameters.databaseId == selectedDatabaseId && + newTableFields.length + ) { + prepoulateFormForEdit(cell); + } + }, [newTableFields]); + + useEffect(() => { + removeEditableColumns(); + tableColumnsObject[selectedTable]?.forEach((tableObject, idx) => { + appendEditableColumns({ + id: idx, + tableName: tableObject.tableName, + columnName: tableObject.columnName, + userAlias: tableObject.columnName, + columnType: tableObject.columnType, + checked: true, + }); + }); + }, [selectedTable]); + + useEffect(() => { + if (getDatabases.status !== 'SUCCESS') { + return; + } + setUserDatabases(getDatabases.data); + }, [getDatabases.status, getDatabases.data]); + + useEffect(() => { + // if any change occurs with checkboxes reassess all joins to display + setJoinsStackHandler(); + updateSelectedTables(); + console.log({ selectedTableNames }); + }, [checkedColumnsCount]); + + useEffect(() => { + if (showPreview) { + retrievePreviewData(); + } + }, [ + aliasesCountObj, + checkedColumnsCount, + showPreview, + selectedDatabaseId, + ]); // endregion @@ -731,288 +770,297 @@ export const DataImportFormModal = observer( // }; /** Construct Submit Pixel for Data Import --- remove? */ - // const constructDataBasePixel = ({ submitData }) => { - // // mimic this pixel structure instead of constructing raw SQL ? - // // or have join autoselect keys and add columns to edit - // // that makes sense with new pixel structure - // // show all tables and selectable rows in edit columns view - // // find way of showing alerts for un joinable columns - // // add form structure to json state (?) - // // make basic non SQL view for notebook cell - // // make edit window - - // // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | - - // // Select ( - // // STATION_SETTINGS__ROLE , - // // USER_SETTINGS__DATE_CREATED , - // // VISN_SETTINGS__EMAIL , - // // VISN_SETTINGS__USER , - // // VISN_SETTINGS__VISN ) - // // .as ( [ - // // ROLE , - // // DATE_CREATED , - // // EMAIL , - // // USER , - // // VISN - // // ] ) | - - // // Join ( ( - // // USER_SETTINGS , - // // inner.join , - // // STATION_SETTINGS - // // ) , ( - // // USER_SETTINGS , - // // inner.join , - // // VISN_SETTINGS - // // ) ) | - - // // Distinct ( false ) | - - // // QueryRowCount ( ) ;", - // console.log({ submitData }); - // let newSQLString = 'SELECT '; - - // newSQLString += submitData.columns - // .filter((ele) => ele.checked) - // .map((colObj) => { - // if (colObj.columnName === colObj.userAlias) { - // return colObj.columnName; - // } else { - // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - // } - // }) - // .join(', '); - - // newSQLString += ` FROM ${submitData.tableSelect}`; - // newSQLString += ';'; - - // if ( - // selectedLeftTable && - // selectedRightTable && - // selectedLeftKey && - // selectedRightKey - // ) { - // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - // } - - // importDataSQLStringRef.current = newSQLString; - // }; + const constructDataBasePixel = ({ submitData }) => { + // // mimic this pixel structure instead of constructing raw SQL ? + // // or have join autoselect keys and add columns to edit + // // that makes sense with new pixel structure + // // show all tables and selectable rows in edit columns view + // // find way of showing alerts for un joinable columns + // // add form structure to json state (?) + // // make basic non SQL view for notebook cell + // // make edit window + + // // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | + + // // Select ( + // // STATION_SETTINGS__ROLE , + // // USER_SETTINGS__DATE_CREATED , + // // VISN_SETTINGS__EMAIL , + // // VISN_SETTINGS__USER , + // // VISN_SETTINGS__VISN ) + // // .as ( [ + // // ROLE , + // // DATE_CREATED , + // // EMAIL , + // // USER , + // // VISN + // // ] ) | + + // // Join ( ( + // // USER_SETTINGS , + // // inner.join , + // // STATION_SETTINGS + // // ) , ( + // // USER_SETTINGS , + // // inner.join , + // // VISN_SETTINGS + // // ) ) | + + // // Distinct ( false ) | + + // // QueryRowCount ( ) ;", + console.log({ submitData }); + let newSQLString = 'SELECT '; + + newSQLString += submitData.columns + .filter((ele) => ele.checked) + .map((colObj) => { + if (colObj.columnName === colObj.userAlias) { + return colObj.columnName; + } else { + return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + } + }) + .join(', '); + + newSQLString += ` FROM ${submitData.tableSelect}`; + newSQLString += ';'; + + if ( + selectedLeftTable && + selectedRightTable && + selectedLeftKey && + selectedRightKey + ) { + newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + } + + importDataSQLStringRef.current = newSQLString; + }; /** Add all the columns from a Table */ - // const addAllTableColumnsHandler = (event) => { - // alert('add all'); - // // TODO: check all columns from table - // }; + const addAllTableColumnsHandler = (event) => { + alert('add all'); + // TODO: check all columns from table + }; /** New Submit for Import Data --- empty */ - // const onImportDataSubmit = (data: NewFormData) => { - // // constructSQLString({ submitData }); - // retrievePreviewData(); - // appendCell('data-import'); - // setIsDataImportModalOpen(false); - // // closeImportModalHandler(); - // }; + const onImportDataSubmit = (data: NewFormData) => { + if (editMode) { + alert('edit onImportDataSubmit'); + } - /** Close and Reset Import Data Form Modal */ - // const closeImportModalHandler = () => { - // setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); - // setHiddenColumnIdsSet(new Set()); - // setIsDataImportModalOpen(false); - // setDatabaseTableHeaders([]); - // setSelectedDatabaseId(null); - // setShowTablePreview(false); - // setTableColumnsObject({}); - // setDatabaseTableRows([]); - // setSelectedTable(null); - // setTableNames([]); - // reset(); - // }; + // constructSQLString({ submitData }); - /** Get Database Information for Data Import Modal */ - // const retrieveDatabaseTablesAndEdges = async (databaseId) => { - // setIsDatabaseLoading(true); - // const pixelString = `META|GetDatabaseTableStructure(database=[ \"${databaseId}\" ]);META|GetDatabaseMetamodel( database=[ \"${databaseId}\" ], options=["dataTypes","positions"]);`; - - // // const pixelResponse = await runPixel(pixelString); - // monolithStore.runQuery(pixelString).then((pixelResponse) => { - // console.log({ pixelResponse }); - // const responseTableStructure = - // pixelResponse.pixelReturn[0].output; - // const isResponseTableStructureGood = - // pixelResponse.pixelReturn[0].operationType.indexOf( - // 'ERROR', - // ) === -1; - - // const responseTableEdgesStructure = - // pixelResponse.pixelReturn[1].output; - // const isResponseTableEdgesStructureGood = - // pixelResponse.pixelReturn[1].operationType.indexOf( - // 'ERROR', - // ) === -1; - - // let newTableNames = []; - - // // populate database structure - // if (isResponseTableStructureGood) { - // console.log({ responseTableStructure }); - // newTableNames = [ - // ...responseTableStructure.reduce((set, ele) => { - // set.add(ele[0]); - // return set; - // }, new Set()), - // ]; + // preview needs to be fixed + // retrievePreviewData(); - // const tableColumnsObject = responseTableStructure.reduce( - // (acc, ele, idx) => { - // const tableName = ele[0]; - // const columnName = ele[1]; - // const columnType = ele[2]; - // // other info seems to not be needed, unsure what flag is representing or if repeat names are aliases etc - // const columnBoolean = ele[3]; - // const columnName2 = ele[4]; - // const tableName2 = ele[4]; - - // if (!acc[tableName]) acc[tableName] = []; - // acc[tableName].push({ - // tableName, - // columnName, - // columnType, - // columnBoolean, - // columnName2, - // tableName2, - // userAlias: columnName, // user editable in Edit Columns - // checked: true, - // }); - - // return acc; - // }, - // {}, - // ); - - // const newTableColumnsObject: Table[] = Object.keys( - // tableColumnsObject, - // ).map((tableName, tableIdx) => ({ - // id: tableIdx, - // name: tableName, - // columns: tableColumnsObject[tableName].map( - // (colObj, colIdx) => ({ - // id: colIdx, - // tableName: tableName, - // columnName: colObj.columnName, - // columnType: colObj.columnType, - // userAlias: colObj.userAlias, - // checked: false, - // }), - // ), - // })); - - // newReset({ - // databaseSelect: databaseId, - // tables: newTableColumnsObject, - // }); - // } else { - // console.error('Error retrieving database tables'); - // } - - // // set visible tables set to all tables - // setTableNames(newTableNames); - // setShownTables(new Set(newTableNames)); - - // // make and populate new edges dict - // if (isResponseTableEdgesStructureGood) { - // const newEdgesDict = - // responseTableEdgesStructure.edges.reduce((acc, ele) => { - // const source = ele.source; - // const target = ele.target; - // const sourceColumn = ele.sourceColumn; - // const targetColumn = ele.targetColumn; - - // if (!acc[source]) { - // acc[source] = { - // [target]: { - // sourceColumn, - // targetColumn, - // }, - // }; - // } else { - // acc[source][target] = { - // sourceColumn, - // targetColumn, - // }; - // } - - // if (!acc[target]) { - // acc[target] = { - // [source]: { - // sourceColumn: targetColumn, - // targetColumn: sourceColumn, - // }, - // }; - // } else { - // acc[target][source] = { - // sourceColumn: targetColumn, - // targetColumn: sourceColumn, - // }; - // } - // return acc; - // }, {}); - - // setTableEdgesObject(newEdgesDict); - // } else { - // console.error('Error retrieving database edges'); - // } - - // // store edges in useState - // const edges = pixelResponse.pixelReturn[1].output.edges; - // const newTableEdges = {}; - // edges.forEach((edge) => { - // // add edge from source direction - // if (newTableEdges[edge.source]) { - // newTableEdges[edge.source][edge.target] = edge.relation; - // } else { - // newTableEdges[edge.source] = { - // [edge.target]: edge.relation, - // }; - // } - // // add edge from target direction - // if (newTableEdges[edge.target]) { - // newTableEdges[edge.target][edge.source] = edge.relation; - // } else { - // newTableEdges[edge.target] = { - // [edge.source]: edge.relation, - // }; - // } - // }); - // setTableEdges(newTableEdges); - // setIsDatabaseLoading(false); - // }); - // }; + // instead of appending cell it will have to be updated + // appendCell('data-import'); + setIsDataImportModalOpen(false); + // closeImportModalHandler(); + }; - // const updateSelectedTables = () => { - // // const databaseId = selectedDatabaseId; - // const pixelTables = new Set(); - // const pixelColumnNames = []; - // const pixelColumnAliases = []; - // // const pixelJoins = []; - - // watchedTables?.forEach((tableObject) => { - // const currTableName = tableObject.name; - // const currTableColumns = tableObject.columns; - - // currTableColumns.forEach((columnObject) => { - // if (columnObject.checked) { - // pixelTables.add(columnObject.tableName); - // pixelColumnNames.push( - // `${columnObject.tableName}__${columnObject.columnName}`, - // ); - // pixelColumnAliases.push(columnObject.userAlias); - // } - // }); - // }); + /** Close and Reset Import Data Form Modal */ + const closeImportModalHandler = () => { + setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); + setHiddenColumnIdsSet(new Set()); + setIsDataImportModalOpen(false); + setDatabaseTableHeaders([]); + setSelectedDatabaseId(null); + setShowTablePreview(false); + setTableColumnsObject({}); + setDatabaseTableRows([]); + setSelectedTable(null); + setTableNames([]); + reset(); + }; - // setSelectedTableNames(pixelTables); - // }; + /** Get Database Information for Data Import Modal */ + const retrieveDatabaseTablesAndEdges = async (databaseId) => { + setIsDatabaseLoading(true); + const pixelString = `META|GetDatabaseTableStructure(database=[ \"${databaseId}\" ]);META|GetDatabaseMetamodel( database=[ \"${databaseId}\" ], options=["dataTypes","positions"]);`; + + // const pixelResponse = await runPixel(pixelString); + monolithStore.runQuery(pixelString).then((pixelResponse) => { + const responseTableStructure = + pixelResponse.pixelReturn[0].output; + const isResponseTableStructureGood = + pixelResponse.pixelReturn[0].operationType.indexOf( + 'ERROR', + ) === -1; + + const responseTableEdgesStructure = + pixelResponse.pixelReturn[1].output; + const isResponseTableEdgesStructureGood = + pixelResponse.pixelReturn[1].operationType.indexOf( + 'ERROR', + ) === -1; + + let newTableNames = []; + + // populate database structure + if (isResponseTableStructureGood) { + console.log({ responseTableStructure }); + newTableNames = [ + ...responseTableStructure.reduce((set, ele) => { + set.add(ele[0]); + return set; + }, new Set()), + ]; + + const tableColumnsObject = responseTableStructure.reduce( + (acc, ele, idx) => { + const tableName = ele[0]; + const columnName = ele[1]; + const columnType = ele[2]; + // other info seems to not be needed, unsure what flag is representing or if repeat names are aliases etc + const columnBoolean = ele[3]; + const columnName2 = ele[4]; + const tableName2 = ele[4]; + + if (!acc[tableName]) acc[tableName] = []; + acc[tableName].push({ + tableName, + columnName, + columnType, + columnBoolean, + columnName2, + tableName2, + userAlias: columnName, // user editable in Edit Columns + checked: true, + }); + + return acc; + }, + {}, + ); + + const newTableColumnsObject: Table[] = Object.keys( + tableColumnsObject, + ).map((tableName, tableIdx) => ({ + id: tableIdx, + name: tableName, + columns: tableColumnsObject[tableName].map( + (colObj, colIdx) => ({ + id: colIdx, + tableName: tableName, + columnName: colObj.columnName, + columnType: colObj.columnType, + userAlias: colObj.userAlias, + checked: false, + }), + ), + })); + + newReset({ + databaseSelect: databaseId, + tables: newTableColumnsObject, + }); + } else { + console.error('Error retrieving database tables'); + } + + // set visible tables set to all tables + setTableNames(newTableNames); + setShownTables(new Set(newTableNames)); + + // make and populate new edges dict + if (isResponseTableEdgesStructureGood) { + const newEdgesDict = + responseTableEdgesStructure.edges.reduce((acc, ele) => { + const source = ele.source; + const target = ele.target; + const sourceColumn = ele.sourceColumn; + const targetColumn = ele.targetColumn; + + if (!acc[source]) { + acc[source] = { + [target]: { + sourceColumn, + targetColumn, + }, + }; + } else { + acc[source][target] = { + sourceColumn, + targetColumn, + }; + } + + if (!acc[target]) { + acc[target] = { + [source]: { + sourceColumn: targetColumn, + targetColumn: sourceColumn, + }, + }; + } else { + acc[target][source] = { + sourceColumn: targetColumn, + targetColumn: sourceColumn, + }; + } + return acc; + }, {}); + + setTableEdgesObject(newEdgesDict); + } else { + console.error('Error retrieving database edges'); + } + + // store edges in useState + const edges = pixelResponse.pixelReturn[1].output.edges; + const newTableEdges = {}; + edges.forEach((edge) => { + // add edge from source direction + if (newTableEdges[edge.source]) { + newTableEdges[edge.source][edge.target] = edge.relation; + } else { + newTableEdges[edge.source] = { + [edge.target]: edge.relation, + }; + } + // add edge from target direction + if (newTableEdges[edge.target]) { + newTableEdges[edge.target][edge.source] = edge.relation; + } else { + newTableEdges[edge.target] = { + [edge.source]: edge.relation, + }; + } + }); + setTableEdges(newTableEdges); + setIsDatabaseLoading(false); + setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.large); + }); + setIsInitLoadComplete(true); + }; + + const updateSelectedTables = () => { + // const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = []; + const pixelColumnAliases = []; + // const pixelJoins = []; + + watchedTables?.forEach((tableObject) => { + const currTableName = tableObject.name; + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + setSelectedTableNames(pixelTables); + }; /** Old Get All Database Tables for Import Data --- remove? */ // const retrieveDatabaseTables = async (databaseId) => { @@ -1074,127 +1122,118 @@ export const DataImportFormModal = observer( // retrieveTableRows(tableName); // }; - // const retrievePreviewData = async () => { - // setIsDatabaseLoading(true); - - // // run database rows reactor - // const databaseId = selectedDatabaseId; - // const pixelTables = new Set(); - // const pixelColumnNames = []; - // const pixelColumnAliases = []; - // const pixelJoins = []; - - // watchedTables.forEach((tableObject) => { - // const currTableName = tableObject.name; - // const currTableColumns = tableObject.columns; - - // currTableColumns.forEach((columnObject) => { - // if (columnObject.checked) { - // pixelTables.add(columnObject.tableName); - // pixelColumnNames.push( - // `${columnObject.tableName}__${columnObject.columnName}`, - // ); - // pixelColumnAliases.push(columnObject.userAlias); - // } - // }); - // }); - - // console.log(joinsSet); - - // Array.from(joinsSet).forEach((joinEle: string) => { - // console.log({ joinEle }); - // const splitJoinsString = joinEle.split(':'); - // pixelJoins.push( - // `( ${splitJoinsString[0]} , inner.join , ${splitJoinsString[1]} )`, - // ); - // }); - - // console.log({ - // databaseId, - // pixelTables, - // pixelColumnNames, - // pixelColumnAliases, - // pixelJoins, - // joinsSet, - // }); - - // // when constructing final pixel string seperate all these with '|' - // let pixelStringPart1 = `Database ( database = [ \"${databaseId}\" ] )`; - // pixelStringPart1 += ` | Select ( ${pixelColumnNames.join(' , ')} )`; - // pixelStringPart1 += `.as ( [ ${pixelColumnAliases.join(' , ')} ] )`; - // if (pixelJoins.length > 0) { - // pixelStringPart1 += ` | Join ( ${pixelJoins.join(' , ')} ) `; - // } - // pixelStringPart1 += ` | Distinct ( false ) | Limit ( 20 )`; - - // // seperated Import out so frame can construct this independently from preview - // const pixelStringPart2 = ` | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; - // const pixelStringPart3 = ` ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; - - // const combinedPixelString = - // pixelStringPart1 + pixelStringPart2 + ' ; ' + pixelStringPart3; - - // // const joinsPixelString = pixelJoins.length > 0 ? `Join ( ${pixelJoins.join(' , ')} ) ` : null; - // // const distinctPixelString = `Distinct ( false ) | Limit ( 20 )`; - // // const importPixelString = `Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; - // // // when constructing string seperate META with ';' - // // const metaPixelString = `META | Frame() | QueryAll() | Limit(50) | Collect(500)` - // // // add ';' at end of final pixel string - - // // const pixelStringObject = { - // // databasePixelString, - // // selectPixelString, - // // aliasPixelString, - // // joinsPixelString, - // // distinctPixelString, - // // limitPixelString, - // // importPixelString, - // // metaPixelString, - // // } - - // const combinedJoinString = - // pixelJoins.length > 0 - // ? `| Join ( ${pixelJoins.join(' , ')} ) ` - // : ''; - - // // const testReactorPixel = - // // 'Database ( database = [ "f9b656cc-06e7-4cce-bae8-b5f92075b6da" ] ) | Select ( STATION_SETTINGS__EMAIL , USER_SETTINGS__PHONE ) .as ( [ EMAIL , PHONE ] ) | Join ( ( USER_SETTINGS , inner.join , STATION_SETTINGS ) ) | Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ "consolidated_settings_FRAME932867__Preview" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);'; - // const reactorPixel = `Database ( database = [ \"${databaseId}\" ] ) | Select ( ${pixelColumnNames.join( - // ' , ', - // )} ) .as ( [ ${pixelColumnAliases.join( - // ' , ', - // // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | `; // end of reactor string is added in cell-defaults/data-import/config.ts to incorporate correct frame variable name - // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; - // // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ); META | Frame() | QueryAll() | Limit(50) | Collect(500);`; - // // ## TODO fix variable import pixel syntax, currently including db name for some reason - - // // these might not be needed with new part1 ref - // setPixelString(reactorPixel); - // pixelStringRef.current = reactorPixel; - - // // this ref is for the form submit - // pixelStringRefPart1.current = pixelStringPart1 + ';'; - - // await monolithStore.runQuery(reactorPixel).then((response) => { - // const type = response.pixelReturn[0]?.operationType; - // const tableHeadersData = - // response.pixelReturn[1]?.output?.data?.headers; - // const tableRawHeadersData = - // response.pixelReturn[1]?.output?.data?.rawHeaders; - // const tableRowsData = - // response.pixelReturn[1]?.output?.data?.values; - - // setDatabaseTableHeaders(tableHeadersData); - // setDatabaseTableRawHeaders(tableRawHeadersData); - // setDatabaseTableRows(tableRowsData); - - // if (type.indexOf('ERROR') != -1) { - // console.error('Error retrieving database tables'); - // } - - // setIsDatabaseLoading(false); - // }); - // }; + const retrievePreviewData = async () => { + setIsDatabaseLoading(true); + + // run database rows reactor + const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = []; + const pixelColumnAliases = []; + const pixelJoins = []; + + watchedTables.forEach((tableObject) => { + const currTableName = tableObject.name; + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + console.log(joinsSet); + + Array.from(joinsSet).forEach((joinEle: string) => { + console.log({ joinEle }); + const splitJoinsString = joinEle.split(':'); + pixelJoins.push( + `( ${splitJoinsString[0]} , inner.join , ${splitJoinsString[1]} )`, + ); + }); + + // when constructing final pixel string seperate all these with '|' + let pixelStringPart1 = `Database ( database = [ \"${databaseId}\" ] )`; + pixelStringPart1 += ` | Select ( ${pixelColumnNames.join(' , ')} )`; + pixelStringPart1 += `.as ( [ ${pixelColumnAliases.join(' , ')} ] )`; + if (pixelJoins.length > 0) { + pixelStringPart1 += ` | Join ( ${pixelJoins.join(' , ')} ) `; + } + pixelStringPart1 += ` | Distinct ( false ) | Limit ( 20 )`; + + // seperated Import out so frame can construct this independently from preview + const pixelStringPart2 = ` | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; + const pixelStringPart3 = ` ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + + // const combinedPixelString = + // pixelStringPart1 + pixelStringPart2 + ' ; ' + pixelStringPart3; + + // // const joinsPixelString = pixelJoins.length > 0 ? `Join ( ${pixelJoins.join(' , ')} ) ` : null; + // // const distinctPixelString = `Distinct ( false ) | Limit ( 20 )`; + // // const importPixelString = `Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; + // // // when constructing string seperate META with ';' + // // const metaPixelString = `META | Frame() | QueryAll() | Limit(50) | Collect(500)` + // // // add ';' at end of final pixel string + + // // const pixelStringObject = { + // // databasePixelString, + // // selectPixelString, + // // aliasPixelString, + // // joinsPixelString, + // // distinctPixelString, + // // limitPixelString, + // // importPixelString, + // // metaPixelString, + // // } + + const combinedJoinString = + pixelJoins.length > 0 + ? `| Join ( ${pixelJoins.join(' , ')} ) ` + : ''; + + // const testReactorPixel = + // 'Database ( database = [ "f9b656cc-06e7-4cce-bae8-b5f92075b6da" ] ) | Select ( STATION_SETTINGS__EMAIL , USER_SETTINGS__PHONE ) .as ( [ EMAIL , PHONE ] ) | Join ( ( USER_SETTINGS , inner.join , STATION_SETTINGS ) ) | Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ "consolidated_settings_FRAME932867__Preview" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);'; + const reactorPixel = `Database ( database = [ \"${databaseId}\" ] ) | Select ( ${pixelColumnNames.join( + ' , ', + )} ) .as ( [ ${pixelColumnAliases.join( + ' , ', + // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | `; // end of reactor string is added in cell-defaults/data-import/config.ts to incorporate correct frame variable name + )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ); META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + // ## TODO fix variable import pixel syntax, currently including db name for some reason + + // these might not be needed with new part1 ref + setPixelString(reactorPixel); + pixelStringRef.current = reactorPixel; + + // this ref is for the form submit + pixelStringRefPart1.current = pixelStringPart1 + ';'; + + await monolithStore.runQuery(reactorPixel).then((response) => { + const type = response.pixelReturn[0]?.operationType; + const tableHeadersData = + response.pixelReturn[1]?.output?.data?.headers; + const tableRawHeadersData = + response.pixelReturn[1]?.output?.data?.rawHeaders; + const tableRowsData = + response.pixelReturn[1]?.output?.data?.values; + + setDatabaseTableHeaders(tableHeadersData); + setDatabaseTableRawHeaders(tableRawHeadersData); + setDatabaseTableRows(tableRowsData); + + if (type.indexOf('ERROR') != -1) { + console.error('Error retrieving database tables'); + } + + setIsDatabaseLoading(false); + }); + }; /** Old Select Tables for Import Data --- unused / remove? */ // const retrieveTableRows = async (tableName) => { @@ -1241,1480 +1280,1510 @@ export const DataImportFormModal = observer( // }; /** Helper Function Update Alias Tracker Object*/ - // const updateAliasCountObj = ( - // isBeingAdded, - // newAlias, - // oldAlias = null, - // ) => { - // const newAliasesCountObj = { ...aliasesCountObj }; - - // console.log({ isBeingAdded, newAlias, oldAlias }); - - // if (isBeingAdded) { - // if (newAliasesCountObj[newAlias]) { - // newAliasesCountObj[newAlias] = - // newAliasesCountObj[newAlias] + 1; - // } else { - // newAliasesCountObj[newAlias] = 1; - // } - // } else { - // if (newAliasesCountObj[newAlias]) { - // newAliasesCountObj[newAlias] = - // newAliasesCountObj[newAlias] - 1; - // } else { - // newAliasesCountObj[newAlias] = 0; - // } - // } - - // if (newAliasesCountObj[newAlias] < 1) { - // delete newAliasesCountObj[newAlias]; - // } - - // if (oldAlias) { - // if (newAliasesCountObj[oldAlias]) { - // newAliasesCountObj[oldAlias] = - // newAliasesCountObj[newAlias] - 1; - // } else { - // newAliasesCountObj[oldAlias] = 0; - // } - // if (newAliasesCountObj[oldAlias] < 1) { - // delete newAliasesCountObj[oldAlias]; - // } - // } - - // console.log({ newAliasesCountObj }); - // setAliasesCountObj(newAliasesCountObj); - // }; + const updateAliasCountObj = ( + isBeingAdded, + newAlias, + oldAlias = null, + ) => { + const newAliasesCountObj = { ...aliasesCountObj }; + + console.log({ isBeingAdded, newAlias, oldAlias }); + + if (isBeingAdded) { + if (newAliasesCountObj[newAlias]) { + newAliasesCountObj[newAlias] = + newAliasesCountObj[newAlias] + 1; + } else { + newAliasesCountObj[newAlias] = 1; + } + } else { + if (newAliasesCountObj[newAlias]) { + newAliasesCountObj[newAlias] = + newAliasesCountObj[newAlias] - 1; + } else { + newAliasesCountObj[newAlias] = 0; + } + } + + if (newAliasesCountObj[newAlias] < 1) { + delete newAliasesCountObj[newAlias]; + } + + if (oldAlias) { + if (newAliasesCountObj[oldAlias]) { + newAliasesCountObj[oldAlias] = + newAliasesCountObj[newAlias] - 1; + } else { + newAliasesCountObj[oldAlias] = 0; + } + if (newAliasesCountObj[oldAlias] < 1) { + delete newAliasesCountObj[oldAlias]; + } + } + + console.log({ newAliasesCountObj }); + setAliasesCountObj(newAliasesCountObj); + }; /** Find Joinable Tables */ - // const findAllJoinableTables = (rootTableName) => { - // const joinableTables = tableEdges[rootTableName] - // ? Object.keys(tableEdges[rootTableName]) - // : []; - // console.log({ - // rootTableName, - // tableEdges, - // joinableTables, - // 'tableEdges[rootTableName]': tableEdges[rootTableName], - // }); - // const newShownTables = new Set([...joinableTables, rootTableName]); - // // debugger; - // setShownTables(newShownTables); - // }; + const findAllJoinableTables = (rootTableName) => { + const joinableTables = tableEdges[rootTableName] + ? Object.keys(tableEdges[rootTableName]) + : []; + console.log({ + rootTableName, + tableEdges, + joinableTables, + 'tableEdges[rootTableName]': tableEdges[rootTableName], + }); + const newShownTables = new Set([...joinableTables, rootTableName]); + // debugger; + setShownTables(newShownTables); + }; /** Checkbox Handler */ - // const checkBoxHandler = (tableIndex, columnIndex) => { - // const columnObject = watchedTables[tableIndex].columns[columnIndex]; - // console.log({ columnObject }); - // updateAliasCountObj(columnObject?.checked, columnObject.userAlias); - // if (columnObject?.checked) { - // if (checkedColumnsCount == 0) { - // findAllJoinableTables(watchedTables[tableIndex].name); - // setRootTable(watchedTables[tableIndex].name); - // } - // setCheckedColumnsCount(checkedColumnsCount + 1); - // } else if (columnObject?.checked == false) { - // if (checkedColumnsCount == 1) { - // setShownTables(new Set(tableNames)); - // setRootTable(null); - // } - // setCheckedColumnsCount(checkedColumnsCount - 1); - // } - // }; - - // const checkTableForSelectedColumns = (tableName) => { - // for (let i = 0; i < watchedTables.length; i++) { - // const currTable = watchedTables[i]; - // if (currTable.name == tableName) { - // const currTableColumns = currTable.columns; - // for (let j = 0; j < currTableColumns.length; j++) { - // const currColumn = currTableColumns[j]; - // if (currColumn.checked == true) return true; - // } - // } - // } - // return false; - // }; - - // const setJoinsStackHandler = () => { - // if (checkedColumnsCount < 2) { - // removeJoinElement(); - // setJoinsSet(new Set()); - // } else { - // const leftTable = rootTable; - // const rightTables = - // tableEdgesObject[rootTable] && - // tableEdgesObject && - // Object.entries(tableEdgesObject[rootTable]); - - // // addresses crash for dbs with only one table / no edges - // rightTables?.forEach((entry, joinIdx) => { - // const rightTable = entry[0]; - // const leftKey = entry[1]['sourceColumn']; - // const rightKey = entry[1]['targetColumn']; - - // const leftTableContainsCheckedColumns = - // checkTableForSelectedColumns(leftTable); - // const rightTableContainsCheckedColumns = - // checkTableForSelectedColumns(rightTable); - - // const defaultJoinType = 'Inner Join'; - - // const joinsSetString = `${leftTable}:${rightTable}`; - // if ( - // leftTableContainsCheckedColumns && - // rightTableContainsCheckedColumns && - // joinsSet.has(joinsSetString) == false - // ) { - // appendJoinElement({ - // leftTable: leftTable, - // rightTable: rightTable, - // joinType: defaultJoinType, - // leftKey: leftKey, - // rightKey: rightKey, - // }); - // addToJoinsSetHelper(joinsSetString); - // } else if ( - // leftTableContainsCheckedColumns == false || - // (rightTableContainsCheckedColumns == false && - // joinsSet.has(joinsSetString)) - // ) { - // joinsSet.delete(joinsSetString); - // joinElements.some((ele, idx) => { - // if ( - // leftTable == ele.leftTable && - // rightTable == ele.rightTable && - // defaultJoinType == ele.joinType && - // leftKey == ele.leftKey && - // rightKey == ele.rightKey - // ) { - // removeJoinElement(idx); - // return true; - // } else { - // return false; - // } - // }); - // } - // }); - // } - // }; - - // const addToJoinsSetHelper = (newJoinSet) => { - // const joinsSetCopy = new Set(joinsSet); - // joinsSetCopy.add(newJoinSet); - // setJoinsSet(joinsSetCopy); - // console.log({ joinsSetCopy }); - // }; + const checkBoxHandler = (tableIndex, columnIndex) => { + const columnObject = watchedTables[tableIndex].columns[columnIndex]; + console.log({ columnObject }); + updateAliasCountObj(columnObject?.checked, columnObject.userAlias); + if (columnObject?.checked) { + if (checkedColumnsCount == 0) { + findAllJoinableTables(watchedTables[tableIndex].name); + setRootTable(watchedTables[tableIndex].name); + } + setCheckedColumnsCount(checkedColumnsCount + 1); + } else if (columnObject?.checked == false) { + if (checkedColumnsCount == 1) { + setShownTables(new Set(tableNames)); + setRootTable(null); + } + setCheckedColumnsCount(checkedColumnsCount - 1); + } + }; + + const prepoulateFormForEdit = (cell) => { + // $$$ + alert('prepoulateFormForEdit'); + + const tablesWithCheckedBoxes = new Set(); + const checkedColumns = new Set(); + const columnAliasMap = {}; + + cell.parameters.selectedColumns.forEach( + (selectedColumnTableCombinedString, idx) => { + const [currTableName, currColumnName] = + selectedColumnTableCombinedString.split('__'); + const currColumnAlias = cell.parameters.columnAliases[idx]; + + tablesWithCheckedBoxes.add(currTableName); + checkedColumns.add(currColumnAlias); + columnAliasMap[selectedColumnTableCombinedString] = + currColumnAlias; + }, + ); + + if (newTableFields) { + // $$$ + alert('newTableFields'); + console.log({ newTableFields }); + newTableFields.forEach((newTableObj, tableIdx) => { + alert(newTableObj.name); + + // go through watched tables... + // for tables in checkedTables set... + // for columns in checkedColumns set... + // check column in fieldArray + // update alias in fieldArray -- regardless of if the alias is different from col name + }); + } + + // watchedTables.forEach((watchedTable, tableIdx) => { + // console.log({ watchedTable, tableIdx }); + // }) + + // console.log({tablesWithCheckedBoxes, checkedColumns, columnAliasMap}); + + // console.log({"cell.parameters.selectedColumns": cell.parameters.selectedColumns}) + }; + + const checkTableForSelectedColumns = (tableName) => { + for (let i = 0; i < watchedTables.length; i++) { + const currTable = watchedTables[i]; + if (currTable.name == tableName) { + const currTableColumns = currTable.columns; + for (let j = 0; j < currTableColumns.length; j++) { + const currColumn = currTableColumns[j]; + if (currColumn.checked == true) return true; + } + } + } + return false; + }; + + const setJoinsStackHandler = () => { + if (checkedColumnsCount < 2) { + removeJoinElement(); + setJoinsSet(new Set()); + } else { + const leftTable = rootTable; + const rightTables = + tableEdgesObject[rootTable] && + tableEdgesObject && + Object.entries(tableEdgesObject[rootTable]); + + // addresses crash for dbs with only one table / no edges + rightTables?.forEach((entry, joinIdx) => { + const rightTable = entry[0]; + const leftKey = entry[1]['sourceColumn']; + const rightKey = entry[1]['targetColumn']; + + const leftTableContainsCheckedColumns = + checkTableForSelectedColumns(leftTable); + const rightTableContainsCheckedColumns = + checkTableForSelectedColumns(rightTable); + + const defaultJoinType = 'Inner Join'; + + const joinsSetString = `${leftTable}:${rightTable}`; + if ( + leftTableContainsCheckedColumns && + rightTableContainsCheckedColumns && + joinsSet.has(joinsSetString) == false + ) { + appendJoinElement({ + leftTable: leftTable, + rightTable: rightTable, + joinType: defaultJoinType, + leftKey: leftKey, + rightKey: rightKey, + }); + addToJoinsSetHelper(joinsSetString); + } else if ( + leftTableContainsCheckedColumns == false || + (rightTableContainsCheckedColumns == false && + joinsSet.has(joinsSetString)) + ) { + joinsSet.delete(joinsSetString); + joinElements.some((ele, idx) => { + if ( + leftTable == ele.leftTable && + rightTable == ele.rightTable && + defaultJoinType == ele.joinType && + leftKey == ele.leftKey && + rightKey == ele.rightKey + ) { + removeJoinElement(idx); + return true; + } else { + return false; + } + }); + } + }); + } + }; + + const addToJoinsSetHelper = (newJoinSet) => { + const joinsSetCopy = new Set(joinsSet); + joinsSetCopy.add(newJoinSet); + setJoinsSet(joinsSetCopy); + console.log({ joinsSetCopy }); + }; + + // return ( + // + // + //
+ // {cell.parameters.databaseId} + //

TABLE NAMES

+ // {cell.parameters.tableNames?.map((tableName, idx) => ( + //
{tableName}
+ // ))} + //

JOINS

+ // {cell.parameters.joins?.map((join, idx) => ( + //
+ // {join.leftTable} ({join.joinType}){join.rightTable} ON + // {join.leftKey} ={join.rightKey} + //
+ // ))} + //

SELECTED COLUMNS

+ // {cell.parameters.selectedColumns?.map((column, idx) => ( + //
{column}
+ // ))} + //

ALIASES

+ // {cell.parameters.columnAliases?.map((alias, idx) => ( + //
{alias}
+ // ))} + // {/* need the selected columns */} + // {/* need the column aliases */} + // {/* need the filters */} + // {/* {cell.parameters.summaries} */} + // + //
+ //
+ //
+ // ); return ( - {cell.parameters.databaseId} -

TABLE NAMES

- {cell.parameters.tableNames?.map((tableName, idx) => ( -
{tableName}
- ))} -

JOINS

- {cell.parameters.joins?.map((join, idx) => ( -
- {join.leftTable} ({join.joinType}){join.rightTable} ON - {join.leftKey} ={join.rightKey} -
- ))} -

SELECTED COLUMNS

- {cell.parameters.selectedColumns?.map((column, idx) => ( -
{column}
- ))} -

ALIASES

- {cell.parameters.columnAliases?.map((alias, idx) => ( -
{alias}
- ))} - {/* need the selected columns */} - {/* need the column aliases */} - {/* need the filters */} - {/* {cell.parameters.summaries} */} - -
- ); - - return ( - <> - {/* Dropdown for All Add Cell Option Sets */} - - {/* - - - {AddCellOptions && - Object.entries(AddCellOptions).map((add, i) => { - const value = add[1]; - return ( - { - if (value.options) { - setAnchorEl(e.currentTarget); - setSelectedAddCell(add[0]); - } else { - appendCell( - value.defaultCellType, + +
+ +
+ + Import Data from + + ( + + )} + /> +
+ + + +
+ {selectedDatabaseId && ( + + +
+ + Data + +
+
+ + +
+
+ + {showEditColumns && ( + + + Available Tables / Columns + + + {newTableFields.map( + (table, tableIndex) => ( +
+ {/* using conditional rendering for each table but if bugs persists set state for showntables in checkbox handler */} + {shownTables.has( + table.name, + ) && ( + + + + + + + { + table.name + } + + + + + + + + + + + + + Fields + + + + + Alias + + + + + Field + Type + + + + + {table.columns.map( + ( + column, + columnIndex, + ) => ( + + + ( + { + field.onChange( + e, + ); + checkBoxHandler( + tableIndex, + columnIndex, + ); + }} + /> + )} + /> + + + { + column.columnName + } + {column.columnName == + 'ID' && ( +
+ PK +
+ )} + {column.columnName.includes( + '_ID', + ) && ( +
+ FK +
+ )} +
+ + + ( + { + if ( + watchedTables[ + tableIndex + ] + .columns[ + columnIndex + ] + .checked + ) { + updateAliasCountObj( + true, + e + .target + .value, + field.value, + ); + } + field.onChange( + e + .target + .value, + ); + }} + /> + )} + /> + {watchedTables[ + tableIndex + ] + .columns[ + columnIndex + ] + .checked && + aliasesCountObj[ + watchedTables[ + tableIndex + ] + .columns[ + columnIndex + ] + .userAlias + ] > + 1 && ( + + + + )} + + + + + ( + + )} + /> + +
+ ), + )} +
+
+
+ )} +
+ ), + )} +
+
+ )} + + {showPreview && ( + + + Preview + + + + + + {databaseTableHeaders + .filter( + (v, colIdx) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map((h, hIdx) => ( + + + {h} + + + ))} + + {databaseTableRows.map( + (r, rIdx) => ( + + {r + .filter( + ( + v, + colIdx, + ) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map( + ( + v, + vIdx, + ) => ( + + { + v + } + + ), + )} + + ), + )} + +
+
+
+ )} +
+ )} + + {/* stack for user-added joins filters and summaries */} + {joinElements.map((join, stackIndex) => ( + + +
- ) : ( - - )) - } > - {value.display} - - ); - })} - - - { - setAnchorEl(null); - }} - > - {selectedAddCell === 'transformation' && - Array.from( - AddCellOptions[selectedAddCell]?.options || [], - ({ display, defaultCellType }, index) => { - return ( - + Join + + + + + {join.leftTable} + + + + + + + + + + + + {join.rightTable} + + + + + where + + + + + {join.leftKey} + + + + + = + + + + + {join.rightKey} + + +
+ {/*
+ { - appendCell(defaultCellType); - setAnchorEl(null); + removeStack(stackIndex); }} > - {display} - - ); - }, - )} - - {selectedAddCell === 'import-data' && ( - <> - {Array.from( - AddCellOptions[selectedAddCell]?.options || - [], - ({ display }, index) => { - return ( - + +
*/} +
+ + {/* {showEditColumns && ( */} + {/* {false && ( + + + Edit Columns + + + + + + + { + setCheckAllColumns( + !checkAllColumns, + ); + const hiddenColumnIdsSetDup = + new Set(); + if ( + checkAllColumns == + false + ) { + editableColumnFields.forEach( + ( + field, + index, + ) => { + // not working need to use setValue + field.checked = + true; + console.log( + { + index, + field, + }, + ); + hiddenColumnIdsSetDup.add( + index, + ); + }, + ); + } else { + editableColumnFields.forEach( + ( + field, + index, + ) => { + // not working need to use setValue + field.checked = + false; + console.log( + { + index, + field, + }, + ); + hiddenColumnIdsSetDup.delete( + index, + ); + }, + ); + } + setHiddenColumnIdsSet( + hiddenColumnIdsSetDup, + ); + }} + color={ + checkAllColumns + ? 'primary' + : 'secondary' + } + sx={{ + marginLeft: + '-10px', + }} + > + + + + + + Fields + + + + + Alias + + + + + Field Type + + + + + {editableColumnFields?.map( + (field, index) => ( + + + ( + { + field.onChange( + e, + ); + const hiddenColumnIdsSetDup = + new Set( + [ + ...hiddenColumnIdsSet, + ], + ); + if ( + field.value == + true + ) { + hiddenColumnIdsSetDup.add( + index, + ); + } else { + hiddenColumnIdsSetDup.delete( + index, + ); + } + + console.log( + { + hiddenColumnIdsSetDup, + editableColumnFields, + }, + ); + + if ( + hiddenColumnIdsSetDup.size == + 0 + ) { + setCheckAllColumns( + true, + ); + } else { + setCheckAllColumns( + false, + ); + } + + setHiddenColumnIdsSet( + hiddenColumnIdsSetDup, + ); + }} + /> + )} + /> + + + { + field.columnName + } + {field.columnName == + 'ID' && ( +
+ PK +
+ )} + {field.columnName.includes( + '_ID', + ) && ( +
+ FK +
+ )} +
+ + ( + { + field.onChange( + e + .target + .value, + ); + const newTableHeaders = + [ + ...databaseTableHeaders, + ]; + newTableHeaders[ + index + ] = + e.target.value; + setDatabaseTableHeaders( + newTableHeaders, + ); + }} + /> + )} + /> + + + ( + + )} + /> + +
+ ), + )} +
+
+ + + + +
+ )} */} + + {/* {showPreview && ( */} + {/* {false && ( + + + Preview + + + + + {databaseTableHeaders + .filter( + (v, colIdx) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map((h, hIdx) => ( + + + {h} + + + ))} + + {databaseTableRows.map( + (r, rIdx) => ( + + {r + .filter( + ( + v, + colIdx, + ) => { + return !hiddenColumnIdsSet.has( + colIdx, + ); + }, + ) + .map( + ( + v, + vIdx, + ) => ( + + { + v + } + + ), + )} + + ), + )} + +
+
+ )} */} +
+ ))} + + + + + + + + + + +
+
+
); }, ); // {/* */} -// -// -//
-// -//
-// -// Import Data from -// -// ( -// -// )} -// /> -//
-// -// -// -//
-// {selectedDatabaseId && ( -// -// -//
-// -// Data -// -//
-//
-// -// -//
-//
- -// {showEditColumns && ( -// -// -// Available Tables / Columns -// -// -// {newTableFields.map( -// (table, tableIndex) => ( -//
-// {/* using conditional rendering for each table but if bugs persists set state for showntables in checkbox handler */} -// {shownTables.has( -// table.name, -// ) && ( -// -// -// -// -// -// -// { -// table.name -// } -// -// -// -// -// -// -// -// -// -// -// -// -// Fields -// -// -// -// -// Alias -// -// -// -// -// Field -// Type -// -// -// - -// {table.columns.map( -// ( -// column, -// columnIndex, -// ) => ( -// -// -// ( -// { -// field.onChange( -// e, -// ); -// checkBoxHandler( -// tableIndex, -// columnIndex, -// ); -// }} -// /> -// )} -// /> -// -// -// { -// column.columnName -// } -// {column.columnName == -// 'ID' && ( -//
-// PK -//
-// )} -// {column.columnName.includes( -// '_ID', -// ) && ( -//
-// FK -//
-// )} -//
-// -// -// ( -// { -// if ( -// watchedTables[ -// tableIndex -// ] -// .columns[ -// columnIndex -// ] -// .checked -// ) { -// updateAliasCountObj( -// true, -// e -// .target -// .value, -// field.value, -// ); -// } -// field.onChange( -// e -// .target -// .value, -// ); -// }} -// /> -// )} -// /> -// {watchedTables[ -// tableIndex -// ] -// .columns[ -// columnIndex -// ] -// .checked && -// aliasesCountObj[ -// watchedTables[ -// tableIndex -// ] -// .columns[ -// columnIndex -// ] -// .userAlias -// ] > -// 1 && ( -// -// -// -// )} -// -// - -// -// ( -// -// )} -// /> -// -//
-// ), -// )} -//
-//
-//
-// )} -//
-// ), -// )} -//
-//
-// )} -// {showPreview && ( -// -// -// Preview -// -// -// -// -// -// {databaseTableHeaders -// .filter( -// ( -// v, -// colIdx, -// ) => { -// return !hiddenColumnIdsSet.has( -// colIdx, -// ); -// }, -// ) -// .map( -// ( -// h, -// hIdx, -// ) => ( -// -// -// { -// h -// } -// -// -// ), -// )} -// -// {databaseTableRows.map( -// (r, rIdx) => ( -// -// {r -// .filter( -// ( -// v, -// colIdx, -// ) => { -// return !hiddenColumnIdsSet.has( -// colIdx, -// ); -// }, -// ) -// .map( -// ( -// v, -// vIdx, -// ) => ( -// -// { -// v -// } -// -// ), -// )} -// -// ), -// )} -// -//
-//
-//
-// )} -//
-// )} - -// {/* stack for user-added joins filters and summaries */} -// {joinElements.map((join, stackIndex) => ( -// -// -//
-// -// Join -// - -// -// -// {join.leftTable} -// -// - -// -// -// -// -// - -// -// -// {join.rightTable} -// -// - -// -// where -// - -// -// -// {join.leftKey} -// -// - -// -// = -// - -// -// -// {join.rightKey} -// -// -//
-// {/*
-// +// {/* Dropdown for All Add Cell Option Sets */} + +// {/* +// +// +// {AddCellOptions && +// Object.entries(AddCellOptions).map((add, i) => { +// const value = add[1]; +// return ( +// { -// removeStack(stackIndex); -// }} -// > -// -// -//
*/} -//
- -// {/* {showEditColumns && ( */} -// {/* {false && ( -// -// -// Edit Columns -// - -// -// -// -// -// { -// setCheckAllColumns( -// !checkAllColumns, -// ); -// const hiddenColumnIdsSetDup = -// new Set(); -// if ( -// checkAllColumns == -// false -// ) { -// editableColumnFields.forEach( -// ( -// field, -// index, -// ) => { -// // not working need to use setValue -// field.checked = -// true; -// console.log( -// { -// index, -// field, -// }, -// ); -// hiddenColumnIdsSetDup.add( -// index, -// ); -// }, -// ); -// } else { -// editableColumnFields.forEach( -// ( -// field, -// index, -// ) => { -// // not working need to use setValue -// field.checked = -// false; -// console.log( -// { -// index, -// field, -// }, -// ); -// hiddenColumnIdsSetDup.delete( -// index, -// ); -// }, -// ); -// } -// setHiddenColumnIdsSet( -// hiddenColumnIdsSetDup, -// ); -// }} -// color={ -// checkAllColumns -// ? 'primary' -// : 'secondary' -// } -// sx={{ -// marginLeft: -// '-10px', -// }} -// > -// -// -// -// -// -// Fields -// -// -// -// -// Alias -// -// -// -// -// Field Type -// -// -// - -// {editableColumnFields?.map( -// (field, index) => ( -// -// -// ( -// { -// field.onChange( -// e, -// ); -// const hiddenColumnIdsSetDup = -// new Set( -// [ -// ...hiddenColumnIdsSet, -// ], -// ); -// if ( -// field.value == -// true -// ) { -// hiddenColumnIdsSetDup.add( -// index, -// ); -// } else { -// hiddenColumnIdsSetDup.delete( -// index, -// ); -// } - -// console.log( -// { -// hiddenColumnIdsSetDup, -// editableColumnFields, -// }, -// ); - -// if ( -// hiddenColumnIdsSetDup.size == -// 0 -// ) { -// setCheckAllColumns( -// true, -// ); -// } else { -// setCheckAllColumns( -// false, -// ); -// } - -// setHiddenColumnIdsSet( -// hiddenColumnIdsSetDup, -// ); -// }} -// /> -// )} -// /> -// -// -// { -// field.columnName -// } -// {field.columnName == -// 'ID' && ( -//
-// PK -//
-// )} -// {field.columnName.includes( -// '_ID', -// ) && ( -//
-// FK -//
-// )} -//
-// -// ( -// { -// field.onChange( -// e -// .target -// .value, -// ); -// const newTableHeaders = -// [ -// ...databaseTableHeaders, -// ]; -// newTableHeaders[ -// index -// ] = -// e.target.value; -// setDatabaseTableHeaders( -// newTableHeaders, -// ); -// }} -// /> -// )} -// /> -// -// -// ( -// -// )} -// /> -// -//
-// ), -// )} -//
-//
-// -// -// -// -//
-// )} */} - -// {/* {showPreview && ( */} -// {/* {false && ( -// -// +// ) : ( +// +// )) +// } // > -// Preview -// -// -// -// -// {databaseTableHeaders -// .filter( -// (v, colIdx) => { -// return !hiddenColumnIdsSet.has( -// colIdx, -// ); -// }, -// ) -// .map((h, hIdx) => ( -// -// -// {h} -// -// -// ))} -// -// {databaseTableRows.map( -// (r, rIdx) => ( -// -// {r -// .filter( -// ( -// v, -// colIdx, -// ) => { -// return !hiddenColumnIdsSet.has( -// colIdx, -// ); -// }, -// ) -// .map( -// ( -// v, -// vIdx, -// ) => ( -// -// { -// v -// } -// -// ), -// )} -// -// ), -// )} -// -//
-//
-// )} */} -//
-// ))} - -// -// -// -// -// -// +// +// { +// setAnchorEl(null); // }} // > -// -// -// -//
-//
-//
+// {selectedAddCell === 'transformation' && +// Array.from( +// AddCellOptions[selectedAddCell]?.options || [], +// ({ display, defaultCellType }, index) => { +// return ( +// { +// appendCell(defaultCellType); +// setAnchorEl(null); +// }} +// > +// {display} +// +// ); +// }, +// )} + +// {selectedAddCell === 'import-data' && ( +// <> +// {Array.from( +// AddCellOptions[selectedAddCell]?.options || +// [], +// ({ display }, index) => { +// return ( +// { +// // loadDatabaseStructure(); +// setImportModalPixelWidth( +// IMPORT_MODAL_WIDTHS.small, +// ); +// setIsDataImportModalOpen( +// true, +// ); +// if ( +// display == +// 'From Data Catalog' +// ) { +// setImportModalType( +// display, +// ); +// } else { +// // open seperate modal / form for From CSV +// } +// setAnchorEl(null); +// }} +// > +// {display} +// +// ); +// }, +// )} +// +// )} +// +// */} + +// {/* New Import Data Modal --- stand-alone component? */} +// +// ); From 2450bfe07696c8720ced6a5d7f43401c45820dab Mon Sep 17 00:00:00 2001 From: Betthauser Date: Thu, 18 Jul 2024 13:59:11 -0700 Subject: [PATCH 38/49] feat(client): checkboxes and joins prepoulating correctly still debugging --- .../notebook/DataImportFormModal.tsx | 88 +++++++++++++------ 1 file changed, 63 insertions(+), 25 deletions(-) diff --git a/packages/client/src/components/notebook/DataImportFormModal.tsx b/packages/client/src/components/notebook/DataImportFormModal.tsx index 8c200c756b..5bc1f3f2bd 100644 --- a/packages/client/src/components/notebook/DataImportFormModal.tsx +++ b/packages/client/src/components/notebook/DataImportFormModal.tsx @@ -438,7 +438,7 @@ export const DataImportFormModal = observer( handleSubmit: newHandleSubmit, reset: newReset, getValues: _newGetValues, - setValue: _newSetValue, + setValue: newSetValue, watch: dataImportwatch, } = useForm(); @@ -486,6 +486,7 @@ export const DataImportFormModal = observer( const [checkedColumnsSet, setCheckedColumnsSet] = useState(new Set()); const [hiddenTablesSet, setHiddenTablesSet] = useState({}); const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } + const aliasesCountObjRef = useRef({}); // { emailAlias: 1, phoneAlias: 2 } const [tableEdges, setTableEdges] = useState({}); // const [rootTable, setRootTable] = useState(null); @@ -630,9 +631,10 @@ export const DataImportFormModal = observer( useEffect(() => { // if any change occurs with checkboxes reassess all joins to display - setJoinsStackHandler(); - updateSelectedTables(); - console.log({ selectedTableNames }); + if (!editMode) { + setJoinsStackHandler(); + updateSelectedTables(); + } }, [checkedColumnsCount]); useEffect(() => { @@ -1323,6 +1325,7 @@ export const DataImportFormModal = observer( console.log({ newAliasesCountObj }); setAliasesCountObj(newAliasesCountObj); + aliasesCountObjRef.current = { ...newAliasesCountObj }; }; /** Find Joinable Tables */ @@ -1344,7 +1347,6 @@ export const DataImportFormModal = observer( /** Checkbox Handler */ const checkBoxHandler = (tableIndex, columnIndex) => { const columnObject = watchedTables[tableIndex].columns[columnIndex]; - console.log({ columnObject }); updateAliasCountObj(columnObject?.checked, columnObject.userAlias); if (columnObject?.checked) { if (checkedColumnsCount == 0) { @@ -1362,48 +1364,84 @@ export const DataImportFormModal = observer( }; const prepoulateFormForEdit = (cell) => { - // $$$ - alert('prepoulateFormForEdit'); - const tablesWithCheckedBoxes = new Set(); const checkedColumns = new Set(); const columnAliasMap = {}; + const newAliasesCountObj = {}; + + setCheckedColumnsCount(cell.parameters.selectedColumns.length); + // checkedColumnsCountRef cell.parameters.selectedColumns.forEach( (selectedColumnTableCombinedString, idx) => { const [currTableName, currColumnName] = selectedColumnTableCombinedString.split('__'); const currColumnAlias = cell.parameters.columnAliases[idx]; - tablesWithCheckedBoxes.add(currTableName); - checkedColumns.add(currColumnAlias); + checkedColumns.add(selectedColumnTableCombinedString); columnAliasMap[selectedColumnTableCombinedString] = currColumnAlias; + newAliasesCountObj[currColumnAlias || currColumnName] = 1; }, ); + setAliasesCountObj({ ...newAliasesCountObj }); + aliasesCountObjRef.current = { ...newAliasesCountObj }; // is this needed? + if (newTableFields) { - // $$$ - alert('newTableFields'); - console.log({ newTableFields }); newTableFields.forEach((newTableObj, tableIdx) => { - alert(newTableObj.name); - - // go through watched tables... - // for tables in checkedTables set... - // for columns in checkedColumns set... - // check column in fieldArray - // update alias in fieldArray -- regardless of if the alias is different from col name + if (tablesWithCheckedBoxes.has(newTableObj.name)) { + const watchedTableColumns = + watchedTables[tableIdx].columns; + watchedTableColumns.forEach( + (tableColumnObj, columnIdx) => { + const columnName = `${tableColumnObj.tableName}__${tableColumnObj.columnName}`; + if (checkedColumns.has(columnName)) { + const columnAlias = + columnAliasMap[columnName]; + console.log( + `${columnName} / ${columnAlias} is checked`, + ); + newSetValue( + `tables.${tableIdx}.columns.${columnIdx}.checked`, + true, + ); + newSetValue( + `tables.${tableIdx}.columns.${columnIdx}.userAlias`, + columnAlias, + ); + } + }, + ); + } }); } - // watchedTables.forEach((watchedTable, tableIdx) => { - // console.log({ watchedTable, tableIdx }); - // }) + // checking all columns + // adding all aliases + // updating checked count + + setTimeout(() => { + console.log('------------------------------'); + console.log({ + checkedColumnsCount, + 'cell.parameters.selectedColumns.length': + cell.parameters.selectedColumns.length, + }); + // setCheckedColumnsCount(cell.parameters.selectedColumns.length); + console.log('------------------------------'); + }, 0); + // need to add joins + cell.parameters.joins.forEach((joinObject) => { + appendJoinElement(joinObject); + }); - // console.log({tablesWithCheckedBoxes, checkedColumns, columnAliasMap}); + // need to update shown tables - // console.log({"cell.parameters.selectedColumns": cell.parameters.selectedColumns}) + // issues... + // preview disabled + // joins not updating, useEffect watching count only running if not in edit mode + // preview crashing app }; const checkTableForSelectedColumns = (tableName) => { From 1beb6a01db0d1bcb65c09eeedf496000f4cba9b4 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Fri, 19 Jul 2024 15:04:41 -0700 Subject: [PATCH 39/49] feat(client): cell edits displaying and persisting when saved for tables columns and aliases --- .../data-import-cell/DataImportCell.tsx | 4 +- .../notebook/DataImportFormModal.tsx | 336 ++++++++++++------ 2 files changed, 234 insertions(+), 106 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index f33406432c..79b1c75048 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -392,13 +392,15 @@ export const DataImportCell: CellComponent = observer( return; } + alert('handleEditorChange'); + state.dispatch({ message: ActionMessages.UPDATE_CELL, payload: { queryId: cell.query.id, cellId: cell.id, path: 'parameters.selectQuery', - value: newValue, + value: 'newValue', }, }); }; diff --git a/packages/client/src/components/notebook/DataImportFormModal.tsx b/packages/client/src/components/notebook/DataImportFormModal.tsx index 5bc1f3f2bd..1865db2ad2 100644 --- a/packages/client/src/components/notebook/DataImportFormModal.tsx +++ b/packages/client/src/components/notebook/DataImportFormModal.tsx @@ -562,16 +562,16 @@ export const DataImportFormModal = observer( // region --- useEffects useEffect(() => { - if (editMode) { - console.log('useEffect watchedTables'); - if (editMode && !checkedColumnsCount) { - retrieveDatabaseTablesAndEdges(cell.parameters.databaseId); - // alert("add selected columns into useForm") - // alert("add joins into useForm") - // alert("add filters into useForm") - // alert("add summaries into useForm") - } - } + // if (editMode) { + // console.log('useEffect watchedTables'); + // if (editMode && !checkedColumnsCount) { + retrieveDatabaseTablesAndEdges(cell.parameters.databaseId); + // alert("add selected columns into useForm") + // alert("add joins into useForm") + // alert("add filters into useForm") + // alert("add summaries into useForm") + // } + // } }, []); useEffect(() => { @@ -679,97 +679,97 @@ export const DataImportFormModal = observer( // endregion /** Create a New Cell and Add to Notebook */ - // const appendCell = (widget: string) => { - // try { - // const newCellId = `${Math.floor(Math.random() * 100000)}`; - - // const config: NewCellAction['payload']['config'] = { - // widget: DefaultCells[widget].widget, - // parameters: DefaultCells[widget].parameters, - // }; - - // if (widget === DataImportCellConfig.widget) { - // config.parameters = { - // ...DefaultCells[widget].parameters, - // frameVariableName: `FRAME_${newCellId}`, - // databaseId: selectedDatabaseId, - // // selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs - // // selectQuery: pixelStringRef.current, // construct query based on useForm inputs - // selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs - // foo: 'moo', - // joins: joinElements, - // tableNames: Array.from(selectedTableNames), - // }; - // } + const appendCell = (widget: string) => { + try { + const newCellId = `${Math.floor(Math.random() * 100000)}`; + + const config: NewCellAction['payload']['config'] = { + widget: DefaultCells[widget].widget, + parameters: DefaultCells[widget].parameters, + }; + + if (widget === DataImportCellConfig.widget) { + config.parameters = { + ...DefaultCells[widget].parameters, + frameVariableName: `FRAME_${newCellId}`, + databaseId: selectedDatabaseId, + // selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs + // selectQuery: pixelStringRef.current, // construct query based on useForm inputs + selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs + foo: 'moo', + joins: joinElements, + tableNames: Array.from(selectedTableNames), + }; + } - // if (widget === QueryImportCellConfig.widget) { - // config.parameters = { - // ...DefaultCells[widget].parameters, - // frameVariableName: `FRAME_${newCellId}`, - // }; - // } + if (widget === QueryImportCellConfig.widget) { + config.parameters = { + ...DefaultCells[widget].parameters, + frameVariableName: `FRAME_${newCellId}`, + }; + } - // if ( - // previousCellId && - // state.queries[query.id].cells[previousCellId].widget === - // widget && - // widget === CodeCellConfig.widget - // ) { - // const previousCellType = - // state.queries[query.id].cells[previousCellId].parameters - // ?.type ?? 'pixel'; - // config.parameters = { - // ...DefaultCells[widget].parameters, - // type: previousCellType, - // }; - // } + if ( + previousCellId && + state.queries[query.id].cells[previousCellId].widget === + widget && + widget === CodeCellConfig.widget + ) { + const previousCellType = + state.queries[query.id].cells[previousCellId].parameters + ?.type ?? 'pixel'; + config.parameters = { + ...DefaultCells[widget].parameters, + type: previousCellType, + }; + } - // // copy and add the step - // state.dispatch({ - // message: ActionMessages.NEW_CELL, - // payload: { - // queryId: query.id, - // cellId: newCellId, - // previousCellId: previousCellId, - // config: config as Omit, - // }, - // }); - // notebook.selectCell(query.id, newCellId); - // } catch (e) { - // console.error(e); - // } - // }; + // copy and add the step + state.dispatch({ + message: ActionMessages.NEW_CELL, + payload: { + queryId: query.id, + cellId: newCellId, + previousCellId: previousCellId, + config: config as Omit, + }, + }); + notebook.selectCell(query.id, newCellId); + } catch (e) { + console.error(e); + } + }; /** Construct a Raw SQL String for Data Import --- remove */ - // const constructSQLString = ({ submitData }) => { - // console.log({ submitData }); - // let newSQLString = 'SELECT '; - - // newSQLString += submitData.columns - // .filter((ele) => ele.checked) - // .map((colObj) => { - // if (colObj.columnName === colObj.userAlias) { - // return colObj.columnName; - // } else { - // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - // } - // }) - // .join(', '); + const constructSQLString = ({ submitData }) => { + console.log({ submitData }); + let newSQLString = 'SELECT '; - // newSQLString += ` FROM ${submitData.tableSelect}`; - // newSQLString += ';'; + newSQLString += submitData.columns + .filter((ele) => ele.checked) + .map((colObj) => { + if (colObj.columnName === colObj.userAlias) { + return colObj.columnName; + } else { + return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + } + }) + .join(', '); - // if ( - // selectedLeftTable && - // selectedRightTable && - // selectedLeftKey && - // selectedRightKey - // ) { - // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - // } + newSQLString += ` FROM ${submitData.tableSelect}`; + newSQLString += ';'; - // importDataSQLStringRef.current = newSQLString; - // }; + if ( + selectedLeftTable && + selectedRightTable && + selectedLeftKey && + selectedRightKey + ) { + newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + } + + importDataSQLStringRef.current = newSQLString; + }; /** Construct Submit Pixel for Data Import --- remove? */ const constructDataBasePixel = ({ submitData }) => { @@ -846,21 +846,71 @@ export const DataImportFormModal = observer( // TODO: check all columns from table }; + const updateSubmitDispatches = () => { + const currTableNamesSet = retrieveSelectedTableNames(); + const currTableNames = Array.from(currTableNamesSet); + + const currSelectedColumns = retrieveSelectedColumnNames(); + const currColumnAliases = retrieveColumnAliasNames(); + + console.log({ + currTableNames, + currSelectedColumns, + currColumnAliases, + }); + + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.tableNames', + value: currTableNames, + }, + }); + + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.selectedColumns', + value: currSelectedColumns, + }, + }); + + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.columnAliases', + value: currColumnAliases, + }, + }); + + // #TODO + // still need to rebuild and update queryString + // still need to fix and update joins + // still need to add filters and summaries + }; + /** New Submit for Import Data --- empty */ const onImportDataSubmit = (data: NewFormData) => { if (editMode) { - alert('edit onImportDataSubmit'); + console.log({ editModeData: data }); + updateSubmitDispatches(); + // #TODO + // preview needs to be fixed + // instead of appending cell it will have to be updated + } else { + constructSQLString({ submitData: data }); + retrievePreviewData(); + appendCell('data-import'); } - // constructSQLString({ submitData }); - - // preview needs to be fixed - // retrievePreviewData(); - - // instead of appending cell it will have to be updated - // appendCell('data-import'); + closeImportModalHandler(); setIsDataImportModalOpen(false); - // closeImportModalHandler(); }; /** Close and Reset Import Data Form Modal */ @@ -1039,6 +1089,84 @@ export const DataImportFormModal = observer( setIsInitLoadComplete(true); }; + const retrieveColumnAliasNames = () => { + // const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = []; + const pixelColumnAliases = []; + // const pixelJoins = []; + + watchedTables?.forEach((tableObject) => { + const currTableName = tableObject.name; + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + // setSelectedTableNames(pixelTables); + return pixelColumnAliases; + }; + + const retrieveSelectedColumnNames = () => { + // const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = []; + const pixelColumnAliases = []; + // const pixelJoins = []; + + watchedTables?.forEach((tableObject) => { + const currTableName = tableObject.name; + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + // setSelectedTableNames(pixelTables); + return pixelColumnNames; + }; + + const retrieveSelectedTableNames = () => { + // const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = []; + const pixelColumnAliases = []; + // const pixelJoins = []; + + watchedTables?.forEach((tableObject) => { + const currTableName = tableObject.name; + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + // setSelectedTableNames(pixelTables); + return pixelTables; + }; + const updateSelectedTables = () => { // const databaseId = selectedDatabaseId; const pixelTables = new Set(); @@ -1062,6 +1190,7 @@ export const DataImportFormModal = observer( }); setSelectedTableNames(pixelTables); + // return pixelTables; }; /** Old Get All Database Tables for Import Data --- remove? */ @@ -1149,10 +1278,7 @@ export const DataImportFormModal = observer( }); }); - console.log(joinsSet); - Array.from(joinsSet).forEach((joinEle: string) => { - console.log({ joinEle }); const splitJoinsString = joinEle.split(':'); pixelJoins.push( `( ${splitJoinsString[0]} , inner.join , ${splitJoinsString[1]} )`, From 5fbae6cea404b92f23c83e6ad2748ffabacfca0d Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 31 Jul 2024 10:31:11 -0700 Subject: [PATCH 40/49] feat(client): reset and re add changes from local branch add and edit working --- .../data-import-cell/DataImportCell.tsx | 10 +- .../cell-defaults/data-import-cell/config.ts | 21 +- .../notebook/DataImportFormModal.tsx | 1129 ++--------------- .../components/notebook/NotebookAddCell.tsx | 5 +- 4 files changed, 92 insertions(+), 1073 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index 79b1c75048..a615769642 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -228,6 +228,8 @@ export interface DataImportCellDef extends CellDef<'data-import'> { columnAliases: string[]; + rootTable: string; + // filters: FilterObject[]; // summaries: FilterObject[]; }; @@ -406,11 +408,6 @@ export const DataImportCell: CellComponent = observer( }; const openEditModal = () => { - console.log({ - databaseId: cell.parameters.databaseId, - tableNames: cell.parameters.tableNames, - joins: cell.parameters.joins, - }); setIsDataImportModalOpen(true); }; @@ -626,8 +623,7 @@ export const DataImportCell: CellComponent = observer( scrollbar: { alwaysConsumeMouseWheel: false, }, - readOnly: false, - // readOnly: true, + readOnly: true, minimap: { enabled: false }, automaticLayout: true, scrollBeyondLastLine: false, diff --git a/packages/client/src/components/cell-defaults/data-import-cell/config.ts b/packages/client/src/components/cell-defaults/data-import-cell/config.ts index c78b06969c..c15605703e 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/config.ts +++ b/packages/client/src/components/cell-defaults/data-import-cell/config.ts @@ -14,6 +14,7 @@ export const DataImportCellConfig: CellConfig = { tableNames: [], selectedColumns: [], columnAliases: [], + rootTable: '', // filters: [], }, toPixel: ({ @@ -24,32 +25,14 @@ export const DataImportCellConfig: CellConfig = { joins, selectedColumns, columnAliases, + rootTable, }) => { - // this only runs when the cell runs - // it will check the frame type and variable name which the user could change - // so NotebookAddCell should track the static first part of the pixel with db id / cols and add Meta | Frame() etc without the import and var name - // then when this runs it can add the Import(...); Meta ...; with the right frametype and varname - - // old not working syntax const splitPixelString = selectQuery.split(';'); const pixelAddition = ` | Import ( frame = [ CreateFrame ( frameType = [ ${frameType} ] , override = [ true ] ) .as ( [ \"${frameVariableName}\" ] ) ] ) `; splitPixelString[0] = splitPixelString[0] + pixelAddition; - const newPixelString = splitPixelString.join(';'); - // return newPixelString; - - // new partially working syntax const pixelImportString = ` | Import ( frame = [ CreateFrame ( frameType = [ ${frameType} ] , override = [ true ] ) .as ( [ \"${frameVariableName}\" ] ) ] ) ; `; - // const pixelMetaString = ` META | Frame() | QueryAll() | Limit(50) | Collect(500);`; - // const combinedPixelString = selectQuery.slice(0, -1) + pixelImportString + pixelMetaString; const combinedPixelString = selectQuery.slice(0, -1) + pixelImportString; - - console.log({ combinedPixelString }); - return combinedPixelString; - - // const firstPixel = `${splitPixelString[0]};`; - // const pixelString = `${selectQuery} Import ( frame = [ CreateFrame ( frameType=[${frameType}] , override = [ true ] ) .as ( ["${frameVariableName}"] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);` - return `Database( database=["${databaseId}"] ) | Query("${selectQuery}") | Import(frame=[CreateFrame(frameType=[${frameType}], override=[true]).as(["${frameVariableName}"])]);`; }, }; diff --git a/packages/client/src/components/notebook/DataImportFormModal.tsx b/packages/client/src/components/notebook/DataImportFormModal.tsx index 1865db2ad2..700bbd243e 100644 --- a/packages/client/src/components/notebook/DataImportFormModal.tsx +++ b/packages/client/src/components/notebook/DataImportFormModal.tsx @@ -70,6 +70,7 @@ import { LoadingScreen } from '@/components/ui'; import { runPixel } from '@/api'; import { TableContainer, alertTitleClasses } from '@mui/material'; +import { debug } from 'console'; // region --- Styled Elements @@ -310,78 +311,6 @@ type NewFormValues = { // region --- Transformations / Options / Constants -// const Transformations = Array.from(Object.values(TransformationCells)).map( -// (item) => { -// return { -// display: item.name, -// defaultCellType: item.widget, -// }; -// }, -// ); - -// const DataImportDropdownOptions = [ -// { -// display: `From Data Catalog`, -// defaultCellType: null, -// }, -// { -// display: `From CSV`, -// defaultCellType: null, -// }, -// ]; - -// const AddCellOptions: Record = { -// code: { -// display: 'Cell', -// defaultCellType: 'code', -// icon: , -// }, -// 'query-import': { -// display: 'Query Import', -// defaultCellType: 'query-import', -// // no DB MUI icon using the icon path from main menu -// icon: ( -// -// -// -// -// -// -// -// -// -// -// ), -// }, -// transformation: { -// display: 'Transformation', -// icon: , -// options: Transformations, -// }, -// 'import-data': { -// display: 'Import Data', -// icon: , -// options: DataImportDropdownOptions, -// disabled: false, -// }, -// text: { -// display: 'Text', -// icon: , -// disabled: true, -// }, -// }; - const IMPORT_MODAL_WIDTHS = { small: '600px', medium: '1150px', @@ -413,13 +342,7 @@ export const DataImportFormModal = observer( const [selectedAddCell, setSelectedAddCell] = useState(''); const [importModalType, setImportModalType] = useState(''); - // needed for new cell? incoming as prop for edit? - // const [isDataImportModalOpen, setIsDataImportModalOpen] = - // useState(false); const open = Boolean(anchorEl); - - // needed for new cell? incoming as prop for edit? - // const { query, previousCellId = '' } = props; const { state, notebook } = useBlocks(); // Old useForm for Data Import --- remove @@ -488,25 +411,29 @@ export const DataImportFormModal = observer( const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } const aliasesCountObjRef = useRef({}); // { emailAlias: 1, phoneAlias: 2 } const [tableEdges, setTableEdges] = useState({}); // - const [rootTable, setRootTable] = useState(null); + const [rootTable, setRootTable] = useState( + cell ? cell.parameters.rootTable : null, + ); const [checkedColumnsCount, setCheckedColumnsCount] = useState(0); const [shownTables, setShownTables] = useState(new Set()); const [selectedTableNames, setSelectedTableNames] = useState(new Set()); - const [joinsSet, setJoinsSet] = useState(new Set()); // Set({ "USERS_TABLE:VISNS_TABLE" }) + const [joinsSet, setJoinsSet] = useState(new Set()); const [pixelString, setPixelString] = useState(''); const pixelStringRef = useRef(''); const pixelStringRefPart1 = useRef(''); const [isInitLoadComplete, setIsInitLoadComplete] = useState(false); + const [initEditPrepopulateComplete, setInitEditPrepopulateComplete] = + useState(editMode ? false : true); // endregion // region --- Import Data Old useFieldArrays const { - fields: stackFields, + fields: _stackFields, append: appendStack, remove: removeStack, } = useFieldArray({ @@ -515,7 +442,7 @@ export const DataImportFormModal = observer( }); const { - fields: editableColumnFields, + fields: _editableColumnFields, append: appendEditableColumns, remove: removeEditableColumns, } = useFieldArray({ @@ -524,9 +451,9 @@ export const DataImportFormModal = observer( }); const { - fields: tableFields, - append: appendEditableTableColumns, - remove: removeEditableTableColumns, + fields: _tableFields, + append: _appendEditableTableColumns, + remove: _removeEditableTableColumns, } = useFieldArray({ control, name: 'tables', @@ -536,13 +463,10 @@ export const DataImportFormModal = observer( // region --- Import Data New useFieldArray - // ### only one field array is necessary? - // do each of these need a field array for the columns? - const { fields: newTableFields, - append: newTableAppend, - remove: newTableRemove, + append: _newTableAppend, + remove: _newTableRemove, } = useFieldArray({ control: newControl, name: 'tables', @@ -562,22 +486,10 @@ export const DataImportFormModal = observer( // region --- useEffects useEffect(() => { - // if (editMode) { - // console.log('useEffect watchedTables'); - // if (editMode && !checkedColumnsCount) { - retrieveDatabaseTablesAndEdges(cell.parameters.databaseId); - // alert("add selected columns into useForm") - // alert("add joins into useForm") - // alert("add filters into useForm") - // alert("add summaries into useForm") - // } - // } + if (editMode) + retrieveDatabaseTablesAndEdges(cell.parameters.databaseId); }, []); - useEffect(() => { - console.log({ joinElements }); - }, [joinElements]); - useEffect(() => { setSelectedLeftKey(null); setSelectedRightKey(null); @@ -586,10 +498,6 @@ export const DataImportFormModal = observer( }, [selectedDatabaseId, selectedTable]); useEffect(() => { - // alert("useEffect selectedDatabaseId") - // console.log(cell.parameters.databaseId) - // console.log(selectedDatabaseId); - removeEditableColumns(); removeStack(); setShowTablePreview(false); @@ -597,12 +505,12 @@ export const DataImportFormModal = observer( }, [selectedDatabaseId]); useEffect(() => { - // $$$ if ( editMode && checkedColumnsCount == 0 && cell.parameters.databaseId == selectedDatabaseId && - newTableFields.length + newTableFields.length && + !initEditPrepopulateComplete ) { prepoulateFormForEdit(cell); } @@ -630,8 +538,7 @@ export const DataImportFormModal = observer( }, [getDatabases.status, getDatabases.data]); useEffect(() => { - // if any change occurs with checkboxes reassess all joins to display - if (!editMode) { + if (!editMode || initEditPrepopulateComplete) { setJoinsStackHandler(); updateSelectedTables(); } @@ -650,34 +557,6 @@ export const DataImportFormModal = observer( // endregion - // region --- cellTypeOptions unused / remove? - // const cellTypeOptions = computed(() => { - // alert("test23") - // const options = { ...AddCellOptions }; - // // transformation cell types can only be added if there exists a query-import cell before it - // if (!previousCellId) { - // delete options['transformation']; - // } else { - // const previousCellIndex = query.list.indexOf(previousCellId); - // let hasFrameVariable = false; - // for (let index = 0; index <= previousCellIndex; index++) { - // if ( - // query.cells[query.list[index]].config.widget === - // 'query-import' - // ) { - // hasFrameVariable = true; - // break; - // } - // } - // if (!hasFrameVariable) { - // delete options['transformation']; - // } - // } - - // return Object.values(options); - // }).get(); - // endregion - /** Create a New Cell and Add to Notebook */ const appendCell = (widget: string) => { try { @@ -693,9 +572,7 @@ export const DataImportFormModal = observer( ...DefaultCells[widget].parameters, frameVariableName: `FRAME_${newCellId}`, databaseId: selectedDatabaseId, - // selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs - // selectQuery: pixelStringRef.current, // construct query based on useForm inputs - selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs + selectQuery: pixelStringRefPart1.current, foo: 'moo', joins: joinElements, tableNames: Array.from(selectedTableNames), @@ -724,7 +601,6 @@ export const DataImportFormModal = observer( }; } - // copy and add the step state.dispatch({ message: ActionMessages.NEW_CELL, payload: { @@ -740,9 +616,8 @@ export const DataImportFormModal = observer( } }; - /** Construct a Raw SQL String for Data Import --- remove */ + /** Construct a Raw SQL String for Data Import */ const constructSQLString = ({ submitData }) => { - console.log({ submitData }); let newSQLString = 'SELECT '; newSQLString += submitData.columns @@ -771,47 +646,8 @@ export const DataImportFormModal = observer( importDataSQLStringRef.current = newSQLString; }; - /** Construct Submit Pixel for Data Import --- remove? */ + /** Construct SQL Pixel for Data Import */ const constructDataBasePixel = ({ submitData }) => { - // // mimic this pixel structure instead of constructing raw SQL ? - // // or have join autoselect keys and add columns to edit - // // that makes sense with new pixel structure - // // show all tables and selectable rows in edit columns view - // // find way of showing alerts for un joinable columns - // // add form structure to json state (?) - // // make basic non SQL view for notebook cell - // // make edit window - - // // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | - - // // Select ( - // // STATION_SETTINGS__ROLE , - // // USER_SETTINGS__DATE_CREATED , - // // VISN_SETTINGS__EMAIL , - // // VISN_SETTINGS__USER , - // // VISN_SETTINGS__VISN ) - // // .as ( [ - // // ROLE , - // // DATE_CREATED , - // // EMAIL , - // // USER , - // // VISN - // // ] ) | - - // // Join ( ( - // // USER_SETTINGS , - // // inner.join , - // // STATION_SETTINGS - // // ) , ( - // // USER_SETTINGS , - // // inner.join , - // // VISN_SETTINGS - // // ) ) | - - // // Distinct ( false ) | - - // // QueryRowCount ( ) ;", - console.log({ submitData }); let newSQLString = 'SELECT '; newSQLString += submitData.columns @@ -842,7 +678,6 @@ export const DataImportFormModal = observer( /** Add all the columns from a Table */ const addAllTableColumnsHandler = (event) => { - alert('add all'); // TODO: check all columns from table }; @@ -853,12 +688,6 @@ export const DataImportFormModal = observer( const currSelectedColumns = retrieveSelectedColumnNames(); const currColumnAliases = retrieveColumnAliasNames(); - console.log({ - currTableNames, - currSelectedColumns, - currColumnAliases, - }); - state.dispatch({ message: ActionMessages.UPDATE_CELL, payload: { @@ -889,20 +718,42 @@ export const DataImportFormModal = observer( }, }); - // #TODO - // still need to rebuild and update queryString - // still need to fix and update joins - // still need to add filters and summaries + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.joins', + value: joinElements, + }, + }); + + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.rootTable', + value: rootTable, + }, + }); + + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.selectQuery', + value: pixelStringRefPart1.current, + }, + }); }; /** New Submit for Import Data --- empty */ const onImportDataSubmit = (data: NewFormData) => { if (editMode) { - console.log({ editModeData: data }); + retrievePreviewData(); updateSubmitDispatches(); - // #TODO - // preview needs to be fixed - // instead of appending cell it will have to be updated } else { constructSQLString({ submitData: data }); retrievePreviewData(); @@ -933,7 +784,6 @@ export const DataImportFormModal = observer( setIsDatabaseLoading(true); const pixelString = `META|GetDatabaseTableStructure(database=[ \"${databaseId}\" ]);META|GetDatabaseMetamodel( database=[ \"${databaseId}\" ], options=["dataTypes","positions"]);`; - // const pixelResponse = await runPixel(pixelString); monolithStore.runQuery(pixelString).then((pixelResponse) => { const responseTableStructure = pixelResponse.pixelReturn[0].output; @@ -951,9 +801,7 @@ export const DataImportFormModal = observer( let newTableNames = []; - // populate database structure if (isResponseTableStructureGood) { - console.log({ responseTableStructure }); newTableNames = [ ...responseTableStructure.reduce((set, ele) => { set.add(ele[0]); @@ -966,7 +814,6 @@ export const DataImportFormModal = observer( const tableName = ele[0]; const columnName = ele[1]; const columnType = ele[2]; - // other info seems to not be needed, unsure what flag is representing or if repeat names are aliases etc const columnBoolean = ele[3]; const columnName2 = ele[4]; const tableName2 = ele[4]; @@ -979,7 +826,7 @@ export const DataImportFormModal = observer( columnBoolean, columnName2, tableName2, - userAlias: columnName, // user editable in Edit Columns + userAlias: columnName, checked: true, }); @@ -1013,11 +860,6 @@ export const DataImportFormModal = observer( console.error('Error retrieving database tables'); } - // set visible tables set to all tables - setTableNames(newTableNames); - setShownTables(new Set(newTableNames)); - - // make and populate new edges dict if (isResponseTableEdgesStructureGood) { const newEdgesDict = responseTableEdgesStructure.edges.reduce((acc, ele) => { @@ -1061,11 +903,9 @@ export const DataImportFormModal = observer( console.error('Error retrieving database edges'); } - // store edges in useState const edges = pixelResponse.pixelReturn[1].output.edges; const newTableEdges = {}; edges.forEach((edge) => { - // add edge from source direction if (newTableEdges[edge.source]) { newTableEdges[edge.source][edge.target] = edge.relation; } else { @@ -1073,7 +913,6 @@ export const DataImportFormModal = observer( [edge.target]: edge.relation, }; } - // add edge from target direction if (newTableEdges[edge.target]) { newTableEdges[edge.target][edge.source] = edge.relation; } else { @@ -1085,16 +924,25 @@ export const DataImportFormModal = observer( setTableEdges(newTableEdges); setIsDatabaseLoading(false); setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.large); + + setTableNames(newTableNames); + if (editMode) { + const newEdges = [ + rootTable, + ...Object.keys(newTableEdges[rootTable]), + ]; + setShownTables(new Set(newEdges)); + } else { + setShownTables(new Set(newTableNames)); + } }); setIsInitLoadComplete(true); }; const retrieveColumnAliasNames = () => { - // const databaseId = selectedDatabaseId; const pixelTables = new Set(); const pixelColumnNames = []; const pixelColumnAliases = []; - // const pixelJoins = []; watchedTables?.forEach((tableObject) => { const currTableName = tableObject.name; @@ -1111,16 +959,13 @@ export const DataImportFormModal = observer( }); }); - // setSelectedTableNames(pixelTables); return pixelColumnAliases; }; const retrieveSelectedColumnNames = () => { - // const databaseId = selectedDatabaseId; const pixelTables = new Set(); const pixelColumnNames = []; const pixelColumnAliases = []; - // const pixelJoins = []; watchedTables?.forEach((tableObject) => { const currTableName = tableObject.name; @@ -1137,16 +982,13 @@ export const DataImportFormModal = observer( }); }); - // setSelectedTableNames(pixelTables); return pixelColumnNames; }; const retrieveSelectedTableNames = () => { - // const databaseId = selectedDatabaseId; const pixelTables = new Set(); const pixelColumnNames = []; const pixelColumnAliases = []; - // const pixelJoins = []; watchedTables?.forEach((tableObject) => { const currTableName = tableObject.name; @@ -1163,16 +1005,13 @@ export const DataImportFormModal = observer( }); }); - // setSelectedTableNames(pixelTables); return pixelTables; }; const updateSelectedTables = () => { - // const databaseId = selectedDatabaseId; const pixelTables = new Set(); const pixelColumnNames = []; const pixelColumnAliases = []; - // const pixelJoins = []; watchedTables?.forEach((tableObject) => { const currTableName = tableObject.name; @@ -1190,73 +1029,11 @@ export const DataImportFormModal = observer( }); setSelectedTableNames(pixelTables); - // return pixelTables; }; - /** Old Get All Database Tables for Import Data --- remove? */ - // const retrieveDatabaseTables = async (databaseId) => { - // setIsDatabaseLoading(true); - // const pixelString = `META | GetDatabaseTableStructure ( database = [ \"${databaseId}\" ] ) ;`; - - // monolithStore.runQuery(pixelString).then((response) => { - // const type = response.pixelReturn[0].operationType; - // const pixelResponse = response.pixelReturn[0].output; - - // if (type.indexOf('ERROR') === -1) { - // const tableNames = [ - // ...pixelResponse.reduce((set, ele) => { - // set.add(ele[0]); - // return set; - // }, new Set()), - // ]; - - // const newTableColumnsObject = pixelResponse.reduce( - // (acc, ele, idx) => { - // const tableName = ele[0]; - // const columnName = ele[1]; - // const columnType = ele[2]; - // // other info seems to not be needed, unsure what flag is representing or if repeat names are aliases etc - // const columnBoolean = ele[3]; - // const columnName2 = ele[4]; - // const tableName2 = ele[4]; - - // if (!acc[tableName]) acc[tableName] = []; - // acc[tableName].push({ - // tableName, - // columnName, - // columnType, - // columnBoolean, - // columnName2, - // tableName2, - // userAlias: columnName, // user editable in Edit Columns - // checked: true, - // }); - - // return acc; - // }, - // {}, - // ); - - // setTableColumnsObject(newTableColumnsObject); - // setTableNames(tableNames); - // } else { - // console.error('Error retrieving database tables'); - // } - - // setIsDatabaseLoading(false); - // }); - // }; - - /** Old Select Tables for Import Data --- remove? */ - // const selectTableHandler = (tableName) => { - // setSelectedTable(tableName); - // retrieveTableRows(tableName); - // }; - const retrievePreviewData = async () => { setIsDatabaseLoading(true); - // run database rows reactor const databaseId = selectedDatabaseId; const pixelTables = new Set(); const pixelColumnNames = []; @@ -1285,7 +1062,6 @@ export const DataImportFormModal = observer( ); }); - // when constructing final pixel string seperate all these with '|' let pixelStringPart1 = `Database ( database = [ \"${databaseId}\" ] )`; pixelStringPart1 += ` | Select ( ${pixelColumnNames.join(' , ')} )`; pixelStringPart1 += `.as ( [ ${pixelColumnAliases.join(' , ')} ] )`; @@ -1294,52 +1070,23 @@ export const DataImportFormModal = observer( } pixelStringPart1 += ` | Distinct ( false ) | Limit ( 20 )`; - // seperated Import out so frame can construct this independently from preview const pixelStringPart2 = ` | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; const pixelStringPart3 = ` ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; - // const combinedPixelString = - // pixelStringPart1 + pixelStringPart2 + ' ; ' + pixelStringPart3; - - // // const joinsPixelString = pixelJoins.length > 0 ? `Join ( ${pixelJoins.join(' , ')} ) ` : null; - // // const distinctPixelString = `Distinct ( false ) | Limit ( 20 )`; - // // const importPixelString = `Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; - // // // when constructing string seperate META with ';' - // // const metaPixelString = `META | Frame() | QueryAll() | Limit(50) | Collect(500)` - // // // add ';' at end of final pixel string - - // // const pixelStringObject = { - // // databasePixelString, - // // selectPixelString, - // // aliasPixelString, - // // joinsPixelString, - // // distinctPixelString, - // // limitPixelString, - // // importPixelString, - // // metaPixelString, - // // } - const combinedJoinString = pixelJoins.length > 0 ? `| Join ( ${pixelJoins.join(' , ')} ) ` : ''; - // const testReactorPixel = - // 'Database ( database = [ "f9b656cc-06e7-4cce-bae8-b5f92075b6da" ] ) | Select ( STATION_SETTINGS__EMAIL , USER_SETTINGS__PHONE ) .as ( [ EMAIL , PHONE ] ) | Join ( ( USER_SETTINGS , inner.join , STATION_SETTINGS ) ) | Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ "consolidated_settings_FRAME932867__Preview" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);'; const reactorPixel = `Database ( database = [ \"${databaseId}\" ] ) | Select ( ${pixelColumnNames.join( ' , ', )} ) .as ( [ ${pixelColumnAliases.join( ' , ', - // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | `; // end of reactor string is added in cell-defaults/data-import/config.ts to incorporate correct frame variable name )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; - // )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ); META | Frame() | QueryAll() | Limit(50) | Collect(500);`; - // ## TODO fix variable import pixel syntax, currently including db name for some reason - // these might not be needed with new part1 ref setPixelString(reactorPixel); pixelStringRef.current = reactorPixel; - // this ref is for the form submit pixelStringRefPart1.current = pixelStringPart1 + ';'; await monolithStore.runQuery(reactorPixel).then((response) => { @@ -1363,50 +1110,6 @@ export const DataImportFormModal = observer( }); }; - /** Old Select Tables for Import Data --- unused / remove? */ - // const retrieveTableRows = async (tableName) => { - // setIsDatabaseLoading(true); - // const selectStringArray = tableColumnsObject[tableName].map( - // (ele) => `${ele.tableName}__${ele.columnName}`, - // ); - - // const selectString = selectStringArray.join(', '); - // const aliasString = tableColumnsObject[tableName] - // .map( - // (ele) => `${ele.columnName}`, // may need to switch to ele.columnName2 but they seem to be identical - // ) - // .join(', '); - - // const limit = 10; // may want this to be a changeable useState variable - // const pixelString = `Database(database=[\"${selectedDatabaseId}\"])|Select(${selectString}).as([${aliasString}])|Distinct(false)|Limit(${limit})|Import(frame=[CreateFrame(frameType=[GRID],override=[true]).as([\"consolidated_settings_FRAME961853__Preview\"])]); META | Frame() | QueryAll() | Limit(${limit}) | Collect(500);`; - - // await monolithStore.runQuery(pixelString).then((response) => { - // const type = response.pixelReturn[0].operationType; - // const tableHeadersData = - // response.pixelReturn[1].output.data.headers; - // const tableRawHeadersData = - // response.pixelReturn[1].output.data.rawHeaders; - // const tableRowsData = - // response.pixelReturn[1].output.data.values; - - // console.log({ - // tableHeadersData, - // tableRawHeadersData, - // tableRowsData, - // }); - - // setDatabaseTableHeaders(tableHeadersData); - // setDatabaseTableRawHeaders(tableRawHeadersData); - // setDatabaseTableRows(tableRowsData); - - // if (type.indexOf('ERROR') != -1) { - // console.error('Error retrieving database tables'); - // } - - // setIsDatabaseLoading(false); - // }); - // }; - /** Helper Function Update Alias Tracker Object*/ const updateAliasCountObj = ( isBeingAdded, @@ -1414,18 +1117,15 @@ export const DataImportFormModal = observer( oldAlias = null, ) => { const newAliasesCountObj = { ...aliasesCountObj }; - - console.log({ isBeingAdded, newAlias, oldAlias }); - if (isBeingAdded) { - if (newAliasesCountObj[newAlias]) { + if (newAliasesCountObj[newAlias] > 0) { newAliasesCountObj[newAlias] = newAliasesCountObj[newAlias] + 1; } else { newAliasesCountObj[newAlias] = 1; } } else { - if (newAliasesCountObj[newAlias]) { + if (newAliasesCountObj[newAlias] > 0) { newAliasesCountObj[newAlias] = newAliasesCountObj[newAlias] - 1; } else { @@ -1436,20 +1136,18 @@ export const DataImportFormModal = observer( if (newAliasesCountObj[newAlias] < 1) { delete newAliasesCountObj[newAlias]; } - - if (oldAlias) { - if (newAliasesCountObj[oldAlias]) { + if (oldAlias != null) { + if (newAliasesCountObj[oldAlias] > 0) { newAliasesCountObj[oldAlias] = - newAliasesCountObj[newAlias] - 1; + newAliasesCountObj[oldAlias] - 1; } else { newAliasesCountObj[oldAlias] = 0; } + if (newAliasesCountObj[oldAlias] < 1) { delete newAliasesCountObj[oldAlias]; } } - - console.log({ newAliasesCountObj }); setAliasesCountObj(newAliasesCountObj); aliasesCountObjRef.current = { ...newAliasesCountObj }; }; @@ -1459,14 +1157,7 @@ export const DataImportFormModal = observer( const joinableTables = tableEdges[rootTableName] ? Object.keys(tableEdges[rootTableName]) : []; - console.log({ - rootTableName, - tableEdges, - joinableTables, - 'tableEdges[rootTableName]': tableEdges[rootTableName], - }); const newShownTables = new Set([...joinableTables, rootTableName]); - // debugger; setShownTables(newShownTables); }; @@ -1487,8 +1178,10 @@ export const DataImportFormModal = observer( } setCheckedColumnsCount(checkedColumnsCount - 1); } + setJoinsStackHandler(); }; + /** Pre-Populate form For Edit */ const prepoulateFormForEdit = (cell) => { const tablesWithCheckedBoxes = new Set(); const checkedColumns = new Set(); @@ -1496,7 +1189,6 @@ export const DataImportFormModal = observer( const newAliasesCountObj = {}; setCheckedColumnsCount(cell.parameters.selectedColumns.length); - // checkedColumnsCountRef cell.parameters.selectedColumns.forEach( (selectedColumnTableCombinedString, idx) => { @@ -1512,7 +1204,7 @@ export const DataImportFormModal = observer( ); setAliasesCountObj({ ...newAliasesCountObj }); - aliasesCountObjRef.current = { ...newAliasesCountObj }; // is this needed? + aliasesCountObjRef.current = { ...newAliasesCountObj }; if (newTableFields) { newTableFields.forEach((newTableObj, tableIdx) => { @@ -1525,9 +1217,6 @@ export const DataImportFormModal = observer( if (checkedColumns.has(columnName)) { const columnAlias = columnAliasMap[columnName]; - console.log( - `${columnName} / ${columnAlias} is checked`, - ); newSetValue( `tables.${tableIdx}.columns.${columnIdx}.checked`, true, @@ -1543,31 +1232,17 @@ export const DataImportFormModal = observer( }); } - // checking all columns - // adding all aliases - // updating checked count - - setTimeout(() => { - console.log('------------------------------'); - console.log({ - checkedColumnsCount, - 'cell.parameters.selectedColumns.length': - cell.parameters.selectedColumns.length, - }); - // setCheckedColumnsCount(cell.parameters.selectedColumns.length); - console.log('------------------------------'); - }, 0); - // need to add joins + const newJoinsSet = new Set(); cell.parameters.joins.forEach((joinObject) => { appendJoinElement(joinObject); + const joinsSetString1 = `${joinObject.leftTable}:${joinObject.rightTable}`; + const joinsSetString2 = `${joinObject.rightTable}:${joinObject.leftTable}`; + newJoinsSet.add(joinsSetString1); + newJoinsSet.add(joinsSetString2); }); - // need to update shown tables - - // issues... - // preview disabled - // joins not updating, useEffect watching count only running if not in edit mode - // preview crashing app + setJoinsSet(newJoinsSet); + setCheckedColumnsCount(checkedColumns.size); }; const checkTableForSelectedColumns = (tableName) => { @@ -1595,7 +1270,6 @@ export const DataImportFormModal = observer( tableEdgesObject && Object.entries(tableEdgesObject[rootTable]); - // addresses crash for dbs with only one table / no edges rightTables?.forEach((entry, joinIdx) => { const rightTable = entry[0]; const leftKey = entry[1]['sourceColumn']; @@ -1645,55 +1319,16 @@ export const DataImportFormModal = observer( } }); } + + setInitEditPrepopulateComplete(true); }; const addToJoinsSetHelper = (newJoinSet) => { const joinsSetCopy = new Set(joinsSet); joinsSetCopy.add(newJoinSet); setJoinsSet(joinsSetCopy); - console.log({ joinsSetCopy }); }; - // return ( - // - // - //
- // {cell.parameters.databaseId} - //

TABLE NAMES

- // {cell.parameters.tableNames?.map((tableName, idx) => ( - //
{tableName}
- // ))} - //

JOINS

- // {cell.parameters.joins?.map((join, idx) => ( - //
- // {join.leftTable} ({join.joinType}){join.rightTable} ON - // {join.leftKey} ={join.rightKey} - //
- // ))} - //

SELECTED COLUMNS

- // {cell.parameters.selectedColumns?.map((column, idx) => ( - //
{column}
- // ))} - //

ALIASES

- // {cell.parameters.columnAliases?.map((alias, idx) => ( - //
{alias}
- // ))} - // {/* need the selected columns */} - // {/* need the column aliases */} - // {/* need the filters */} - // {/* {cell.parameters.summaries} */} - // - //
- //
- //
- // ); - return ( @@ -1830,7 +1465,6 @@ export const DataImportFormModal = observer(
- {/* using conditional rendering for each table but if bugs persists set state for showntables in checkbox handler */} {shownTables.has( table.name, ) && ( @@ -2067,7 +1701,6 @@ export const DataImportFormModal = observer( .target .value, ); - // unclear what desired effect is }} value={ field.value || @@ -2182,7 +1815,6 @@ export const DataImportFormModal = observer( )} - {/* stack for user-added joins filters and summaries */} {joinElements.map((join, stackIndex) => (
- {/*
- { - removeStack(stackIndex); - }} - > - - -
*/} - - {/* {showEditColumns && ( */} - {/* {false && ( - - - Edit Columns - - - - - - - { - setCheckAllColumns( - !checkAllColumns, - ); - const hiddenColumnIdsSetDup = - new Set(); - if ( - checkAllColumns == - false - ) { - editableColumnFields.forEach( - ( - field, - index, - ) => { - // not working need to use setValue - field.checked = - true; - console.log( - { - index, - field, - }, - ); - hiddenColumnIdsSetDup.add( - index, - ); - }, - ); - } else { - editableColumnFields.forEach( - ( - field, - index, - ) => { - // not working need to use setValue - field.checked = - false; - console.log( - { - index, - field, - }, - ); - hiddenColumnIdsSetDup.delete( - index, - ); - }, - ); - } - setHiddenColumnIdsSet( - hiddenColumnIdsSetDup, - ); - }} - color={ - checkAllColumns - ? 'primary' - : 'secondary' - } - sx={{ - marginLeft: - '-10px', - }} - > - - - - - - Fields - - - - - Alias - - - - - Field Type - - - - - {editableColumnFields?.map( - (field, index) => ( - - - ( - { - field.onChange( - e, - ); - const hiddenColumnIdsSetDup = - new Set( - [ - ...hiddenColumnIdsSet, - ], - ); - if ( - field.value == - true - ) { - hiddenColumnIdsSetDup.add( - index, - ); - } else { - hiddenColumnIdsSetDup.delete( - index, - ); - } - - console.log( - { - hiddenColumnIdsSetDup, - editableColumnFields, - }, - ); - - if ( - hiddenColumnIdsSetDup.size == - 0 - ) { - setCheckAllColumns( - true, - ); - } else { - setCheckAllColumns( - false, - ); - } - - setHiddenColumnIdsSet( - hiddenColumnIdsSetDup, - ); - }} - /> - )} - /> - - - { - field.columnName - } - {field.columnName == - 'ID' && ( -
- PK -
- )} - {field.columnName.includes( - '_ID', - ) && ( -
- FK -
- )} -
- - ( - { - field.onChange( - e - .target - .value, - ); - const newTableHeaders = - [ - ...databaseTableHeaders, - ]; - newTableHeaders[ - index - ] = - e.target.value; - setDatabaseTableHeaders( - newTableHeaders, - ); - }} - /> - )} - /> - - - ( - - )} - /> - -
- ), - )} -
-
- - - - -
- )} */} - - {/* {showPreview && ( */} - {/* {false && ( - - - Preview - - - - - {databaseTableHeaders - .filter( - (v, colIdx) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map((h, hIdx) => ( - - - {h} - - - ))} - - {databaseTableRows.map( - (r, rIdx) => ( - - {r - .filter( - ( - v, - colIdx, - ) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map( - ( - v, - vIdx, - ) => ( - - { - v - } - - ), - )} - - ), - )} - -
-
- )} */} ))} @@ -2816,10 +1979,11 @@ export const DataImportFormModal = observer( !checkedColumnsCount || Object.values(aliasesCountObj).some( (key: number) => key > 1, - ) + ) || + aliasesCountObj[''] > 0 } > - Import + {editMode ? 'Update Cell' : 'Import'} @@ -2828,126 +1992,3 @@ export const DataImportFormModal = observer( ); }, ); - -// {/* */} - -// return ( -// <> -// {/* Dropdown for All Add Cell Option Sets */} - -// {/* -// -// -// {AddCellOptions && -// Object.entries(AddCellOptions).map((add, i) => { -// const value = add[1]; -// return ( -// { -// if (value.options) { -// setAnchorEl(e.currentTarget); -// setSelectedAddCell(add[0]); -// } else { -// appendCell( -// value.defaultCellType, -// ); -// } -// }} -// endIcon={ -// Array.isArray(value.options) && -// (selectedAddCell == add[0] && -// open ? ( -// -// ) : ( -// -// )) -// } -// > -// {value.display} -// -// ); -// })} -// -// -// { -// setAnchorEl(null); -// }} -// > -// {selectedAddCell === 'transformation' && -// Array.from( -// AddCellOptions[selectedAddCell]?.options || [], -// ({ display, defaultCellType }, index) => { -// return ( -// { -// appendCell(defaultCellType); -// setAnchorEl(null); -// }} -// > -// {display} -// -// ); -// }, -// )} - -// {selectedAddCell === 'import-data' && ( -// <> -// {Array.from( -// AddCellOptions[selectedAddCell]?.options || -// [], -// ({ display }, index) => { -// return ( -// { -// // loadDatabaseStructure(); -// setImportModalPixelWidth( -// IMPORT_MODAL_WIDTHS.small, -// ); -// setIsDataImportModalOpen( -// true, -// ); -// if ( -// display == -// 'From Data Catalog' -// ) { -// setImportModalType( -// display, -// ); -// } else { -// // open seperate modal / form for From CSV -// } -// setAnchorEl(null); -// }} -// > -// {display} -// -// ); -// }, -// )} -// -// )} -// -// */} - -// {/* New Import Data Modal --- stand-alone component? */} -// -// ); diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index 71e1a0562d..b640c127ce 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -558,7 +558,6 @@ export const NotebookAddCell = observer( useEffect(() => { removeEditableColumns(); tableColumnsObject[selectedTable]?.forEach((tableObject, idx) => { - console.log({ tableObject }); appendEditableColumns({ id: idx, tableName: tableObject.tableName, @@ -581,7 +580,6 @@ export const NotebookAddCell = observer( // if any change occurs with checkboxes reassess all joins to display setJoinsStackHandler(); updateSelectedTables(); - console.log({ selectedTableNames }); }, [checkedColumnsCount]); useEffect(() => { @@ -647,6 +645,8 @@ export const NotebookAddCell = observer( tableNames: Array.from(selectedTableNames), selectedColumns: getSelectedColumnNames(), columnAliases: getColumnAliases(), + rootTable: rootTable, + // filters: filters, }; } @@ -1323,7 +1323,6 @@ export const NotebookAddCell = observer( /** Checkbox Handler */ const checkBoxHandler = (tableIndex, columnIndex) => { const columnObject = watchedTables[tableIndex].columns[columnIndex]; - console.log({ columnObject }); updateAliasCountObj(columnObject?.checked, columnObject.userAlias); if (columnObject?.checked) { if (checkedColumnsCount == 0) { From 618f963325fc0c72f6e47412dea267840838c82e Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 31 Jul 2024 15:23:41 -0700 Subject: [PATCH 41/49] feat(client): consolidate edit and create into single modal component and debug --- .../data-import-cell/DataImportCell.tsx | 2 +- .../notebook/DataImportFormModal.tsx | 475 ++++-- .../components/notebook/NotebookAddCell.tsx | 1354 ++--------------- 3 files changed, 432 insertions(+), 1399 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index a615769642..83d6cfd726 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -722,7 +722,7 @@ export const DataImportCell: CellComponent = observer( {isDataImportModalOpen && ( { const { query, previousCellId, - isDataImportModalOpen, + // isDataImportModalOpen, setIsDataImportModalOpen, editMode, cell, @@ -371,43 +371,43 @@ export const DataImportFormModal = observer( const [userDatabases, setUserDatabases] = useState(null); const [queryElementCounter, setQueryElementCounter] = useState(0); - const [databaseTableRawHeaders, setDatabaseTableRawHeaders] = useState( - [], - ); + // const [databaseTableRawHeaders, setDatabaseTableRawHeaders] = useState( + // [], + // ); const [importModalPixelWidth, setImportModalPixelWidth] = useState(IMPORT_MODAL_WIDTHS.small); - const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); + // const [hiddenColumnIdsSet, setHiddenColumnIdsSet] = useState(new Set()); const [databaseTableHeaders, setDatabaseTableHeaders] = useState([]); const [selectedDatabaseId, setSelectedDatabaseId] = useState( cell ? cell.parameters.databaseId : null, ); - const [tableColumnsObject, setTableColumnsObject] = useState({}); + // const [tableColumnsObject, setTableColumnsObject] = useState({}); const [databaseTableRows, setDatabaseTableRows] = useState([]); const [tableNames, setTableNames] = useState([]); - const [selectedTable, setSelectedTable] = useState(null); - const importDataSQLStringRef = useRef(''); + // const [selectedTable, setSelectedTable] = useState(null); + // const importDataSQLStringRef = useRef(''); const getDatabases = usePixel('META | GetDatabaseList ( ) ;'); // making repeat network calls, move to load data modal open const [isDatabaseLoading, setIsDatabaseLoading] = useState(false); const [showPreview, setShowTablePreview] = useState(false); const [showEditColumns, setShowEditColumns] = useState(true); // ### change back to false - const [checkAllColumns, setCheckAllColumns] = useState(true); - const { configStore, monolithStore } = useRootStore(); + // const [checkAllColumns, setCheckAllColumns] = useState(true); + const { monolithStore } = useRootStore(); // // State Vars for Old useForm --- all uneeded / deletable - const [selectedLeftTable, setSelectedLeftTable] = - useState(null); - const [selectedRightTable, setSelectedRightTable] = - useState(null); - const [selectedRightKey, setSelectedRightKey] = useState(null); - const [columnDataTypesDict, setColumnDataTypesDict] = useState(null); - const [selectedLeftKey, setSelectedLeftKey] = useState(null); + // const [selectedLeftTable, setSelectedLeftTable] = + // useState(null); + // const [selectedRightTable, setSelectedRightTable] = + // useState(null); + // const [selectedRightKey, setSelectedRightKey] = useState(null); + // const [columnDataTypesDict, setColumnDataTypesDict] = useState(null); + // const [selectedLeftKey, setSelectedLeftKey] = useState(null); const [tableEdgesObject, setTableEdgesObject] = useState(null); // // State Vars for new useForm Structure // // checkedColumnsSet - const [checkedColumnsSet, setCheckedColumnsSet] = useState(new Set()); - const [hiddenTablesSet, setHiddenTablesSet] = useState({}); + // const [checkedColumnsSet, setCheckedColumnsSet] = useState(new Set()); + // const [hiddenTablesSet, setHiddenTablesSet] = useState({}); const [aliasesCountObj, setAliasesCountObj] = useState({}); // { emailAlias: 1, phoneAlias: 2 } const aliasesCountObjRef = useRef({}); // { emailAlias: 1, phoneAlias: 2 } const [tableEdges, setTableEdges] = useState({}); // @@ -491,11 +491,12 @@ export const DataImportFormModal = observer( }, []); useEffect(() => { - setSelectedLeftKey(null); - setSelectedRightKey(null); + // setSelectedLeftKey(null); + // setSelectedRightKey(null); removeEditableColumns(); removeStack(); - }, [selectedDatabaseId, selectedTable]); + }, [selectedDatabaseId]); + // }, [selectedDatabaseId, selectedTable]); useEffect(() => { removeEditableColumns(); @@ -516,19 +517,19 @@ export const DataImportFormModal = observer( } }, [newTableFields]); - useEffect(() => { - removeEditableColumns(); - tableColumnsObject[selectedTable]?.forEach((tableObject, idx) => { - appendEditableColumns({ - id: idx, - tableName: tableObject.tableName, - columnName: tableObject.columnName, - userAlias: tableObject.columnName, - columnType: tableObject.columnType, - checked: true, - }); - }); - }, [selectedTable]); + // useEffect(() => { + // removeEditableColumns(); + // tableColumnsObject[selectedTable]?.forEach((tableObject, idx) => { + // appendEditableColumns({ + // id: idx, + // tableName: tableObject.tableName, + // columnName: tableObject.columnName, + // userAlias: tableObject.columnName, + // columnType: tableObject.columnType, + // checked: true, + // }); + // }); + // }, [selectedTable]); useEffect(() => { if (getDatabases.status !== 'SUCCESS') { @@ -557,8 +558,52 @@ export const DataImportFormModal = observer( // endregion + const getSelectedColumnNames = () => { + const pixelTables = new Set(); + const pixelColumnNames = []; + + watchedTables.forEach((tableObject) => { + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + } + }); + }); + + return pixelColumnNames; + }; + + const getColumnAliases = () => { + const pixelTables = new Set(); + const pixelColumnAliases = []; + + watchedTables.forEach((tableObject) => { + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + return pixelColumnAliases; + }; + /** Create a New Cell and Add to Notebook */ const appendCell = (widget: string) => { + console.log({ + previousCellId, + widget, + DefaultCells, + // "DefaultCells[widget].parameters": DefaultCells[widget].parameters, + }); try { const newCellId = `${Math.floor(Math.random() * 100000)}`; @@ -572,19 +617,24 @@ export const DataImportFormModal = observer( ...DefaultCells[widget].parameters, frameVariableName: `FRAME_${newCellId}`, databaseId: selectedDatabaseId, - selectQuery: pixelStringRefPart1.current, - foo: 'moo', + // selectQuery: importDataSQLStringRef.current, // construct query based on useForm inputs + // selectQuery: pixelStringRef.current, // construct query based on useForm inputs + selectQuery: pixelStringRefPart1.current, // construct query based on useForm inputs joins: joinElements, tableNames: Array.from(selectedTableNames), + selectedColumns: getSelectedColumnNames(), + columnAliases: getColumnAliases(), + rootTable: rootTable, + // filters: filters, }; } - if (widget === QueryImportCellConfig.widget) { - config.parameters = { - ...DefaultCells[widget].parameters, - frameVariableName: `FRAME_${newCellId}`, - }; - } + // if (widget === QueryImportCellConfig.widget) { + // config.parameters = { + // ...DefaultCells[widget].parameters, + // frameVariableName: `FRAME_${newCellId}`, + // }; + // } if ( previousCellId && @@ -617,64 +667,64 @@ export const DataImportFormModal = observer( }; /** Construct a Raw SQL String for Data Import */ - const constructSQLString = ({ submitData }) => { - let newSQLString = 'SELECT '; - - newSQLString += submitData.columns - .filter((ele) => ele.checked) - .map((colObj) => { - if (colObj.columnName === colObj.userAlias) { - return colObj.columnName; - } else { - return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - } - }) - .join(', '); - - newSQLString += ` FROM ${submitData.tableSelect}`; - newSQLString += ';'; - - if ( - selectedLeftTable && - selectedRightTable && - selectedLeftKey && - selectedRightKey - ) { - newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - } - - importDataSQLStringRef.current = newSQLString; - }; + // const constructSQLString = ({ submitData }) => { + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } + + // importDataSQLStringRef.current = newSQLString; + // }; /** Construct SQL Pixel for Data Import */ - const constructDataBasePixel = ({ submitData }) => { - let newSQLString = 'SELECT '; - - newSQLString += submitData.columns - .filter((ele) => ele.checked) - .map((colObj) => { - if (colObj.columnName === colObj.userAlias) { - return colObj.columnName; - } else { - return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - } - }) - .join(', '); - - newSQLString += ` FROM ${submitData.tableSelect}`; - newSQLString += ';'; - - if ( - selectedLeftTable && - selectedRightTable && - selectedLeftKey && - selectedRightKey - ) { - newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - } - - importDataSQLStringRef.current = newSQLString; - }; + // const constructDataBasePixel = ({ submitData }) => { + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } + + // importDataSQLStringRef.current = newSQLString; + // }; /** Add all the columns from a Table */ const addAllTableColumnsHandler = (event) => { @@ -747,6 +797,16 @@ export const DataImportFormModal = observer( value: pixelStringRefPart1.current, }, }); + + state.dispatch({ + message: ActionMessages.UPDATE_CELL, + payload: { + queryId: cell.query.id, + cellId: cell.id, + path: 'parameters.databaseId', + value: selectedDatabaseId, + }, + }); }; /** New Submit for Import Data --- empty */ @@ -755,7 +815,6 @@ export const DataImportFormModal = observer( retrievePreviewData(); updateSubmitDispatches(); } else { - constructSQLString({ submitData: data }); retrievePreviewData(); appendCell('data-import'); } @@ -766,17 +825,17 @@ export const DataImportFormModal = observer( /** Close and Reset Import Data Form Modal */ const closeImportModalHandler = () => { - setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); - setHiddenColumnIdsSet(new Set()); + // setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.small); + // setHiddenColumnIdsSet(new Set()); setIsDataImportModalOpen(false); - setDatabaseTableHeaders([]); - setSelectedDatabaseId(null); - setShowTablePreview(false); - setTableColumnsObject({}); - setDatabaseTableRows([]); - setSelectedTable(null); - setTableNames([]); - reset(); + // setDatabaseTableHeaders([]); + // setSelectedDatabaseId(null); + // setShowTablePreview(false); + // setTableColumnsObject({}); + // setDatabaseTableRows([]); + // setSelectedTable(null); + // setTableNames([]); + // reset(); }; /** Get Database Information for Data Import Modal */ @@ -835,29 +894,31 @@ export const DataImportFormModal = observer( {}, ); - const newTableColumnsObject: Table[] = Object.keys( - tableColumnsObject, - ).map((tableName, tableIdx) => ({ - id: tableIdx, - name: tableName, - columns: tableColumnsObject[tableName].map( - (colObj, colIdx) => ({ - id: colIdx, - tableName: tableName, - columnName: colObj.columnName, - columnType: colObj.columnType, - userAlias: colObj.userAlias, - checked: false, - }), - ), - })); + const newTableColumnsObject: Table[] = tableColumnsObject + ? Object.keys(tableColumnsObject).map( + (tableName, tableIdx) => ({ + id: tableIdx, + name: tableName, + columns: tableColumnsObject[tableName].map( + (colObj, colIdx) => ({ + id: colIdx, + tableName: tableName, + columnName: colObj.columnName, + columnType: colObj.columnType, + userAlias: colObj.userAlias, + checked: false, + }), + ), + }), + ) + : []; newReset({ databaseSelect: databaseId, tables: newTableColumnsObject, }); } else { - console.error('Error retrieving database tables'); + console.error('Error retrieving database tables (920)'); } if (isResponseTableEdgesStructureGood) { @@ -926,16 +987,44 @@ export const DataImportFormModal = observer( setImportModalPixelWidth(IMPORT_MODAL_WIDTHS.large); setTableNames(newTableNames); - if (editMode) { + + // shown tables filtered only on init load of edit mode + if (editMode && !isInitLoadComplete) { const newEdges = [ rootTable, - ...Object.keys(newTableEdges[rootTable]), + ...(newTableEdges[rootTable] + ? Object.keys(newTableEdges[rootTable]) + : []), ]; setShownTables(new Set(newEdges)); } else { setShownTables(new Set(newTableNames)); } + + if (!editMode || isInitLoadComplete) { + setAliasesCountObj({}); + aliasesCountObjRef.current = {}; + removeJoinElement(); + setJoinsSet(new Set()); + } }); + + // TODO bugs when changing database, temporarily diabled + // correctly resetting joins in UI + // not in cell pixel though + // run cell broken + // preview crashing app + + // resetting aliases and joins needed for new and edit modes + // moving these to databaseId useEffect + setAliasesCountObj({}); + aliasesCountObjRef.current = {}; + removeJoinElement(); + // updateQueryPixelString() + // retrievePreviewData(); + // newReset() + // reset() + setIsInitLoadComplete(true); }; @@ -1031,6 +1120,87 @@ export const DataImportFormModal = observer( setSelectedTableNames(pixelTables); }; + const updateQueryPixelString = async () => { + // setIsDatabaseLoading(true); + + const databaseId = selectedDatabaseId; + const pixelTables = new Set(); + const pixelColumnNames = []; + const pixelColumnAliases = []; + const pixelJoins = []; + + watchedTables.forEach((tableObject) => { + const currTableName = tableObject.name; + const currTableColumns = tableObject.columns; + + currTableColumns.forEach((columnObject) => { + if (columnObject.checked) { + pixelTables.add(columnObject.tableName); + pixelColumnNames.push( + `${columnObject.tableName}__${columnObject.columnName}`, + ); + pixelColumnAliases.push(columnObject.userAlias); + } + }); + }); + + Array.from(joinsSet).forEach((joinEle: string) => { + const splitJoinsString = joinEle.split(':'); + pixelJoins.push( + `( ${splitJoinsString[0]} , inner.join , ${splitJoinsString[1]} )`, + ); + }); + + let pixelStringPart1 = `Database ( database = [ \"${databaseId}\" ] )`; + pixelStringPart1 += ` | Select ( ${pixelColumnNames.join(' , ')} )`; + pixelStringPart1 += `.as ( [ ${pixelColumnAliases.join(' , ')} ] )`; + if (pixelJoins.length > 0) { + pixelStringPart1 += ` | Join ( ${pixelJoins.join(' , ')} ) `; + } + pixelStringPart1 += ` | Distinct ( false ) | Limit ( 20 )`; + + // const pixelStringPart2 = ` | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] )`; + // const pixelStringPart3 = ` ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + + const combinedJoinString = + pixelJoins.length > 0 + ? `| Join ( ${pixelJoins.join(' , ')} ) ` + : ''; + + const reactorPixel = `Database ( database = [ \"${databaseId}\" ] ) | Select ( ${pixelColumnNames.join( + ' , ', + )} ) .as ( [ ${pixelColumnAliases.join( + ' , ', + )} ] ) ${combinedJoinString}| Distinct ( false ) | Limit ( 20 ) | Import ( frame = [ CreateFrame ( frameType = [ GRID ] , override = [ true ] ) .as ( [ \"consolidated_settings_FRAME932867__Preview\" ] ) ] ) ; META | Frame() | QueryAll() | Limit(50) | Collect(500);`; + + setPixelString(reactorPixel); + pixelStringRef.current = reactorPixel; + + pixelStringRefPart1.current = pixelStringPart1 + ';'; + + // return pixelStringRefPart1.current + + // await monolithStore.runQuery(reactorPixel).then((response) => { + // const type = response.pixelReturn[0]?.operationType; + // const tableHeadersData = + // response.pixelReturn[1]?.output?.data?.headers; + // const tableRawHeadersData = + // response.pixelReturn[1]?.output?.data?.rawHeaders; + // const tableRowsData = + // response.pixelReturn[1]?.output?.data?.values; + + // setDatabaseTableHeaders(tableHeadersData); + // // setDatabaseTableRawHeaders(tableRawHeadersData); + // setDatabaseTableRows(tableRowsData); + + // if (type.indexOf('ERROR') != -1) { + // console.error('Error retrieving database tables'); + // } + + // setIsDatabaseLoading(false); + // }); + }; + const retrievePreviewData = async () => { setIsDatabaseLoading(true); @@ -1099,11 +1269,11 @@ export const DataImportFormModal = observer( response.pixelReturn[1]?.output?.data?.values; setDatabaseTableHeaders(tableHeadersData); - setDatabaseTableRawHeaders(tableRawHeadersData); + // setDatabaseTableRawHeaders(tableRawHeadersData); setDatabaseTableRows(tableRowsData); if (type.indexOf('ERROR') != -1) { - console.error('Error retrieving database tables'); + console.error('Error retrieving database tables (1270)'); } setIsDatabaseLoading(false); @@ -1330,7 +1500,8 @@ export const DataImportFormModal = observer( }; return ( - + // +
@@ -1757,13 +1928,16 @@ export const DataImportFormModal = observer( {databaseTableHeaders - .filter( - (v, colIdx) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) + // .filter( + // (v, colIdx) => { + // console.log(!hiddenColumnIdsSet.has( + // colIdx, + // )); + // return !hiddenColumnIdsSet.has( + // colIdx, + // ); + // }, + // ) .map((h, hIdx) => ( {r - .filter( - ( - v, - colIdx, - ) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) + // .filter( + // ( + // v, + // colIdx, + // ) => { + + // return !hiddenColumnIdsSet.has( + // colIdx, + // ); + // }, + // ) .map( ( v, diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index b640c127ce..6f28ca2ce9 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -66,6 +66,8 @@ import { DataImportCellConfig } from '../cell-defaults/data-import-cell'; import { CodeCellConfig } from '../cell-defaults/code-cell'; import { useFieldArray, useForm, Form, Controller } from 'react-hook-form'; +import { DataImportFormModal } from './DataImportFormModal'; + import { LoadingScreen } from '@/components/ui'; import { runPixel } from '@/api'; @@ -689,104 +691,104 @@ export const NotebookAddCell = observer( }; /** Construct a Raw SQL String for Data Import --- remove */ - const constructSQLString = ({ submitData }) => { - console.log({ submitData }); - let newSQLString = 'SELECT '; - - newSQLString += submitData.columns - .filter((ele) => ele.checked) - .map((colObj) => { - if (colObj.columnName === colObj.userAlias) { - return colObj.columnName; - } else { - return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - } - }) - .join(', '); - - newSQLString += ` FROM ${submitData.tableSelect}`; - newSQLString += ';'; - - if ( - selectedLeftTable && - selectedRightTable && - selectedLeftKey && - selectedRightKey - ) { - newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - } + // const constructSQLString = ({ submitData }) => { + // console.log({ submitData }); + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } - importDataSQLStringRef.current = newSQLString; - }; + // importDataSQLStringRef.current = newSQLString; + // }; /** Construct Submit Pixel for Data Import --- remove? */ - const constructDataBasePixel = ({ submitData }) => { - // mimic this pixel structure instead of constructing raw SQL ? - // or have join autoselect keys and add columns to edit - // that makes sense with new pixel structure - // show all tables and selectable rows in edit columns view - // find way of showing alerts for un joinable columns - // add form structure to json state (?) - // make basic non SQL view for notebook cell - // make edit window - - // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | - - // Select ( - // STATION_SETTINGS__ROLE , - // USER_SETTINGS__DATE_CREATED , - // VISN_SETTINGS__EMAIL , - // VISN_SETTINGS__USER , - // VISN_SETTINGS__VISN ) - // .as ( [ - // ROLE , - // DATE_CREATED , - // EMAIL , - // USER , - // VISN - // ] ) | - - // Join ( ( - // USER_SETTINGS , - // inner.join , - // STATION_SETTINGS - // ) , ( - // USER_SETTINGS , - // inner.join , - // VISN_SETTINGS - // ) ) | - - // Distinct ( false ) | - - // QueryRowCount ( ) ;", - console.log({ submitData }); - let newSQLString = 'SELECT '; - - newSQLString += submitData.columns - .filter((ele) => ele.checked) - .map((colObj) => { - if (colObj.columnName === colObj.userAlias) { - return colObj.columnName; - } else { - return `${colObj.columnName} AS \"${colObj.userAlias}\"`; - } - }) - .join(', '); - - newSQLString += ` FROM ${submitData.tableSelect}`; - newSQLString += ';'; - - if ( - selectedLeftTable && - selectedRightTable && - selectedLeftKey && - selectedRightKey - ) { - newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; - } + // const constructDataBasePixel = ({ submitData }) => { + // // mimic this pixel structure instead of constructing raw SQL ? + // // or have join autoselect keys and add columns to edit + // // that makes sense with new pixel structure + // // show all tables and selectable rows in edit columns view + // // find way of showing alerts for un joinable columns + // // add form structure to json state (?) + // // make basic non SQL view for notebook cell + // // make edit window + + // // "pixelExpression": "Database ( database = [ \"f9b656cc-06e7-4cce-bae8-b5f92075b6da\" ] ) | + + // // Select ( + // // STATION_SETTINGS__ROLE , + // // USER_SETTINGS__DATE_CREATED , + // // VISN_SETTINGS__EMAIL , + // // VISN_SETTINGS__USER , + // // VISN_SETTINGS__VISN ) + // // .as ( [ + // // ROLE , + // // DATE_CREATED , + // // EMAIL , + // // USER , + // // VISN + // // ] ) | + + // // Join ( ( + // // USER_SETTINGS , + // // inner.join , + // // STATION_SETTINGS + // // ) , ( + // // USER_SETTINGS , + // // inner.join , + // // VISN_SETTINGS + // // ) ) | + + // // Distinct ( false ) | + + // // QueryRowCount ( ) ;", + // console.log({ submitData }); + // let newSQLString = 'SELECT '; + + // newSQLString += submitData.columns + // .filter((ele) => ele.checked) + // .map((colObj) => { + // if (colObj.columnName === colObj.userAlias) { + // return colObj.columnName; + // } else { + // return `${colObj.columnName} AS \"${colObj.userAlias}\"`; + // } + // }) + // .join(', '); + + // newSQLString += ` FROM ${submitData.tableSelect}`; + // newSQLString += ';'; + + // if ( + // selectedLeftTable && + // selectedRightTable && + // selectedLeftKey && + // selectedRightKey + // ) { + // newSQLString = `SELECT ${'*'} FROM ${selectedLeftTable} INNER JOIN ${selectedRightTable} ON ${selectedLeftTable}.${selectedLeftKey}=${selectedRightTable}.${selectedRightKey};`; + // } - importDataSQLStringRef.current = newSQLString; - }; + // importDataSQLStringRef.current = newSQLString; + // }; /** Add all the columns from a Table */ const addAllTableColumnsHandler = (event) => { @@ -1540,1160 +1542,16 @@ export const NotebookAddCell = observer( - {/* New Import Data Modal --- stand-alone component? */} - - - - - -
- - Import Data from - - ( - - )} - /> -
- - - -
- {selectedDatabaseId && ( - - -
- - Data - -
-
- - -
-
- - {showEditColumns && ( - - - Available Tables / Columns - - - {newTableFields.map( - (table, tableIndex) => ( -
- {/* using conditional rendering for each table but if bugs persists set state for showntables in checkbox handler */} - {shownTables.has( - table.name, - ) && ( - - - - - - - { - table.name - } - - - - - - - - - - - - - Fields - - - - - Alias - - - - - Field - Type - - - - - {table.columns.map( - ( - column, - columnIndex, - ) => ( - - - ( - { - field.onChange( - e, - ); - checkBoxHandler( - tableIndex, - columnIndex, - ); - }} - /> - )} - /> - - - { - column.columnName - } - {column.columnName == - 'ID' && ( -
- PK -
- )} - {column.columnName.includes( - '_ID', - ) && ( -
- FK -
- )} -
- - - ( - { - if ( - watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .checked - ) { - updateAliasCountObj( - true, - e - .target - .value, - field.value, - ); - } - field.onChange( - e - .target - .value, - ); - }} - /> - )} - /> - {watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .checked && - aliasesCountObj[ - watchedTables[ - tableIndex - ] - .columns[ - columnIndex - ] - .userAlias - ] > - 1 && ( - - - - )} - - - - - ( - - )} - /> - -
- ), - )} -
-
-
- )} -
- ), - )} -
-
- )} - - {showPreview && ( - - - Preview - - - - - - {databaseTableHeaders - .filter( - ( - v, - colIdx, - ) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map( - ( - h, - hIdx, - ) => ( - - - { - h - } - - - ), - )} - - {databaseTableRows.map( - (r, rIdx) => ( - - {r - .filter( - ( - v, - colIdx, - ) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map( - ( - v, - vIdx, - ) => ( - - { - v - } - - ), - )} - - ), - )} - -
-
-
- )} -
- )} - - {/* stack for user-added joins filters and summaries */} - {joinElements.map((join, stackIndex) => ( - - -
- - Join - - - - - {join.leftTable} - - - - - - - - - - - - {join.rightTable} - - - - - where - - - - - {join.leftKey} - - - - - = - - - - - {join.rightKey} - - -
- {/*
- { - removeStack(stackIndex); - }} - > - - -
*/} -
- - {/* {showEditColumns && ( */} - {/* {false && ( - - - Edit Columns - - - - - - - { - setCheckAllColumns( - !checkAllColumns, - ); - const hiddenColumnIdsSetDup = - new Set(); - if ( - checkAllColumns == - false - ) { - editableColumnFields.forEach( - ( - field, - index, - ) => { - // not working need to use setValue - field.checked = - true; - console.log( - { - index, - field, - }, - ); - hiddenColumnIdsSetDup.add( - index, - ); - }, - ); - } else { - editableColumnFields.forEach( - ( - field, - index, - ) => { - // not working need to use setValue - field.checked = - false; - console.log( - { - index, - field, - }, - ); - hiddenColumnIdsSetDup.delete( - index, - ); - }, - ); - } - setHiddenColumnIdsSet( - hiddenColumnIdsSetDup, - ); - }} - color={ - checkAllColumns - ? 'primary' - : 'secondary' - } - sx={{ - marginLeft: - '-10px', - }} - > - - - - - - Fields - - - - - Alias - - - - - Field Type - - - - - {editableColumnFields?.map( - (field, index) => ( - - - ( - { - field.onChange( - e, - ); - const hiddenColumnIdsSetDup = - new Set( - [ - ...hiddenColumnIdsSet, - ], - ); - if ( - field.value == - true - ) { - hiddenColumnIdsSetDup.add( - index, - ); - } else { - hiddenColumnIdsSetDup.delete( - index, - ); - } - - console.log( - { - hiddenColumnIdsSetDup, - editableColumnFields, - }, - ); - - if ( - hiddenColumnIdsSetDup.size == - 0 - ) { - setCheckAllColumns( - true, - ); - } else { - setCheckAllColumns( - false, - ); - } - - setHiddenColumnIdsSet( - hiddenColumnIdsSetDup, - ); - }} - /> - )} - /> - - - { - field.columnName - } - {field.columnName == - 'ID' && ( -
- PK -
- )} - {field.columnName.includes( - '_ID', - ) && ( -
- FK -
- )} -
- - ( - { - field.onChange( - e - .target - .value, - ); - const newTableHeaders = - [ - ...databaseTableHeaders, - ]; - newTableHeaders[ - index - ] = - e.target.value; - setDatabaseTableHeaders( - newTableHeaders, - ); - }} - /> - )} - /> - - - ( - - )} - /> - -
- ), - )} -
-
- - - - -
- )} */} - - {/* {showPreview && ( */} - {/* {false && ( - - - Preview - - - - - {databaseTableHeaders - .filter( - (v, colIdx) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map((h, hIdx) => ( - - - {h} - - - ))} - - {databaseTableRows.map( - (r, rIdx) => ( - - {r - .filter( - ( - v, - colIdx, - ) => { - return !hiddenColumnIdsSet.has( - colIdx, - ); - }, - ) - .map( - ( - v, - vIdx, - ) => ( - - { - v - } - - ), - )} - - ), - )} - -
-
- )} */} -
- ))} - - - - - - - - - - - -
-
+ {isDataImportModalOpen && ( + + )} ); }, From 8d54f2237babd283009703f0501c52955c4ece56 Mon Sep 17 00:00:00 2001 From: Betthauser Date: Wed, 14 Aug 2024 13:20:51 -0700 Subject: [PATCH 42/49] feat(client): test patch and refactor pixel view and formatting for cell copy paste --- .../data-import-cell/DataImportCell.tsx | 404 ++++++------------ .../notebook/DataImportFormModal.tsx | 7 + 2 files changed, 148 insertions(+), 263 deletions(-) diff --git a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx index aa1bde4fae..c536db9cba 100644 --- a/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx +++ b/packages/client/src/components/cell-defaults/data-import-cell/DataImportCell.tsx @@ -1,23 +1,20 @@ import { observer } from 'mobx-react-lite'; import { useEffect, useRef, useState } from 'react'; -import Editor, { Monaco } from '@monaco-editor/react'; import { StyledSelect, StyledSelectItem } from '../shared'; +import Editor, { Monaco } from '@monaco-editor/react'; import { styled, Button, - Menu, - MenuProps, TextField, - Stack, InputAdornment, Typography, + IconButton, Tooltip, + Stack, Modal, - IconButton, } from '@semoss/ui'; import { - AccountTree, CropFree, KeyboardArrowDown, DriveFileRenameOutlineRounded, @@ -28,13 +25,10 @@ import { JoinFull, Edit, } from '@mui/icons-material'; -import { editor } from 'monaco-editor'; -import { DatabaseTables } from './DatabaseTables'; - import { ActionMessages, CellComponent, CellDef } from '@/stores'; -import { useBlocks, usePixel } from '@/hooks'; - import { DataImportFormModal } from '../../notebook/DataImportFormModal'; +import { useBlocks, usePixel } from '@/hooks'; +import { editor } from 'monaco-editor'; const EDITOR_LINE_HEIGHT = 19; const EDITOR_MAX_HEIGHT = 500; // ~25 lines @@ -70,99 +64,52 @@ const JOIN_ICONS = { }; const BlueStyledJoinDiv = styled('div')(({ theme }) => ({ - border: 'none', + backgroundColor: theme.palette.primary.selected, padding: '0px 12px', borderRadius: '12px', fontSize: '12.5px', + border: 'none', color: 'black', cursor: 'default', - backgroundColor: theme.palette.primary.selected, fontWeight: '500', })); const GreenStyledJoinDiv = styled('div')(({ theme }) => ({ border: 'none', padding: '0px 12px', - borderRadius: '12px', - fontSize: '12.5px', - color: 'black', - cursor: 'default', backgroundColor: '#DEF4F3', - fontWeight: '500', -})); - -const PurpleStyledJoinDiv = styled('div')(({ theme }) => ({ - border: 'none', - padding: '0px 12px', borderRadius: '12px', fontSize: '12.5px', - color: '#BAB4C2', + color: 'black', cursor: 'default', - backgroundColor: '#F1E9FB', fontWeight: '500', })); const StyledJoinTypography = styled(Typography)(({ theme }) => ({ - marginLeft: '12.5px', - marginRight: '12.5px', color: theme.palette.secondary.dark, + marginRight: '12.5px', + marginLeft: '12.5px', cursor: 'default', })); const StyledModalTitleWrapper2 = styled(Modal.Title)(({ theme }) => ({ - display: 'flex', alignContent: 'center', + display: 'flex', padding: '0px', - // justifyContent: 'space-between', -})); - -const TableIconButton = styled(Tooltip)(({ theme }) => ({ - marginLeft: '-3px', - marginRight: '7px', - color: theme.palette.primary.main, - // color: 'black', })); const StyledTableTitleBubble = styled('div')(({ theme }) => ({ marginTop: '0px', - // marginBottom: '15px', - // marginLeft: '15px', marginRight: '15px', - // backgroundColor: theme.palette.primary.selected, - backgroundColor: '#F1E9FB', width: 'fit-content', + backgroundColor: '#F1E9FB', padding: '7.5px 17.5px', - borderRadius: '10px', display: 'inline-flex', + borderRadius: '10px', alignItems: 'center', - cursor: 'default', - fontSize: '12.5px', fontWeight: '400', -})); - -const StyledJoinElementBlueBubble = styled(Typography)(({ theme }) => ({ - marginTop: '0px', - marginBottom: '15px', - // marginLeft: '15px', - marginRight: '15px', - backgroundColor: theme.palette.primary.selected, - width: 'fit-content', - padding: '10px 20px', - borderRadius: '10px', - // display: 'block', - // alignItems: 'center', - cursor: 'default', fontSize: '12.5px', -})); - -const StyledBlueDiv = styled('div')(({ theme }) => ({ - padding: '5px 10px', - borderRadius: '12px', - // backgroundColor: '#F1E9FB', // light purple - backgroundColor: theme.palette.primary.selected, - fontSize: '13px', - textAlign: 'center', - width: 'fit-content', + cursor: 'default', })); const StyledContent = styled('div')(({ theme }) => ({ @@ -170,24 +117,11 @@ const StyledContent = styled('div')(({ theme }) => ({ width: '100%', })); -const StyledButton = styled(Button)(({ theme }) => ({ - color: theme.palette.text.secondary, - border: `1px solid ${theme.palette.divider}`, -})); - -const StyledButtonLabel = styled('span', { - shouldForwardProp: (prop) => prop !== 'width', -})<{ width: number }>(({ theme, width }) => ({ - width: theme.spacing(width), - display: 'block', - textAlign: 'start', -})); - const StyledTextField = styled(TextField)(({ theme }) => ({ '& .MuiInputBase-root': { color: theme.palette.text.secondary, - display: 'flex', gap: theme.spacing(1), + display: 'flex', height: '30px', width: '200px', }, @@ -196,50 +130,36 @@ const StyledTextField = styled(TextField)(({ theme }) => ({ const StyledContainer = styled('div')(({ theme }) => ({})); interface JoinObject { - // table1: string; - // table2: string; - // key1: string; - // key2: string; - // joinType: string; id: string; joinType: string; - leftKey: string; leftTable: string; - rightKey: string; rightTable: string; + rightKey: string; + leftKey: string; } -interface FilterObject { - // structure for filters tbd -} +// TODO add filters and summaries +// interface FilterObject { +// // structure for filters +// } +// interface summaryObject { +// // structure for summaries +// } export interface DataImportCellDef extends CellDef<'data-import'> { widget: 'data-import'; parameters: { - /** Database associated with the cell */ databaseId: string; - - /** Output frame type */ frameType: 'NATIVE' | 'PY' | 'R' | 'GRID' | 'PIXEL'; - - /** Ouput variable name */ frameVariableName: string; - - /** Select query rendered in the cell */ selectQuery: string; - - // foo: string; - - tableNames: string[]; - - joins: JoinObject[]; - + rootTable: string; selectedColumns: string[]; - columnAliases: string[]; + tableNames: string[]; + joins: JoinObject[]; - rootTable: string; - + // TODO add filters and summaries // filters: FilterObject[]; // summaries: FilterObject[]; }; @@ -249,24 +169,23 @@ export interface DataImportCellDef extends CellDef<'data-import'> { export const DataImportCell: CellComponent = observer( (props) => { const editorRef = useRef(null); - + const [showStyledView, setShowStyledView] = useState(true); const { cell, isExpanded } = props; const { state } = useBlocks(); - const [showTables, setShowTables] = useState(false); - const [showStyledView, setShowStyledView] = useState(true); - const [isDataImportModalOpen, setIsDataImportModalOpen] = useState(false); const [cfgLibraryDatabases, setCfgLibraryDatabases] = useState({ loading: true, - ids: [], display: {}, + ids: [], }); + const myDbs = usePixel<{ app_id: string; app_name: string }[]>( `MyEngines(engineTypes=['DATABASE']);`, ); + useEffect(() => { if (myDbs.status !== 'SUCCESS') { return; @@ -274,23 +193,25 @@ export const DataImportCell: CellComponent = observer( const dbIds: string[] = []; const dbDisplay = {}; + myDbs.data.forEach((db) => { dbIds.push(db.app_id); dbDisplay[db.app_id] = db.app_name; }); + setCfgLibraryDatabases({ loading: false, - ids: dbIds, display: dbDisplay, + ids: dbIds, }); if (!cell.parameters.databaseId && dbIds.length) { state.dispatch({ message: ActionMessages.UPDATE_CELL, payload: { + path: 'parameters.databaseId', queryId: cell.query.id, cellId: cell.id, - path: 'parameters.databaseId', value: dbIds[0], }, }); @@ -299,7 +220,6 @@ export const DataImportCell: CellComponent = observer( /** * Handle mounting of the editor - * * @param editor - editor that mounted * @param monaco - monaco instance */ @@ -337,9 +257,9 @@ export const DataImportCell: CellComponent = observer( state.dispatch({ message: ActionMessages.UPDATE_CELL, payload: { + path: 'parameters.selectQuery', queryId: cell.query.id, cellId: cell.id, - path: 'parameters.selectQuery', value: newValue, }, }); @@ -359,8 +279,7 @@ export const DataImportCell: CellComponent = observer( inherit: false, rules: [], colors: { - 'editor.background': '#FAFAFA', // Background color - // 'editor.lineHighlightBorder': '#FFF', // Border around selected line + 'editor.background': '#FAFAFA', }, }); @@ -395,11 +314,12 @@ export const DataImportCell: CellComponent = observer( }; /** - * Handle changes in the editor + * Handle changes in the editor - currently not in use, will need work if edits are enabled * @param newValue - newValue * @returns */ const handleEditorChange = (newValue: string) => { + console.log('handleEditorChange'); if (cell.isLoading) { return; } @@ -407,10 +327,10 @@ export const DataImportCell: CellComponent = observer( state.dispatch({ message: ActionMessages.UPDATE_CELL, payload: { + value: newValue, + path: 'parameters.selectQuery', queryId: cell.query.id, cellId: cell.id, - path: 'parameters.selectQuery', - value: 'newValue', }, }); }; @@ -425,15 +345,15 @@ export const DataImportCell: CellComponent = observer( {isExpanded && ( = observer( state.dispatch({ message: ActionMessages.UPDATE_CELL, payload: { + path: 'parameters.databaseId', queryId: cell.query.id, cellId: cell.id, - path: 'parameters.databaseId', value: value, }, }); @@ -484,168 +404,132 @@ export const DataImportCell: CellComponent = observer( <>
- {/* - Data from: - */} {cell.parameters.tableNames && cell.parameters.tableNames.map( (tableName) => ( - // - // - // - // - // - // {tableName} - // - // - {/* <> */} {tableName} - {/* */} ), )}
- {/* stack for user-added joins filters and summaries */} {isExpanded && cell.parameters.joins && - cell.parameters.joins.map( - (join, stackIndex) => ( - - -
- - - {join.leftTable} - - - - - - { - JOIN_ICONS[ - join - .joinType - ] - } - - - - - - {join.rightTable} - - - - - ON - - - - - {join.leftKey} - - - - - = - - - - - {join.rightKey} - - -
- {/*
- { - removeStack(stackIndex); + cell.parameters.joins.map((join) => ( + + +
- - -
*/} -
-
- ), - )} + + + {join.leftTable} + + + + + + { + JOIN_ICONS[ + join.joinType + ] + } + + + + + + {join.rightTable} + + + + + ON + + + + + {join.leftKey} + + + + + = + + + + + {join.rightKey} + + +
+
+
+ ))} ) : ( = observer( )} {isExpanded && (