Skip to content

Conversation

@iOvergaard
Copy link
Contributor

Summary

Fixes an issue where clicking "Save and Preview" multiple times causes the preview tab to show the published version instead of the latest saved version. This PR addresses the root cause: new preview sessions were being created on each "Save and Preview" action, invalidating the preview cookie in the already-open preview tab.

Changes

1. Cache-busting for preview URLs

Added a ?rnd=timestamp parameter to preview URLs to ensure the browser reloads the page with the new preview session token, even when the preview window is reused.

Files changed:

2. Preview window reference tracking

Store a reference to the preview window to avoid creating unnecessary new preview sessions. When the preview window is still open and showing the same document, we simply focus it and let SignalR handle the content refresh.

Files changed:

3. Document-specific preview window tracking

Track which document the preview window is showing to ensure each document gets its own preview session. This prevents reusing a preview window when navigating between different documents in the backoffice.

Files changed:

4. Close preview window when ending session

Modified the "End Preview" action to close the preview window instead of navigating away. This ensures that subsequent "Save and Preview" actions create a new session rather than attempting to reuse a tab that's no longer in preview mode.

Files changed:

5. Fix preview cookie expiration

Added proper cookie expiration methods that match the security attributes used when creating preview cookies. This fixes an issue where clicking "Preview website" would still show the preview overlay because the preview cookie wasn't being properly removed.

Files changed:

The preview cookies now use SameSite=None and Secure=true to support cross-site scenarios (e.g., when the backoffice is on a different domain/port than the frontend during development). SameSite=None requires Secure=true per browser specifications.

How this fixes issue #20981

The original issue occurred because:

  1. First "Save and Preview" creates preview session A and opens a tab
  2. Second "Save and Preview" creates preview session B, invalidating session A
  3. The browser attempts to reuse the existing tab (same window name)
  4. The tab still has session A's cookie, which is now invalid
  5. Backend falls back to showing the published version

This PR fixes it by:

  1. Cache-busting: Forces the browser to reload with the new preview session cookie
  2. Window tracking: Avoids creating new sessions when the same document is being previewed
  3. Document-specific tracking: Ensures different documents get separate preview sessions
  4. Proper cleanup: Closes preview windows when ending the session to prevent stale state

Test steps

Test 1: Original issue - Same document, multiple saves

  1. Create a content item with a template and enter some content
  2. Click "Save and publish"
  3. Make a content change
  4. Click "Save and preview" → New tab opens showing the saved version ✅
  5. Return to the editing tab (keep preview tab open)
  6. Make another content change
  7. Click "Save and preview" → Preview tab updates to show the new saved version ✅

Expected: Preview shows the latest saved version
Previously: Preview showed the published version ❌

Test 2: Different documents

  1. Open Document A and click "Save and preview" → Preview window opens showing Document A
  2. Navigate in backoffice to Document B
  3. Click "Save and preview" → Preview window updates to show Document B ✅

Expected: Preview shows Document B
Previously: Preview would just focus without changing content ❌

Test 3: End preview session

  1. Open a document and click "Save and preview"
  2. In the preview window, click "End Preview"
  3. The preview window should close ✅
  4. Click "Save and preview" again → New preview session starts ✅

Expected: Clean session lifecycle
Previously: Preview tab would stay open causing issues ❌

Test 4: Preview website

  1. Open a document and click "Save and preview"
  2. In the preview window, click "Preview website"
  3. A new tab opens showing the published site WITHOUT the preview overlay ✅

Expected: No preview overlay on published site
Previously: Preview overlay would appear on published site ❌

Test 5: Cross-site scenario

  1. Run backend on HTTPS and frontend on HTTP (different ports)
  2. Click "Save and preview"
  3. Preview should work correctly with proper cookie handling ✅

Expected: Preview cookies work in cross-site scenarios

Breaking changes

None. New method overloads were added with obsolete attributes on old methods to maintain backwards compatibility. Old methods will be removed in Umbraco 19.

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

iOvergaard and others added 5 commits November 28, 2025 10:19
…d multiple times

Fixes #20981

When clicking "Save and Preview" multiple times, the preview tab would show the published version instead of the latest saved version. This occurred because:

1. Each "Save and Preview" creates a new preview session with a new token
2. The preview window is reused (via named window target)
3. Without a URL change, the browser doesn't reload and misses the new session token
4. The stale page gets redirected to the published URL

Solution: Add a cache-busting parameter (?rnd=timestamp) to the preview URL, forcing the browser to reload and pick up the new preview session token. This aligns with how SignalR refreshes work.

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

Co-Authored-By: Claude <noreply@anthropic.com>
…lready open

When clicking "Save and Preview" multiple times with a preview tab already open, the entire preview tab would reload. This enhancement makes it behave like the "Save" button - only the iframe reloads, not the entire preview wrapper.

Changes:
- Store reference to preview window when opened
- Check if preview window is still open before creating new session
- If open, just focus it and let SignalR handle the iframe refresh
- If closed, create new preview session and open new window

