grider refactor

This commit is contained in:
Jan Prochazka 2020-10-24 18:35:26 +02:00
parent b314e363cd
commit abc007753a
11 changed files with 393 additions and 182 deletions

View File

@ -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<number>;
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];
}
}

View File

@ -126,7 +126,7 @@ const LoadingInfoBox = styled.div`
border: 1px solid gray; border: 1px solid gray;
`; `;
/** @param props {import('./types').DataGridCoreProps} */ /** @param props {import('./types').DataGridProps} */
export default function DataGridCore(props) { export default function DataGridCore(props) {
const { const {
display, display,
@ -135,7 +135,6 @@ export default function DataGridCore(props) {
changeSetState, changeSetState,
dispatchChangeSet, dispatchChangeSet,
tabVisible, tabVisible,
rows,
loadNextData, loadNextData,
errorMessage, errorMessage,
isLoadedAll, isLoadedAll,
@ -145,6 +144,7 @@ export default function DataGridCore(props) {
openQuery, openQuery,
insertedRowCount, insertedRowCount,
isLoading, isLoading,
grider,
} = props; } = props;
// console.log('RENDER GRID', display.baseTable.pureName); // console.log('RENDER GRID', display.baseTable.pureName);
const columns = React.useMemo(() => display.allColumns, [display]); const columns = React.useMemo(() => display.allColumns, [display]);
@ -236,8 +236,8 @@ export default function DataGridCore(props) {
// usePropsCompare({ loadedRows, columns, containerWidth, display }); // usePropsCompare({ loadedRows, columns, containerWidth, display });
const columnSizes = React.useMemo(() => countColumnSizes(rows, columns, containerWidth, display), [ const columnSizes = React.useMemo(() => countColumnSizes(grider, columns, containerWidth, display), [
rows, grider,
columns, columns,
containerWidth, containerWidth,
display, display,
@ -269,10 +269,10 @@ export default function DataGridCore(props) {
}, [columnSizes, gridScrollAreaWidth]); }, [columnSizes, gridScrollAreaWidth]);
React.useEffect(() => { React.useEffect(() => {
if (props.onReferenceSourceChanged && ((rows && rows.length > 0) || isLoadedAll)) { if (props.onReferenceSourceChanged && (grider.rowCount > 0 || isLoadedAll)) {
props.onReferenceSourceChanged(getSelectedRowData(), loadedTime); props.onReferenceSourceChanged(getSelectedRowData(), loadedTime);
} }
}, [selectedCells, props.refReloadToken, rows && rows[0]]); }, [selectedCells, props.refReloadToken, grider.getRowData(0)]);
// const handleCloseInplaceEditor = React.useCallback( // const handleCloseInplaceEditor = React.useCallback(
// mode => { // mode => {
@ -312,7 +312,7 @@ export default function DataGridCore(props) {
}, [display && display.focusedColumn]); }, [display && display.focusedColumn]);
React.useEffect(() => { React.useEffect(() => {
if (rows && loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= rows.length) { if (loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= grider.rowCount) {
loadNextData(); loadNextData();
} }
}); });
@ -334,7 +334,7 @@ export default function DataGridCore(props) {
const rowCountInfo = React.useMemo(() => { const rowCountInfo = React.useMemo(() => {
if (selectedCells.length > 1 && selectedCells.every((x) => _.isNumber(x[0]) && _.isNumber(x[1]))) { if (selectedCells.length > 1 && selectedCells.every((x) => _.isNumber(x[0]) && _.isNumber(x[1]))) {
let sum = _.sumBy(selectedCells, (cell) => { let sum = _.sumBy(selectedCells, (cell) => {
const row = rows[cell[0]]; const row = grider.getRowData(cell[0]);
if (row) { if (row) {
const colName = realColumnUniqueNames[cell[1]]; const colName = realColumnUniqueNames[cell[1]];
if (colName) { if (colName) {
@ -356,9 +356,9 @@ export default function DataGridCore(props) {
// if (this.isLoadingFirstPage) return "Loading first page..."; // if (this.isLoadingFirstPage) return "Loading first page...";
// if (this.isFirstPageError) return "Error loading first page"; // if (this.isFirstPageError) return "Error loading first page";
// return `Rows: ${this.rowCount.toLocaleString()}`; // 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 ( return (
<LoadingInfoWrapper> <LoadingInfoWrapper>
<LoadingInfoBox> <LoadingInfoBox>
@ -551,7 +551,7 @@ export default function DataGridCore(props) {
const rowIndexes = _.sortBy(_.uniq(cells.map((x) => x[0]))); const rowIndexes = _.sortBy(_.uniq(cells.map((x) => x[0])));
const lines = rowIndexes.map((rowIndex) => { const lines = rowIndexes.map((rowIndex) => {
let colIndexes = _.sortBy(cells.filter((x) => x[0] == rowIndex).map((x) => x[1])); 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 ''; if (!rowData) return '';
const line = colIndexes const line = colIndexes
.map((col) => realColumnUniqueNames[col]) .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); const rowIndexes = _.uniq((autofillSelectedCells || []).map((x) => x[0])).filter((x) => x != currentRowNumber);
// @ts-ignore // @ts-ignore
const colNames = selectedCells.map((cell) => realColumnUniqueNames[cell[1]]); const colNames = selectedCells.map((cell) => realColumnUniqueNames[cell[1]]);
const changeObject = _.pick(rows[currentRowNumber], colNames); const changeObject = _.pick(grider.getRowData(currentRowNumber), colNames);
setChangeSet( setChangeSet(
batchUpdateChangeSet( batchUpdateChangeSet(
changeSet, changeSet,
@ -629,7 +629,7 @@ export default function DataGridCore(props) {
} }
function getSelectedRowData() { function getSelectedRowData() {
return _.compact(getSelectedRowIndexes().map((index) => rows && rows[index])); return _.compact(getSelectedRowIndexes().map((index) => grider.getRowData(index)));
} }
function revertRowChanges() { function revertRowChanges() {
@ -646,7 +646,7 @@ export default function DataGridCore(props) {
if (!isRegularCell(cell)) continue; if (!isRegularCell(cell)) continue;
const modelIndex = columnSizes.realToModel(cell[1]); const modelIndex = columnSizes.realToModel(cell[1]);
const columnName = columns[modelIndex].uniqueName; 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); let svalue = getFilterValueExpression(value, columns[modelIndex].dataType);
if (_.has(flts, columnName)) flts[columnName] += ',' + svalue; if (_.has(flts, columnName)) flts[columnName] += ',' + svalue;
else flts[columnName] = svalue; else flts[columnName] = svalue;
@ -672,7 +672,7 @@ export default function DataGridCore(props) {
if (event.deltaY < 0) { if (event.deltaY < 0) {
newFirstVisibleRowScrollIndex -= wheelRowCount; newFirstVisibleRowScrollIndex -= wheelRowCount;
} }
let rowCount = rows.length; let rowCount = grider.rowCount;
if (newFirstVisibleRowScrollIndex + visibleRowCountLowerBound > rowCount) { if (newFirstVisibleRowScrollIndex + visibleRowCountLowerBound > rowCount) {
newFirstVisibleRowScrollIndex = rowCount - visibleRowCountLowerBound + 1; newFirstVisibleRowScrollIndex = rowCount - visibleRowCountLowerBound + 1;
} }
@ -728,8 +728,9 @@ export default function DataGridCore(props) {
const insertNewRow = () => { const insertNewRow = () => {
if (display.baseTable) { if (display.baseTable) {
setChangeSet(changeSetInsertNewRow(changeSet, display.baseTable)); const rowIndex = grider.insertRow();
const cell = [rows.length, (currentCell && currentCell[1]) || 0]; // setChangeSet(changeSetInsertNewRow(changeSet, display.baseTable));
const cell = [rowIndex, (currentCell && currentCell[1]) || 0];
// @ts-ignore // @ts-ignore
setCurrentCell(cell); setCurrentCell(cell);
// @ts-ignore // @ts-ignore
@ -843,7 +844,7 @@ export default function DataGridCore(props) {
function handleCursorMove(event) { function handleCursorMove(event) {
if (!isRegularCell(currentCell)) return null; if (!isRegularCell(currentCell)) return null;
let rowCount = rows.length; let rowCount = grider.rowCount;
if (event.ctrlKey) { if (event.ctrlKey) {
switch (event.keyCode) { switch (event.keyCode) {
case keycodes.upArrow: case keycodes.upArrow:
@ -901,7 +902,7 @@ export default function DataGridCore(props) {
} }
function moveCurrentCell(row, col, event = null) { function moveCurrentCell(row, col, event = null) {
const rowCount = rows.length; const rowCount = grider.rowCount;
if (row < 0) row = 0; if (row < 0) row = 0;
if (row >= rowCount) row = rowCount - 1; if (row >= rowCount) row = rowCount - 1;
@ -923,7 +924,7 @@ export default function DataGridCore(props) {
if (row != null) { if (row != null) {
let newRow = null; let newRow = null;
const rowCount = rows.length; const rowCount = grider.rowCount;
if (rowCount == 0) return; if (rowCount == 0) return;
if (row < firstVisibleRowScrollIndex) newRow = row; if (row < firstVisibleRowScrollIndex) newRow = row;
@ -1065,28 +1066,29 @@ export default function DataGridCore(props) {
)} )}
</TableHead> </TableHead>
<TableBody ref={tableBodyRef}> <TableBody ref={tableBodyRef}>
{rows {_.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound)
.slice(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) // .slice(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound)
.map((row, index) => ( .map((rowIndex) => (
<DataGridRow <DataGridRow
key={firstVisibleRowScrollIndex + index} key={rowIndex}
rowIndex={firstVisibleRowScrollIndex + index} grider={grider}
rowIndex={rowIndex}
rowHeight={rowHeight} rowHeight={rowHeight}
visibleRealColumns={visibleRealColumns} visibleRealColumns={visibleRealColumns}
inplaceEditorState={inplaceEditorState} inplaceEditorState={inplaceEditorState}
dispatchInsplaceEditor={dispatchInsplaceEditor} dispatchInsplaceEditor={dispatchInsplaceEditor}
autofillSelectedCells={autofillSelectedCells} autofillSelectedCells={autofillSelectedCells}
selectedCells={filterCellsForRow(selectedCells, firstVisibleRowScrollIndex + index)} selectedCells={filterCellsForRow(selectedCells, rowIndex)}
insertedRowIndex={ // insertedRowIndex={
firstVisibleRowScrollIndex + index >= rows.length - (insertedRowCount || 0) // firstVisibleRowScrollIndex + index >= rows.length - (insertedRowCount || 0)
? firstVisibleRowScrollIndex + index - rows.length - (insertedRowCount || 0) // ? firstVisibleRowScrollIndex + index - rows.length - (insertedRowCount || 0)
: null // : null
} // }
autofillMarkerCell={filterCellForRow(autofillMarkerCell, firstVisibleRowScrollIndex + index)} autofillMarkerCell={filterCellForRow(autofillMarkerCell, rowIndex)}
changeSet={changeSet} // changeSet={changeSet}
setChangeSet={setChangeSet} // setChangeSet={setChangeSet}
display={display} display={display}
row={row} // row={row}
focusedColumn={display.focusedColumn} focusedColumn={display.focusedColumn}
/> />
))} ))}
@ -1104,9 +1106,9 @@ export default function DataGridCore(props) {
valueToSet={vScrollValueToSet} valueToSet={vScrollValueToSet}
valueToSetDate={vScrollValueToSetDate} valueToSetDate={vScrollValueToSetDate}
minimum={0} minimum={0}
maximum={rows.length - visibleRowCountUpperBound + 2} maximum={grider.rowCount - visibleRowCountUpperBound + 2}
onScroll={handleRowScroll} onScroll={handleRowScroll}
viewportRatio={visibleRowCountUpperBound / rows.length} viewportRatio={visibleRowCountUpperBound / grider.rowCount}
/> />
<ConfirmSqlModal <ConfirmSqlModal
modalState={confirmSqlModalState} modalState={confirmSqlModalState}

View File

@ -81,8 +81,7 @@ const TableBodyCell = styled.td`
// from http://www.patternify.com/ // from http://www.patternify.com/
background-repeat: repeat-x; background-repeat: repeat-x;
background-position: 50% 50%;`} background-position: 50% 50%;`}
`;
`;
const HintSpan = styled.span` const HintSpan = styled.span`
color: gray; color: gray;
@ -163,22 +162,25 @@ function CellFormattedValue({ value, dataType }) {
return value.toString(); return value.toString();
} }
function DataGridRow({ /** @param props {import('./types').DataGridProps} */
function DataGridRow(props) {
const {
rowHeight, rowHeight,
rowIndex, rowIndex,
visibleRealColumns, visibleRealColumns,
inplaceEditorState, inplaceEditorState,
dispatchInsplaceEditor, dispatchInsplaceEditor,
row, // row,
display, display,
changeSet, // changeSet,
setChangeSet, // setChangeSet,
insertedRowIndex, insertedRowIndex,
autofillMarkerCell, autofillMarkerCell,
selectedCells, selectedCells,
autofillSelectedCells, autofillSelectedCells,
focusedColumn, focusedColumn,
}) { grider,
} = props;
// usePropsCompare({ // usePropsCompare({
// rowHeight, // rowHeight,
// rowIndex, // rowIndex,
@ -197,18 +199,23 @@ function DataGridRow({
// console.log('RENDER ROW', rowIndex); // console.log('RENDER ROW', rowIndex);
const rowDefinition = display.getChangeSetRow(row, insertedRowIndex); const rowData = grider.getRowData(rowIndex);
const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(changeSet, rowDefinition); const rowStatus = grider.getRowStatus(rowIndex);
const rowUpdated = matchedChangeSetItem ? { ...row, ...matchedChangeSetItem.fields } : row;
// const rowDefinition = display.getChangeSetRow(row, insertedRowIndex);
// const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(changeSet, rowDefinition);
// const rowUpdated = matchedChangeSetItem ? { ...row, ...matchedChangeSetItem.fields } : row;
const hintFieldsAllowed = visibleRealColumns const hintFieldsAllowed = visibleRealColumns
.filter((col) => { .filter((col) => {
if (!col.hintColumnName) return false; if (!col.hintColumnName) return false;
if (matchedChangeSetItem && matchedField == 'updates' && col.uniqueName in matchedChangeSetItem.fields) if (rowStatus.status == 'updated' && rowStatus.modifiedFields.has(col.uniqueName)) return false;
return false;
return true; return true;
}) })
.map((col) => col.uniqueName); .map((col) => col.uniqueName);
if (!rowData) return null;
return ( return (
<TableBodyRow style={{ height: `${rowHeight}px` }}> <TableBodyRow style={{ height: `${rowHeight}px` }}>
<TableHeaderCell data-row={rowIndex} data-col="header"> <TableHeaderCell data-row={rowIndex} data-col="header">
@ -226,13 +233,11 @@ function DataGridRow({
data-col={col.colIndex} data-col={col.colIndex}
isSelected={cellIsSelected(rowIndex, col.colIndex, selectedCells)} isSelected={cellIsSelected(rowIndex, col.colIndex, selectedCells)}
isAutofillSelected={cellIsSelected(rowIndex, col.colIndex, autofillSelectedCells)} isAutofillSelected={cellIsSelected(rowIndex, col.colIndex, autofillSelectedCells)}
isModifiedRow={!!matchedChangeSetItem} isModifiedRow={rowStatus.status == 'updated'}
isFocusedColumn={col.uniqueName == focusedColumn} isFocusedColumn={col.uniqueName == focusedColumn}
isModifiedCell={ isModifiedCell={rowStatus.status == 'updated' && rowStatus.modifiedFields.has(col.uniqueName)}
matchedChangeSetItem && matchedField == 'updates' && col.uniqueName in matchedChangeSetItem.fields
}
isInsertedRow={insertedRowIndex != null} isInsertedRow={insertedRowIndex != null}
isDeletedRow={matchedField == 'deletes'} isDeletedRow={rowStatus.status == 'deleted'}
> >
{inplaceEditorState.cell && {inplaceEditorState.cell &&
rowIndex == inplaceEditorState.cell[0] && rowIndex == inplaceEditorState.cell[0] &&
@ -241,16 +246,19 @@ function DataGridRow({
widthPx={col.widthPx} widthPx={col.widthPx}
inplaceEditorState={inplaceEditorState} inplaceEditorState={inplaceEditorState}
dispatchInsplaceEditor={dispatchInsplaceEditor} dispatchInsplaceEditor={dispatchInsplaceEditor}
cellValue={rowUpdated[col.uniqueName]} cellValue={rowData[col.uniqueName]}
changeSet={changeSet} grider={grider}
setChangeSet={setChangeSet} rowIndex={rowIndex}
insertedRowIndex={insertedRowIndex} uniqueName={col.uniqueName}
definition={display.getChangeSetField(row, col.uniqueName, insertedRowIndex)} // changeSet={changeSet}
// setChangeSet={setChangeSet}
// insertedRowIndex={insertedRowIndex}
// definition={display.getChangeSetField(row, col.uniqueName, insertedRowIndex)}
/> />
) : ( ) : (
<> <>
<CellFormattedValue value={rowUpdated[col.uniqueName]} dataType={col.dataType} /> <CellFormattedValue value={rowData[col.uniqueName]} dataType={col.dataType} />
{hintFieldsAllowed.includes(col.uniqueName) && <HintSpan>{row[col.hintColumnName]}</HintSpan>} {hintFieldsAllowed.includes(col.uniqueName) && <HintSpan>{rowData[col.hintColumnName]}</HintSpan>}
</> </>
)} )}
{autofillMarkerCell && autofillMarkerCell[1] == col.colIndex && autofillMarkerCell[0] == rowIndex && ( {autofillMarkerCell && autofillMarkerCell[1] == col.colIndex && autofillMarkerCell[0] == rowIndex && (

View File

@ -0,0 +1,28 @@
export interface GriderRowStatus {
status: 'regular' | 'updated' | 'deleted' | 'inserted';
modifiedFields: Set<string>;
}
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;
}
}

View File

@ -16,13 +16,16 @@ const StyledInput = styled.input`
export default function InplaceEditor({ export default function InplaceEditor({
widthPx, widthPx,
definition, // definition,
changeSet, // changeSet,
setChangeSet, // setChangeSet,
rowIndex,
uniqueName,
grider,
cellValue, cellValue,
inplaceEditorState, inplaceEditorState,
dispatchInsplaceEditor, dispatchInsplaceEditor,
isInsertedRow, // isInsertedRow,
}) { }) {
const editorRef = React.useRef(); const editorRef = React.useRef();
const isChangedRef = React.useRef(!!inplaceEditorState.text); const isChangedRef = React.useRef(!!inplaceEditorState.text);
@ -37,7 +40,8 @@ export default function InplaceEditor({
function handleBlur() { function handleBlur() {
if (isChangedRef.current) { if (isChangedRef.current) {
const editor = editorRef.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; isChangedRef.current = false;
} }
dispatchInsplaceEditor({ type: 'close' }); dispatchInsplaceEditor({ type: 'close' });
@ -45,7 +49,8 @@ export default function InplaceEditor({
if (inplaceEditorState.shouldSave) { if (inplaceEditorState.shouldSave) {
const editor = editorRef.current; const editor = editorRef.current;
if (isChangedRef.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; isChangedRef.current = false;
} }
editor.blur(); editor.blur();
@ -60,7 +65,8 @@ export default function InplaceEditor({
break; break;
case keycodes.enter: case keycodes.enter:
if (isChangedRef.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; isChangedRef.current = false;
} }
editor.blur(); editor.blur();
@ -69,7 +75,8 @@ export default function InplaceEditor({
case keycodes.s: case keycodes.s:
if (event.ctrlKey) { if (event.ctrlKey) {
if (isChangedRef.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; isChangedRef.current = false;
} }
event.preventDefault(); event.preventDefault();

View File

@ -8,6 +8,7 @@ import ImportExportModal from '../modals/ImportExportModal';
import { getChangeSetInsertedRows } from '@dbgate/datalib'; import { getChangeSetInsertedRows } from '@dbgate/datalib';
import { openNewTab } from '../utility/common'; import { openNewTab } from '../utility/common';
import LoadingDataGridCore from './LoadingDataGridCore'; import LoadingDataGridCore from './LoadingDataGridCore';
import RowsArrayGrider from './RowsArrayGrider';
async function loadDataPage(props, offset, limit) { async function loadDataPage(props, offset, limit) {
const { jslid } = props; const { jslid } = props;
@ -88,6 +89,8 @@ export default function JslDataGridCore(props) {
loadRowCount={loadRowCount} loadRowCount={loadRowCount}
loadNextDataToken={changeIndex} loadNextDataToken={changeIndex}
onReload={() => setChangeIndex(0)} onReload={() => setChangeIndex(0)}
griderFactory={RowsArrayGrider.factory}
griderFactoryDeps={RowsArrayGrider.factoryDeps}
/> />
); );
} }

View File

@ -8,75 +8,75 @@ import ImportExportModal from '../modals/ImportExportModal';
import { getChangeSetInsertedRows } from '@dbgate/datalib'; import { getChangeSetInsertedRows } from '@dbgate/datalib';
import { openNewTab } from '../utility/common'; import { openNewTab } from '../utility/common';
/** @param props {import('./types').LoadingDataGridProps} */ // /** @param props {import('./types').LoadingDataGridProps} */
async function loadDataPage(props, offset, limit) { // async function loadDataPage(props, offset, limit) {
const { display, conid, database, jslid } = props; // const { display, conid, database, jslid } = props;
if (jslid) { // if (jslid) {
const response = await axios.request({ // const response = await axios.request({
url: 'jsldata/get-rows', // url: 'jsldata/get-rows',
method: 'get', // method: 'get',
params: { // params: {
jslid, // jslid,
offset, // offset,
limit, // limit,
}, // },
}); // });
return response.data; // return response.data;
} // }
const sql = display.getPageQuery(offset, limit); // const sql = display.getPageQuery(offset, limit);
const response = await axios.request({ // const response = await axios.request({
url: 'database-connections/query-data', // url: 'database-connections/query-data',
method: 'post', // method: 'post',
params: { // params: {
conid, // conid,
database, // database,
}, // },
data: { sql }, // data: { sql },
}); // });
if (response.data.errorMessage) return response.data; // if (response.data.errorMessage) return response.data;
return response.data.rows; // return response.data.rows;
} // }
function dataPageAvailable(props) { // function dataPageAvailable(props) {
const { display, jslid } = props; // const { display, jslid } = props;
if (jslid) return true; // if (jslid) return true;
const sql = display.getPageQuery(0, 1); // const sql = display.getPageQuery(0, 1);
return !!sql; // return !!sql;
} // }
/** @param props {import('./types').LoadingDataGridProps} */ // /** @param props {import('./types').LoadingDataGridProps} */
async function loadRowCount(props) { // async function loadRowCount(props) {
const { display, conid, database, jslid } = props; // const { display, conid, database, jslid } = props;
if (jslid) { // if (jslid) {
const response = await axios.request({ // const response = await axios.request({
url: 'jsldata/get-stats', // url: 'jsldata/get-stats',
method: 'get', // method: 'get',
params: { // params: {
jslid, // jslid,
}, // },
}); // });
return response.data.rowCount; // return response.data.rowCount;
} // }
const sql = display.getCountQuery(); // const sql = display.getCountQuery();
const response = await axios.request({ // const response = await axios.request({
url: 'database-connections/query-data', // url: 'database-connections/query-data',
method: 'post', // method: 'post',
params: { // params: {
conid, // conid,
database, // database,
}, // },
data: { sql }, // data: { sql },
}); // });
return parseInt(response.data.rows[0].count); // return parseInt(response.data.rows[0].count);
} // }
export default function LoadingDataGridCore(props) { export default function LoadingDataGridCore(props) {
const { const {
@ -91,6 +91,8 @@ export default function LoadingDataGridCore(props) {
onReload, onReload,
exportGrid, exportGrid,
openQuery, openQuery,
griderFactory,
griderFactoryDeps,
} = props; } = props;
const [loadProps, setLoadProps] = React.useState({ const [loadProps, setLoadProps] = React.useState({
@ -187,12 +189,12 @@ export default function LoadingDataGridCore(props) {
} }
}; };
React.useEffect(()=>{ React.useEffect(() => {
setLoadProps((oldProps) => ({ setLoadProps((oldProps) => ({
...oldProps, ...oldProps,
isLoadedAll: false, isLoadedAll: false,
})); }));
},[loadNextDataToken]); }, [loadNextDataToken]);
const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable); const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable);
const rowCountNewIncluded = loadedRows.length + insertedRows.length; 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 ( return (
<DataGridCore <DataGridCore
{...props} {...props}
@ -214,10 +219,11 @@ export default function LoadingDataGridCore(props) {
isLoadedAll={isLoadedAll} isLoadedAll={isLoadedAll}
loadedTime={loadedTime} loadedTime={loadedTime}
exportGrid={exportGrid} exportGrid={exportGrid}
allRowCount={allRowCount} // allRowCount={allRowCount}
openQuery={openQuery} openQuery={openQuery}
isLoading={isLoading} isLoading={isLoading}
rows={loadedRows} // rows={loadedRows}
grider={grider}
/> />
); );
} }

View File

@ -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;
}
}

View File

@ -8,8 +8,9 @@ import ImportExportModal from '../modals/ImportExportModal';
import { getChangeSetInsertedRows } from '@dbgate/datalib'; import { getChangeSetInsertedRows } from '@dbgate/datalib';
import { openNewTab } from '../utility/common'; import { openNewTab } from '../utility/common';
import LoadingDataGridCore from './LoadingDataGridCore'; import LoadingDataGridCore from './LoadingDataGridCore';
import ChangeSetGrider from './ChangeSetGrider';
/** @param props {import('./types').LoadingDataGridProps} */ /** @param props {import('./types').DataGridProps} */
async function loadDataPage(props, offset, limit) { async function loadDataPage(props, offset, limit) {
const { display, conid, database } = props; const { display, conid, database } = props;
@ -53,6 +54,7 @@ async function loadRowCount(props) {
return parseInt(response.data.rows[0].count); return parseInt(response.data.rows[0].count);
} }
/** @param props {import('./types').DataGridProps} */
export default function SqlDataGridCore(props) { export default function SqlDataGridCore(props) {
const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible } = props; const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible } = props;
const showModal = useShowModal(); const showModal = useShowModal();
@ -82,6 +84,8 @@ export default function SqlDataGridCore(props) {
}); });
} }
// const grider = React.useMemo(()=>new ChangeSetGrider())
return ( return (
<LoadingDataGridCore <LoadingDataGridCore
{...props} {...props}
@ -90,6 +94,8 @@ export default function SqlDataGridCore(props) {
loadDataPage={loadDataPage} loadDataPage={loadDataPage}
dataPageAvailable={dataPageAvailable} dataPageAvailable={dataPageAvailable}
loadRowCount={loadRowCount} loadRowCount={loadRowCount}
griderFactory={ChangeSetGrider.factory}
griderFactoryDeps={ChangeSetGrider.factoryDeps}
/> />
); );
} }

View File

@ -2,10 +2,11 @@ import _ from 'lodash';
import { SeriesSizes } from './SeriesSizes'; import { SeriesSizes } from './SeriesSizes';
import { CellAddress } from './selection'; import { CellAddress } from './selection';
import { GridDisplay } from '@dbgate/datalib'; 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(); const columnSizes = new SeriesSizes();
if (!loadedRows || !columns) return columnSizes; if (!grider || !columns) return columnSizes;
let canvas = document.createElement('canvas'); let canvas = document.createElement('canvas');
let context = canvas.getContext('2d'); let context = canvas.getContext('2d');
@ -51,7 +52,8 @@ export function countColumnSizes(loadedRows, columns, containerWidth, display: G
// if (headerWidth > this.rowHeaderWidth) this.rowHeaderWidth = headerWidth; // if (headerWidth > this.rowHeaderWidth) this.rowHeaderWidth = headerWidth;
context.font = '14px Helvetica'; 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++) { for (let colIndex = 0; colIndex < columns.length; colIndex++) {
const uqName = columns[colIndex].uniqueName; const uqName = columns[colIndex].uniqueName;

View File

@ -1,4 +1,5 @@
import { GridDisplay, ChangeSet, GridReferenceDefinition } from '@dbgate/datalib'; import { GridDisplay, ChangeSet, GridReferenceDefinition } from '@dbgate/datalib';
import Grider from './Grider';
export interface DataGridProps { export interface DataGridProps {
display: GridDisplay; display: GridDisplay;
@ -12,28 +13,34 @@ export interface DataGridProps {
refReloadToken?: string; refReloadToken?: string;
masterLoadedTime?: number; masterLoadedTime?: number;
managerSize?: number; managerSize?: number;
} grider?: Grider;
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; conid?: string;
database?: string; database?: string;
jslid?: 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;
// }