Skip to content

Add undo/redo and unsaved-changes protection to the flow builder - #4278

Merged
DonOmalVindula merged 1 commit into
thunder-id:mainfrom
DonOmalVindula:feat/4062-undo-redo-unsaved-protection
Jul 27, 2026
Merged

Add undo/redo and unsaved-changes protection to the flow builder#4278
DonOmalVindula merged 1 commit into
thunder-id:mainfrom
DonOmalVindula:feat/4062-undo-redo-unsaved-protection

Conversation

@DonOmalVindula

@DonOmalVindula DonOmalVindula commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Purpose

Adds a safety net for editing in the flow builder canvas, implementing all three parts of #4062:

  1. Undo/redo for canvas edits — a snapshot history over add/delete/move/rewire/rename/property changes, capped by the existing MAX_HISTORY_ITEMS (20). Ctrl/Cmd+Z undoes, Ctrl/Cmd+Shift+Z (and Ctrl+Y) redoes; undo/redo buttons sit in the canvas toolbar next to auto-layout/zoom.
  2. Unsaved-changes protection — a dirty-state dot on the Save button, a "Discard unsaved changes?" dialog when clicking Back-to-Flows with unsaved work, and a beforeunload prompt on tab-close/reload.
  3. Save during preview — the Save button is no longer disabled while previewing; clicking it stops the preview first (so the persisted viewport is the settled canvas, not the zoomed preview camera) and then saves.

Node/edge deletion stays a single click with no confirmation — with undo/redo in place that is the intended safety net, per the issue.

Approach

Undo/redo (snapshot history). Canvas mutations are scattered across ~15 hooks and go through both setNodes/setEdges and React Flow's updateNodeData/deleteElements, so a new useFlowHistory hook observes the authoritative nodes/edges at the state owner (LoginFlowBuilder) rather than wrapping every call site. A debounced (400ms) effect commits the prior graph to the undo stack once the graph settles into a new structural signature, so one drag or one burst of typing collapses to a single entry. Undo/redo apply cloned snapshots through the existing setters; an "applying" guard stops a restore from recording itself. undo/redo/canUndo/canRedo thread down to CanvasToolbar as props (mirroring onAutoLayout); a keydown listener in LoginFlowBuilder handles the shortcuts and ignores events from inputs/rich-text so native text undo still works.

