feat: expose clearHistory() to reset the undo/redo stack#373
feat: expose clearHistory() to reset the undo/redo stack#373SSShooter merged 6 commits intoSSShooter:masterfrom
Conversation
Adds a clearHistory() method to the operationHistory plugin that resets the undo/redo stack to an empty state with a fresh baseline snapshot. This is needed by hosts that load new data into an existing MindElixir instance (e.g. via refresh()) and want to prevent users from undoing back into the previous diagram's state.
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a potential data-loss and confusing user experience when an application refreshes a MindElixir instance with new data. By exposing a new Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a clearHistory() method to the MindElixir instance, allowing users to reset the undo/redo stack after loading new data. No security vulnerabilities were found. However, there is a type safety concern where the MindElixirInstance interface defines clearHistory as a mandatory method, but its runtime assignment is conditional on the allowUndo option, which could lead to runtime errors if invoked when allowUndo is false.
src/types/index.ts
Outdated
| /** | ||
| * Reset the undo/redo stack and update the internal baseline snapshot to the | ||
| * current diagram state. Call this after loading new data into an existing | ||
| * instance (e.g. after `refresh()`) to prevent users from undoing back into | ||
| * a previously loaded diagram. | ||
| */ | ||
| clearHistory: () => void |
There was a problem hiding this comment.
The clearHistory method is declared as mandatory in the MindElixirInstance interface. However, its implementation in src/plugin/operationHistory.ts is only applied to the instance if the allowUndo option is true (as seen in src/methods.ts, line 94). If allowUndo is false, mei.clearHistory will not be defined at runtime, which could lead to a TypeError if the method is called, despite the type definition indicating its presence. To prevent this type-runtime mismatch, clearHistory should be marked as optional in the interface.
| /** | |
| * Reset the undo/redo stack and update the internal baseline snapshot to the | |
| * current diagram state. Call this after loading new data into an existing | |
| * instance (e.g. after `refresh()`) to prevent users from undoing back into | |
| * a previously loaded diagram. | |
| */ | |
| clearHistory: () => void | |
| /** | |
| * Reset the undo/redo stack and update the internal baseline snapshot to the | |
| * current diagram state. Call this after loading new data into an existing | |
| * instance (e.g. after `refresh()`) to prevent users from undoing back into | |
| * a previously loaded diagram. | |
| */ | |
| clearHistory?: () => void |
There was a problem hiding this comment.
Fixed in 15a42c9 — changed to clearHistory?: () => void and updated the JSDoc to note that it is only available when allowUndo is true.
There was a problem hiding this comment.
Pull request overview
This PR adds a public API to reset MindElixir’s undo/redo history after loading new data into an existing instance (e.g., via refresh()), preventing users from undoing back into a previously loaded diagram.
Changes:
- Add
mei.clearHistory()to clear the operation history stack and re-baseline the “current” snapshot. - Extend
MindElixirInstancetypings with a documentedclearHistory()method.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/plugin/operationHistory.ts |
Implements mei.clearHistory() to reset internal history state and baseline snapshot. |
src/types/index.ts |
Exposes clearHistory(): void on the public MindElixirInstance type with JSDoc guidance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/types/index.ts
Outdated
| * instance (e.g. after `refresh()`) to prevent users from undoing back into | ||
| * a previously loaded diagram. | ||
| */ | ||
| clearHistory: () => void |
There was a problem hiding this comment.
clearHistory is declared as a required method on MindElixirInstance, but it’s only assigned inside the operationHistory plugin (and that plugin is skipped when allowUndo is false and in lite mode). This makes the type contract unsafe for consumers because mind.clearHistory() can be undefined at runtime. Consider either (a) making clearHistory optional in the interface, or (b) defining a default no-op implementation on the instance/prototype so it always exists regardless of allowUndo/build mode.
| clearHistory: () => void | |
| clearHistory?: () => void |
There was a problem hiding this comment.
Fixed in 15a42c9 — changed to clearHistory?: () => void and updated the JSDoc to note that it is only available when allowUndo is true.
| mei.clearHistory = function () { | ||
| history = [] | ||
| currentIndex = -1 | ||
| current = mei.getData() |
There was a problem hiding this comment.
clearHistory() clears the history stack but leaves currentSelectedNodes unchanged. Since the intended usage is right after refresh(), selection is typically cleared, and the next operation may incorrectly record the previous diagram’s selected node IDs in currentSelected, which can break selection restoration on undo/redo. Reset currentSelectedNodes inside clearHistory() (e.g., derive it from mei.currentNodes) or update the selection tracking to handle deselection events as well.
| current = mei.getData() | |
| current = mei.getData() | |
| // keep cached selection in sync with current diagram state | |
| currentSelectedNodes = mei.currentNodes.map(n => n.nodeObj) |
There was a problem hiding this comment.
Fixed in 601dc4b — added currentSelectedNodes = [] to clearHistory() so stale node IDs from the previous diagram cannot affect selection restoration after refresh() + clearHistory().
| mei.clearHistory = function () { | ||
| history = [] | ||
| currentIndex = -1 | ||
| current = mei.getData() | ||
| } |
There was a problem hiding this comment.
No automated test is added for the new clearHistory() behavior. There are existing Playwright specs covering operation history/undo/redo; please add a test that (1) performs some operations, (2) calls refresh(newData) + clearHistory(), then (3) asserts that undo/redo cannot revert into the pre-refresh diagram and that the first undo baseline is the refreshed data.
There was a problem hiding this comment.
Added in 1e50bf0 — new file tests/clear-history.spec.ts with three Playwright tests:
- Undo cannot revert into the pre-refresh diagram — performs ops on diagram A, calls
refresh(B)+clearHistory(), then asserts Ctrl+Z/Ctrl+Y are no-ops across the diagram boundary. - Operations after
clearHistory()are undoable normally — verifies that new operations on diagram B undo/redo correctly, and that the stack doesn't reach back into diagram A. - First undo baseline is the refreshed state — verifies that undoing the first post-refresh operation lands exactly on the refreshed diagram, not an earlier one.
…iew fixes - Reset currentSelectedNodes to [] so stale selection IDs from the previous diagram cannot corrupt undo/redo selection restoration after a refresh + clearHistory() call. - (types updated in next commit to mark clearHistory as optional)
clearHistory is only registered by the operationHistory plugin, which is skipped when allowUndo is false. Declaring it as a required method would be a type-runtime mismatch. Mark it optional and update the JSDoc to mention the allowUndo prerequisite.
|
Thank you both for the reviews! Fixed in the two follow-up commits:
Tests — noted. The existing Playwright test suite for operation history would be the right place; happy to add a test case if that would help move this forward. |
Tests verify: - Undo cannot revert into a pre-refresh diagram after clearHistory() - Operations performed after clearHistory() are themselves undoable/redoable - The first undo baseline is the refreshed diagram state, not a prior one
SSShooter
left a comment
There was a problem hiding this comment.
Thanks for your contribution! This is indeed a design oversight, but a few changes are needed here.
src/plugin/operationHistory.ts
Outdated
| history = [] | ||
| currentIndex = -1 | ||
| current = mei.getData() | ||
| currentSelectedNodes = [] |
There was a problem hiding this comment.
better use mei.clearSelection()
There was a problem hiding this comment.
That's indeed better. Done.
There was a problem hiding this comment.
If the test is failing, please remove it for now.
There was a problem hiding this comment.
Oups...
The tests should pass now.
8596e68 to
90b0e0e
Compare
Motivation
When an application loads new data into an existing MindElixir instance via
refresh(), the internal undo/redo history still contains snapshots from the previous diagram. This lets users press Ctrl+Z and silently travel back into an earlier diagram's state — a confusing and data-loss-prone experience.A host needs a way to discard that stale history after loading new data.
Changes
src/plugin/operationHistory.tsAdds
mei.clearHistory(), which:historyarraycurrentIndexto-1currentfrommei.getData()so the fresh snapshot is the new undo baselinesrc/types/index.tsDeclares
clearHistory: () => voidonMindElixirInstancewith a JSDoc comment explaining its purpose.Usage