-
-
Notifications
You must be signed in to change notification settings - Fork 287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Single-update undo/redo #1374
Single-update undo/redo #1374
Conversation
@Janpot I've removed some methods from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If dom changes are done in atomic update why do we still need throttle? Wouldn't the goal of this PR be to get rid of throttle entirely?
You mentioned in other PR that throttle might still be needed when undoing changes in a text input, though our undo/redo implementation should not be even triggered inside text inputs, so I'm wondering if it's related to that?
The undo would happen natively in the text input, but the toolpad undo stack won't reflect this, it will just add another stack entry on top instead of popping one off. a subsequent redo will behave wrong. example (this is already current behavior):
We'll need to fix this and ☝️ can be an integration test The problem will compound the more text you write and undo/redo in the text input. As soon as we remove the throttling, every update to the textinput will get its own stack entry. So one entry for every letter typed, and then one entry for every time undo or redo is called within the textinput. |
Thanks for explanation Jan (I missed your reply in another PR), now its clear to me. I agree we need to fix that and cover with test |
Can I get a final review here in order to merge, please? All suggestions should have been addressed already. Edit: Ah nevermind this still needs the text input changes or it's a bit broken - feel free to pre-approve this PR anyway so I can do that in a separate PR |
@@ -42,42 +41,3 @@ test('test basic undo and redo', async ({ page, browserName, api }) => { | |||
// Redo should bring back text field | |||
await expect(canvasInputLocator).toHaveCount(3); | |||
}); | |||
|
|||
test('test batching quick actions into single undo entry', async ({ page, browserName, api }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This spec should still be relevant, specifically for text field changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can have something more specific once we have specific logic for text inputs?
Anyway I won't merge this until I add a test that does the same that this one did.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test should work fine after all, I had the impression that it was testing more general changes but I was wrong!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from from spec comment all seems to be working great 👍
0aa258c
to
baabb44
Compare
I've merged text input undo/redo into this PR so that it works as a whole and can be merged (#1459). Also re-added the batching test as looks like it's perfect for testing the text inputs after all! Preview URL: https://toolpad-pr-1374.onrender.com/ |
I'm gonna merge this PR later today if it's ok! |
}, | ||
[connectionNode, domApi], | ||
[connectionNode, dom, domApi], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙂 I think this is why I suggested to use a function in domApi.update
. This callback invalidates on every dom change, and it's also not 100% sure it will get the last dom
. e.g. imagine a function:
const addConnection = React.useCallback(() => domApi.update(appDom.addConnection(dom)), [dom]);
// somewhere else, this function called twice
addConnection();
addConnection();
Those would get the same initial version of dom
, meaning only one connection is added. While I would expect to have two connections. It would be different if
const addConnection = React.useCallback(
() => domApi.update((draft) => appDom.addConnection(draft)),
[],
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it work to restore and use methods such as domApi.setNodeNamespacedProp
(which I had deleted) in cases like this?
And use domApi.update
as I'm using it but only when a temporary DOM is needed? domApi.update
replaces the whole DOM anyway so in those cases maybe it's fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still thinking of better alternatives, your proposal does seem more "atomic", it's just more difficult to use in RenderOverlay
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try supporting domApi.update((draft) => ...
and use it as much as possible where I can, except in the few cases where it's hard to use, I think that should be possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still thinking of better alternatives, your proposal does seem more "atomic", it's just more difficult to use in
RenderOverlay
.
We can support both methods, like
update: (draft: React.SetStateAction<AppDom>) => void
Also, wouldn't necessarily recommend it, but nothing prevents you from doing:
const addConnection = React.useCallback(
() => domApi.update(() => appDom.addConnection(dom)),
[dom],
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like I was able to use an updater function everywhere after all!
Commit: 1f7779e
After the refactoring I had made in RenderOverlay
I guess it wasn't so difficult there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this PR is using the updater function now I will merge this part already!
Closes #845
Closes #1192
Preview URL: https://toolpad-pr-1374.onrender.com/
Update the DOM only a single time for each drag & drop operation/resizing/delete, so that undo/redo works without throttling.