Skip to content

UN-1722 [FIX] Persist export reminder state across page reloads - #1733

Merged
ritwik-g merged 1 commit into
mainfrom
feat/persist-export-reminder-state
Jan 19, 2026
Merged

UN-1722 [FIX] Persist export reminder state across page reloads#1733
ritwik-g merged 1 commit into
mainfrom
feat/persist-export-reminder-state

Conversation

@athul-rs

@athul-rs athul-rs commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

What

  • Added sessionStorage persistence for the export reminder notification state
  • State is now preserved across page reloads within the same browser session

Why

How

Frontend Changes:

  • Added sessionStorage key prefix unstract-unsaved-changes-{toolId} for per-tool state isolation
  • Modified setHasUnsavedChanges in custom-tool-store to persist to sessionStorage
  • Modified markChangesAsExported to clear sessionStorage on successful export
  • Added restoreUnsavedChangesFromSession action to restore state from sessionStorage
  • Added useEffect in ToolIde to restore state when tool is loaded

Storage Pattern:

  • Uses sessionStorage (not localStorage) for session-based expiration
  • State automatically clears when browser tab is closed
  • Each tool has isolated state via scoped keys

Can this PR break any existing features. If yes, please list possible items. If no, please explain why.

No, this PR will not break any existing features because:

  • It only extends the existing export reminder functionality from PR UN-1722 [FEAT] Add export reminder for Prompt Studio projects in use #1547
  • All changes are additive - new storage logic wraps existing state management
  • The notification system continues to work exactly as before, but now persists across reloads
  • Follows existing sessionStorage patterns used elsewhere in the codebase (OAuth flows)

Database Migrations

  • N/A (No database schema changes required)

Env Config

  • N/A (No new environment variables required)

Relevant Docs

  • Extends functionality from UN-1722 JIRA ticket

Related Issues or PRs

Dependencies Versions

  • N/A (No new dependencies added)

Notes on Testing

  • ✅ Make changes to prompts → verify reminder appears
  • ✅ Reload page → verify reminder still shows (sessionStorage persisted)
  • ✅ Export changes → verify reminder clears and sessionStorage cleared
  • ✅ Close browser tab, reopen → verify reminder is cleared (session-based)
  • ✅ Test with multiple tools in different tabs (state should be isolated per tool_id)

Checklist

I have read and understood the Contribution Guidelines.

🤖 Generated with Claude Code

- Add sessionStorage persistence for hasUnsavedChanges flag per tool_id
- Modify setHasUnsavedChanges to save/remove from sessionStorage
- Modify markChangesAsExported to clear sessionStorage on export
- Add restoreUnsavedChangesFromSession action to restore state
- Add useEffect in ToolIde to restore state when tool is loaded

This fixes the issue where the export reminder notification would
disappear after page reload, even if changes hadn't been exported.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Unsaved changes now persist automatically across page reloads and are restored when you return to a tool. Your work is recovered instantly, preventing data loss from unexpected browser refreshes, crashes, or accidental navigation away from your editing session.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

The changes implement sessionStorage-based persistence for unsaved changes in custom tools. A new effect in ToolIde restores unsaved state from session storage when a tool is loaded, and the store now manages per-tool unsaved-change entries in sessionStorage via new helper methods and an updated setHasUnsavedChanges function.

Changes

Cohort / File(s) Summary
Session Storage Persistence Layer
frontend/src/store/custom-tool-store.js
Introduces UNSAVED_CHANGES_KEY_PREFIX and getSessionStorageKey(toolId) helper. Modified setHasUnsavedChanges to write/remove per-tool unsaved state in sessionStorage. Added restoreUnsavedChangesFromSession(toolId) to read and restore unsaved state. Added markChangesAsExported to clear per-tool sessionStorage entry.
Unsaved Changes Restoration
frontend/src/components/custom-tools/tool-ide/ToolIde.jsx
Adds new effect triggered on details.tool_id changes that calls restoreUnsavedChangesFromSession(tool_id). On successful restoration, resets hasCheckedForCurrentSessionRef flag to allow subsequent deployment-usage checks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: persisting export reminder state across page reloads, which is the primary objective of the PR.
Description check ✅ Passed The description comprehensively covers all required template sections with detailed explanations of what changed, why it was needed, how it works, and testing approach.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

@sonarqubecloud

sonarqubecloud Bot commented Jan 8, 2026

Copy link
Copy Markdown

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/store/custom-tool-store.js (1)

71-99: Critical: sessionStorage not updated when adding/deleting prompts.

