diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index c1a200860..b751e66ce 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -96,7 +96,7 @@ const FocusField = styled.input` /** @param props {import('./types').DataGridProps} */ export default function DataGridCore(props) { - const { conid, database, display, changeSet, setChangeSet, tabVisible } = props; + const { conid, database, display, changeSetState, dispatchChangeSet, tabVisible } = props; const columns = display.getGridColumns(); // console.log(`GRID, conid=${conid}, database=${database}, sql=${sql}`); @@ -129,6 +129,9 @@ export default function DataGridCore(props) { // const [inplaceEditorShouldSave, setInplaceEditorShouldSave] = React.useState(false); // const [inplaceEditorChangedOnCreate, setInplaceEditorChangedOnCreate] = React.useState(false); + const changeSet = changeSetState.value; + const setChangeSet = value => dispatchChangeSet({ type: 'set', value }); + const changeSetRef = React.useRef(changeSet); changeSetRef.current = changeSet; @@ -537,6 +540,13 @@ export default function DataGridCore(props) { // await sleep(1); // } + function undo() { + dispatchChangeSet({ type: 'undo' }); + } + function redo() { + dispatchChangeSet({ type: 'redo' }); + } + function handleSave() { if (inplaceEditorState.cell) { // @ts-ignore @@ -560,7 +570,7 @@ export default function DataGridCore(props) { data: { sql: confirmSql }, }); - setChangeSet(createChangeSet()); + dispatchChangeSet({ type: 'reset', value: createChangeSet() }); setConfirmSql(null); display.reload(); } @@ -577,6 +587,16 @@ export default function DataGridCore(props) { revertRowChanges(); } + if (event.keyCode == keycodes.z && event.ctrlKey) { + event.preventDefault(); + undo(); + } + + if (event.keyCode == keycodes.y && event.ctrlKey) { + event.preventDefault(); + redo(); + } + if (event.keyCode == keycodes.c && event.ctrlKey) { event.preventDefault(); copyToClipboard(); diff --git a/packages/web/src/datagrid/InplaceEditor.js b/packages/web/src/datagrid/InplaceEditor.js index bb91ca4e8..b2138cb33 100644 --- a/packages/web/src/datagrid/InplaceEditor.js +++ b/packages/web/src/datagrid/InplaceEditor.js @@ -38,12 +38,16 @@ export default function InplaceEditor({ if (isChangedRef.current) { const editor = editorRef.current; setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + isChangedRef.current = false; } dispatchInsplaceEditor({ type: 'close' }); } if (inplaceEditorState.shouldSave) { const editor = editorRef.current; - setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + if (isChangedRef.current) { + setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + isChangedRef.current = false; + } editor.blur(); dispatchInsplaceEditor({ type: 'close', mode: 'save' }); } @@ -55,7 +59,10 @@ export default function InplaceEditor({ dispatchInsplaceEditor({ type: 'close' }); break; case keycodes.enter: - setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + if (isChangedRef.current) { + setChangeSet(setChangeSetValue(changeSet, definition, editor.value)); + isChangedRef.current = false; + } editor.blur(); dispatchInsplaceEditor({ type: 'close', mode: 'enter' }); break; diff --git a/packages/web/src/datagrid/types.ts b/packages/web/src/datagrid/types.ts index 5ca7774e6..81fe31720 100644 --- a/packages/web/src/datagrid/types.ts +++ b/packages/web/src/datagrid/types.ts @@ -5,6 +5,6 @@ export interface DataGridProps { database: string; display: GridDisplay; tabVisible?: boolean; - changeSet?: ChangeSet; - setChangeSet?: Function; + changeSetState: { value: ChangeSet }; + dispatchChangeSet: Function; } diff --git a/packages/web/src/tabs/TableDataTab.js b/packages/web/src/tabs/TableDataTab.js index 17fa0f38a..dc4644f7b 100644 --- a/packages/web/src/tabs/TableDataTab.js +++ b/packages/web/src/tabs/TableDataTab.js @@ -8,12 +8,13 @@ import useTableInfo from '../utility/useTableInfo'; import useConnectionInfo from '../utility/useConnectionInfo'; import engines from '@dbgate/engines'; import getTableInfo from '../utility/getTableInfo'; +import useUndoReducer from '../utility/useUndoReducer'; export default function TableDataTab({ conid, database, schemaName, pureName, tabVisible }) { const tableInfo = useTableInfo({ conid, database, schemaName, pureName }); const [config, setConfig] = React.useState(createGridConfig()); const [cache, setCache] = React.useState(createGridCache()); - const [changeSet, setChangeSet] = React.useState(createChangeSet()); + const [changeSetState, dispatchChangeSet] = useUndoReducer(createChangeSet()); // console.log('changeSet', changeSet); @@ -37,8 +38,8 @@ export default function TableDataTab({ conid, database, schemaName, pureName, ta database={database} display={display} tabVisible={tabVisible} - changeSet={changeSet} - setChangeSet={setChangeSet} + changeSetState={changeSetState} + dispatchChangeSet={dispatchChangeSet} /> ); } diff --git a/packages/web/src/utility/useUndoReducer.js b/packages/web/src/utility/useUndoReducer.js new file mode 100644 index 000000000..c1ead534e --- /dev/null +++ b/packages/web/src/utility/useUndoReducer.js @@ -0,0 +1,43 @@ +import React from 'react'; + +function reducer(state, action) { + switch (action.type) { + case 'set': + // console.log('SET', state.history, action.value); + return { + history: [...state.history.slice(0, state.current + 1), action.value], + current: state.current + 1, + value: action.value, + }; + case 'undo': + if (state.current > 0) + return { + history: state.history, + current: state.current - 1, + value: state.history[state.current - 1], + }; + return state; + case 'redo': + if (state.current < state.history.length - 1) + return { + history: state.history, + current: state.current + 1, + value: state.history[state.current + 1], + }; + return state; + case 'reset': + return { + history: [action.value], + current: 0, + value: action.value, + }; + } +} + +export default function useUndoReducer(initialValue) { + return React.useReducer(reducer, { + history: [initialValue], + current: 0, + value: initialValue, + }); +}