mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-22 18:06:01 +00:00
autofill
This commit is contained in:
@@ -33,6 +33,7 @@ import {
|
||||
getChangeSetInsertedRows,
|
||||
changeSetInsertNewRow,
|
||||
deleteChangeSetRows,
|
||||
batchUpdateChangeSet,
|
||||
} from '@dbgate/datalib';
|
||||
import { scriptToSql } from '@dbgate/sqltree';
|
||||
import { sleep } from '../utility/common';
|
||||
@@ -111,6 +112,8 @@ export default function DataGridCore(props) {
|
||||
const [selectedCells, setSelectedCells] = React.useState(emptyCellArray);
|
||||
const [dragStartCell, setDragStartCell] = React.useState(nullCell);
|
||||
const [shiftDragStartCell, setShiftDragStartCell] = React.useState(nullCell);
|
||||
const [autofillDragStartCell, setAutofillDragStartCell] = React.useState(nullCell);
|
||||
const [autofillSelectedCells, setAutofillSelectedCells] = React.useState(emptyCellArray);
|
||||
|
||||
// const [inplaceEditorCell, setInplaceEditorCell] = React.useState(nullCell);
|
||||
// const [inplaceEditorInitText, setInplaceEditorInitText] = React.useState('');
|
||||
@@ -121,6 +124,14 @@ export default function DataGridCore(props) {
|
||||
|
||||
changeSetRef.current = changeSet;
|
||||
|
||||
const autofillMarkerCell = React.useMemo(
|
||||
() =>
|
||||
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
||||
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
||||
: null,
|
||||
[selectedCells]
|
||||
);
|
||||
|
||||
const loadNextData = async () => {
|
||||
if (isLoading) return;
|
||||
setLoadProps({
|
||||
@@ -280,21 +291,6 @@ export default function DataGridCore(props) {
|
||||
[columnSizes, firstVisibleColumnScrollIndex, gridScrollAreaWidth, columns]
|
||||
);
|
||||
|
||||
const cellIsSelected = React.useCallback(
|
||||
(row, col) => {
|
||||
const [currentRow, currentCol] = currentCell;
|
||||
if (row == currentRow && col == currentCol) return true;
|
||||
for (const [selectedRow, selectedCol] of selectedCells) {
|
||||
if (row == selectedRow && col == selectedCol) return true;
|
||||
if (selectedRow == 'header' && col == selectedCol) return true;
|
||||
if (row == selectedRow && selectedCol == 'header') return true;
|
||||
if (selectedRow == 'header' && selectedCol == 'header') return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
[currentCell, selectedCells]
|
||||
);
|
||||
|
||||
if (!loadedRows || !columns) return null;
|
||||
const insertedRows = getChangeSetInsertedRows(changeSet, display.baseTable);
|
||||
const rowCountNewIncluded = loadedRows.length + insertedRows.length;
|
||||
@@ -310,21 +306,33 @@ export default function DataGridCore(props) {
|
||||
function handleGridMouseDown(event) {
|
||||
event.target.closest('table').focus();
|
||||
const cell = cellFromEvent(event);
|
||||
setCurrentCell(cell);
|
||||
setSelectedCells(getCellRange(cell, cell));
|
||||
setDragStartCell(cell);
|
||||
const autofill = event.target.closest('div.autofillHandleMarker');
|
||||
if (autofill) {
|
||||
setAutofillDragStartCell(cell);
|
||||
} else {
|
||||
setCurrentCell(cell);
|
||||
setSelectedCells(getCellRange(cell, cell));
|
||||
setDragStartCell(cell);
|
||||
|
||||
if (isRegularCell(cell) && !_.isEqual(cell, inplaceEditorState.cell) && _.isEqual(cell, currentCell)) {
|
||||
// @ts-ignore
|
||||
dispatchInsplaceEditor({ type: 'show', cell, selectAll: true });
|
||||
} else if (!_.isEqual(cell, inplaceEditorState.cell)) {
|
||||
// @ts-ignore
|
||||
dispatchInsplaceEditor({ type: 'close' });
|
||||
if (isRegularCell(cell) && !_.isEqual(cell, inplaceEditorState.cell) && _.isEqual(cell, currentCell)) {
|
||||
// @ts-ignore
|
||||
dispatchInsplaceEditor({ type: 'show', cell, selectAll: true });
|
||||
} else if (!_.isEqual(cell, inplaceEditorState.cell)) {
|
||||
// @ts-ignore
|
||||
dispatchInsplaceEditor({ type: 'close' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleGridMouseMove(event) {
|
||||
if (dragStartCell) {
|
||||
if (autofillDragStartCell) {
|
||||
const cell = cellFromEvent(event);
|
||||
if (isRegularCell(cell) && (cell[0] == autofillDragStartCell[0] || cell[1] == autofillDragStartCell[1])) {
|
||||
const autoFillStart = [selectedCells[0][0], _.min(selectedCells.map(x => x[1]))];
|
||||
// @ts-ignore
|
||||
setAutofillSelectedCells(getCellRange(autoFillStart, cell));
|
||||
}
|
||||
} else if (dragStartCell) {
|
||||
const cell = cellFromEvent(event);
|
||||
setCurrentCell(cell);
|
||||
setSelectedCells(getCellRange(dragStartCell, cell));
|
||||
@@ -338,24 +346,44 @@ export default function DataGridCore(props) {
|
||||
setSelectedCells(getCellRange(dragStartCell, cell));
|
||||
setDragStartCell(null);
|
||||
}
|
||||
if (autofillDragStartCell) {
|
||||
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 => columns[columnSizes.realToModel(cell[1])].uniqueName);
|
||||
const changeObject = _.pick(loadedAndInsertedRows[currentRowNumber], colNames);
|
||||
setChangeSet(
|
||||
batchUpdateChangeSet(
|
||||
changeSet,
|
||||
getRowDefinitions(rowIndexes),
|
||||
// @ts-ignore
|
||||
rowIndexes.map(() => changeObject)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
setAutofillDragStartCell(null);
|
||||
setAutofillSelectedCells([]);
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedRowDefinitions() {
|
||||
function getRowDefinitions(rowIndexes) {
|
||||
const res = [];
|
||||
if (!loadedAndInsertedRows) return res;
|
||||
const rowIndexes = _.uniq((selectedCells || []).map(x => x[0]));
|
||||
for (const index of rowIndexes) {
|
||||
if (loadedAndInsertedRows[index] && _.isNumber(index)) {
|
||||
const insertedRowIndex =
|
||||
firstVisibleRowScrollIndex + index >= loadedRows.length
|
||||
? firstVisibleRowScrollIndex + index - loadedRows.length
|
||||
: null;
|
||||
const insertedRowIndex = index >= loadedRows.length ? index - loadedRows.length : null;
|
||||
res.push(display.getChangeSetRow(loadedAndInsertedRows[index], insertedRowIndex));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function getSelectedRowDefinitions() {
|
||||
return getRowDefinitions(_.uniq((selectedCells || []).map(x => x[0])));
|
||||
}
|
||||
|
||||
function revertRowChanges() {
|
||||
const updatedChangeSet = getSelectedRowDefinitions().reduce(
|
||||
(chs, row) => revertChangeSetRowChanges(chs, row),
|
||||
@@ -365,10 +393,7 @@ export default function DataGridCore(props) {
|
||||
}
|
||||
|
||||
function deleteCurrentRow() {
|
||||
const updatedChangeSet = getSelectedRowDefinitions().reduce(
|
||||
(chs, row) => deleteChangeSetRows(chs, row),
|
||||
changeSet
|
||||
);
|
||||
const updatedChangeSet = getSelectedRowDefinitions().reduce((chs, row) => deleteChangeSetRows(chs, row), changeSet);
|
||||
setChangeSet(updatedChangeSet);
|
||||
}
|
||||
|
||||
@@ -699,12 +724,14 @@ export default function DataGridCore(props) {
|
||||
visibleRealColumns={visibleRealColumns}
|
||||
inplaceEditorState={inplaceEditorState}
|
||||
dispatchInsplaceEditor={dispatchInsplaceEditor}
|
||||
cellIsSelected={cellIsSelected}
|
||||
autofillSelectedCells={autofillSelectedCells}
|
||||
selectedCells={selectedCells}
|
||||
insertedRowIndex={
|
||||
firstVisibleRowScrollIndex + index >= loadedRows.length
|
||||
? firstVisibleRowScrollIndex + index - loadedRows.length
|
||||
: null
|
||||
}
|
||||
autofillMarkerCell={autofillMarkerCell}
|
||||
changeSet={changeSet}
|
||||
setChangeSet={setChangeSet}
|
||||
display={display}
|
||||
|
||||
@@ -22,22 +22,34 @@ const TableBodyCell = styled.td`
|
||||
// border-collapse: collapse;
|
||||
padding: 2px;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
${props =>
|
||||
props.isSelected &&
|
||||
!props.isAutofillSelected &&
|
||||
`
|
||||
background: initial;
|
||||
background-color: deepskyblue;
|
||||
color: white;`}
|
||||
|
||||
${props =>
|
||||
props.isAutofillSelected &&
|
||||
`
|
||||
background: initial;
|
||||
background-color: magenta;
|
||||
color: white;`}
|
||||
|
||||
${props =>
|
||||
props.isModifiedRow &&
|
||||
!props.isInsertedRow &&
|
||||
!props.isSelected &&
|
||||
!props.isAutofillSelected &&
|
||||
!props.isModifiedCell &&
|
||||
`
|
||||
background-color: #FFFFDB;`}
|
||||
${props =>
|
||||
!props.isSelected &&
|
||||
!props.isAutofillSelected &&
|
||||
!props.isInsertedRow &&
|
||||
props.isModifiedCell &&
|
||||
`
|
||||
@@ -45,20 +57,27 @@ const TableBodyCell = styled.td`
|
||||
|
||||
${props =>
|
||||
!props.isSelected &&
|
||||
!props.isAutofillSelected &&
|
||||
props.isInsertedRow &&
|
||||
`
|
||||
background-color: #DBFFDB;`}
|
||||
|
||||
${props =>
|
||||
!props.isSelected &&
|
||||
!props.isAutofillSelected &&
|
||||
props.isDeletedRow &&
|
||||
`
|
||||
background-color: #FFDBFF;
|
||||
`}
|
||||
|
||||
${props =>
|
||||
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`
|
||||
@@ -89,24 +108,47 @@ const TableHeaderCell = styled.td`
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const AutoFillPoint = styled.div`
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #1a73e8;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
overflow: visible;
|
||||
cursor: crosshair;
|
||||
`;
|
||||
|
||||
function CellFormattedValue({ value }) {
|
||||
if (value == null) return <NullSpan>(NULL)</NullSpan>;
|
||||
if (_.isDate(value)) return moment(value).format('YYYY-MM-DD HH:mm:ss');
|
||||
return value;
|
||||
}
|
||||
|
||||
function cellIsSelected(row, col, selectedCells) {
|
||||
for (const [selectedRow, selectedCol] of selectedCells) {
|
||||
if (row == selectedRow && col == selectedCol) return true;
|
||||
if (selectedRow == 'header' && col == selectedCol) return true;
|
||||
if (row == selectedRow && selectedCol == 'header') return true;
|
||||
if (selectedRow == 'header' && selectedCol == 'header') return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default function DataGridRow({
|
||||
rowHeight,
|
||||
rowIndex,
|
||||
visibleRealColumns,
|
||||
inplaceEditorState,
|
||||
dispatchInsplaceEditor,
|
||||
cellIsSelected,
|
||||
row,
|
||||
display,
|
||||
changeSet,
|
||||
setChangeSet,
|
||||
insertedRowIndex,
|
||||
autofillMarkerCell,
|
||||
selectedCells,
|
||||
autofillSelectedCells,
|
||||
}) {
|
||||
// console.log('RENDER ROW', rowIndex);
|
||||
const rowDefinition = display.getChangeSetRow(row, insertedRowIndex);
|
||||
@@ -120,6 +162,7 @@ export default function DataGridRow({
|
||||
return true;
|
||||
})
|
||||
.map(col => col.uniqueName);
|
||||
|
||||
return (
|
||||
<TableBodyRow style={{ height: `${rowHeight}px` }}>
|
||||
<TableHeaderCell data-row={rowIndex} data-col="header">
|
||||
@@ -135,8 +178,8 @@ export default function DataGridRow({
|
||||
}}
|
||||
data-row={rowIndex}
|
||||
data-col={col.colIndex}
|
||||
// @ts-ignore
|
||||
isSelected={cellIsSelected(rowIndex, col.colIndex)}
|
||||
isSelected={cellIsSelected(rowIndex, col.colIndex, selectedCells)}
|
||||
isAutofillSelected={cellIsSelected(rowIndex, col.colIndex, autofillSelectedCells)}
|
||||
isModifiedRow={!!matchedChangeSetItem}
|
||||
isModifiedCell={
|
||||
matchedChangeSetItem && matchedField == 'updates' && col.uniqueName in matchedChangeSetItem.fields
|
||||
@@ -163,6 +206,9 @@ export default function DataGridRow({
|
||||
{hintFieldsAllowed.includes(col.uniqueName) && <HintSpan>{row[col.hintColumnName]}</HintSpan>}
|
||||
</>
|
||||
)}
|
||||
{autofillMarkerCell && autofillMarkerCell[1] == col.colIndex && autofillMarkerCell[0] == rowIndex && (
|
||||
<AutoFillPoint className="autofillHandleMarker"></AutoFillPoint>
|
||||
)}
|
||||
</TableBodyCell>
|
||||
))}
|
||||
</TableBodyRow>
|
||||
|
||||
Reference in New Issue
Block a user