Both addNewInstance (line 86) and deleteInstance (line 97) set hasUnsavedChanges = true directly but don't update sessionStorage. This breaks persistence across reloads:

  1. User adds or deletes a prompt → hasUnsavedChanges is set to true in memory
  2. User reloads the page → restoration reads sessionStorage (still empty)
  3. Export reminder doesn't appear, defeating the purpose of this PR
🔧 Proposed fix to sync sessionStorage in both methods
 addNewInstance: (type) => {
   const newState = { ...getState() };
   const promptsAndNotes = newState?.details?.prompts;
 
   if (type === promptType.prompt) {
     const newPrompt = { ...defaultPromptInstance };
     newPrompt["prompt_id"] = `unsaved_${promptsAndNotes.length + 1}`;
     promptsAndNotes.push(newPrompt);
   } else {
     const newNote = { ...defaultNoteInstance };
     newNote["prompt_id"] = `unsaved_${promptsAndNotes.length + 1}`;
     promptsAndNotes.push(newNote);
   }
   newState["details"]["prompts"] = [...promptsAndNotes];
   // Mark as having unsaved changes when a new prompt/note is added
   newState["hasUnsavedChanges"] = true;
+  // Persist to sessionStorage
+  const toolId = newState.details?.tool_id;
+  if (toolId) {
+    sessionStorage.setItem(getSessionStorageKey(toolId), "true");
+  }
   setState({ ...newState });
 },
 deleteInstance: (promptId) => {
   const newState = { ...getState() };
   const promptsAndNotes = newState?.details?.prompts;
   const filteredData = promptsAndNotes.filter(
     (item) => item?.prompt_id !== promptId
   );
   newState["details"]["prompts"] = filteredData;
   // Mark as having unsaved changes when a prompt/note is deleted
   newState["hasUnsavedChanges"] = true;
+  // Persist to sessionStorage
+  const toolId = newState.details?.tool_id;
+  if (toolId) {
+    sessionStorage.setItem(getSessionStorageKey(toolId), "true");
+  }
   setState({ ...newState });
 },
🧹 Nitpick comments (1)
frontend/src/store/custom-tool-store.js (1)

121-157: Consider adding error handling for sessionStorage operations.

While sessionStorage is widely supported, operations can throw in restricted environments (e.g., storage disabled, quota exceeded). Wrapping calls in try-catch blocks would prevent potential crashes and degrade gracefully.

🛡️ Example: Graceful error handling
 setHasUnsavedChanges: (hasChanges) => {
   const toolId = getState().details?.tool_id;
   if (toolId) {
-    if (hasChanges) {
-      sessionStorage.setItem(getSessionStorageKey(toolId), "true");
-    } else {
-      sessionStorage.removeItem(getSessionStorageKey(toolId));
+    try {
+      if (hasChanges) {
+        sessionStorage.setItem(getSessionStorageKey(toolId), "true");
+      } else {
+        sessionStorage.removeItem(getSessionStorageKey(toolId));
+      }
+    } catch (error) {
+      console.warn("Failed to persist unsaved changes to sessionStorage:", error);
     }
   }
   setState({ hasUnsavedChanges: hasChanges });
 },

Apply the same pattern to markChangesAsExported and restoreUnsavedChangesFromSession.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between fa9c162 and 85badce.

📒 Files selected for processing (2)
  • frontend/src/components/custom-tools/tool-ide/ToolIde.jsx
  • frontend/src/store/custom-tool-store.js
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/store/custom-tool-store.js (1)
frontend/src/components/agency/side-panel/SidePanel.jsx (1)
  • toolId (14-14)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
frontend/src/components/custom-tools/tool-ide/ToolIde.jsx (1)

160-172: LGTM! Restoration logic is well-integrated.

The restoration effect correctly:

  • Runs when the tool loads or changes (via details?.tool_id dependency)
  • Uses the proper Zustand getState() pattern to avoid dependency issues
  • Resets the deployment usage check flag when unsaved changes are restored, ensuring the export reminder appears appropriately
frontend/src/store/custom-tool-store.js (2)

5-9: LGTM! Per-tool storage key pattern is clean.

The prefix and helper function provide good isolation between tools, and the naming convention is clear.


148-157: LGTM! Restoration logic is correct.

The method safely reads from sessionStorage and returns a boolean indicating whether restoration occurred, which allows the caller to take appropriate action.

Comment thread frontend/src/store/custom-tool-store.js
@ritwik-g
ritwik-g merged commit 0bde7ba into main Jan 19, 2026
6 checks passed
@ritwik-g
ritwik-g deleted the feat/persist-export-reminder-state branch January 19, 2026 07:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants