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; +// }