This provides a smoother UX where subsequent saves don't cause the preview frame and controls to reload, only the content iframe refreshes via SignalR.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Changes the "End Preview" behavior to close the preview tab instead of navigating to the published URL. This provides a cleaner UX and ensures subsequent "Save and Preview" actions will always create a fresh preview session.

Benefits:
- Eliminates edge case where preview window remains open but is no longer in preview mode
- Simpler behavior - preview session ends and window closes
- Users can use "Preview website" button if they want to view published page

Also removes unnecessary await on SignalR connection.stop() to prevent blocking if the connection cleanup hangs.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses cookie management issues in the preview system:

1. **Cookie Expiration API Enhancement**
   - Added `ExpireCookie` overload with security parameters (httpOnly, secure, sameSiteMode)
   - Added `SetCookieValue` overload with optional expires parameter
   - Marked old methods as obsolete for removal in Umbraco 19
   - Ensures cookies are expired with matching security attributes

2. **PreviewService Cookie Handling**
   - Changed to use new `ExpireCookie` method with explicit security attributes
   - Maintains `Secure=true` and `SameSite=None` for cross-site scenarios
   - Uses new `SetCookieValue` overload with explicit expires parameter
   - Properly expires preview cookies when ending preview session

3. **Frontend Error Handling**
   - Added try-catch around preview window reference checks
   - Handles stale window references gracefully
   - Prevents potential errors from accessing closed window properties

These changes ensure preview cookies are properly managed throughout their
lifecycle and support both same-site and cross-site scenarios (e.g., when
the backoffice is on a different domain/port during development).

Fixes #20981

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

Co-Authored-By: Claude <noreply@anthropic.com>
… different documents

When navigating from one document to another in the backoffice, the preview window reference was being reused even though it was showing a different document. This meant clicking "Save and Preview" would just focus the existing window without updating it to show the new document.

Now we track which document the preview window is showing and only reuse the window if:
1. The window is still open
2. The window is showing the same document

This ensures each document gets its own preview session while still avoiding unnecessary full page reloads when repeatedly previewing the same document.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

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 fixes a preview issue (#20981) where clicking "Save and Preview" multiple times would show the published version instead of the latest saved changes. The root cause was that each "Save and Preview" action created a new preview session, invalidating the cookie in the already-open preview tab.

Key changes:

  • Implemented preview window reference tracking to reuse existing windows when previewing the same document
  • Added cache-busting to preview URLs to force browser reloads when creating new preview sessions
  • Updated preview exit behavior to close the window instead of navigating away
  • Enhanced cookie management API to properly expire cookies with matching security attributes

Reviewed changes

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

Show a summary per file
File Description
src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts Adds window reference tracking (#previewWindow, #previewWindowDocumentId) to reuse existing preview windows for the same document and avoid unnecessary preview session creation; adds cache-busting to preview URLs
src/Umbraco.Web.UI.Client/src/packages/preview/preview-apps/preview-environments.element.ts Adds cache-busting to preview environment URLs to ensure preview tabs reload with new session tokens
src/Umbraco.Web.UI.Client/src/packages/preview/context/preview.context.ts Changes "End Preview" behavior to close the window instead of navigating to published URL, ensuring clean session lifecycle; removes await on SignalR connection stop for faster cleanup
src/Umbraco.Core/Web/ICookieManager.cs Adds new overloads for ExpireCookie and SetCookieValue that accept security attributes and expiration dates; marks old methods as obsolete
src/Umbraco.Web.Common/AspNetCore/AspNetCoreCookieManager.cs Implements new cookie management overloads with proper security attribute handling
src/Umbraco.Core/Services/PreviewService.cs Updates preview cookie creation and expiration to use proper security attributes (SameSite=None, Secure=true, HttpOnly=true) for cross-site scenarios

Copy link
Contributor

@AndyButland AndyButland left a comment

Choose a reason for hiding this comment

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

I've fixed the issue with the preview path we were discussing, and simplified the cookie expiry to use .Delete, which meant we then didn't need the overloads. Preview looks to work as expected now. Happy to approve but I'll just leave you to look over next week just to be sure I didn't break anything in my updates or missing anything you were looking to do.

@iOvergaard
Copy link
Contributor Author

I tested it out, and it works, @AndyButland, so great find on the .Delete method. We could think of adding the CookieSecurePolicy to make cookies work the same throughout the app, but I don't think that is a strict requirement at the moment given that Preview mode seems to have always required Secure cookies (= only works on https).

        options.Cookie.SecurePolicy =
            _globalSettings.UseHttps ? CookieSecurePolicy.Always : CookieSecurePolicy.SameAsRequest

I'll wait for @leekelleher to test out the Backoffice functionality and see if preview mode has improved, too :-)

Copy link
Member

@leekelleher leekelleher left a comment

Choose a reason for hiding this comment

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

Tested out, works as described. 🚀

@leekelleher leekelleher merged commit 820c344 into main Dec 1, 2025
27 of 28 checks passed
@leekelleher leekelleher deleted the v17/bugfix/preview-session-invalidates-open-tab branch December 1, 2025 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

4 participants