From a7ed6bf62beae660527ad62a556c33b7a4d45a27 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sun, 18 Oct 2020 18:13:58 +0200 Subject: [PATCH 1/8] loading data grid --- packages/web/src/datagrid/DataGrid.js | 7 ++++--- packages/web/src/datagrid/LoadingDataGrid.js | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 packages/web/src/datagrid/LoadingDataGrid.js diff --git a/packages/web/src/datagrid/DataGrid.js b/packages/web/src/datagrid/DataGrid.js index a7bf2c5f4..36db23626 100644 --- a/packages/web/src/datagrid/DataGrid.js +++ b/packages/web/src/datagrid/DataGrid.js @@ -15,6 +15,7 @@ import { } from './ManagerStyles'; import ReferenceManager from './ReferenceManager'; import { HorizontalSplitter } from '../widgets/Splitter'; +import LoadingDataGrid from './LoadingDataGrid'; const MainContainer = styled.div` position: absolute; @@ -50,18 +51,18 @@ export default function DataGrid(props) { - + {props.showReferences && ( - + )} - + diff --git a/packages/web/src/datagrid/LoadingDataGrid.js b/packages/web/src/datagrid/LoadingDataGrid.js new file mode 100644 index 000000000..c9ba3dd85 --- /dev/null +++ b/packages/web/src/datagrid/LoadingDataGrid.js @@ -0,0 +1,6 @@ +import React from 'react'; +import DataGridCore from './DataGridCore'; + +export default function LoadingDataGrid(props) { + return ; +} From b439c7bb705ca5eba0a09692ec09d9dd8bb4ff83 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Thu, 22 Oct 2020 15:22:58 +0200 Subject: [PATCH 2/8] data grid refactor - working read only --- .../web/src/datagrid/ChangeSetDataGrid.js | 17 + packages/web/src/datagrid/DataGrid.js | 2 +- packages/web/src/datagrid/DataGridCore.js | 528 +++++------------- packages/web/src/datagrid/LoadingDataGrid.js | 259 ++++++++- packages/web/src/datagrid/types.ts | 27 +- 5 files changed, 453 insertions(+), 380 deletions(-) create mode 100644 packages/web/src/datagrid/ChangeSetDataGrid.js diff --git a/packages/web/src/datagrid/ChangeSetDataGrid.js b/packages/web/src/datagrid/ChangeSetDataGrid.js new file mode 100644 index 000000000..3c20ec515 --- /dev/null +++ b/packages/web/src/datagrid/ChangeSetDataGrid.js @@ -0,0 +1,17 @@ +import { getChangeSetInsertedRows } from '@dbgate/datalib'; +import React from 'react'; +import DataGridCore from './DataGridCore'; + +export default function ChangeSetDataGrid(props) { + const { changeSet, display, dispatchChangeSet } = props; + function undo() { + dispatchChangeSet({ type: 'undo' }); + } + function redo() { + dispatchChangeSet({ type: 'redo' }); + } + + const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); + + return ; +} diff --git a/packages/web/src/datagrid/DataGrid.js b/packages/web/src/datagrid/DataGrid.js index 36db23626..f7cfb19c4 100644 --- a/packages/web/src/datagrid/DataGrid.js +++ b/packages/web/src/datagrid/DataGrid.js @@ -42,7 +42,7 @@ const DataGridContainer = styled.div` flex-grow: 1; `; -/** @param props {import('./types').DataGridProps} */ +/** @param props {import('./types').LoadingDataGridProps} */ export default function DataGrid(props) { const Container1 = props.showReferences ? ManagerOuterContainer1 : ManagerOuterContainerFull; const [managerSize, setManagerSize] = React.useState(0); diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index e7e5791a9..d67480e8c 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -126,98 +126,35 @@ const LoadingInfoBox = styled.div` border: 1px solid gray; `; -/** @param props {import('./types').DataGridProps} */ -async function loadDataPage(props, offset, limit) { - const { display, conid, database, jslid } = props; - - if (jslid) { - const response = await axios.request({ - url: 'jsldata/get-rows', - method: 'get', - params: { - jslid, - offset, - limit, - }, - }); - return response.data; - } - - const sql = display.getPageQuery(offset, limit); - - const response = await axios.request({ - url: 'database-connections/query-data', - method: 'post', - params: { - conid, - database, - }, - data: { sql }, - }); - - if (response.data.errorMessage) return response.data; - return response.data.rows; -} - -function dataPageAvailable(props) { - const { display, jslid } = props; - if (jslid) return true; - const sql = display.getPageQuery(0, 1); - return !!sql; -} - -/** @param props {import('./types').DataGridProps} */ -async function loadRowCount(props) { - const { display, conid, database, jslid } = props; - - if (jslid) { - const response = await axios.request({ - url: 'jsldata/get-stats', - method: 'get', - params: { - jslid, - }, - }); - return response.data.rowCount; - } - - const sql = display.getCountQuery(); - - const response = await axios.request({ - url: 'database-connections/query-data', - method: 'post', - params: { - conid, - database, - }, - data: { sql }, - }); - - return parseInt(response.data.rows[0].count); -} - -/** @param props {import('./types').DataGridProps} */ +/** @param props {import('./types').DataGridCoreProps} */ export default function DataGridCore(props) { - const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible, jslid } = props; + const { + display, + conid, + database, + changeSetState, + dispatchChangeSet, + tabVisible, + rows, + loadNextData, + errorMessage, + isLoadedAll, + loadedTime, + exportGrid, + allRowCount, + openQuery, + insertedRowCount, + isLoading, + undo, + redo + } = props; // console.log('RENDER GRID', display.baseTable.pureName); const columns = React.useMemo(() => display.allColumns, [display]); // usePropsCompare(props); // console.log(`GRID, conid=${conid}, database=${database}, sql=${sql}`); - const [loadProps, setLoadProps] = React.useState({ - isLoading: false, - loadedRows: [], - isLoadedAll: false, - loadedTime: new Date().getTime(), - allRowCount: null, - errorMessage: null, - jslStatsCounter: 0, - jslChangeIndex: 0, - }); - const { isLoading, loadedRows, isLoadedAll, loadedTime, allRowCount, errorMessage } = loadProps; - const loadedTimeRef = React.useRef(0); const focusFieldRef = React.useRef(null); const [vScrollValueToSet, setvScrollValueToSet] = React.useState(); @@ -239,14 +176,6 @@ export default function DataGridCore(props) { // const [inplaceEditorShouldSave, setInplaceEditorShouldSave] = React.useState(false); // const [inplaceEditorChangedOnCreate, setInplaceEditorChangedOnCreate] = React.useState(false); - const changeSet = changeSetState && changeSetState.value; - const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); - const setOpenedTabs = useSetOpenedTabs(); - - const changeSetRef = React.useRef(changeSet); - - changeSetRef.current = changeSet; - const autofillMarkerCell = React.useMemo( () => selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map((x) => x[0])).length == 1 @@ -257,54 +186,6 @@ export default function DataGridCore(props) { const showModal = useShowModal(); - const handleLoadRowCount = async () => { - const rowCount = await loadRowCount(props); - setLoadProps((oldLoadProps) => ({ - ...oldLoadProps, - allRowCount: rowCount, - })); - }; - - const loadNextData = async () => { - if (isLoading) return; - setLoadProps((oldLoadProps) => ({ - ...oldLoadProps, - isLoading: true, - })); - const loadStart = new Date().getTime(); - loadedTimeRef.current = loadStart; - - const nextRows = await loadDataPage(props, loadedRows.length, 100); - if (loadedTimeRef.current !== loadStart) { - // new load was dispatched - return; - } - // if (!_.isArray(nextRows)) { - // console.log('Error loading data from server', nextRows); - // nextRows = []; - // } - // console.log('nextRows', nextRows); - if (nextRows.errorMessage) { - setLoadProps((oldLoadProps) => ({ - ...oldLoadProps, - isLoading: false, - errorMessage: nextRows.errorMessage, - })); - } else { - if (allRowCount == null) handleLoadRowCount(); - const loadedInfo = { - loadedRows: [...loadedRows, ...nextRows], - loadedTime, - }; - setLoadProps((oldLoadProps) => ({ - ...oldLoadProps, - isLoading: false, - isLoadedAll: oldLoadProps.jslStatsCounter == loadProps.jslStatsCounter && nextRows.length === 0, - ...loadedInfo, - })); - } - }; - // const data = useFetch({ // url: 'database-connections/query-data', // method: 'post', @@ -317,7 +198,6 @@ export default function DataGridCore(props) { // const { rows, columns } = data || {}; const [firstVisibleRowScrollIndex, setFirstVisibleRowScrollIndex] = React.useState(0); const [firstVisibleColumnScrollIndex, setFirstVisibleColumnScrollIndex] = React.useState(0); - const socket = useSocket(); const [headerRowRef, { height: rowHeight }] = useDimensions(); const [tableBodyRef] = useDimensions(); @@ -326,6 +206,9 @@ export default function DataGridCore(props) { const confirmSqlModalState = useModalState(); const [confirmSql, setConfirmSql] = React.useState(''); + const changeSet = changeSetState && changeSetState.value; + const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); + const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => { switch (action.type) { case 'show': @@ -355,8 +238,8 @@ export default function DataGridCore(props) { // usePropsCompare({ loadedRows, columns, containerWidth, display }); - const columnSizes = React.useMemo(() => countColumnSizes(loadedRows, columns, containerWidth, display), [ - loadedRows, + const columnSizes = React.useMemo(() => countColumnSizes(rows, columns, containerWidth, display), [ + rows, columns, containerWidth, display, @@ -376,43 +259,6 @@ export default function DataGridCore(props) { // console.log('visibleRowCountUpperBound', visibleRowCountUpperBound); // console.log('rowHeight', rowHeight); - const reload = () => { - setLoadProps({ - allRowCount: null, - isLoading: false, - loadedRows: [], - isLoadedAll: false, - loadedTime: new Date().getTime(), - errorMessage: null, - jslStatsCounter: 0, - jslChangeIndex: 0, - }); - }; - - const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); - - const rowCountNewIncluded = loadedRows.length + insertedRows.length; - - React.useEffect(() => { - if ( - !isLoadedAll && - !errorMessage && - firstVisibleRowScrollIndex + visibleRowCountUpperBound >= loadedRows.length && - insertedRows.length == 0 - ) { - if (dataPageAvailable(props)) { - // If not, callbacks to load missing metadata are dispatched - loadNextData(); - } - } - if (props.masterLoadedTime && props.masterLoadedTime > loadedTime) { - display.reload(); - } - if (display.cache.refreshTime > loadedTime) { - reload(); - } - }); - React.useEffect(() => { if (tabVisible) { if (focusFieldRef.current) focusFieldRef.current.focus(); @@ -424,31 +270,11 @@ export default function DataGridCore(props) { return newColumn; }, [columnSizes, gridScrollAreaWidth]); - const handleJslDataStats = React.useCallback((stats) => { - if (stats.changeIndex < loadProps.jslChangeIndex) return; - setLoadProps((oldProps) => ({ - ...oldProps, - allRowCount: stats.rowCount, - isLoadedAll: false, - jslStatsCounter: oldProps.jslStatsCounter + 1, - jslChangeIndex: stats.changeIndex, - })); - }, []); - React.useEffect(() => { - if (jslid && socket) { - socket.on(`jsldata-stats-${jslid}`, handleJslDataStats); - return () => { - socket.off(`jsldata-stats-${jslid}`, handleJslDataStats); - }; - } - }, [jslid]); - - React.useEffect(() => { - if (props.onReferenceSourceChanged && ((loadedRows && loadedRows.length > 0) || isLoadedAll)) { + if (props.onReferenceSourceChanged && ((rows && rows.length > 0) || isLoadedAll)) { props.onReferenceSourceChanged(getSelectedRowData(), loadedTime); } - }, [selectedCells, props.refReloadToken, loadedRows && loadedRows[0]]); + }, [selectedCells, props.refReloadToken, rows && rows[0]]); // const handleCloseInplaceEditor = React.useCallback( // mode => { @@ -487,6 +313,12 @@ export default function DataGridCore(props) { } }, [display && display.focusedColumn]); + React.useEffect(() => { + if (rows && loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= rows.length) { + loadNextData(); + } + }); + React.useEffect(() => { if (display.groupColumns) { props.onReferenceClick({ @@ -504,7 +336,7 @@ export default function DataGridCore(props) { const rowCountInfo = React.useMemo(() => { if (selectedCells.length > 1 && selectedCells.every((x) => _.isNumber(x[0]) && _.isNumber(x[1]))) { let sum = _.sumBy(selectedCells, (cell) => { - const row = loadedRows[cell[0]]; + const row = rows[cell[0]]; if (row) { const colName = realColumnUniqueNames[cell[1]]; if (colName) { @@ -526,9 +358,9 @@ export default function DataGridCore(props) { // if (this.isLoadingFirstPage) return "Loading first page..."; // if (this.isFirstPageError) return "Error loading first page"; // return `Rows: ${this.rowCount.toLocaleString()}`; - }, [selectedCells, allRowCount, loadedRows, visibleRealColumns]); + }, [selectedCells, allRowCount, rows, visibleRealColumns]); - if (!loadedRows || !columns || columns.length == 0) + if (!rows || !columns || columns.length == 0) return ( @@ -563,7 +395,7 @@ export default function DataGridCore(props) { setNull={setNull} exportGrid={exportGrid} filterSelectedValue={filterSelectedValue} - openQuery={display.baseTable ? openQuery : null} + openQuery={openQuery} /> ); }; @@ -617,108 +449,83 @@ export default function DataGridCore(props) { copyToClipboard(); } - function exportGrid() { - const initialValues = {}; - if (jslid) { - const archiveMatch = jslid.match(/^archive:\/\/([^/]+)\/(.*)$/); - if (archiveMatch) { - initialValues.sourceStorageType = 'archive'; - initialValues.sourceArchiveFolder = archiveMatch[1]; - initialValues.sourceList = [archiveMatch[2]]; - } else { - initialValues.sourceStorageType = 'jsldata'; - initialValues.sourceJslId = jslid; - initialValues.sourceList = ['query-data']; - } - } else { - initialValues.sourceStorageType = 'query'; - initialValues.sourceConnectionId = conid; - initialValues.sourceDatabaseName = database; - initialValues.sourceSql = display.getExportQuery(); - initialValues.sourceList = display.baseTable ? [display.baseTable.pureName] : []; - } - showModal((modalState) => ); - } - function setCellValue(chs, cell, value) { - return setChangeSetValue( - chs, - display.getChangeSetField( - loadedAndInsertedRows[cell[0]], - realColumnUniqueNames[cell[1]], - cell[0] >= loadedRows.length ? cell[0] - loadedRows.length : null - ), - value - ); + // return setChangeSetValue( + // chs, + // display.getChangeSetField( + // rows[cell[0]], + // realColumnUniqueNames[cell[1]], + // cell[0] >= rows.length ? cell[0] - rows.length : null + // ), + // value + // ); } function handlePaste(event) { - var pastedText = undefined; - // @ts-ignore - if (window.clipboardData && window.clipboardData.getData) { - // IE - // @ts-ignore - pastedText = window.clipboardData.getData('Text'); - } else if (event.clipboardData && event.clipboardData.getData) { - pastedText = event.clipboardData.getData('text/plain'); - } - event.preventDefault(); - const pasteRows = pastedText - .replace(/\r/g, '') - .split('\n') - .map((row) => row.split('\t')); - let chs = changeSet; - let allRows = loadedAndInsertedRows; - - if (selectedCells.length <= 1) { - const startRow = isRegularCell(currentCell) ? currentCell[0] : loadedAndInsertedRows.length; - const startCol = isRegularCell(currentCell) ? currentCell[1] : 0; - let rowIndex = startRow; - for (const rowData of pasteRows) { - if (rowIndex >= allRows.length) { - chs = changeSetInsertNewRow(chs, display.baseTable); - allRows = [...loadedRows, ...getChangeSetInsertedRows(chs, display.baseTable)]; - } - let colIndex = startCol; - const row = allRows[rowIndex]; - for (const cell of rowData) { - chs = setChangeSetValue( - chs, - display.getChangeSetField( - row, - realColumnUniqueNames[colIndex], - rowIndex >= loadedRows.length ? rowIndex - loadedRows.length : null - ), - cell == '(NULL)' ? null : cell - ); - colIndex += 1; - } - rowIndex += 1; - } - } - if (selectedCells.length > 1) { - const regularSelected = selectedCells.filter(isRegularCell); - const startRow = _.min(regularSelected.map((x) => x[0])); - const startCol = _.min(regularSelected.map((x) => x[1])); - for (const cell of regularSelected) { - const [rowIndex, colIndex] = cell; - const selectionRow = rowIndex - startRow; - const selectionCol = colIndex - startCol; - const pasteRow = pasteRows[selectionRow % pasteRows.length]; - const pasteCell = pasteRow[selectionCol % pasteRow.length]; - chs = setCellValue(chs, cell, pasteCell); - } - } - - setChangeSet(chs); + // var pastedText = undefined; + // // @ts-ignore + // if (window.clipboardData && window.clipboardData.getData) { + // // IE + // // @ts-ignore + // pastedText = window.clipboardData.getData('Text'); + // } else if (event.clipboardData && event.clipboardData.getData) { + // pastedText = event.clipboardData.getData('text/plain'); + // } + // event.preventDefault(); + // const pasteRows = pastedText + // .replace(/\r/g, '') + // .split('\n') + // .map((row) => row.split('\t')); + // let chs = changeSet; + // let allRows = loadedAndInsertedRows; + // if (selectedCells.length <= 1) { + // const startRow = isRegularCell(currentCell) ? currentCell[0] : loadedAndInsertedRows.length; + // const startCol = isRegularCell(currentCell) ? currentCell[1] : 0; + // let rowIndex = startRow; + // for (const rowData of pasteRows) { + // if (rowIndex >= allRows.length) { + // chs = changeSetInsertNewRow(chs, display.baseTable); + // allRows = [...loadedRows, ...getChangeSetInsertedRows(chs, display.baseTable)]; + // } + // let colIndex = startCol; + // const row = allRows[rowIndex]; + // for (const cell of rowData) { + // chs = setChangeSetValue( + // chs, + // display.getChangeSetField( + // row, + // realColumnUniqueNames[colIndex], + // rowIndex >= loadedRows.length ? rowIndex - loadedRows.length : null + // ), + // cell == '(NULL)' ? null : cell + // ); + // colIndex += 1; + // } + // rowIndex += 1; + // } + // } + // if (selectedCells.length > 1) { + // const regularSelected = selectedCells.filter(isRegularCell); + // const startRow = _.min(regularSelected.map((x) => x[0])); + // const startCol = _.min(regularSelected.map((x) => x[1])); + // for (const cell of regularSelected) { + // const [rowIndex, colIndex] = cell; + // const selectionRow = rowIndex - startRow; + // const selectionCol = colIndex - startCol; + // const pasteRow = pasteRows[selectionRow % pasteRows.length]; + // const pasteCell = pasteRow[selectionCol % pasteRow.length]; + // chs = setCellValue(chs, cell, pasteCell); + // } + // } + // setChangeSet(chs); } function setNull() { - let chs = changeSet; - selectedCells.filter(isRegularCell).forEach((cell) => { - chs = setCellValue(chs, cell, null); - }); - setChangeSet(chs); + // let chs = changeSet; + // selectedCells.filter(isRegularCell).forEach((cell) => { + // chs = setCellValue(chs, cell, null); + // }); + // setChangeSet(chs); } function cellsToRegularCells(cells) { @@ -746,7 +553,7 @@ export default function DataGridCore(props) { const rowIndexes = _.sortBy(_.uniq(cells.map((x) => x[0]))); const lines = rowIndexes.map((rowIndex) => { let colIndexes = _.sortBy(cells.filter((x) => x[0] == rowIndex).map((x) => x[1])); - const rowData = loadedAndInsertedRows[rowIndex]; + const rowData = rows[rowIndex]; if (!rowData) return ''; const line = colIndexes .map((col) => realColumnUniqueNames[col]) @@ -786,7 +593,7 @@ export default function DataGridCore(props) { const rowIndexes = _.uniq((autofillSelectedCells || []).map((x) => x[0])).filter((x) => x != currentRowNumber); // @ts-ignore const colNames = selectedCells.map((cell) => realColumnUniqueNames[cell[1]]); - const changeObject = _.pick(loadedAndInsertedRows[currentRowNumber], colNames); + const changeObject = _.pick(rows[currentRowNumber], colNames); setChangeSet( batchUpdateChangeSet( changeSet, @@ -805,13 +612,13 @@ export default function DataGridCore(props) { function getRowDefinitions(rowIndexes) { const res = []; - if (!loadedAndInsertedRows) return res; - for (const index of rowIndexes) { - if (loadedAndInsertedRows[index] && _.isNumber(index)) { - const insertedRowIndex = index >= loadedRows.length ? index - loadedRows.length : null; - res.push(display.getChangeSetRow(loadedAndInsertedRows[index], insertedRowIndex)); - } - } + // if (!loadedAndInsertedRows) return res; + // for (const index of rowIndexes) { + // if (loadedAndInsertedRows[index] && _.isNumber(index)) { + // const insertedRowIndex = index >= loadedRows.length ? index - loadedRows.length : null; + // res.push(display.getChangeSetRow(loadedAndInsertedRows[index], insertedRowIndex)); + // } + // } return res; } @@ -824,7 +631,7 @@ export default function DataGridCore(props) { } function getSelectedRowData() { - return _.compact(getSelectedRowIndexes().map((index) => loadedRows && loadedRows[index])); + return _.compact(getSelectedRowIndexes().map((index) => rows && rows[index])); } function revertRowChanges() { @@ -841,7 +648,7 @@ export default function DataGridCore(props) { if (!isRegularCell(cell)) continue; const modelIndex = columnSizes.realToModel(cell[1]); const columnName = columns[modelIndex].uniqueName; - let value = loadedRows[cell[0]][columnName]; + let value = rows[cell[0]][columnName]; let svalue = getFilterValueExpression(value, columns[modelIndex].dataType); if (_.has(flts, columnName)) flts[columnName] += ',' + svalue; else flts[columnName] = svalue; @@ -850,21 +657,6 @@ export default function DataGridCore(props) { display.setFilters(flts); } - function openQuery() { - openNewTab(setOpenedTabs, { - title: 'Query', - icon: 'sql.svg', - tabComponent: 'QueryTab', - props: { - initialScript: display.getExportQuery(), - schemaName: display.baseTable.schemaName, - pureName: display.baseTable.pureName, - conid, - database, - }, - }); - } - function revertAllChanges() { setChangeSet(createChangeSet()); } @@ -882,7 +674,7 @@ export default function DataGridCore(props) { if (event.deltaY < 0) { newFirstVisibleRowScrollIndex -= wheelRowCount; } - let rowCount = rowCountNewIncluded; + let rowCount = rows.length; if (newFirstVisibleRowScrollIndex + visibleRowCountLowerBound > rowCount) { newFirstVisibleRowScrollIndex = rowCount - visibleRowCountLowerBound + 1; } @@ -895,58 +687,44 @@ export default function DataGridCore(props) { setvScrollValueToSetDate(new Date()); } - // async function blurEditorAndSave() { - // setInplaceEditorCell(null); - // setInplaceEditorInitText(null); - // await sleep(1); - // } - - function undo() { - dispatchChangeSet({ type: 'undo' }); - } - function redo() { - dispatchChangeSet({ type: 'redo' }); - } - function handleSave() { if (inplaceEditorState.cell) { // @ts-ignore dispatchInsplaceEditor({ type: 'shouldSave' }); return; } - const script = changeSetToSql(changeSetRef.current, display.dbinfo); - const sql = scriptToSql(display.driver, script); - setConfirmSql(sql); - confirmSqlModalState.open(); + // const script = changeSetToSql(changeSetRef.current, display.dbinfo); + // const sql = scriptToSql(display.driver, script); + // setConfirmSql(sql); + // confirmSqlModalState.open(); } async function handleConfirmSql() { - const resp = await axios.request({ - url: 'database-connections/query-data', - method: 'post', - params: { - conid, - database, - }, - data: { sql: confirmSql }, - }); - - const { errorMessage } = resp.data || {}; - if (errorMessage) { - showModal((modalState) => ( - - )); - } else { - dispatchChangeSet({ type: 'reset', value: createChangeSet() }); - setConfirmSql(null); - display.reload(); - } + // const resp = await axios.request({ + // url: 'database-connections/query-data', + // method: 'post', + // params: { + // conid, + // database, + // }, + // data: { sql: confirmSql }, + // }); + // const { errorMessage } = resp.data || {}; + // if (errorMessage) { + // showModal((modalState) => ( + // + // )); + // } else { + // dispatchChangeSet({ type: 'reset', value: createChangeSet() }); + // setConfirmSql(null); + // display.reload(); + // } } const insertNewRow = () => { if (display.baseTable) { setChangeSet(changeSetInsertNewRow(changeSet, display.baseTable)); - const cell = [rowCountNewIncluded, (currentCell && currentCell[1]) || 0]; + const cell = [rows.length, (currentCell && currentCell[1]) || 0]; // @ts-ignore setCurrentCell(cell); // @ts-ignore @@ -1060,7 +838,7 @@ export default function DataGridCore(props) { function handleCursorMove(event) { if (!isRegularCell(currentCell)) return null; - let rowCount = rowCountNewIncluded; + let rowCount = rows.length; if (event.ctrlKey) { switch (event.keyCode) { case keycodes.upArrow: @@ -1118,7 +896,7 @@ export default function DataGridCore(props) { } function moveCurrentCell(row, col, event = null) { - const rowCount = rowCountNewIncluded; + const rowCount = rows.length; if (row < 0) row = 0; if (row >= rowCount) row = rowCount - 1; @@ -1140,7 +918,7 @@ export default function DataGridCore(props) { if (row != null) { let newRow = null; - const rowCount = rowCountNewIncluded; + const rowCount = rows.length; if (rowCount == 0) return; if (row < firstVisibleRowScrollIndex) newRow = row; @@ -1202,7 +980,7 @@ export default function DataGridCore(props) { // columnSizes.getVisibleScrollSizeSum() // ); - const loadedAndInsertedRows = [...loadedRows, ...insertedRows]; + // const loadedAndInsertedRows = [...loadedRows, ...insertedRows]; // console.log('focusFieldRef.current', focusFieldRef.current); @@ -1282,7 +1060,7 @@ export default function DataGridCore(props) { )} - {loadedAndInsertedRows + {rows .slice(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) .map((row, index) => ( = loadedRows.length - ? firstVisibleRowScrollIndex + index - loadedRows.length + firstVisibleRowScrollIndex + index >= rows.length - (insertedRowCount || 0) + ? firstVisibleRowScrollIndex + index - rows.length - (insertedRowCount || 0) : null } autofillMarkerCell={filterCellForRow(autofillMarkerCell, firstVisibleRowScrollIndex + index)} @@ -1321,9 +1099,9 @@ export default function DataGridCore(props) { valueToSet={vScrollValueToSet} valueToSetDate={vScrollValueToSetDate} minimum={0} - maximum={rowCountNewIncluded - visibleRowCountUpperBound + 2} + maximum={rows.length - visibleRowCountUpperBound + 2} onScroll={handleRowScroll} - viewportRatio={visibleRowCountUpperBound / rowCountNewIncluded} + viewportRatio={visibleRowCountUpperBound / rows.length} /> ; + const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible, jslid } = props; + + const [loadProps, setLoadProps] = React.useState({ + isLoading: false, + loadedRows: [], + isLoadedAll: false, + loadedTime: new Date().getTime(), + allRowCount: null, + errorMessage: null, + jslStatsCounter: 0, + jslChangeIndex: 0, + }); + const { isLoading, loadedRows, isLoadedAll, loadedTime, allRowCount, errorMessage } = loadProps; + const showModal = useShowModal(); + + const loadedTimeRef = React.useRef(0); + + const changeSet = changeSetState && changeSetState.value; + const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); + const setOpenedTabs = useSetOpenedTabs(); + const socket = useSocket(); + + const changeSetRef = React.useRef(changeSet); + + changeSetRef.current = changeSet; + + const handleLoadRowCount = async () => { + const rowCount = await loadRowCount(props); + setLoadProps((oldLoadProps) => ({ + ...oldLoadProps, + allRowCount: rowCount, + })); + }; + + const reload = () => { + setLoadProps({ + allRowCount: null, + isLoading: false, + loadedRows: [], + isLoadedAll: false, + loadedTime: new Date().getTime(), + errorMessage: null, + jslStatsCounter: 0, + jslChangeIndex: 0, + }); + }; + + function exportGrid() { + const initialValues = {}; + if (jslid) { + const archiveMatch = jslid.match(/^archive:\/\/([^/]+)\/(.*)$/); + if (archiveMatch) { + initialValues.sourceStorageType = 'archive'; + initialValues.sourceArchiveFolder = archiveMatch[1]; + initialValues.sourceList = [archiveMatch[2]]; + } else { + initialValues.sourceStorageType = 'jsldata'; + initialValues.sourceJslId = jslid; + initialValues.sourceList = ['query-data']; + } + } else { + initialValues.sourceStorageType = 'query'; + initialValues.sourceConnectionId = conid; + initialValues.sourceDatabaseName = database; + initialValues.sourceSql = display.getExportQuery(); + initialValues.sourceList = display.baseTable ? [display.baseTable.pureName] : []; + } + showModal((modalState) => ); + } + + React.useEffect(() => { + if (props.masterLoadedTime && props.masterLoadedTime > loadedTime) { + display.reload(); + } + if (display.cache.refreshTime > loadedTime) { + reload(); + } + }); + + const loadNextData = async () => { + if (isLoading) return; + setLoadProps((oldLoadProps) => ({ + ...oldLoadProps, + isLoading: true, + })); + const loadStart = new Date().getTime(); + loadedTimeRef.current = loadStart; + + const nextRows = await loadDataPage(props, loadedRows.length, 100); + if (loadedTimeRef.current !== loadStart) { + // new load was dispatched + return; + } + // if (!_.isArray(nextRows)) { + // console.log('Error loading data from server', nextRows); + // nextRows = []; + // } + // console.log('nextRows', nextRows); + if (nextRows.errorMessage) { + setLoadProps((oldLoadProps) => ({ + ...oldLoadProps, + isLoading: false, + errorMessage: nextRows.errorMessage, + })); + } else { + if (allRowCount == null) handleLoadRowCount(); + const loadedInfo = { + loadedRows: [...loadedRows, ...nextRows], + loadedTime, + }; + setLoadProps((oldLoadProps) => ({ + ...oldLoadProps, + isLoading: false, + isLoadedAll: oldLoadProps.jslStatsCounter == loadProps.jslStatsCounter && nextRows.length === 0, + ...loadedInfo, + })); + } + }; + + const handleJslDataStats = React.useCallback((stats) => { + if (stats.changeIndex < loadProps.jslChangeIndex) return; + setLoadProps((oldProps) => ({ + ...oldProps, + allRowCount: stats.rowCount, + isLoadedAll: false, + jslStatsCounter: oldProps.jslStatsCounter + 1, + jslChangeIndex: stats.changeIndex, + })); + }, []); + + React.useEffect(() => { + if (jslid && socket) { + socket.on(`jsldata-stats-${jslid}`, handleJslDataStats); + return () => { + socket.off(`jsldata-stats-${jslid}`, handleJslDataStats); + }; + } + }, [jslid]); + + const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); + const rowCountNewIncluded = loadedRows.length + insertedRows.length; + + const handleLoadNextData = () => { + if (!isLoadedAll && !errorMessage && insertedRows.length == 0) { + if (dataPageAvailable(props)) { + // If not, callbacks to load missing metadata are dispatched + loadNextData(); + } + } + }; + + function openQuery() { + openNewTab(setOpenedTabs, { + title: 'Query', + icon: 'sql.svg', + tabComponent: 'QueryTab', + props: { + initialScript: display.getExportQuery(), + schemaName: display.baseTable.schemaName, + pureName: display.baseTable.pureName, + conid, + database, + }, + }); + } + + return ( + + ); } diff --git a/packages/web/src/datagrid/types.ts b/packages/web/src/datagrid/types.ts index 65a591ada..069fbeefd 100644 --- a/packages/web/src/datagrid/types.ts +++ b/packages/web/src/datagrid/types.ts @@ -1,14 +1,11 @@ import { GridDisplay, ChangeSet, GridReferenceDefinition } from '@dbgate/datalib'; export interface DataGridProps { - conid?: string; - database?: string; display: GridDisplay; tabVisible?: boolean; changeSetState?: { value: ChangeSet }; dispatchChangeSet?: Function; toolbarPortalRef?: any; - jslid?: string; showReferences?: boolean; onReferenceClick?: (def: GridReferenceDefinition) => void; onReferenceSourceChanged?: Function; @@ -16,3 +13,27 @@ export interface DataGridProps { masterLoadedTime?: number; managerSize?: number; } + +export interface DataGridCoreProps extends DataGridProps { + rows: any[]; + loadNextData?: Function; + exportGrid?: Function; + openQuery?: Function; + undo?: Function; + redo?: Function; + + errorMessage?: string; + isLoadedAll?: boolean; + loadedTime?: any; + allRowCount?: number; + conid?: string; + database?: string; + insertedRowCount?: number; + isLoading?: boolean; +} + +export interface LoadingDataGridProps extends DataGridProps { + conid?: string; + database?: string; + jslid?: string; +} From b314e363cdf9a46d4be0fb04a9d98f6997774621 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 24 Oct 2020 09:32:06 +0200 Subject: [PATCH 3/8] loading grid - split into JslDataGridCode and SqlDataGridCore --- packages/api/src/proc/sessionProcess.js | 2 +- .../web/src/datagrid/ChangeSetDataGrid.js | 17 ---- packages/web/src/datagrid/DataGrid.js | 5 +- packages/web/src/datagrid/DataGridCore.js | 9 +- packages/web/src/datagrid/JslDataGridCore.js | 93 ++++++++++++++++++ ...dingDataGrid.js => LoadingDataGridCore.js} | 86 +++++------------ packages/web/src/datagrid/SqlDataGridCore.js | 95 +++++++++++++++++++ packages/web/src/datagrid/TableDataGrid.js | 2 + packages/web/src/sqleditor/JslDataGrid.js | 3 +- packages/web/src/tabs/ViewDataTab.js | 4 +- 10 files changed, 228 insertions(+), 88 deletions(-) delete mode 100644 packages/web/src/datagrid/ChangeSetDataGrid.js create mode 100644 packages/web/src/datagrid/JslDataGridCore.js rename packages/web/src/datagrid/{LoadingDataGrid.js => LoadingDataGridCore.js} (69%) create mode 100644 packages/web/src/datagrid/SqlDataGridCore.js diff --git a/packages/api/src/proc/sessionProcess.js b/packages/api/src/proc/sessionProcess.js index a15bb3f83..ef15c74af 100644 --- a/packages/api/src/proc/sessionProcess.js +++ b/packages/api/src/proc/sessionProcess.js @@ -19,7 +19,7 @@ class TableWriter { this.jslid = uuidv1(); this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`); this.currentRowCount = 0; - this.currentChangeIndex = 0; + this.currentChangeIndex = 1; fs.writeFileSync(this.currentFile, JSON.stringify({ columns }) + '\n'); this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' }); this.writeCurrentStats(false, false); diff --git a/packages/web/src/datagrid/ChangeSetDataGrid.js b/packages/web/src/datagrid/ChangeSetDataGrid.js deleted file mode 100644 index 3c20ec515..000000000 --- a/packages/web/src/datagrid/ChangeSetDataGrid.js +++ /dev/null @@ -1,17 +0,0 @@ -import { getChangeSetInsertedRows } from '@dbgate/datalib'; -import React from 'react'; -import DataGridCore from './DataGridCore'; - -export default function ChangeSetDataGrid(props) { - const { changeSet, display, dispatchChangeSet } = props; - function undo() { - dispatchChangeSet({ type: 'undo' }); - } - function redo() { - dispatchChangeSet({ type: 'redo' }); - } - - const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); - - return ; -} diff --git a/packages/web/src/datagrid/DataGrid.js b/packages/web/src/datagrid/DataGrid.js index f7cfb19c4..c03078fc1 100644 --- a/packages/web/src/datagrid/DataGrid.js +++ b/packages/web/src/datagrid/DataGrid.js @@ -15,7 +15,6 @@ import { } from './ManagerStyles'; import ReferenceManager from './ReferenceManager'; import { HorizontalSplitter } from '../widgets/Splitter'; -import LoadingDataGrid from './LoadingDataGrid'; const MainContainer = styled.div` position: absolute; @@ -42,8 +41,8 @@ const DataGridContainer = styled.div` flex-grow: 1; `; -/** @param props {import('./types').LoadingDataGridProps} */ export default function DataGrid(props) { + const { GridCore } = props; const Container1 = props.showReferences ? ManagerOuterContainer1 : ManagerOuterContainerFull; const [managerSize, setManagerSize] = React.useState(0); return ( @@ -62,7 +61,7 @@ export default function DataGrid(props) { - + diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index d67480e8c..6edaf3e5d 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -145,8 +145,6 @@ export default function DataGridCore(props) { openQuery, insertedRowCount, isLoading, - undo, - redo } = props; // console.log('RENDER GRID', display.baseTable.pureName); const columns = React.useMemo(() => display.allColumns, [display]); @@ -687,6 +685,13 @@ export default function DataGridCore(props) { setvScrollValueToSetDate(new Date()); } + function undo() { + dispatchChangeSet({ type: 'undo' }); + } + function redo() { + dispatchChangeSet({ type: 'redo' }); + } + function handleSave() { if (inplaceEditorState.cell) { // @ts-ignore diff --git a/packages/web/src/datagrid/JslDataGridCore.js b/packages/web/src/datagrid/JslDataGridCore.js new file mode 100644 index 000000000..53ae17505 --- /dev/null +++ b/packages/web/src/datagrid/JslDataGridCore.js @@ -0,0 +1,93 @@ +import React from 'react'; +import axios from '../utility/axios'; +import { useSetOpenedTabs } from '../utility/globalState'; +import DataGridCore from './DataGridCore'; +import useSocket from '../utility/SocketProvider'; +import useShowModal from '../modals/showModal'; +import ImportExportModal from '../modals/ImportExportModal'; +import { getChangeSetInsertedRows } from '@dbgate/datalib'; +import { openNewTab } from '../utility/common'; +import LoadingDataGridCore from './LoadingDataGridCore'; + +async function loadDataPage(props, offset, limit) { + const { jslid } = props; + + const response = await axios.request({ + url: 'jsldata/get-rows', + method: 'get', + params: { + jslid, + offset, + limit, + }, + }); + return response.data; +} + +function dataPageAvailable(props) { + return true; +} + +async function loadRowCount(props) { + const { jslid } = props; + + const response = await axios.request({ + url: 'jsldata/get-stats', + method: 'get', + params: { + jslid, + }, + }); + return response.data.rowCount; +} + +export default function JslDataGridCore(props) { + const { jslid } = props; + const [changeIndex, setChangeIndex] = React.useState(0); + + const showModal = useShowModal(); + + const setOpenedTabs = useSetOpenedTabs(); + const socket = useSocket(); + + function exportGrid() { + const initialValues = {}; + const archiveMatch = jslid.match(/^archive:\/\/([^/]+)\/(.*)$/); + if (archiveMatch) { + initialValues.sourceStorageType = 'archive'; + initialValues.sourceArchiveFolder = archiveMatch[1]; + initialValues.sourceList = [archiveMatch[2]]; + } else { + initialValues.sourceStorageType = 'jsldata'; + initialValues.sourceJslId = jslid; + initialValues.sourceList = ['query-data']; + } + showModal((modalState) => ); + } + + const handleJslDataStats = React.useCallback((stats) => { + if (stats.changeIndex < changeIndex) return; + setChangeIndex(stats.changeIndex); + }, [changeIndex]); + + React.useEffect(() => { + if (jslid && socket) { + socket.on(`jsldata-stats-${jslid}`, handleJslDataStats); + return () => { + socket.off(`jsldata-stats-${jslid}`, handleJslDataStats); + }; + } + }, [jslid]); + + return ( + setChangeIndex(0)} + /> + ); +} diff --git a/packages/web/src/datagrid/LoadingDataGrid.js b/packages/web/src/datagrid/LoadingDataGridCore.js similarity index 69% rename from packages/web/src/datagrid/LoadingDataGrid.js rename to packages/web/src/datagrid/LoadingDataGridCore.js index d08ce67ea..9b87ff74f 100644 --- a/packages/web/src/datagrid/LoadingDataGrid.js +++ b/packages/web/src/datagrid/LoadingDataGridCore.js @@ -6,7 +6,6 @@ import useSocket from '../utility/SocketProvider'; import useShowModal from '../modals/showModal'; import ImportExportModal from '../modals/ImportExportModal'; import { getChangeSetInsertedRows } from '@dbgate/datalib'; -import ChangeSetDataGrid from './ChangeSetDataGrid'; import { openNewTab } from '../utility/common'; /** @param props {import('./types').LoadingDataGridProps} */ @@ -79,8 +78,20 @@ async function loadRowCount(props) { return parseInt(response.data.rows[0].count); } -export default function LoadingDataGrid(props) { - const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible, jslid } = props; +export default function LoadingDataGridCore(props) { + const { + display, + changeSetState, + dispatchChangeSet, + tabVisible, + loadDataPage, + dataPageAvailable, + loadRowCount, + loadNextDataToken, + onReload, + exportGrid, + openQuery, + } = props; const [loadProps, setLoadProps] = React.useState({ isLoading: false, @@ -89,8 +100,7 @@ export default function LoadingDataGrid(props) { loadedTime: new Date().getTime(), allRowCount: null, errorMessage: null, - jslStatsCounter: 0, - jslChangeIndex: 0, + loadNextDataToken: 0, }); const { isLoading, loadedRows, isLoadedAll, loadedTime, allRowCount, errorMessage } = loadProps; const showModal = useShowModal(); @@ -122,34 +132,11 @@ export default function LoadingDataGrid(props) { isLoadedAll: false, loadedTime: new Date().getTime(), errorMessage: null, - jslStatsCounter: 0, - jslChangeIndex: 0, + loadNextDataToken: 0, }); + if (onReload) onReload(); }; - function exportGrid() { - const initialValues = {}; - if (jslid) { - const archiveMatch = jslid.match(/^archive:\/\/([^/]+)\/(.*)$/); - if (archiveMatch) { - initialValues.sourceStorageType = 'archive'; - initialValues.sourceArchiveFolder = archiveMatch[1]; - initialValues.sourceList = [archiveMatch[2]]; - } else { - initialValues.sourceStorageType = 'jsldata'; - initialValues.sourceJslId = jslid; - initialValues.sourceList = ['query-data']; - } - } else { - initialValues.sourceStorageType = 'query'; - initialValues.sourceConnectionId = conid; - initialValues.sourceDatabaseName = database; - initialValues.sourceSql = display.getExportQuery(); - initialValues.sourceList = display.baseTable ? [display.baseTable.pureName] : []; - } - showModal((modalState) => ); - } - React.useEffect(() => { if (props.masterLoadedTime && props.masterLoadedTime > loadedTime) { display.reload(); @@ -193,31 +180,19 @@ export default function LoadingDataGrid(props) { setLoadProps((oldLoadProps) => ({ ...oldLoadProps, isLoading: false, - isLoadedAll: oldLoadProps.jslStatsCounter == loadProps.jslStatsCounter && nextRows.length === 0, + isLoadedAll: oldLoadProps.loadNextDataToken == loadNextDataToken && nextRows.length === 0, + loadNextDataToken, ...loadedInfo, })); } }; - const handleJslDataStats = React.useCallback((stats) => { - if (stats.changeIndex < loadProps.jslChangeIndex) return; + React.useEffect(()=>{ setLoadProps((oldProps) => ({ ...oldProps, - allRowCount: stats.rowCount, isLoadedAll: false, - jslStatsCounter: oldProps.jslStatsCounter + 1, - jslChangeIndex: stats.changeIndex, })); - }, []); - - React.useEffect(() => { - if (jslid && socket) { - socket.on(`jsldata-stats-${jslid}`, handleJslDataStats); - return () => { - socket.off(`jsldata-stats-${jslid}`, handleJslDataStats); - }; - } - }, [jslid]); + },[loadNextDataToken]); const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); const rowCountNewIncluded = loadedRows.length + insertedRows.length; @@ -231,23 +206,8 @@ export default function LoadingDataGrid(props) { } }; - function openQuery() { - openNewTab(setOpenedTabs, { - title: 'Query', - icon: 'sql.svg', - tabComponent: 'QueryTab', - props: { - initialScript: display.getExportQuery(), - schemaName: display.baseTable.schemaName, - pureName: display.baseTable.pureName, - conid, - database, - }, - }); - } - return ( - diff --git a/packages/web/src/datagrid/SqlDataGridCore.js b/packages/web/src/datagrid/SqlDataGridCore.js new file mode 100644 index 000000000..c44711124 --- /dev/null +++ b/packages/web/src/datagrid/SqlDataGridCore.js @@ -0,0 +1,95 @@ +import React from 'react'; +import axios from '../utility/axios'; +import { useSetOpenedTabs } from '../utility/globalState'; +import DataGridCore from './DataGridCore'; +import useSocket from '../utility/SocketProvider'; +import useShowModal from '../modals/showModal'; +import ImportExportModal from '../modals/ImportExportModal'; +import { getChangeSetInsertedRows } from '@dbgate/datalib'; +import { openNewTab } from '../utility/common'; +import LoadingDataGridCore from './LoadingDataGridCore'; + +/** @param props {import('./types').LoadingDataGridProps} */ +async function loadDataPage(props, offset, limit) { + const { display, conid, database } = props; + + const sql = display.getPageQuery(offset, limit); + + const response = await axios.request({ + url: 'database-connections/query-data', + method: 'post', + params: { + conid, + database, + }, + data: { sql }, + }); + + if (response.data.errorMessage) return response.data; + return response.data.rows; +} + +function dataPageAvailable(props) { + const { display } = props; + const sql = display.getPageQuery(0, 1); + return !!sql; +} + +async function loadRowCount(props) { + const { display, conid, database } = props; + + const sql = display.getCountQuery(); + + const response = await axios.request({ + url: 'database-connections/query-data', + method: 'post', + params: { + conid, + database, + }, + data: { sql }, + }); + + return parseInt(response.data.rows[0].count); +} + +export default function SqlDataGridCore(props) { + const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible } = props; + const showModal = useShowModal(); + const setOpenedTabs = useSetOpenedTabs(); + + function exportGrid() { + const initialValues = {}; + initialValues.sourceStorageType = 'query'; + initialValues.sourceConnectionId = conid; + initialValues.sourceDatabaseName = database; + initialValues.sourceSql = display.getExportQuery(); + initialValues.sourceList = display.baseTable ? [display.baseTable.pureName] : []; + showModal((modalState) => ); + } + function openQuery() { + openNewTab(setOpenedTabs, { + title: 'Query', + icon: 'sql.svg', + tabComponent: 'QueryTab', + props: { + initialScript: display.getExportQuery(), + schemaName: display.baseTable.schemaName, + pureName: display.baseTable.pureName, + conid, + database, + }, + }); + } + + return ( + + ); +} diff --git a/packages/web/src/datagrid/TableDataGrid.js b/packages/web/src/datagrid/TableDataGrid.js index 685465fe6..0f2fd147c 100644 --- a/packages/web/src/datagrid/TableDataGrid.js +++ b/packages/web/src/datagrid/TableDataGrid.js @@ -10,6 +10,7 @@ import useSocket from '../utility/SocketProvider'; import { VerticalSplitter } from '../widgets/Splitter'; import stableStringify from 'json-stable-stringify'; import ReferenceHeader from './ReferenceHeader'; +import SqlDataGridCore from './SqlDataGridCore'; const ReferenceContainer = styled.div` position: absolute; @@ -162,6 +163,7 @@ export default function TableDataGrid({ onReferenceSourceChanged={reference ? handleReferenceSourceChanged : null} refReloadToken={refReloadToken.toString()} masterLoadedTime={masterLoadedTime} + GridCore={SqlDataGridCore} /> {reference && ( diff --git a/packages/web/src/sqleditor/JslDataGrid.js b/packages/web/src/sqleditor/JslDataGrid.js index ad4dd3378..192c0ce03 100644 --- a/packages/web/src/sqleditor/JslDataGrid.js +++ b/packages/web/src/sqleditor/JslDataGrid.js @@ -2,6 +2,7 @@ import React from 'react'; import DataGrid from '../datagrid/DataGrid'; import { JslGridDisplay, createGridConfig, createGridCache } from '@dbgate/datalib'; import useFetch from '../utility/useFetch'; +import JslDataGridCore from '../datagrid/JslDataGridCore'; export default function JslDataGrid({ jslid }) { const info = useFetch({ @@ -19,5 +20,5 @@ export default function JslDataGrid({ jslid }) { cache, ]); - return ; + return ; } diff --git a/packages/web/src/tabs/ViewDataTab.js b/packages/web/src/tabs/ViewDataTab.js index ca134c2fa..14d0c546f 100644 --- a/packages/web/src/tabs/ViewDataTab.js +++ b/packages/web/src/tabs/ViewDataTab.js @@ -10,6 +10,7 @@ import useUndoReducer from '../utility/useUndoReducer'; import usePropsCompare from '../utility/usePropsCompare'; import { useUpdateDatabaseForTab } from '../utility/globalState'; import useGridConfig from '../utility/useGridConfig'; +import SqlDataGridCore from '../datagrid/SqlDataGridCore'; export default function ViewDataTab({ conid, database, schemaName, pureName, tabVisible, toolbarPortalRef, tabid }) { const viewInfo = useViewInfo({ conid, database, schemaName, pureName }); @@ -50,6 +51,7 @@ export default function ViewDataTab({ conid, database, schemaName, pureName, tab changeSetState={changeSetState} dispatchChangeSet={dispatchChangeSet} toolbarPortalRef={toolbarPortalRef} - /> + GridCore={SqlDataGridCore} + /> ); } From abc007753aa89ffc3c2f6cd02a15f7d63639b3b5 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 24 Oct 2020 18:35:26 +0200 Subject: [PATCH 4/8] grider refactor --- packages/web/src/datagrid/ChangeSetGrider.ts | 119 ++++++++++++++++ packages/web/src/datagrid/DataGridCore.js | 76 +++++----- packages/web/src/datagrid/DataGridRow.js | 106 +++++++------- packages/web/src/datagrid/Grider.ts | 28 ++++ packages/web/src/datagrid/InplaceEditor.js | 23 +-- packages/web/src/datagrid/JslDataGridCore.js | 3 + .../web/src/datagrid/LoadingDataGridCore.js | 132 +++++++++--------- packages/web/src/datagrid/RowsArrayGrider.ts | 23 +++ packages/web/src/datagrid/SqlDataGridCore.js | 8 +- packages/web/src/datagrid/gridutil.ts | 8 +- packages/web/src/datagrid/types.ts | 49 ++++--- 11 files changed, 393 insertions(+), 182 deletions(-) create mode 100644 packages/web/src/datagrid/ChangeSetGrider.ts create mode 100644 packages/web/src/datagrid/Grider.ts create mode 100644 packages/web/src/datagrid/RowsArrayGrider.ts diff --git a/packages/web/src/datagrid/ChangeSetGrider.ts b/packages/web/src/datagrid/ChangeSetGrider.ts new file mode 100644 index 000000000..3ad7d895e --- /dev/null +++ b/packages/web/src/datagrid/ChangeSetGrider.ts @@ -0,0 +1,119 @@ +import { + ChangeSet, + changeSetInsertNewRow, + deleteChangeSetRows, + findExistingChangeSetItem, + getChangeSetInsertedRows, + GridDisplay, + setChangeSetValue, +} from '@dbgate/datalib'; +import Grider, { GriderRowStatus } from './Grider'; + +export default class ChangeSetGrider extends Grider { + public insertedRows: any[]; + public setChangeSet: Function; + private rowCacheIndexes: Set; + private rowDataCache; + private rowStatusCache; + private rowDefinitionsCache; + private batchChangeSet: ChangeSet; + + constructor( + public sourceRows: any[], + public changeSet: ChangeSet, + public dispatchChangeSet, + public display: GridDisplay + ) { + super(); + this.insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); + this.setChangeSet = (value) => dispatchChangeSet({ type: 'set', value }); + this.rowCacheIndexes = new Set(); + this.rowDataCache = {}; + this.rowStatusCache = {}; + this.rowDefinitionsCache = {}; + this.batchChangeSet = null; + } + + getRowSource(index: number) { + if (index < this.sourceRows.length) return this.sourceRows[index]; + return null; + } + + getInsertedRowIndex(index) { + return index >= this.sourceRows.length ? index - this.sourceRows.length : null; + } + + requireRowCache(index: number) { + if (this.rowCacheIndexes.has(index)) return; + const row = this.getRowSource(index); + const insertedRowIndex = this.getInsertedRowIndex(index); + const rowDefinition = this.display.getChangeSetRow(row, insertedRowIndex); + const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(this.changeSet, rowDefinition); + const rowUpdated = matchedChangeSetItem ? { ...row, ...matchedChangeSetItem.fields } : row; + let status = 'regular'; + if (matchedChangeSetItem && matchedField == 'updates') status = 'updated'; + if (matchedField == 'deletes') status = 'deleted'; + if (insertedRowIndex != null) status = 'inserted'; + const rowStatus = { + status, + modifiedFields: new Set(matchedChangeSetItem ? Object.keys(matchedChangeSetItem.fields) : []), + }; + this.rowDataCache[index] = rowUpdated; + this.rowStatusCache[index] = rowStatus; + this.rowDefinitionsCache[index] = rowDefinition; + this.rowCacheIndexes.add(index); + } + + getRowData(index: number) { + this.requireRowCache(index); + return this.rowDataCache[index]; + } + + getRowStatus(index): GriderRowStatus { + this.requireRowCache(index); + return this.rowStatusCache[index]; + } + + get rowCount() { + return this.sourceRows.length + this.insertedRows.length; + } + + applyModification(changeSetReducer) { + if (this.batchChangeSet) { + this.batchChangeSet = changeSetReducer(this.batchChangeSet); + } else { + this.setChangeSet(changeSetReducer(this.changeSet)); + } + } + + setCellValue(index: number, uniqueName: string, value: any) { + const row = this.getRowSource(index); + const definition = this.display.getChangeSetField(row, uniqueName, this.getInsertedRowIndex(index)); + this.applyModification((chs) => setChangeSetValue(chs, definition, value)); + } + + deleteRow(index: number) { + this.requireRowCache(index); + this.applyModification((chs) => deleteChangeSetRows(chs, this.rowDefinitionsCache[index])); + } + + insertRow(): number { + this.applyModification((chs) => changeSetInsertNewRow(chs, this.display.baseTable)); + return this.rowCount; + } + + beginUpdate() { + this.batchChangeSet = this.changeSet; + } + endUpdate() { + this.setChangeSet(this.batchChangeSet); + this.batchChangeSet = null; + } + + static factory({ sourceRows, changeSet, dispatchChangeSet, display }): ChangeSetGrider { + return new ChangeSetGrider(sourceRows, changeSet, dispatchChangeSet, display); + } + static factoryDeps({ sourceRows, changeSet, dispatchChangeSet, display }) { + return [sourceRows, changeSet, dispatchChangeSet, display]; + } +} diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index 6edaf3e5d..96e742bee 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -126,7 +126,7 @@ const LoadingInfoBox = styled.div` border: 1px solid gray; `; -/** @param props {import('./types').DataGridCoreProps} */ +/** @param props {import('./types').DataGridProps} */ export default function DataGridCore(props) { const { display, @@ -135,7 +135,6 @@ export default function DataGridCore(props) { changeSetState, dispatchChangeSet, tabVisible, - rows, loadNextData, errorMessage, isLoadedAll, @@ -145,6 +144,7 @@ export default function DataGridCore(props) { openQuery, insertedRowCount, isLoading, + grider, } = props; // console.log('RENDER GRID', display.baseTable.pureName); const columns = React.useMemo(() => display.allColumns, [display]); @@ -236,8 +236,8 @@ export default function DataGridCore(props) { // usePropsCompare({ loadedRows, columns, containerWidth, display }); - const columnSizes = React.useMemo(() => countColumnSizes(rows, columns, containerWidth, display), [ - rows, + const columnSizes = React.useMemo(() => countColumnSizes(grider, columns, containerWidth, display), [ + grider, columns, containerWidth, display, @@ -269,10 +269,10 @@ export default function DataGridCore(props) { }, [columnSizes, gridScrollAreaWidth]); React.useEffect(() => { - if (props.onReferenceSourceChanged && ((rows && rows.length > 0) || isLoadedAll)) { + if (props.onReferenceSourceChanged && (grider.rowCount > 0 || isLoadedAll)) { props.onReferenceSourceChanged(getSelectedRowData(), loadedTime); } - }, [selectedCells, props.refReloadToken, rows && rows[0]]); + }, [selectedCells, props.refReloadToken, grider.getRowData(0)]); // const handleCloseInplaceEditor = React.useCallback( // mode => { @@ -312,7 +312,7 @@ export default function DataGridCore(props) { }, [display && display.focusedColumn]); React.useEffect(() => { - if (rows && loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= rows.length) { + if (loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= grider.rowCount) { loadNextData(); } }); @@ -334,7 +334,7 @@ export default function DataGridCore(props) { const rowCountInfo = React.useMemo(() => { if (selectedCells.length > 1 && selectedCells.every((x) => _.isNumber(x[0]) && _.isNumber(x[1]))) { let sum = _.sumBy(selectedCells, (cell) => { - const row = rows[cell[0]]; + const row = grider.getRowData(cell[0]); if (row) { const colName = realColumnUniqueNames[cell[1]]; if (colName) { @@ -356,9 +356,9 @@ export default function DataGridCore(props) { // if (this.isLoadingFirstPage) return "Loading first page..."; // if (this.isFirstPageError) return "Error loading first page"; // return `Rows: ${this.rowCount.toLocaleString()}`; - }, [selectedCells, allRowCount, rows, visibleRealColumns]); + }, [selectedCells, allRowCount, grider, visibleRealColumns]); - if (!rows || !columns || columns.length == 0) + if (!columns || columns.length == 0) return ( @@ -551,7 +551,7 @@ export default function DataGridCore(props) { const rowIndexes = _.sortBy(_.uniq(cells.map((x) => x[0]))); const lines = rowIndexes.map((rowIndex) => { let colIndexes = _.sortBy(cells.filter((x) => x[0] == rowIndex).map((x) => x[1])); - const rowData = rows[rowIndex]; + const rowData = grider.getRowData(rowIndex); if (!rowData) return ''; const line = colIndexes .map((col) => realColumnUniqueNames[col]) @@ -591,7 +591,7 @@ export default function DataGridCore(props) { const rowIndexes = _.uniq((autofillSelectedCells || []).map((x) => x[0])).filter((x) => x != currentRowNumber); // @ts-ignore const colNames = selectedCells.map((cell) => realColumnUniqueNames[cell[1]]); - const changeObject = _.pick(rows[currentRowNumber], colNames); + const changeObject = _.pick(grider.getRowData(currentRowNumber), colNames); setChangeSet( batchUpdateChangeSet( changeSet, @@ -629,7 +629,7 @@ export default function DataGridCore(props) { } function getSelectedRowData() { - return _.compact(getSelectedRowIndexes().map((index) => rows && rows[index])); + return _.compact(getSelectedRowIndexes().map((index) => grider.getRowData(index))); } function revertRowChanges() { @@ -646,7 +646,7 @@ export default function DataGridCore(props) { if (!isRegularCell(cell)) continue; const modelIndex = columnSizes.realToModel(cell[1]); const columnName = columns[modelIndex].uniqueName; - let value = rows[cell[0]][columnName]; + let value = grider.getRowData(cell[0])[columnName]; let svalue = getFilterValueExpression(value, columns[modelIndex].dataType); if (_.has(flts, columnName)) flts[columnName] += ',' + svalue; else flts[columnName] = svalue; @@ -672,7 +672,7 @@ export default function DataGridCore(props) { if (event.deltaY < 0) { newFirstVisibleRowScrollIndex -= wheelRowCount; } - let rowCount = rows.length; + let rowCount = grider.rowCount; if (newFirstVisibleRowScrollIndex + visibleRowCountLowerBound > rowCount) { newFirstVisibleRowScrollIndex = rowCount - visibleRowCountLowerBound + 1; } @@ -728,8 +728,9 @@ export default function DataGridCore(props) { const insertNewRow = () => { if (display.baseTable) { - setChangeSet(changeSetInsertNewRow(changeSet, display.baseTable)); - const cell = [rows.length, (currentCell && currentCell[1]) || 0]; + const rowIndex = grider.insertRow(); + // setChangeSet(changeSetInsertNewRow(changeSet, display.baseTable)); + const cell = [rowIndex, (currentCell && currentCell[1]) || 0]; // @ts-ignore setCurrentCell(cell); // @ts-ignore @@ -843,7 +844,7 @@ export default function DataGridCore(props) { function handleCursorMove(event) { if (!isRegularCell(currentCell)) return null; - let rowCount = rows.length; + let rowCount = grider.rowCount; if (event.ctrlKey) { switch (event.keyCode) { case keycodes.upArrow: @@ -901,7 +902,7 @@ export default function DataGridCore(props) { } function moveCurrentCell(row, col, event = null) { - const rowCount = rows.length; + const rowCount = grider.rowCount; if (row < 0) row = 0; if (row >= rowCount) row = rowCount - 1; @@ -923,7 +924,7 @@ export default function DataGridCore(props) { if (row != null) { let newRow = null; - const rowCount = rows.length; + const rowCount = grider.rowCount; if (rowCount == 0) return; if (row < firstVisibleRowScrollIndex) newRow = row; @@ -1065,28 +1066,29 @@ export default function DataGridCore(props) { )} - {rows - .slice(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) - .map((row, index) => ( + {_.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) + // .slice(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) + .map((rowIndex) => ( = rows.length - (insertedRowCount || 0) - ? firstVisibleRowScrollIndex + index - rows.length - (insertedRowCount || 0) - : null - } - autofillMarkerCell={filterCellForRow(autofillMarkerCell, firstVisibleRowScrollIndex + index)} - changeSet={changeSet} - setChangeSet={setChangeSet} + selectedCells={filterCellsForRow(selectedCells, rowIndex)} + // insertedRowIndex={ + // firstVisibleRowScrollIndex + index >= rows.length - (insertedRowCount || 0) + // ? firstVisibleRowScrollIndex + index - rows.length - (insertedRowCount || 0) + // : null + // } + autofillMarkerCell={filterCellForRow(autofillMarkerCell, rowIndex)} + // changeSet={changeSet} + // setChangeSet={setChangeSet} display={display} - row={row} + // row={row} focusedColumn={display.focusedColumn} /> ))} @@ -1104,9 +1106,9 @@ export default function DataGridCore(props) { valueToSet={vScrollValueToSet} valueToSetDate={vScrollValueToSetDate} minimum={0} - maximum={rows.length - visibleRowCountUpperBound + 2} + maximum={grider.rowCount - visibleRowCountUpperBound + 2} onScroll={handleRowScroll} - viewportRatio={visibleRowCountUpperBound / rows.length} + viewportRatio={visibleRowCountUpperBound / grider.rowCount} /> - props.isModifiedRow && - !props.isInsertedRow && - !props.isSelected && - !props.isAutofillSelected && - !props.isModifiedCell && - !props.isFocusedColumn && - ` + props.isModifiedRow && + !props.isInsertedRow && + !props.isSelected && + !props.isAutofillSelected && + !props.isModifiedCell && + !props.isFocusedColumn && + ` background-color: #FFFFDB;`} ${(props) => !props.isSelected && @@ -60,11 +60,11 @@ const TableBodyCell = styled.td` background-color: #DBFFDB;`} ${(props) => - !props.isSelected && - !props.isAutofillSelected && - !props.isFocusedColumn && - props.isDeletedRow && - ` + !props.isSelected && + !props.isAutofillSelected && + !props.isFocusedColumn && + props.isDeletedRow && + ` background-color: #FFDBFF; `} @@ -75,14 +75,13 @@ const TableBodyCell = styled.td` `} ${(props) => - props.isDeletedRow && - ` + props.isDeletedRow && + ` background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEElEQVQImWNgIAX8x4KJBAD+agT8INXz9wAAAABJRU5ErkJggg=='); // from http://www.patternify.com/ background-repeat: repeat-x; background-position: 50% 50%;`} - - `; +`; const HintSpan = styled.span` color: gray; @@ -163,22 +162,25 @@ function CellFormattedValue({ value, dataType }) { return value.toString(); } -function DataGridRow({ - rowHeight, - rowIndex, - visibleRealColumns, - inplaceEditorState, - dispatchInsplaceEditor, - row, - display, - changeSet, - setChangeSet, - insertedRowIndex, - autofillMarkerCell, - selectedCells, - autofillSelectedCells, - focusedColumn, -}) { +/** @param props {import('./types').DataGridProps} */ +function DataGridRow(props) { + const { + rowHeight, + rowIndex, + visibleRealColumns, + inplaceEditorState, + dispatchInsplaceEditor, + // row, + display, + // changeSet, + // setChangeSet, + insertedRowIndex, + autofillMarkerCell, + selectedCells, + autofillSelectedCells, + focusedColumn, + grider, + } = props; // usePropsCompare({ // rowHeight, // rowIndex, @@ -197,18 +199,23 @@ function DataGridRow({ // console.log('RENDER ROW', rowIndex); - const rowDefinition = display.getChangeSetRow(row, insertedRowIndex); - const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(changeSet, rowDefinition); - const rowUpdated = matchedChangeSetItem ? { ...row, ...matchedChangeSetItem.fields } : row; + const rowData = grider.getRowData(rowIndex); + const rowStatus = grider.getRowStatus(rowIndex); + + // const rowDefinition = display.getChangeSetRow(row, insertedRowIndex); + // const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(changeSet, rowDefinition); + // const rowUpdated = matchedChangeSetItem ? { ...row, ...matchedChangeSetItem.fields } : row; + const hintFieldsAllowed = visibleRealColumns .filter((col) => { if (!col.hintColumnName) return false; - if (matchedChangeSetItem && matchedField == 'updates' && col.uniqueName in matchedChangeSetItem.fields) - return false; + if (rowStatus.status == 'updated' && rowStatus.modifiedFields.has(col.uniqueName)) return false; return true; }) .map((col) => col.uniqueName); + if (!rowData) return null; + return ( @@ -226,13 +233,11 @@ function DataGridRow({ data-col={col.colIndex} isSelected={cellIsSelected(rowIndex, col.colIndex, selectedCells)} isAutofillSelected={cellIsSelected(rowIndex, col.colIndex, autofillSelectedCells)} - isModifiedRow={!!matchedChangeSetItem} + isModifiedRow={rowStatus.status == 'updated'} isFocusedColumn={col.uniqueName == focusedColumn} - isModifiedCell={ - matchedChangeSetItem && matchedField == 'updates' && col.uniqueName in matchedChangeSetItem.fields - } + isModifiedCell={rowStatus.status == 'updated' && rowStatus.modifiedFields.has(col.uniqueName)} isInsertedRow={insertedRowIndex != null} - isDeletedRow={matchedField == 'deletes'} + isDeletedRow={rowStatus.status == 'deleted'} > {inplaceEditorState.cell && rowIndex == inplaceEditorState.cell[0] && @@ -241,16 +246,19 @@ function DataGridRow({ widthPx={col.widthPx} inplaceEditorState={inplaceEditorState} dispatchInsplaceEditor={dispatchInsplaceEditor} - cellValue={rowUpdated[col.uniqueName]} - changeSet={changeSet} - setChangeSet={setChangeSet} - insertedRowIndex={insertedRowIndex} - definition={display.getChangeSetField(row, col.uniqueName, insertedRowIndex)} + cellValue={rowData[col.uniqueName]} + grider={grider} + rowIndex={rowIndex} + uniqueName={col.uniqueName} + // changeSet={changeSet} + // setChangeSet={setChangeSet} + // insertedRowIndex={insertedRowIndex} + // definition={display.getChangeSetField(row, col.uniqueName, insertedRowIndex)} /> ) : ( <> - - {hintFieldsAllowed.includes(col.uniqueName) && {row[col.hintColumnName]}} + + {hintFieldsAllowed.includes(col.uniqueName) && {rowData[col.hintColumnName]}} )} {autofillMarkerCell && autofillMarkerCell[1] == col.colIndex && autofillMarkerCell[0] == rowIndex && ( diff --git a/packages/web/src/datagrid/Grider.ts b/packages/web/src/datagrid/Grider.ts new file mode 100644 index 000000000..b5e818a18 --- /dev/null +++ b/packages/web/src/datagrid/Grider.ts @@ -0,0 +1,28 @@ +export interface GriderRowStatus { + status: 'regular' | 'updated' | 'deleted' | 'inserted'; + modifiedFields: Set; +} + +export default abstract class Grider { + abstract getRowData(index): any; + abstract get rowCount(): number; + + getRowsSample() { + return [this.getRowData(0)]; + } + + getRowStatus(index): GriderRowStatus { + const res: GriderRowStatus = { + status: 'regular', + modifiedFields: new Set(), + }; + return res; + } + beginUpdate() {} + endUpdate() {} + setCellValue(index: number, uniqueName: string, value: any) {} + deleteRow(index: number) {} + insertRow(): number { + return null; + } +} diff --git a/packages/web/src/datagrid/InplaceEditor.js b/packages/web/src/datagrid/InplaceEditor.js index a1b547249..edfd35bca 100644 --- a/packages/web/src/datagrid/InplaceEditor.js +++ b/packages/web/src/datagrid/InplaceEditor.js @@ -16,13 +16,16 @@ const StyledInput = styled.input` export default function InplaceEditor({ widthPx, - definition, - changeSet, - setChangeSet, + // definition, + // changeSet, + // setChangeSet, + rowIndex, + uniqueName, + grider, cellValue, inplaceEditorState, dispatchInsplaceEditor, - isInsertedRow, + // isInsertedRow, }) { const editorRef = React.useRef(); const isChangedRef = React.useRef(!!inplaceEditorState.text); @@ -37,7 +40,8 @@ export default function InplaceEditor({ function handleBlur() { if (isChangedRef.current) { const editor = editorRef.current; - setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + grider.setCellValue(rowIndex, uniqueName, editor.value); + // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } dispatchInsplaceEditor({ type: 'close' }); @@ -45,7 +49,8 @@ export default function InplaceEditor({ if (inplaceEditorState.shouldSave) { const editor = editorRef.current; if (isChangedRef.current) { - setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + grider.setCellValue(rowIndex, uniqueName, editor.value); + // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } editor.blur(); @@ -60,7 +65,8 @@ export default function InplaceEditor({ break; case keycodes.enter: if (isChangedRef.current) { - setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + grider.setCellValue(rowIndex, uniqueName, editor.value); + // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } editor.blur(); @@ -69,7 +75,8 @@ export default function InplaceEditor({ case keycodes.s: if (event.ctrlKey) { if (isChangedRef.current) { - setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + grider.setCellValue(rowIndex, uniqueName, editor.value); + // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } event.preventDefault(); diff --git a/packages/web/src/datagrid/JslDataGridCore.js b/packages/web/src/datagrid/JslDataGridCore.js index 53ae17505..e9e1a2eaf 100644 --- a/packages/web/src/datagrid/JslDataGridCore.js +++ b/packages/web/src/datagrid/JslDataGridCore.js @@ -8,6 +8,7 @@ import ImportExportModal from '../modals/ImportExportModal'; import { getChangeSetInsertedRows } from '@dbgate/datalib'; import { openNewTab } from '../utility/common'; import LoadingDataGridCore from './LoadingDataGridCore'; +import RowsArrayGrider from './RowsArrayGrider'; async function loadDataPage(props, offset, limit) { const { jslid } = props; @@ -88,6 +89,8 @@ export default function JslDataGridCore(props) { loadRowCount={loadRowCount} loadNextDataToken={changeIndex} onReload={() => setChangeIndex(0)} + griderFactory={RowsArrayGrider.factory} + griderFactoryDeps={RowsArrayGrider.factoryDeps} /> ); } diff --git a/packages/web/src/datagrid/LoadingDataGridCore.js b/packages/web/src/datagrid/LoadingDataGridCore.js index 9b87ff74f..c744fc3aa 100644 --- a/packages/web/src/datagrid/LoadingDataGridCore.js +++ b/packages/web/src/datagrid/LoadingDataGridCore.js @@ -8,75 +8,75 @@ import ImportExportModal from '../modals/ImportExportModal'; import { getChangeSetInsertedRows } from '@dbgate/datalib'; import { openNewTab } from '../utility/common'; -/** @param props {import('./types').LoadingDataGridProps} */ -async function loadDataPage(props, offset, limit) { - const { display, conid, database, jslid } = props; +// /** @param props {import('./types').LoadingDataGridProps} */ +// async function loadDataPage(props, offset, limit) { +// const { display, conid, database, jslid } = props; - if (jslid) { - const response = await axios.request({ - url: 'jsldata/get-rows', - method: 'get', - params: { - jslid, - offset, - limit, - }, - }); - return response.data; - } +// if (jslid) { +// const response = await axios.request({ +// url: 'jsldata/get-rows', +// method: 'get', +// params: { +// jslid, +// offset, +// limit, +// }, +// }); +// return response.data; +// } - const sql = display.getPageQuery(offset, limit); +// const sql = display.getPageQuery(offset, limit); - const response = await axios.request({ - url: 'database-connections/query-data', - method: 'post', - params: { - conid, - database, - }, - data: { sql }, - }); +// const response = await axios.request({ +// url: 'database-connections/query-data', +// method: 'post', +// params: { +// conid, +// database, +// }, +// data: { sql }, +// }); - if (response.data.errorMessage) return response.data; - return response.data.rows; -} +// if (response.data.errorMessage) return response.data; +// return response.data.rows; +// } -function dataPageAvailable(props) { - const { display, jslid } = props; - if (jslid) return true; - const sql = display.getPageQuery(0, 1); - return !!sql; -} +// function dataPageAvailable(props) { +// const { display, jslid } = props; +// if (jslid) return true; +// const sql = display.getPageQuery(0, 1); +// return !!sql; +// } -/** @param props {import('./types').LoadingDataGridProps} */ -async function loadRowCount(props) { - const { display, conid, database, jslid } = props; +// /** @param props {import('./types').LoadingDataGridProps} */ +// async function loadRowCount(props) { +// const { display, conid, database, jslid } = props; - if (jslid) { - const response = await axios.request({ - url: 'jsldata/get-stats', - method: 'get', - params: { - jslid, - }, - }); - return response.data.rowCount; - } +// if (jslid) { +// const response = await axios.request({ +// url: 'jsldata/get-stats', +// method: 'get', +// params: { +// jslid, +// }, +// }); +// return response.data.rowCount; +// } - const sql = display.getCountQuery(); +// const sql = display.getCountQuery(); - const response = await axios.request({ - url: 'database-connections/query-data', - method: 'post', - params: { - conid, - database, - }, - data: { sql }, - }); +// const response = await axios.request({ +// url: 'database-connections/query-data', +// method: 'post', +// params: { +// conid, +// database, +// }, +// data: { sql }, +// }); - return parseInt(response.data.rows[0].count); -} +// return parseInt(response.data.rows[0].count); +// } export default function LoadingDataGridCore(props) { const { @@ -91,6 +91,8 @@ export default function LoadingDataGridCore(props) { onReload, exportGrid, openQuery, + griderFactory, + griderFactoryDeps, } = props; const [loadProps, setLoadProps] = React.useState({ @@ -187,12 +189,12 @@ export default function LoadingDataGridCore(props) { } }; - React.useEffect(()=>{ + React.useEffect(() => { setLoadProps((oldProps) => ({ ...oldProps, isLoadedAll: false, })); - },[loadNextDataToken]); + }, [loadNextDataToken]); const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); const rowCountNewIncluded = loadedRows.length + insertedRows.length; @@ -206,6 +208,9 @@ export default function LoadingDataGridCore(props) { } }; + const griderProps = { ...props, sourceRows: loadedRows }; + const grider = React.useMemo(() => griderFactory(griderProps), griderFactoryDeps(griderProps)); + return ( ); } diff --git a/packages/web/src/datagrid/RowsArrayGrider.ts b/packages/web/src/datagrid/RowsArrayGrider.ts new file mode 100644 index 000000000..7f2ac9581 --- /dev/null +++ b/packages/web/src/datagrid/RowsArrayGrider.ts @@ -0,0 +1,23 @@ +import Grider, { GriderRowStatus } from './Grider'; + +export default class RowsArrayGrider extends Grider { + constructor(private rows: any[]) { + super(); + } + getRowData(index: any) { + return this.rows[index]; + } + get rowCount() { + return this.rows.length; + } + + static factory({ sourceRows }): RowsArrayGrider { + return new RowsArrayGrider(sourceRows); + } + static factoryDeps({ sourceRows }) { + return [sourceRows]; + } + getRowsSample() { + return this.rows; + } +} diff --git a/packages/web/src/datagrid/SqlDataGridCore.js b/packages/web/src/datagrid/SqlDataGridCore.js index c44711124..f401d6432 100644 --- a/packages/web/src/datagrid/SqlDataGridCore.js +++ b/packages/web/src/datagrid/SqlDataGridCore.js @@ -8,8 +8,9 @@ import ImportExportModal from '../modals/ImportExportModal'; import { getChangeSetInsertedRows } from '@dbgate/datalib'; import { openNewTab } from '../utility/common'; import LoadingDataGridCore from './LoadingDataGridCore'; +import ChangeSetGrider from './ChangeSetGrider'; -/** @param props {import('./types').LoadingDataGridProps} */ +/** @param props {import('./types').DataGridProps} */ async function loadDataPage(props, offset, limit) { const { display, conid, database } = props; @@ -53,6 +54,7 @@ async function loadRowCount(props) { return parseInt(response.data.rows[0].count); } +/** @param props {import('./types').DataGridProps} */ export default function SqlDataGridCore(props) { const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible } = props; const showModal = useShowModal(); @@ -82,6 +84,8 @@ export default function SqlDataGridCore(props) { }); } + // const grider = React.useMemo(()=>new ChangeSetGrider()) + return ( ); } diff --git a/packages/web/src/datagrid/gridutil.ts b/packages/web/src/datagrid/gridutil.ts index 3cf4bc809..7dc3f2aa2 100644 --- a/packages/web/src/datagrid/gridutil.ts +++ b/packages/web/src/datagrid/gridutil.ts @@ -2,10 +2,11 @@ import _ from 'lodash'; import { SeriesSizes } from './SeriesSizes'; import { CellAddress } from './selection'; import { GridDisplay } from '@dbgate/datalib'; +import Grider from './Grider'; -export function countColumnSizes(loadedRows, columns, containerWidth, display: GridDisplay) { +export function countColumnSizes(grider: Grider, columns, containerWidth, display: GridDisplay) { const columnSizes = new SeriesSizes(); - if (!loadedRows || !columns) return columnSizes; + if (!grider || !columns) return columnSizes; let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); @@ -51,7 +52,8 @@ export function countColumnSizes(loadedRows, columns, containerWidth, display: G // if (headerWidth > this.rowHeaderWidth) this.rowHeaderWidth = headerWidth; context.font = '14px Helvetica'; - for (let row of loadedRows.slice(0, 20)) { + for (let rowIndex = 0; rowIndex < Math.min(grider.rowCount, 20); rowIndex += 1) { + const row = grider.getRowData(rowIndex); for (let colIndex = 0; colIndex < columns.length; colIndex++) { const uqName = columns[colIndex].uniqueName; diff --git a/packages/web/src/datagrid/types.ts b/packages/web/src/datagrid/types.ts index 069fbeefd..8727292e8 100644 --- a/packages/web/src/datagrid/types.ts +++ b/packages/web/src/datagrid/types.ts @@ -1,4 +1,5 @@ import { GridDisplay, ChangeSet, GridReferenceDefinition } from '@dbgate/datalib'; +import Grider from './Grider'; export interface DataGridProps { display: GridDisplay; @@ -12,28 +13,34 @@ export interface DataGridProps { refReloadToken?: string; masterLoadedTime?: number; managerSize?: number; -} - -export interface DataGridCoreProps extends DataGridProps { - rows: any[]; - loadNextData?: Function; - exportGrid?: Function; - openQuery?: Function; - undo?: Function; - redo?: Function; - - errorMessage?: string; - isLoadedAll?: boolean; - loadedTime?: any; - allRowCount?: number; - conid?: string; - database?: string; - insertedRowCount?: number; - isLoading?: boolean; -} - -export interface LoadingDataGridProps extends DataGridProps { + grider?: Grider; conid?: string; database?: string; jslid?: string; + + [field: string]: any; } + +// export interface DataGridCoreProps extends DataGridProps { +// rows: any[]; +// loadNextData?: Function; +// exportGrid?: Function; +// openQuery?: Function; +// undo?: Function; +// redo?: Function; + +// errorMessage?: string; +// isLoadedAll?: boolean; +// loadedTime?: any; +// allRowCount?: number; +// conid?: string; +// database?: string; +// insertedRowCount?: number; +// isLoading?: boolean; +// } + +// export interface LoadingDataGridProps extends DataGridProps { +// conid?: string; +// database?: string; +// jslid?: string; +// } From 00453ae379a4cd68bac6e0fcc43c115b50726622 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 24 Oct 2020 20:31:03 +0200 Subject: [PATCH 5/8] basic updates again working --- packages/web/src/datagrid/ChangeSetGrider.ts | 4 +- packages/web/src/datagrid/DataGridCore.js | 40 +++-------- packages/web/src/datagrid/DataGridRow.js | 6 +- packages/web/src/datagrid/SqlDataGridCore.js | 72 +++++++++++++++++--- 4 files changed, 76 insertions(+), 46 deletions(-) diff --git a/packages/web/src/datagrid/ChangeSetGrider.ts b/packages/web/src/datagrid/ChangeSetGrider.ts index 3ad7d895e..22116d2e6 100644 --- a/packages/web/src/datagrid/ChangeSetGrider.ts +++ b/packages/web/src/datagrid/ChangeSetGrider.ts @@ -56,7 +56,9 @@ export default class ChangeSetGrider extends Grider { if (insertedRowIndex != null) status = 'inserted'; const rowStatus = { status, - modifiedFields: new Set(matchedChangeSetItem ? Object.keys(matchedChangeSetItem.fields) : []), + modifiedFields: new Set( + matchedChangeSetItem && matchedChangeSetItem.fields ? Object.keys(matchedChangeSetItem.fields) : [] + ), }; this.rowDataCache[index] = rowUpdated; this.rowStatusCache[index] = rowStatus; diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index 96e742bee..b7f8cd752 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -142,6 +142,7 @@ export default function DataGridCore(props) { exportGrid, allRowCount, openQuery, + onSave, insertedRowCount, isLoading, grider, @@ -201,8 +202,6 @@ export default function DataGridCore(props) { const [tableBodyRef] = useDimensions(); const [containerRef, { height: containerHeight, width: containerWidth }] = useDimensions(); // const [tableRef, { height: tableHeight, width: tableWidth }] = useDimensions(); - const confirmSqlModalState = useModalState(); - const [confirmSql, setConfirmSql] = React.useState(''); const changeSet = changeSetState && changeSetState.value; const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); @@ -660,8 +659,13 @@ export default function DataGridCore(props) { } function deleteSelectedRows() { - const updatedChangeSet = getSelectedRowDefinitions().reduce((chs, row) => deleteChangeSetRows(chs, row), changeSet); - setChangeSet(updatedChangeSet); + grider.beginUpdate(); + for (const index of getSelectedRowIndexes()) { + if (_.isNumber(index)) grider.deleteRow(index); + } + grider.endUpdate(); + // const updatedChangeSet = getSelectedRowDefinitions().reduce((chs, row) => deleteChangeSetRows(chs, row), changeSet); + // setChangeSet(updatedChangeSet); } function handleGridWheel(event) { @@ -698,33 +702,13 @@ export default function DataGridCore(props) { dispatchInsplaceEditor({ type: 'shouldSave' }); return; } + if (onSave) onSave(); // const script = changeSetToSql(changeSetRef.current, display.dbinfo); // const sql = scriptToSql(display.driver, script); // setConfirmSql(sql); // confirmSqlModalState.open(); } - async function handleConfirmSql() { - // const resp = await axios.request({ - // url: 'database-connections/query-data', - // method: 'post', - // params: { - // conid, - // database, - // }, - // data: { sql: confirmSql }, - // }); - // const { errorMessage } = resp.data || {}; - // if (errorMessage) { - // showModal((modalState) => ( - // - // )); - // } else { - // dispatchChangeSet({ type: 'reset', value: createChangeSet() }); - // setConfirmSql(null); - // display.reload(); - // } - } const insertNewRow = () => { if (display.baseTable) { @@ -1110,12 +1094,6 @@ export default function DataGridCore(props) { onScroll={handleRowScroll} viewportRatio={visibleRowCountUpperBound / grider.rowCount} /> - {allRowCount && {rowCountInfo}} {props.toolbarPortalRef && tabVisible && diff --git a/packages/web/src/datagrid/DataGridRow.js b/packages/web/src/datagrid/DataGridRow.js index 5334d7558..bbda7ea0d 100644 --- a/packages/web/src/datagrid/DataGridRow.js +++ b/packages/web/src/datagrid/DataGridRow.js @@ -171,10 +171,10 @@ function DataGridRow(props) { inplaceEditorState, dispatchInsplaceEditor, // row, - display, + // display, // changeSet, // setChangeSet, - insertedRowIndex, + // insertedRowIndex, autofillMarkerCell, selectedCells, autofillSelectedCells, @@ -236,7 +236,7 @@ function DataGridRow(props) { isModifiedRow={rowStatus.status == 'updated'} isFocusedColumn={col.uniqueName == focusedColumn} isModifiedCell={rowStatus.status == 'updated' && rowStatus.modifiedFields.has(col.uniqueName)} - isInsertedRow={insertedRowIndex != null} + isInsertedRow={rowStatus.status == 'inserted'} isDeletedRow={rowStatus.status == 'deleted'} > {inplaceEditorState.cell && diff --git a/packages/web/src/datagrid/SqlDataGridCore.js b/packages/web/src/datagrid/SqlDataGridCore.js index f401d6432..8c22e93ca 100644 --- a/packages/web/src/datagrid/SqlDataGridCore.js +++ b/packages/web/src/datagrid/SqlDataGridCore.js @@ -5,10 +5,14 @@ import DataGridCore from './DataGridCore'; import useSocket from '../utility/SocketProvider'; import useShowModal from '../modals/showModal'; import ImportExportModal from '../modals/ImportExportModal'; -import { getChangeSetInsertedRows } from '@dbgate/datalib'; +import { changeSetToSql, createChangeSet, getChangeSetInsertedRows } from '@dbgate/datalib'; import { openNewTab } from '../utility/common'; import LoadingDataGridCore from './LoadingDataGridCore'; import ChangeSetGrider from './ChangeSetGrider'; +import { scriptToSql } from '@dbgate/sqltree'; +import useModalState from '../modals/useModalState'; +import ConfirmSqlModal from '../modals/ConfirmSqlModal'; +import ErrorMessageModal from '../modals/ErrorMessageModal'; /** @param props {import('./types').DataGridProps} */ async function loadDataPage(props, offset, limit) { @@ -60,6 +64,13 @@ export default function SqlDataGridCore(props) { const showModal = useShowModal(); const setOpenedTabs = useSetOpenedTabs(); + const confirmSqlModalState = useModalState(); + const [confirmSql, setConfirmSql] = React.useState(''); + + const changeSet = changeSetState && changeSetState.value; + const changeSetRef = React.useRef(changeSet); + changeSetRef.current = changeSet; + function exportGrid() { const initialValues = {}; initialValues.sourceStorageType = 'query'; @@ -84,18 +95,57 @@ export default function SqlDataGridCore(props) { }); } + function handleSave() { + const script = changeSetToSql(changeSetRef.current, display.dbinfo); + const sql = scriptToSql(display.driver, script); + setConfirmSql(sql); + confirmSqlModalState.open(); + } + + async function handleConfirmSql() { + const resp = await axios.request({ + url: 'database-connections/query-data', + method: 'post', + params: { + conid, + database, + }, + data: { sql: confirmSql }, + }); + const { errorMessage } = resp.data || {}; + if (errorMessage) { + showModal((modalState) => ( + + )); + } else { + dispatchChangeSet({ type: 'reset', value: createChangeSet() }); + setConfirmSql(null); + display.reload(); + } + } + // const grider = React.useMemo(()=>new ChangeSetGrider()) return ( - + <> + + + ); } From 45d172d0b1005fce1f51e55aec9a7641efe7d7b1 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 24 Oct 2020 21:05:24 +0200 Subject: [PATCH 6/8] grider refactor WIP --- packages/web/src/datagrid/ChangeSetGrider.ts | 48 ++++++++--- packages/web/src/datagrid/DataGridCore.js | 86 ++++++++++--------- packages/web/src/datagrid/DataGridToolbar.js | 11 ++- packages/web/src/datagrid/Grider.ts | 21 +++++ .../web/src/datagrid/LoadingDataGridCore.js | 26 +++--- packages/web/src/datagrid/SqlDataGridCore.js | 2 +- 6 files changed, 123 insertions(+), 71 deletions(-) diff --git a/packages/web/src/datagrid/ChangeSetGrider.ts b/packages/web/src/datagrid/ChangeSetGrider.ts index 22116d2e6..84c1508c0 100644 --- a/packages/web/src/datagrid/ChangeSetGrider.ts +++ b/packages/web/src/datagrid/ChangeSetGrider.ts @@ -1,16 +1,20 @@ import { ChangeSet, + changeSetContainsChanges, changeSetInsertNewRow, + createChangeSet, deleteChangeSetRows, findExistingChangeSetItem, getChangeSetInsertedRows, GridDisplay, + revertChangeSetRowChanges, setChangeSetValue, } from '@dbgate/datalib'; import Grider, { GriderRowStatus } from './Grider'; export default class ChangeSetGrider extends Grider { public insertedRows: any[]; + public changeSet: ChangeSet; public setChangeSet: Function; private rowCacheIndexes: Set; private rowDataCache; @@ -18,14 +22,10 @@ export default class ChangeSetGrider extends Grider { private rowDefinitionsCache; private batchChangeSet: ChangeSet; - constructor( - public sourceRows: any[], - public changeSet: ChangeSet, - public dispatchChangeSet, - public display: GridDisplay - ) { + constructor(public sourceRows: any[], public changeSetState, public dispatchChangeSet, public display: GridDisplay) { super(); - this.insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); + this.changeSet = changeSetState && changeSetState.value; + this.insertedRows = getChangeSetInsertedRows(this.changeSet, display.baseTable); this.setChangeSet = (value) => dispatchChangeSet({ type: 'set', value }); this.rowCacheIndexes = new Set(); this.rowDataCache = {}; @@ -112,10 +112,36 @@ export default class ChangeSetGrider extends Grider { this.batchChangeSet = null; } - static factory({ sourceRows, changeSet, dispatchChangeSet, display }): ChangeSetGrider { - return new ChangeSetGrider(sourceRows, changeSet, dispatchChangeSet, display); + revertRowChanges(index: number) { + this.requireRowCache(index); + this.applyModification((chs) => revertChangeSetRowChanges(chs, this.rowDefinitionsCache[index])); } - static factoryDeps({ sourceRows, changeSet, dispatchChangeSet, display }) { - return [sourceRows, changeSet, dispatchChangeSet, display]; + revertAllChanges() { + this.applyModification((chs) => createChangeSet()); + } + undo() { + this.dispatchChangeSet({ type: 'undo' }); + } + redo() { + this.dispatchChangeSet({ type: 'redo' }); + } + get canUndo() { + return this.changeSetState.canUndo; + } + get canRedo() { + return this.changeSetState.canRedo; + } + get containsChanges() { + return changeSetContainsChanges(this.changeSet); + } + get disableLoadNextPage() { + return this.insertedRows.length > 0; + } + + static factory({ sourceRows, changeSetState, dispatchChangeSet, display }): ChangeSetGrider { + return new ChangeSetGrider(sourceRows, changeSetState, dispatchChangeSet, display); + } + static factoryDeps({ sourceRows, changeSetState, dispatchChangeSet, display }) { + return [sourceRows, changeSetState ? changeSetState.value : null, dispatchChangeSet, display]; } } diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index b7f8cd752..98cb48a3f 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -132,8 +132,8 @@ export default function DataGridCore(props) { display, conid, database, - changeSetState, - dispatchChangeSet, + // changeSetState, + // dispatchChangeSet, tabVisible, loadNextData, errorMessage, @@ -203,8 +203,8 @@ export default function DataGridCore(props) { const [containerRef, { height: containerHeight, width: containerWidth }] = useDimensions(); // const [tableRef, { height: tableHeight, width: tableWidth }] = useDimensions(); - const changeSet = changeSetState && changeSetState.value; - const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); + // const changeSet = changeSetState && changeSetState.value; + // const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => { switch (action.type) { @@ -446,7 +446,8 @@ export default function DataGridCore(props) { copyToClipboard(); } - function setCellValue(chs, cell, value) { + function setCellValue(cell, value) { + grider.setCellValue(cell[0], realColumnUniqueNames[cell[1]], value); // return setChangeSetValue( // chs, // display.getChangeSetField( @@ -518,6 +519,11 @@ export default function DataGridCore(props) { } function setNull() { + grider.beginUpdate(); + selectedCells.filter(isRegularCell).forEach((cell) => { + setCellValue(cell, null); + }); + grider.endUpdate(); // let chs = changeSet; // selectedCells.filter(isRegularCell).forEach((cell) => { // chs = setCellValue(chs, cell, null); @@ -588,17 +594,11 @@ export default function DataGridCore(props) { const currentRowNumber = currentCell[0]; if (_.isNumber(currentRowNumber)) { const rowIndexes = _.uniq((autofillSelectedCells || []).map((x) => x[0])).filter((x) => x != currentRowNumber); - // @ts-ignore const colNames = selectedCells.map((cell) => realColumnUniqueNames[cell[1]]); const changeObject = _.pick(grider.getRowData(currentRowNumber), colNames); - setChangeSet( - batchUpdateChangeSet( - changeSet, - getRowDefinitions(rowIndexes), - // @ts-ignore - rowIndexes.map(() => changeObject) - ) - ); + grider.beginUpdate(); + for (const index of rowIndexes) grider.updateRow(index, changeObject); + grider.endUpdate(); } setAutofillDragStartCell(null); @@ -607,36 +607,41 @@ export default function DataGridCore(props) { } } - function getRowDefinitions(rowIndexes) { - const res = []; - // if (!loadedAndInsertedRows) return res; - // for (const index of rowIndexes) { - // if (loadedAndInsertedRows[index] && _.isNumber(index)) { - // const insertedRowIndex = index >= loadedRows.length ? index - loadedRows.length : null; - // res.push(display.getChangeSetRow(loadedAndInsertedRows[index], insertedRowIndex)); - // } - // } - return res; - } + // function getRowDefinitions(rowIndexes) { + // const res = []; + // // if (!loadedAndInsertedRows) return res; + // // for (const index of rowIndexes) { + // // if (loadedAndInsertedRows[index] && _.isNumber(index)) { + // // const insertedRowIndex = index >= loadedRows.length ? index - loadedRows.length : null; + // // res.push(display.getChangeSetRow(loadedAndInsertedRows[index], insertedRowIndex)); + // // } + // // } + // return res; + // } function getSelectedRowIndexes() { return _.uniq((selectedCells || []).map((x) => x[0])); } - function getSelectedRowDefinitions() { - return getRowDefinitions(getSelectedRowIndexes()); - } + // function getSelectedRowDefinitions() { + // return getRowDefinitions(getSelectedRowIndexes()); + // } function getSelectedRowData() { return _.compact(getSelectedRowIndexes().map((index) => grider.getRowData(index))); } function revertRowChanges() { - const updatedChangeSet = getSelectedRowDefinitions().reduce( - (chs, row) => revertChangeSetRowChanges(chs, row), - changeSet - ); - setChangeSet(updatedChangeSet); + grider.beginUpdate(); + for (const index of getSelectedRowIndexes()) { + if (_.isNumber(index)) grider.revertRowChanges(index); + } + grider.endUpdate(); + // const updatedChangeSet = getSelectedRowDefinitions().reduce( + // (chs, row) => revertChangeSetRowChanges(chs, row), + // changeSet + // ); + // setChangeSet(updatedChangeSet); } function filterSelectedValue() { @@ -655,7 +660,8 @@ export default function DataGridCore(props) { } function revertAllChanges() { - setChangeSet(createChangeSet()); + grider.revertAllChanges(); + // setChangeSet(createChangeSet()); } function deleteSelectedRows() { @@ -690,10 +696,10 @@ export default function DataGridCore(props) { } function undo() { - dispatchChangeSet({ type: 'undo' }); + grider.undo(); } function redo() { - dispatchChangeSet({ type: 'redo' }); + grider.redo(); } function handleSave() { @@ -709,7 +715,6 @@ export default function DataGridCore(props) { // confirmSqlModalState.open(); } - const insertNewRow = () => { if (display.baseTable) { const rowIndex = grider.insertRow(); @@ -1101,9 +1106,10 @@ export default function DataGridCore(props) { display.reload()} save={handleSave} - changeSetState={changeSetState} - dispatchChangeSet={dispatchChangeSet} - revert={revertAllChanges} + grider={grider} + // changeSetState={changeSetState} + // dispatchChangeSet={dispatchChangeSet} + // revert={revertAllChanges} />, props.toolbarPortalRef.current )} diff --git a/packages/web/src/datagrid/DataGridToolbar.js b/packages/web/src/datagrid/DataGridToolbar.js index edfc9eb3f..6fef8c3ae 100644 --- a/packages/web/src/datagrid/DataGridToolbar.js +++ b/packages/web/src/datagrid/DataGridToolbar.js @@ -1,23 +1,22 @@ import React from 'react'; import ToolbarButton from '../widgets/ToolbarButton'; -import { changeSetContainsChanges } from '@dbgate/datalib'; -export default function DataGridToolbar({ reload, changeSetState, dispatchChangeSet, save, revert }) { +export default function DataGridToolbar({ reload, grider, save }) { return ( <> Refresh - dispatchChangeSet({ type: 'undo' })} icon="fas fa-undo"> + grider.undo()} icon="fas fa-undo"> Undo - dispatchChangeSet({ type: 'redo' })} icon="fas fa-redo"> + grider.redo()} icon="fas fa-redo"> Redo - + Save - + grider.revertAllChanges()} icon="fas fa-times"> Revert diff --git a/packages/web/src/datagrid/Grider.ts b/packages/web/src/datagrid/Grider.ts index b5e818a18..7ef8f6f22 100644 --- a/packages/web/src/datagrid/Grider.ts +++ b/packages/web/src/datagrid/Grider.ts @@ -25,4 +25,25 @@ export default abstract class Grider { insertRow(): number { return null; } + revertRowChanges(index: number) {} + revertAllChanges() {} + undo() {} + redo() {} + get canUndo() { + return false; + } + get canRedo() { + return false; + } + get containsChanges() { + return false; + } + get disableLoadNextPage() { + return false; + } + updateRow(index, changeObject) { + for (const key of Object.keys(changeObject)) { + this.setCellValue(index, key, changeObject[key]); + } + } } diff --git a/packages/web/src/datagrid/LoadingDataGridCore.js b/packages/web/src/datagrid/LoadingDataGridCore.js index c744fc3aa..52ad56aef 100644 --- a/packages/web/src/datagrid/LoadingDataGridCore.js +++ b/packages/web/src/datagrid/LoadingDataGridCore.js @@ -109,14 +109,14 @@ export default function LoadingDataGridCore(props) { const loadedTimeRef = React.useRef(0); - const changeSet = changeSetState && changeSetState.value; - const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); - const setOpenedTabs = useSetOpenedTabs(); - const socket = useSocket(); + // const changeSet = changeSetState && changeSetState.value; + // const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); + // const setOpenedTabs = useSetOpenedTabs(); + // const socket = useSocket(); - const changeSetRef = React.useRef(changeSet); + // const changeSetRef = React.useRef(changeSet); - changeSetRef.current = changeSet; + // changeSetRef.current = changeSet; const handleLoadRowCount = async () => { const rowCount = await loadRowCount(props); @@ -196,11 +196,14 @@ export default function LoadingDataGridCore(props) { })); }, [loadNextDataToken]); - const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); - const rowCountNewIncluded = loadedRows.length + insertedRows.length; + // const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); + // const rowCountNewIncluded = loadedRows.length + insertedRows.length; + + const griderProps = { ...props, sourceRows: loadedRows }; + const grider = React.useMemo(() => griderFactory(griderProps), griderFactoryDeps(griderProps)); const handleLoadNextData = () => { - if (!isLoadedAll && !errorMessage && insertedRows.length == 0) { + if (!isLoadedAll && !errorMessage && !grider.disableLoadNextPage) { if (dataPageAvailable(props)) { // If not, callbacks to load missing metadata are dispatched loadNextData(); @@ -208,9 +211,6 @@ export default function LoadingDataGridCore(props) { } }; - const griderProps = { ...props, sourceRows: loadedRows }; - const grider = React.useMemo(() => griderFactory(griderProps), griderFactoryDeps(griderProps)); - return ( Date: Sat, 24 Oct 2020 21:27:56 +0200 Subject: [PATCH 7/8] paste using grider implementation --- packages/web/src/datagrid/ChangeSetGrider.ts | 12 +- packages/web/src/datagrid/DataGridCore.js | 131 +++++++++---------- packages/web/src/datagrid/Grider.ts | 3 + 3 files changed, 74 insertions(+), 72 deletions(-) diff --git a/packages/web/src/datagrid/ChangeSetGrider.ts b/packages/web/src/datagrid/ChangeSetGrider.ts index 84c1508c0..a4ca2ec00 100644 --- a/packages/web/src/datagrid/ChangeSetGrider.ts +++ b/packages/web/src/datagrid/ChangeSetGrider.ts @@ -99,9 +99,19 @@ export default class ChangeSetGrider extends Grider { this.applyModification((chs) => deleteChangeSetRows(chs, this.rowDefinitionsCache[index])); } + get rowCountInUpdate() { + if (this.batchChangeSet) { + const newRows = getChangeSetInsertedRows(this.batchChangeSet, this.display.baseTable); + return this.sourceRows.length + newRows.length; + } else { + return this.rowCount; + } + } + insertRow(): number { + const res = this.rowCountInUpdate; this.applyModification((chs) => changeSetInsertNewRow(chs, this.display.baseTable)); - return this.rowCount; + return res; } beginUpdate() { diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index 98cb48a3f..6cb292fc8 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -448,73 +448,67 @@ export default function DataGridCore(props) { function setCellValue(cell, value) { grider.setCellValue(cell[0], realColumnUniqueNames[cell[1]], value); - // return setChangeSetValue( - // chs, - // display.getChangeSetField( - // rows[cell[0]], - // realColumnUniqueNames[cell[1]], - // cell[0] >= rows.length ? cell[0] - rows.length : null - // ), - // value - // ); } function handlePaste(event) { - // var pastedText = undefined; - // // @ts-ignore - // if (window.clipboardData && window.clipboardData.getData) { - // // IE - // // @ts-ignore - // pastedText = window.clipboardData.getData('Text'); - // } else if (event.clipboardData && event.clipboardData.getData) { - // pastedText = event.clipboardData.getData('text/plain'); - // } - // event.preventDefault(); - // const pasteRows = pastedText - // .replace(/\r/g, '') - // .split('\n') - // .map((row) => row.split('\t')); + var pastedText = undefined; + // @ts-ignore + if (window.clipboardData && window.clipboardData.getData) { + // IE + // @ts-ignore + pastedText = window.clipboardData.getData('Text'); + } else if (event.clipboardData && event.clipboardData.getData) { + pastedText = event.clipboardData.getData('text/plain'); + } + event.preventDefault(); + grider.beginUpdate(); + const pasteRows = pastedText + .replace(/\r/g, '') + .split('\n') + .map((row) => row.split('\t')); // let chs = changeSet; // let allRows = loadedAndInsertedRows; - // if (selectedCells.length <= 1) { - // const startRow = isRegularCell(currentCell) ? currentCell[0] : loadedAndInsertedRows.length; - // const startCol = isRegularCell(currentCell) ? currentCell[1] : 0; - // let rowIndex = startRow; - // for (const rowData of pasteRows) { - // if (rowIndex >= allRows.length) { - // chs = changeSetInsertNewRow(chs, display.baseTable); - // allRows = [...loadedRows, ...getChangeSetInsertedRows(chs, display.baseTable)]; - // } - // let colIndex = startCol; - // const row = allRows[rowIndex]; - // for (const cell of rowData) { - // chs = setChangeSetValue( - // chs, - // display.getChangeSetField( - // row, - // realColumnUniqueNames[colIndex], - // rowIndex >= loadedRows.length ? rowIndex - loadedRows.length : null - // ), - // cell == '(NULL)' ? null : cell - // ); - // colIndex += 1; - // } - // rowIndex += 1; - // } - // } - // if (selectedCells.length > 1) { - // const regularSelected = selectedCells.filter(isRegularCell); - // const startRow = _.min(regularSelected.map((x) => x[0])); - // const startCol = _.min(regularSelected.map((x) => x[1])); - // for (const cell of regularSelected) { - // const [rowIndex, colIndex] = cell; - // const selectionRow = rowIndex - startRow; - // const selectionCol = colIndex - startCol; - // const pasteRow = pasteRows[selectionRow % pasteRows.length]; - // const pasteCell = pasteRow[selectionCol % pasteRow.length]; - // chs = setCellValue(chs, cell, pasteCell); - // } - // } + if (selectedCells.length <= 1) { + const startRow = isRegularCell(currentCell) ? currentCell[0] : grider.rowCount; + const startCol = isRegularCell(currentCell) ? currentCell[1] : 0; + let rowIndex = startRow; + for (const rowData of pasteRows) { + if (rowIndex >= grider.rowCountInUpdate) { + grider.insertRow(); + } + let colIndex = startCol; + // const row = allRows[rowIndex]; + for (const cell of rowData) { + setCellValue([rowIndex, colIndex], cell == '(NULL)' ? null : cell); + // chs = setChangeSetValue( + // chs, + // display.getChangeSetField( + // row, + // realColumnUniqueNames[colIndex], + // rowIndex >= loadedRows.length ? rowIndex - loadedRows.length : null + // ), + // cell == '(NULL)' ? null : cell + // ); + colIndex += 1; + } + rowIndex += 1; + } + } + if (selectedCells.length > 1) { + const regularSelected = selectedCells.filter(isRegularCell); + const startRow = _.min(regularSelected.map((x) => x[0])); + const startCol = _.min(regularSelected.map((x) => x[1])); + for (const cell of regularSelected) { + const [rowIndex, colIndex] = cell; + const selectionRow = rowIndex - startRow; + const selectionCol = colIndex - startCol; + const pasteRow = pasteRows[selectionRow % pasteRows.length]; + const pasteCell = pasteRow[selectionCol % pasteRow.length]; + setCellValue(cell, pasteCell); + // chs = setCellValue(chs, cell, pasteCell); + } + } + grider.endUpdate(); // setChangeSet(chs); } @@ -524,11 +518,6 @@ export default function DataGridCore(props) { setCellValue(cell, null); }); grider.endUpdate(); - // let chs = changeSet; - // selectedCells.filter(isRegularCell).forEach((cell) => { - // chs = setCellValue(chs, cell, null); - // }); - // setChangeSet(chs); } function cellsToRegularCells(cells) { @@ -659,10 +648,10 @@ export default function DataGridCore(props) { display.setFilters(flts); } - function revertAllChanges() { - grider.revertAllChanges(); - // setChangeSet(createChangeSet()); - } + // function revertAllChanges() { + // grider.revertAllChanges(); + // // setChangeSet(createChangeSet()); + // } function deleteSelectedRows() { grider.beginUpdate(); diff --git a/packages/web/src/datagrid/Grider.ts b/packages/web/src/datagrid/Grider.ts index 7ef8f6f22..d0c5d18c2 100644 --- a/packages/web/src/datagrid/Grider.ts +++ b/packages/web/src/datagrid/Grider.ts @@ -29,6 +29,9 @@ export default abstract class Grider { revertAllChanges() {} undo() {} redo() {} + get rowCountInUpdate() { + return this.rowCount; + } get canUndo() { return false; } From 22a263a5988b17f178f38cfc0cb800d5ad849595 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 24 Oct 2020 21:36:17 +0200 Subject: [PATCH 8/8] code cleanup --- packages/web/src/datagrid/DataGridCore.js | 120 ------------------ packages/web/src/datagrid/DataGridRow.js | 13 -- packages/web/src/datagrid/InplaceEditor.js | 9 -- packages/web/src/datagrid/JslDataGridCore.js | 3 - .../web/src/datagrid/LoadingDataGridCore.js | 94 -------------- 5 files changed, 239 deletions(-) diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index 6cb292fc8..ba8b6b155 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -4,7 +4,6 @@ import ReactDOM from 'react-dom'; import styled from 'styled-components'; import { HorizontalScrollBar, VerticalScrollBar } from './ScrollBars'; import useDimensions from '../utility/useDimensions'; -import axios from '../utility/axios'; import DataFilterControl from './DataFilterControl'; import stableStringify from 'json-stable-stringify'; import { getFilterType, getFilterValueExpression } from '@dbgate/filterparser'; @@ -18,19 +17,6 @@ import { filterCellsForRow, cellIsSelected, } from './gridutil'; -import useModalState from '../modals/useModalState'; -import ConfirmSqlModal from '../modals/ConfirmSqlModal'; -import { - changeSetToSql, - createChangeSet, - revertChangeSetRowChanges, - getChangeSetInsertedRows, - changeSetInsertNewRow, - deleteChangeSetRows, - batchUpdateChangeSet, - setChangeSetValue, -} from '@dbgate/datalib'; -import { scriptToSql } from '@dbgate/sqltree'; import { copyTextToClipboard } from '../utility/clipboard'; import DataGridToolbar from './DataGridToolbar'; // import usePropsCompare from '../utility/usePropsCompare'; @@ -38,14 +24,8 @@ import ColumnHeaderControl from './ColumnHeaderControl'; import InlineButton from '../widgets/InlineButton'; import { showMenu } from '../modals/DropDownMenu'; import DataGridContextMenu from './DataGridContextMenu'; -import useSocket from '../utility/SocketProvider'; import LoadingInfo from '../widgets/LoadingInfo'; import ErrorInfo from '../widgets/ErrorInfo'; -import useShowModal from '../modals/showModal'; -import ErrorMessageModal from '../modals/ErrorMessageModal'; -import ImportExportModal from '../modals/ImportExportModal'; -import { openNewTab } from '../utility/common'; -import { useSetOpenedTabs } from '../utility/globalState'; const GridContainer = styled.div` position: absolute; @@ -132,8 +112,6 @@ export default function DataGridCore(props) { display, conid, database, - // changeSetState, - // dispatchChangeSet, tabVisible, loadNextData, errorMessage, @@ -143,7 +121,6 @@ export default function DataGridCore(props) { allRowCount, openQuery, onSave, - insertedRowCount, isLoading, grider, } = props; @@ -170,11 +147,6 @@ export default function DataGridCore(props) { const [autofillSelectedCells, setAutofillSelectedCells] = React.useState(emptyCellArray); const [focusFilterInputs, setFocusFilterInputs] = React.useState({}); - // const [inplaceEditorCell, setInplaceEditorCell] = React.useState(nullCell); - // const [inplaceEditorInitText, setInplaceEditorInitText] = React.useState(''); - // const [inplaceEditorShouldSave, setInplaceEditorShouldSave] = React.useState(false); - // const [inplaceEditorChangedOnCreate, setInplaceEditorChangedOnCreate] = React.useState(false); - const autofillMarkerCell = React.useMemo( () => selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map((x) => x[0])).length == 1 @@ -183,28 +155,12 @@ export default function DataGridCore(props) { [selectedCells] ); - const showModal = useShowModal(); - - // const data = useFetch({ - // url: 'database-connections/query-data', - // method: 'post', - // params: { - // conid, - // database, - // }, - // data: { sql }, - // }); - // const { rows, columns } = data || {}; const [firstVisibleRowScrollIndex, setFirstVisibleRowScrollIndex] = React.useState(0); const [firstVisibleColumnScrollIndex, setFirstVisibleColumnScrollIndex] = React.useState(0); const [headerRowRef, { height: rowHeight }] = useDimensions(); const [tableBodyRef] = useDimensions(); const [containerRef, { height: containerHeight, width: containerWidth }] = useDimensions(); - // const [tableRef, { height: tableHeight, width: tableWidth }] = useDimensions(); - - // const changeSet = changeSetState && changeSetState.value; - // const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => { switch (action.type) { @@ -273,20 +229,6 @@ export default function DataGridCore(props) { } }, [selectedCells, props.refReloadToken, grider.getRowData(0)]); - // const handleCloseInplaceEditor = React.useCallback( - // mode => { - // const [row, col] = currentCell || []; - // setInplaceEditorCell(null); - // setInplaceEditorInitText(null); - // setInplaceEditorShouldSave(false); - // if (tableElement) tableElement.focus(); - // // @ts-ignore - // if (mode == 'enter' && row) moveCurrentCell(row + 1, col); - // if (mode == 'save') setTimeout(handleSave, 1); - // }, - // [tableElement, currentCell] - // ); - // usePropsCompare({ columnSizes, firstVisibleColumnScrollIndex, gridScrollAreaWidth, columns }); const visibleRealColumns = React.useMemo( @@ -352,9 +294,6 @@ export default function DataGridCore(props) { } if (allRowCount == null) return 'Loading row count...'; return `Rows: ${allRowCount.toLocaleString()}`; - // if (this.isLoadingFirstPage) return "Loading first page..."; - // if (this.isFirstPageError) return "Error loading first page"; - // return `Rows: ${this.rowCount.toLocaleString()}`; }, [selectedCells, allRowCount, grider, visibleRealColumns]); if (!columns || columns.length == 0) @@ -466,8 +405,6 @@ export default function DataGridCore(props) { .replace(/\r/g, '') .split('\n') .map((row) => row.split('\t')); - // let chs = changeSet; - // let allRows = loadedAndInsertedRows; if (selectedCells.length <= 1) { const startRow = isRegularCell(currentCell) ? currentCell[0] : grider.rowCount; const startCol = isRegularCell(currentCell) ? currentCell[1] : 0; @@ -477,18 +414,8 @@ export default function DataGridCore(props) { grider.insertRow(); } let colIndex = startCol; - // const row = allRows[rowIndex]; for (const cell of rowData) { setCellValue([rowIndex, colIndex], cell == '(NULL)' ? null : cell); - // chs = setChangeSetValue( - // chs, - // display.getChangeSetField( - // row, - // realColumnUniqueNames[colIndex], - // rowIndex >= loadedRows.length ? rowIndex - loadedRows.length : null - // ), - // cell == '(NULL)' ? null : cell - // ); colIndex += 1; } rowIndex += 1; @@ -505,11 +432,9 @@ export default function DataGridCore(props) { const pasteRow = pasteRows[selectionRow % pasteRows.length]; const pasteCell = pasteRow[selectionCol % pasteRow.length]; setCellValue(cell, pasteCell); - // chs = setCellValue(chs, cell, pasteCell); } } grider.endUpdate(); - // setChangeSet(chs); } function setNull() { @@ -596,26 +521,10 @@ export default function DataGridCore(props) { } } - // function getRowDefinitions(rowIndexes) { - // const res = []; - // // if (!loadedAndInsertedRows) return res; - // // for (const index of rowIndexes) { - // // if (loadedAndInsertedRows[index] && _.isNumber(index)) { - // // const insertedRowIndex = index >= loadedRows.length ? index - loadedRows.length : null; - // // res.push(display.getChangeSetRow(loadedAndInsertedRows[index], insertedRowIndex)); - // // } - // // } - // return res; - // } - function getSelectedRowIndexes() { return _.uniq((selectedCells || []).map((x) => x[0])); } - // function getSelectedRowDefinitions() { - // return getRowDefinitions(getSelectedRowIndexes()); - // } - function getSelectedRowData() { return _.compact(getSelectedRowIndexes().map((index) => grider.getRowData(index))); } @@ -626,11 +535,6 @@ export default function DataGridCore(props) { if (_.isNumber(index)) grider.revertRowChanges(index); } grider.endUpdate(); - // const updatedChangeSet = getSelectedRowDefinitions().reduce( - // (chs, row) => revertChangeSetRowChanges(chs, row), - // changeSet - // ); - // setChangeSet(updatedChangeSet); } function filterSelectedValue() { @@ -648,19 +552,12 @@ export default function DataGridCore(props) { display.setFilters(flts); } - // function revertAllChanges() { - // grider.revertAllChanges(); - // // setChangeSet(createChangeSet()); - // } - function deleteSelectedRows() { grider.beginUpdate(); for (const index of getSelectedRowIndexes()) { if (_.isNumber(index)) grider.deleteRow(index); } grider.endUpdate(); - // const updatedChangeSet = getSelectedRowDefinitions().reduce((chs, row) => deleteChangeSetRows(chs, row), changeSet); - // setChangeSet(updatedChangeSet); } function handleGridWheel(event) { @@ -698,16 +595,11 @@ export default function DataGridCore(props) { return; } if (onSave) onSave(); - // const script = changeSetToSql(changeSetRef.current, display.dbinfo); - // const sql = scriptToSql(display.driver, script); - // setConfirmSql(sql); - // confirmSqlModalState.open(); } const insertNewRow = () => { if (display.baseTable) { const rowIndex = grider.insertRow(); - // setChangeSet(changeSetInsertNewRow(changeSet, display.baseTable)); const cell = [rowIndex, (currentCell && currentCell[1]) || 0]; // @ts-ignore setCurrentCell(cell); @@ -1045,7 +937,6 @@ export default function DataGridCore(props) { {_.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) - // .slice(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) .map((rowIndex) => ( = rows.length - (insertedRowCount || 0) - // ? firstVisibleRowScrollIndex + index - rows.length - (insertedRowCount || 0) - // : null - // } autofillMarkerCell={filterCellForRow(autofillMarkerCell, rowIndex)} - // changeSet={changeSet} - // setChangeSet={setChangeSet} display={display} - // row={row} focusedColumn={display.focusedColumn} /> ))} @@ -1096,9 +979,6 @@ export default function DataGridCore(props) { reload={() => display.reload()} save={handleSave} grider={grider} - // changeSetState={changeSetState} - // dispatchChangeSet={dispatchChangeSet} - // revert={revertAllChanges} />, props.toolbarPortalRef.current )} diff --git a/packages/web/src/datagrid/DataGridRow.js b/packages/web/src/datagrid/DataGridRow.js index bbda7ea0d..db355af36 100644 --- a/packages/web/src/datagrid/DataGridRow.js +++ b/packages/web/src/datagrid/DataGridRow.js @@ -170,11 +170,6 @@ function DataGridRow(props) { visibleRealColumns, inplaceEditorState, dispatchInsplaceEditor, - // row, - // display, - // changeSet, - // setChangeSet, - // insertedRowIndex, autofillMarkerCell, selectedCells, autofillSelectedCells, @@ -202,10 +197,6 @@ function DataGridRow(props) { const rowData = grider.getRowData(rowIndex); const rowStatus = grider.getRowStatus(rowIndex); - // const rowDefinition = display.getChangeSetRow(row, insertedRowIndex); - // const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(changeSet, rowDefinition); - // const rowUpdated = matchedChangeSetItem ? { ...row, ...matchedChangeSetItem.fields } : row; - const hintFieldsAllowed = visibleRealColumns .filter((col) => { if (!col.hintColumnName) return false; @@ -250,10 +241,6 @@ function DataGridRow(props) { grider={grider} rowIndex={rowIndex} uniqueName={col.uniqueName} - // changeSet={changeSet} - // setChangeSet={setChangeSet} - // insertedRowIndex={insertedRowIndex} - // definition={display.getChangeSetField(row, col.uniqueName, insertedRowIndex)} /> ) : ( <> diff --git a/packages/web/src/datagrid/InplaceEditor.js b/packages/web/src/datagrid/InplaceEditor.js index edfd35bca..142ead7bd 100644 --- a/packages/web/src/datagrid/InplaceEditor.js +++ b/packages/web/src/datagrid/InplaceEditor.js @@ -5,7 +5,6 @@ import React from 'react'; import styled from 'styled-components'; import theme from '../theme'; import keycodes from '../utility/keycodes'; -import { setChangeSetValue } from '@dbgate/datalib'; const StyledInput = styled.input` border: 0px solid; @@ -16,16 +15,12 @@ const StyledInput = styled.input` export default function InplaceEditor({ widthPx, - // definition, - // changeSet, - // setChangeSet, rowIndex, uniqueName, grider, cellValue, inplaceEditorState, dispatchInsplaceEditor, - // isInsertedRow, }) { const editorRef = React.useRef(); const isChangedRef = React.useRef(!!inplaceEditorState.text); @@ -41,7 +36,6 @@ export default function InplaceEditor({ if (isChangedRef.current) { const editor = editorRef.current; grider.setCellValue(rowIndex, uniqueName, editor.value); - // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } dispatchInsplaceEditor({ type: 'close' }); @@ -50,7 +44,6 @@ export default function InplaceEditor({ const editor = editorRef.current; if (isChangedRef.current) { grider.setCellValue(rowIndex, uniqueName, editor.value); - // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } editor.blur(); @@ -66,7 +59,6 @@ export default function InplaceEditor({ case keycodes.enter: if (isChangedRef.current) { grider.setCellValue(rowIndex, uniqueName, editor.value); - // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } editor.blur(); @@ -76,7 +68,6 @@ export default function InplaceEditor({ if (event.ctrlKey) { if (isChangedRef.current) { grider.setCellValue(rowIndex, uniqueName, editor.value); - // setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); isChangedRef.current = false; } event.preventDefault(); diff --git a/packages/web/src/datagrid/JslDataGridCore.js b/packages/web/src/datagrid/JslDataGridCore.js index e9e1a2eaf..88351a87f 100644 --- a/packages/web/src/datagrid/JslDataGridCore.js +++ b/packages/web/src/datagrid/JslDataGridCore.js @@ -1,12 +1,9 @@ import React from 'react'; import axios from '../utility/axios'; import { useSetOpenedTabs } from '../utility/globalState'; -import DataGridCore from './DataGridCore'; import useSocket from '../utility/SocketProvider'; import useShowModal from '../modals/showModal'; import ImportExportModal from '../modals/ImportExportModal'; -import { getChangeSetInsertedRows } from '@dbgate/datalib'; -import { openNewTab } from '../utility/common'; import LoadingDataGridCore from './LoadingDataGridCore'; import RowsArrayGrider from './RowsArrayGrider'; diff --git a/packages/web/src/datagrid/LoadingDataGridCore.js b/packages/web/src/datagrid/LoadingDataGridCore.js index 52ad56aef..66776ca0e 100644 --- a/packages/web/src/datagrid/LoadingDataGridCore.js +++ b/packages/web/src/datagrid/LoadingDataGridCore.js @@ -1,89 +1,9 @@ import React from 'react'; -import axios from '../utility/axios'; -import { useSetOpenedTabs } from '../utility/globalState'; import DataGridCore from './DataGridCore'; -import useSocket from '../utility/SocketProvider'; -import useShowModal from '../modals/showModal'; -import ImportExportModal from '../modals/ImportExportModal'; -import { getChangeSetInsertedRows } from '@dbgate/datalib'; -import { openNewTab } from '../utility/common'; - -// /** @param props {import('./types').LoadingDataGridProps} */ -// async function loadDataPage(props, offset, limit) { -// const { display, conid, database, jslid } = props; - -// if (jslid) { -// const response = await axios.request({ -// url: 'jsldata/get-rows', -// method: 'get', -// params: { -// jslid, -// offset, -// limit, -// }, -// }); -// return response.data; -// } - -// const sql = display.getPageQuery(offset, limit); - -// const response = await axios.request({ -// url: 'database-connections/query-data', -// method: 'post', -// params: { -// conid, -// database, -// }, -// data: { sql }, -// }); - -// if (response.data.errorMessage) return response.data; -// return response.data.rows; -// } - -// function dataPageAvailable(props) { -// const { display, jslid } = props; -// if (jslid) return true; -// const sql = display.getPageQuery(0, 1); -// return !!sql; -// } - -// /** @param props {import('./types').LoadingDataGridProps} */ -// async function loadRowCount(props) { -// const { display, conid, database, jslid } = props; - -// if (jslid) { -// const response = await axios.request({ -// url: 'jsldata/get-stats', -// method: 'get', -// params: { -// jslid, -// }, -// }); -// return response.data.rowCount; -// } - -// const sql = display.getCountQuery(); - -// const response = await axios.request({ -// url: 'database-connections/query-data', -// method: 'post', -// params: { -// conid, -// database, -// }, -// data: { sql }, -// }); - -// return parseInt(response.data.rows[0].count); -// } export default function LoadingDataGridCore(props) { const { display, - changeSetState, - dispatchChangeSet, - tabVisible, loadDataPage, dataPageAvailable, loadRowCount, @@ -105,19 +25,9 @@ export default function LoadingDataGridCore(props) { loadNextDataToken: 0, }); const { isLoading, loadedRows, isLoadedAll, loadedTime, allRowCount, errorMessage } = loadProps; - const showModal = useShowModal(); const loadedTimeRef = React.useRef(0); - // const changeSet = changeSetState && changeSetState.value; - // const setChangeSet = React.useCallback((value) => dispatchChangeSet({ type: 'set', value }), [dispatchChangeSet]); - // const setOpenedTabs = useSetOpenedTabs(); - // const socket = useSocket(); - - // const changeSetRef = React.useRef(changeSet); - - // changeSetRef.current = changeSet; - const handleLoadRowCount = async () => { const rowCount = await loadRowCount(props); setLoadProps((oldLoadProps) => ({ @@ -196,9 +106,6 @@ export default function LoadingDataGridCore(props) { })); }, [loadNextDataToken]); - // const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); - // const rowCountNewIncluded = loadedRows.length + insertedRows.length; - const griderProps = { ...props, sourceRows: loadedRows }; const grider = React.useMemo(() => griderFactory(griderProps), griderFactoryDeps(griderProps)); @@ -222,7 +129,6 @@ export default function LoadingDataGridCore(props) { allRowCount={allRowCount} openQuery={openQuery} isLoading={isLoading} - // rows={loadedRows} grider={grider} /> );