Dirty tracking + navigation guard. LoginFlowBuilder captures a graph-signature baseline after load and after each save (useFlowSave gained an onSaved callback); isDirty is the current-vs-baseline diff. The app uses BrowserRouter (no useBlocker), so the guard is manual: a beforeunload handler for hard exits and a new DiscardChangesDialog on the Back-to-Flows button. (Known gap: SPA sidebar navigation isn't intercepted — that needs a data-router migration, deferred.)

Save during preview. Since the preview only affects the viewport and transient CSS classes (never the authoritative nodes/edges), handleSave stops the simulation, fits the view instantly, then persists.

Scope decisions (confirmed before implementing): one PR for all three parts; local draft autosave via AUTO_SAVE_INTERVAL deferred to a follow-up; manual nav guard rather than a router migration.

Related Issues

Related PRs

Checklist

  • Followed the contribution guidelines.
  • Manual test round performed and verified.
  • Documentation provided. (Add links if there are any)
    • Ran Vale and fixed all errors and warnings
  • Tests provided. (Add links if there are any)
    • Unit Tests
    • Integration Tests
  • Breaking changes. (Fill if applicable)
    • Breaking changes section filled.
    • breaking change label added.

Security checks

  • Followed secure coding standards in WSO2 Secure Coding Guidelines
  • Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Undo and Redo controls to the flow designer, including keyboard shortcuts.
    • Added unsaved-change indicators and warnings when leaving or closing the page.
    • Added a confirmation dialog before discarding unsaved changes.
    • Saving remains available during flow preview.
  • Bug Fixes

    • Improved save-state handling so successful saves clear the unsaved-change indicator.
  • Tests

    • Added coverage for undo/redo behavior, history tracking, save state, and discard confirmations.

Copilot AI review requested due to automatic review settings July 23, 2026 07:07
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@DonOmalVindula, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 27 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ea21dfc-fec1-4c6c-a269-d40b249523b7

📥 Commits

Reviewing files that changed from the base of the PR and between 072af3a and 41d4da3.

📒 Files selected for processing (12)
  • frontend/apps/console/src/features/flows/components/visual-flow/CanvasToolbar.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/DiscardChangesDialog.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/__tests__/CanvasToolbar.test.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/__tests__/DecoratedVisualFlow.test.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/__tests__/DiscardChangesDialog.test.tsx
  • frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx
  • frontend/apps/console/src/features/login-flow/hooks/__tests__/useFlowHistory.test.tsx
  • frontend/apps/console/src/features/login-flow/hooks/__tests__/useFlowSave.test.ts
  • frontend/apps/console/src/features/login-flow/hooks/useFlowHistory.ts
  • frontend/apps/console/src/features/login-flow/hooks/useFlowSave.ts
  • frontend/packages/i18n/src/locales/en-US.ts
📝 Walkthrough

Walkthrough

Adds snapshot-based undo/redo history, keyboard shortcuts, dirty-state tracking, preview-aware saving, unsaved-change navigation protection, toolbar controls, a discard dialog, translations, and associated tests.

Changes

Flow Builder History and Save Protection

Layer / File(s) Summary
Graph history engine
frontend/apps/console/src/features/login-flow/hooks/useFlowHistory.ts, frontend/apps/console/src/features/login-flow/hooks/__tests__/useFlowHistory.test.tsx
Adds debounced snapshot history with undo, redo, reset, bounded stacks, restore guards, and coverage for graph and edge changes.
Builder history and dirty-state integration
frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx, frontend/apps/console/src/features/login-flow/hooks/useFlowSave.ts
Connects history to the builder, tracks saved graph signatures, handles shortcuts and unload warnings, and resets the dirty baseline after successful saves.
Visual flow save and discard flow
frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx, frontend/apps/console/src/features/flows/components/visual-flow/DiscardChangesDialog.tsx, frontend/apps/console/src/features/flows/components/visual-flow/__tests__/*, frontend/packages/i18n/src/locales/en-US.ts
Adds preview-aware persistence, dirty save indicators, back-navigation confirmation, localized discard controls, and related tests.
Toolbar undo and redo controls
frontend/apps/console/src/features/flows/components/visual-flow/CanvasToolbar.tsx, frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx, frontend/apps/console/src/features/flows/components/visual-flow/__tests__/CanvasToolbar.test.tsx
Conditionally renders undo and redo buttons, wires availability and callbacks, and tests disabled, enabled, hidden, and click states.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: jeradrutnam, brionmario, copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: undo/redo plus unsaved-changes protection in the flow builder.
Description check ✅ Passed The description follows the template well and covers purpose, approach, related issues/PRs, checklist, and security checks.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds editing safety features to the Flow Builder UI (login-flow builder + shared visual-flow components): snapshot-based undo/redo, unsaved-changes (dirty) indicators + navigation protection, and enables saving while in preview by exiting preview first.

Changes:

  • Introduces a debounced snapshot history hook (useFlowHistory) and wires undo/redo into the canvas toolbar and keyboard shortcuts.
  • Adds dirty-state tracking with a Save-button dot indicator, a discard-confirmation dialog on “Back to Flows”, and a beforeunload prompt.
  • Keeps Save enabled during preview, stopping simulation before persisting the viewport/layout.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
frontend/packages/i18n/src/locales/en-US.ts Adds i18n strings for discard-changes dialog + undo/redo labels.
frontend/apps/console/src/features/login-flow/hooks/useFlowSave.ts Adds an optional onSaved callback to clear dirty state after persistence.
frontend/apps/console/src/features/login-flow/hooks/useFlowHistory.ts New snapshot-based undo/redo hook + graph signature function.
frontend/apps/console/src/features/login-flow/hooks/tests/useFlowHistory.test.tsx Unit tests covering history behavior (debounce, cap, undo/redo).
frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx Wires history + dirty tracking + shortcuts + beforeunload warning into login flow builder.
frontend/apps/console/src/features/flows/components/visual-flow/DiscardChangesDialog.tsx New dialog component for confirming discard of unsaved changes.
frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx Adds Save dirty indicator, discard dialog on navigation, and save-while-previewing behavior.
frontend/apps/console/src/features/flows/components/visual-flow/CanvasToolbar.tsx Adds optional undo/redo buttons to the canvas toolbar.
frontend/apps/console/src/features/flows/components/visual-flow/tests/DiscardChangesDialog.test.tsx Tests the discard dialog rendering and callbacks.
frontend/apps/console/src/features/flows/components/visual-flow/tests/DecoratedVisualFlow.test.tsx Updates expectation: save remains enabled during preview.
frontend/apps/console/src/features/flows/components/visual-flow/tests/CanvasToolbar.test.tsx Adds tests for undo/redo toolbar controls.

Comment thread frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx Outdated
Comment thread frontend/apps/console/src/features/login-flow/hooks/useFlowHistory.ts Outdated
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.56716% with 27 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...eatures/login-flow/components/LoginFlowBuilder.tsx 70.37% 16 Missing ⚠️
...ows/components/visual-flow/DecoratedVisualFlow.tsx 56.25% 7 Missing ⚠️
...le/src/features/login-flow/hooks/useFlowHistory.ts 96.15% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copilot AI review requested due to automatic review settings July 23, 2026 08:52
@DonOmalVindula
DonOmalVindula force-pushed the feat/4062-undo-redo-unsaved-protection branch 2 times, most recently from def0327 to 16ff5e0 Compare July 23, 2026 08:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx:227

  • isDirty is derived only from the nodes/edges signature and the baseline is currently set via setSavedSignature(...) during render. This means (a) unsaved edits to the flow name/handle won’t trigger the dirty indicator or navigation guards, and (b) the render-time state update can lead to React warnings/unstable behavior (especially under StrictMode). Consider folding name/handle into the dirty signature and moving baseline initialization into an effect.
  // Unsaved-changes tracking. The baseline is the graph signature captured after
  // the initial load and after each successful save; the flow is dirty when the
  // current graph diverges from it.
  const [savedSignature, setSavedSignature] = useState<string | null>(null);
  const currentSignature = useMemo(() => computeGraphSignature(nodes, edges), [nodes, edges]);

Copilot AI review requested due to automatic review settings July 23, 2026 08:59
@DonOmalVindula
DonOmalVindula force-pushed the feat/4062-undo-redo-unsaved-protection branch from 05e146b to 072af3a Compare July 23, 2026 09:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (3)

frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx:233

  • Calling setSavedSignature(...) during render can trigger React warnings/extra renders, and it can also capture the baseline before the initial edges are generated (new-flow initialization sets nodes first, then edges in a later RAF), which will immediately mark the flow dirty on load. Move baseline initialization into an effect and wait for the initial graph to fully settle (nodes + edges) before setting the baseline signature.

  // The graph keeps mutating for a moment after load (metadata resolution, field
  // normalization, node internals), so the baseline is captured only once the
  // graph has gone quiet — not on the first frame, which would read as dirty.
  const baselineReadyRef = useRef<boolean>(false);

frontend/apps/console/src/features/login-flow/hooks/useFlowHistory.ts:67

  • computeGraphSignature() is order-dependent (iterates nodes/edges in array order) and it omits edge.type. That means semantically identical graphs can produce different signatures if array order changes, and edge-style changes (which update edge.type) won’t be reflected in history/dirty tracking. Sort nodes/edges by id and include edge.type in the signature.
export function computeGraphSignature(nodes: Node[], edges: Edge[]): string {
  let signature = '';
  for (const node of nodes) {
    const data = node.data as StepData | undefined;
    signature +=

frontend/apps/console/src/features/flows/components/visual-flow/CanvasToolbar.tsx:99

  • Redo is enabled/disabled solely based on canRedo, but onRedo itself is optional. If a caller passes canRedo=true without an onRedo handler, the button will be enabled but do nothing. Make the disabled condition also depend on the handler being present.
                <IconButton
                  size="small"
                  onClick={onRedo}
                  disabled={!canRedo}
                  sx={{borderRadius: 1, color: 'text.secondary'}}

Comment thread frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx Outdated
Comment thread frontend/apps/console/src/features/login-flow/hooks/useFlowSave.ts
Copilot AI review requested due to automatic review settings July 23, 2026 09:06
@DonOmalVindula
DonOmalVindula force-pushed the feat/4062-undo-redo-unsaved-protection branch from 072af3a to 583ef75 Compare July 23, 2026 09:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
frontend/apps/console/src/features/flows/components/visual-flow/__tests__/DecoratedVisualFlow.test.tsx (1)

424-432: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Test the save interaction, not only button availability.

This test never clicks save-flow-button, so it does not verify the behavior described by its title: stopping preview before saving. Capture onSave, click Save while previewing, and assert persistence plus preview exit or canvas-fit behavior.

Suggested test adjustment
-      renderComponent(<DecoratedVisualFlow {...defaultProps} nodes={nodes} onSave={vi.fn()} />);
+      const onSave = vi.fn();
+      renderComponent(<DecoratedVisualFlow {...defaultProps} nodes={nodes} onSave={onSave} />);

       expect(screen.getByTestId('save-flow-button')).toBeEnabled();

       fireEvent.click(screen.getByTestId('simulate-flow-button'));

       expect(screen.getByTestId('save-flow-button')).toBeEnabled();
+      fireEvent.click(screen.getByTestId('save-flow-button'));
+      expect(onSave).toHaveBeenCalledTimes(1);

As per coding guidelines, write tests for new features and bug fixes, targeting at least 80% coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@frontend/apps/console/src/features/flows/components/visual-flow/__tests__/DecoratedVisualFlow.test.tsx`
around lines 424 - 432, Update the test using DecoratedVisualFlow to capture the
onSave mock, click save-flow-button after starting preview with
simulate-flow-button, and assert that saving occurs while preview is stopped,
including the expected preview exit or canvas-fit behavior. Retain the
enabled-state assertion only as supporting coverage.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx`:
- Around line 717-724: Replace the hardcoded '/flows' destinations in
handleBackToFlows and handleConfirmDiscard with the corresponding RouteConfig
route value. Ensure both navigate calls resolve their destination from
RouteConfig while preserving the existing discard-dialog behavior.
- Line 900: Update the Save label’s translation call in the component rendering
this header panel to provide the fallback string “Save”, matching the
surrounding i18n calls such as the one near line 862 and preserving the existing
translation key.

In
`@frontend/apps/console/src/features/flows/components/visual-flow/DiscardChangesDialog.tsx`:
- Around line 39-46: Update the Dialog in DiscardChangesDialog to set
aria-labelledby to a stable title identifier, and assign the same id to
DialogTitle. Also connect DialogContentText to the Dialog through
aria-describedby with a matching stable description identifier unless the
component library already wires it automatically.

---

Nitpick comments:
In
`@frontend/apps/console/src/features/flows/components/visual-flow/__tests__/DecoratedVisualFlow.test.tsx`:
- Around line 424-432: Update the test using DecoratedVisualFlow to capture the
onSave mock, click save-flow-button after starting preview with
simulate-flow-button, and assert that saving occurs while preview is stopped,
including the expected preview exit or canvas-fit behavior. Retain the
enabled-state assertion only as supporting coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d42ca107-3aba-4b35-a298-bac329415480

📥 Commits

Reviewing files that changed from the base of the PR and between 1173b4c and 072af3a.

📒 Files selected for processing (11)
  • frontend/apps/console/src/features/flows/components/visual-flow/CanvasToolbar.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/DiscardChangesDialog.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/__tests__/CanvasToolbar.test.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/__tests__/DecoratedVisualFlow.test.tsx
  • frontend/apps/console/src/features/flows/components/visual-flow/__tests__/DiscardChangesDialog.test.tsx
  • frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx
  • frontend/apps/console/src/features/login-flow/hooks/__tests__/useFlowHistory.test.tsx
  • frontend/apps/console/src/features/login-flow/hooks/useFlowHistory.ts
  • frontend/apps/console/src/features/login-flow/hooks/useFlowSave.ts
  • frontend/packages/i18n/src/locales/en-US.ts

@DonOmalVindula
DonOmalVindula force-pushed the feat/4062-undo-redo-unsaved-protection branch from 583ef75 to 82f85de Compare July 23, 2026 09:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

frontend/apps/console/src/features/flows/components/visual-flow/CanvasToolbar.tsx:57

  • showHistoryControls becomes true when either handler is provided, but the toolbar renders both buttons. If only one handler is passed (e.g., onRedo without onUndo), the other button can render with an undefined click handler (and could even be enabled if canUndo/canRedo are set), leading to a non-functional control. Require both handlers before showing the history controls (or gate each button individually).
  const showHistoryControls = Boolean(onUndo ?? onRedo);

frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx:412

  • When saving during preview, fitView() errors currently fall back to persistCanvas(). If fitView() rejects (which the codebase already treats as possible elsewhere), this can still persist the preview’s zoomed-in viewport, defeating the intent of stopping preview before saving. Consider retrying fitView() on the next animation frame before falling back to persisting.
  const handleToggleSimulation = useCallback((): void => {

Copilot AI review requested due to automatic review settings July 23, 2026 09:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

frontend/apps/console/src/features/flows/components/visual-flow/CanvasToolbar.tsx:57

  • showHistoryControls becomes true when either onUndo or onRedo is provided, but the component always renders both buttons. That can surface an enabled button whose handler is undefined (e.g., canUndo true but onUndo missing), resulting in a non-functional control.
  const showHistoryControls = Boolean(onUndo ?? onRedo);

frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx:278

  • handleSaved clears the dirty baseline using the current nodes/edges at the moment the save request succeeds. Since the UI does not disable editing while useFlowSave is pending, users can continue editing during the in-flight save; when the request resolves, this will incorrectly mark those post-click edits as saved (clearing the dirty indicator and rebasing history).
  const handleSaved = useCallback(() => {
    hasInteractedRef.current = true;
    setSavedSignature(computeGraphSignature(nodes, edges));
    resetHistory();
  }, [nodes, edges, resetHistory]);

Copilot AI review requested due to automatic review settings July 23, 2026 09:33
@DonOmalVindula
DonOmalVindula force-pushed the feat/4062-undo-redo-unsaved-protection branch from 82f85de to f54e247 Compare July 23, 2026 09:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

frontend/apps/console/src/features/flows/components/visual-flow/DecoratedVisualFlow.tsx:754

  • handleBackToFlows navigates using a hard-coded '/flows' path, while the discard-confirm path uses RouteConfig.flows.list(). This can drift if route segments change; use RouteConfig.flows.list() consistently.
  const handleBackToFlows = useCallback((): void => {
    if (isDirty) {
      setIsDiscardDialogOpen(true);
      return;
    }
    // eslint-disable-next-line @typescript-eslint/no-floating-promises
    navigate('/flows');
  }, [isDirty, navigate]);

Comment thread frontend/packages/i18n/src/locales/en-US.ts Outdated
@DonOmalVindula
DonOmalVindula force-pushed the feat/4062-undo-redo-unsaved-protection branch from f54e247 to 41d4da3 Compare July 24, 2026 08:49
@DonOmalVindula DonOmalVindula added the trigger-pr-builder Add when the PR is ready for CI; starts the PR Builder for this and all later pushes label Jul 27, 2026
Adds a snapshot-based undo/redo history for canvas edits (toolbar buttons
and Ctrl/Cmd+Z / Ctrl/Cmd+Shift+Z), a dirty-state indicator with a
navigation guard (discard-changes dialog on back, beforeunload on
tab-close/reload), and lets Save run during preview by stopping the
preview first.

Refs thunder-id#4062
@DonOmalVindula
DonOmalVindula force-pushed the feat/4062-undo-redo-unsaved-protection branch from 41d4da3 to f87647e Compare July 27, 2026 04:18
@DonOmalVindula
DonOmalVindula enabled auto-merge July 27, 2026 05:02
@DonOmalVindula
DonOmalVindula added this pull request to the merge queue Jul 27, 2026
Merged via the queue into thunder-id:main with commit ef960bc Jul 27, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trigger-pr-builder Add when the PR is ready for CI; starts the PR Builder for this and all later pushes Type/Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants