mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
fixes: undo/redo actions
This commit is contained in:
parent
e556715e5f
commit
453405d7f2
1 changed files with 93 additions and 94 deletions
|
|
@ -129,7 +129,6 @@ const EditorComponent = (props) => {
|
|||
|
||||
const { isMaintenanceOn, appId, app, currentUser, currentVersionId, appDefinitionDiff } = useAppInfo();
|
||||
|
||||
const [currentVersionChanges, setCurrentVersionChanges] = useState({});
|
||||
const [currentPageId, setCurrentPageId] = useState(null);
|
||||
const [zoomLevel, setZoomLevel] = useState(1);
|
||||
const [isQueryPaneDragging, setIsQueryPaneDragging] = useState(false);
|
||||
|
|
@ -143,6 +142,9 @@ const EditorComponent = (props) => {
|
|||
const [showPageDeletionConfirmation, setShowPageDeletionConfirmation] = useState(null);
|
||||
const [isDeletingPage, setIsDeletingPage] = useState(false);
|
||||
|
||||
const [undoStack, setUndoStack] = useState([]);
|
||||
const [redoStack, setRedoStack] = useState([]);
|
||||
|
||||
// refs
|
||||
const canvasContainerRef = useRef(null);
|
||||
const dataSourceModalRef = useRef(null);
|
||||
|
|
@ -280,7 +282,7 @@ const EditorComponent = (props) => {
|
|||
const currentVersion = {
|
||||
[currentPageId]: -1,
|
||||
};
|
||||
setCurrentVersionChanges({});
|
||||
|
||||
updateEditorState({
|
||||
canUndo: false,
|
||||
canRedo: false,
|
||||
|
|
@ -714,7 +716,14 @@ const EditorComponent = (props) => {
|
|||
}
|
||||
};
|
||||
|
||||
const appDefinitionChanged = (newDefinition, opts = {}) => {
|
||||
const diffToPatches = (diffObj) => {
|
||||
return Object.keys(diffObj).reduce((patches, path) => {
|
||||
const value = diffObj[path];
|
||||
return [...patches, { path: path.split('.'), value, op: 'replace' }];
|
||||
}, []);
|
||||
};
|
||||
|
||||
const appDefinitionChanged = async (newDefinition, opts = {}) => {
|
||||
if (config.ENABLE_MULTIPLAYER_EDITING && !opts.skipYmapUpdate) {
|
||||
props.ymap?.set('appDef', {
|
||||
newDefinition,
|
||||
|
|
@ -735,45 +744,51 @@ const EditorComponent = (props) => {
|
|||
}
|
||||
|
||||
let updatedAppDefinition;
|
||||
const copyOfAppDefinition = JSON.parse(JSON.stringify(appDefinition));
|
||||
|
||||
updatedAppDefinition = _.cloneDeep(appDefinition);
|
||||
|
||||
if (_.isEmpty(updatedAppDefinition)) return;
|
||||
|
||||
if (opts?.containerChanges || opts?.componentDefinitionChanged) {
|
||||
const currentPageComponents = newDefinition.pages[currentPageId]?.components;
|
||||
|
||||
updatedAppDefinition.pages[currentPageId].components = currentPageComponents;
|
||||
}
|
||||
|
||||
if (opts?.pageDefinitionChanged) {
|
||||
updatedAppDefinition.pages = newDefinition.pages;
|
||||
}
|
||||
|
||||
if (opts?.homePageChanged) {
|
||||
updatedAppDefinition.homePageId = newDefinition.homePageId;
|
||||
}
|
||||
|
||||
if (opts?.generalAppDefinitionChanged || opts?.globalSettings) {
|
||||
updatedAppDefinition = newDefinition;
|
||||
}
|
||||
|
||||
const diffPatches = diff(appDefinition, updatedAppDefinition);
|
||||
const shouldUpdate = !_.isEmpty(diffPatches) && !isEqual(appDefinitionDiff, diffPatches);
|
||||
|
||||
console.log('--arpit | appDefinitionChanged func() | diffPatches', {
|
||||
diffPatches,
|
||||
appDefinitionDiff,
|
||||
shouldUpdate,
|
||||
console.log('--arpit | appDefinitionChanged func()', {
|
||||
opts,
|
||||
newDefinition,
|
||||
});
|
||||
|
||||
updatedAppDefinition = produce(copyOfAppDefinition, (draft) => {
|
||||
if (_.isEmpty(draft)) return;
|
||||
|
||||
if (opts?.containerChanges || opts?.componentDefinitionChanged) {
|
||||
const currentPageComponents = newDefinition.pages[currentPageId]?.components;
|
||||
|
||||
draft.pages[currentPageId].components = currentPageComponents;
|
||||
}
|
||||
|
||||
if (opts?.pageDefinitionChanged) {
|
||||
draft.pages = newDefinition.pages;
|
||||
}
|
||||
|
||||
if (opts?.homePageChanged) {
|
||||
draft.homePageId = newDefinition.homePageId;
|
||||
}
|
||||
|
||||
if (opts?.generalAppDefinitionChanged || opts?.globalSettings) {
|
||||
Object.assign(draft, newDefinition);
|
||||
}
|
||||
});
|
||||
|
||||
const diffPatches = diff(appDefinition, updatedAppDefinition);
|
||||
const inversePatches = diff(updatedAppDefinition, appDefinition);
|
||||
const shouldUpdate = !_.isEmpty(diffPatches) && !isEqual(appDefinitionDiff, diffPatches);
|
||||
|
||||
if (shouldUpdate) {
|
||||
// const redoPatch = diffToPatches(diffPatches);
|
||||
const undoPatches = diffToPatches(inversePatches);
|
||||
|
||||
setUndoStack((prev) => [...prev, undoPatches]);
|
||||
|
||||
updateAppDefinitionDiff(diffPatches);
|
||||
updateEditorState({
|
||||
isSaving: true,
|
||||
appDefinition: updatedAppDefinition,
|
||||
});
|
||||
updateAppDefinitionDiff(diffPatches);
|
||||
|
||||
computeComponentState(updatedAppDefinition.pages[currentPageId]?.components);
|
||||
props.ymap?.set('appDef', {
|
||||
newDefinition: updatedAppDefinition,
|
||||
|
|
@ -825,99 +840,83 @@ const EditorComponent = (props) => {
|
|||
const realtimeSave = debounce(appDefinitionChanged, 500);
|
||||
const autoSave = debounce(saveEditingVersion, 3000);
|
||||
|
||||
const handleAddPatch = (patches, inversePatches) => {
|
||||
if (isEmpty(patches) && isEmpty(inversePatches)) return;
|
||||
if (isEqual(patches, inversePatches)) return;
|
||||
function handlePaths(prevPatch, path = [], appJSON) {
|
||||
const paths = [...path];
|
||||
|
||||
const currentPage = currentPageId;
|
||||
const _currentVersion = currentVersion[currentPage] ?? -1;
|
||||
for (let key in prevPatch) {
|
||||
const type = typeof prevPatch[key];
|
||||
|
||||
let _currentVersionChanges = {};
|
||||
|
||||
_currentVersionChanges[currentPage] = currentVersionChanges[currentPage] ?? {};
|
||||
|
||||
_currentVersionChanges[currentPage][_currentVersion] = {
|
||||
redo: patches,
|
||||
undo: inversePatches,
|
||||
};
|
||||
|
||||
setCurrentVersionChanges(_currentVersionChanges);
|
||||
|
||||
const _canUndo = _currentVersionChanges[currentPage].hasOwnProperty(_currentVersion);
|
||||
const _canRedo = _currentVersionChanges[currentPage].hasOwnProperty(_currentVersion + 1);
|
||||
|
||||
_currentVersion[currentPage] = currentVersion + 1;
|
||||
|
||||
delete _currentVersionChanges[currentPage][_currentVersion + 1];
|
||||
delete _currentVersionChanges[currentPage][_currentVersion - noOfVersionsSupported];
|
||||
|
||||
setCurrentVersionChanges(_currentVersionChanges);
|
||||
|
||||
updateEditorState({
|
||||
canUndo: _canUndo,
|
||||
canRedo: _canRedo,
|
||||
currentVersion: _currentVersion,
|
||||
if (type === 'object') {
|
||||
handlePaths(prevPatch[key], [...paths, key], appJSON);
|
||||
} else {
|
||||
const currentpath = [...paths, key].join('.');
|
||||
_.update(appJSON, currentpath, () => prevPatch[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function removeUndefined(obj) {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
if (obj[key] && typeof obj[key] === 'object') removeUndefined(obj[key]);
|
||||
else if (obj[key] === undefined) delete obj[key];
|
||||
});
|
||||
};
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
const handleUndo = () => {
|
||||
if (canUndo) {
|
||||
let _currentVersion = currentVersion[currentPageId];
|
||||
const patchesToUndo = undoStack[undoStack.length - 1];
|
||||
|
||||
const _appDefinition = applyPatches(appDefinition, currentVersionChanges[currentPageId][currentVersion - 1].undo);
|
||||
const updatedAppDefinition = JSON.parse(JSON.stringify(appDefinition));
|
||||
|
||||
const _canUndo = currentVersionChanges[currentPageId].hasOwnProperty(currentVersion - 1);
|
||||
const _canRedo = true;
|
||||
_currentVersion[currentPageId] = _currentVersion - 1;
|
||||
handlePaths(patchesToUndo[0]?.value, [...patchesToUndo[0].path], updatedAppDefinition);
|
||||
|
||||
if (!_appDefinition) return;
|
||||
removeUndefined(updatedAppDefinition);
|
||||
|
||||
const _diffPatches = diff(updatedAppDefinition, appDefinition);
|
||||
|
||||
setUndoStack((prev) => prev.slice(0, prev.length - 1));
|
||||
setRedoStack((prev) => [...prev, diffToPatches(_diffPatches)]);
|
||||
|
||||
updateEditorState({
|
||||
appDefinition: _appDefinition,
|
||||
canUndo: _canUndo,
|
||||
canRedo: _canRedo,
|
||||
currentVersion: _currentVersion,
|
||||
appDefinition: updatedAppDefinition,
|
||||
currentSidebarTab: 2,
|
||||
isSaving: true,
|
||||
});
|
||||
|
||||
props.ymap?.set('appDef', {
|
||||
newDefinition: appDefinition,
|
||||
editingVersionId: props.editingVersion?.id,
|
||||
});
|
||||
|
||||
// autoSave();
|
||||
}
|
||||
};
|
||||
|
||||
const handleRedo = () => {
|
||||
if (canRedo) {
|
||||
let _currentVersion = currentVersion[currentPageId];
|
||||
const patchesToRedo = redoStack[redoStack.length - 1];
|
||||
|
||||
const _appDefinition = applyPatches(appDefinition, currentVersionChanges[currentPageId][currentVersion].redo);
|
||||
const updatedAppDefinition = JSON.parse(JSON.stringify(appDefinition));
|
||||
|
||||
const _canUndo = true;
|
||||
const _canRedo = currentVersionChanges[currentPageId].hasOwnProperty(currentVersion + 1);
|
||||
_currentVersion[currentPageId] = currentVersion + 1;
|
||||
handlePaths(patchesToRedo[0]?.value, [...patchesToRedo[0].path], updatedAppDefinition);
|
||||
|
||||
if (!_appDefinition) return;
|
||||
const _diffPatches = diff(updatedAppDefinition, appDefinition);
|
||||
|
||||
setRedoStack((prev) => prev.slice(0, prev.length - 1));
|
||||
setUndoStack((prev) => [...prev, diffToPatches(_diffPatches)]);
|
||||
|
||||
updateEditorState({
|
||||
appDefinition: _appDefinition,
|
||||
canUndo: _canUndo,
|
||||
canRedo: _canRedo,
|
||||
currentVersion: _currentVersion,
|
||||
appDefinition: updatedAppDefinition,
|
||||
isSaving: true,
|
||||
});
|
||||
|
||||
props.ymap?.set('appDef', {
|
||||
newDefinition: appDefinition,
|
||||
editingVersionId: props.editingVersion?.id,
|
||||
});
|
||||
|
||||
// autoSave();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateEditorState({
|
||||
canUndo: undoStack.length > 0,
|
||||
canRedo: redoStack.length > 0,
|
||||
});
|
||||
}, [JSON.stringify(undoStack), JSON.stringify(redoStack)]);
|
||||
|
||||
const componentDefinitionChanged = (componentDefinition, props) => {
|
||||
if (props?.isVersionReleased) {
|
||||
useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
|
||||
|
|
|
|||
Loading…
Reference in a new issue