Skip to content

fix(dashboard): redirect using sanitized slug from save response - #42853

Open
sadpandajoe wants to merge 1 commit into
masterfrom
fix-dashboard-slug-redirect-sanitized-redo
Open

fix(dashboard): redirect using sanitized slug from save response#42853
sadpandajoe wants to merge 1 commit into
masterfrom
fix-dashboard-slug-redirect-sanitized-redo

Conversation

@sadpandajoe

Copy link
Copy Markdown
Member

SUMMARY

Fixes a dashboard post-save redirect bug (Shortcut sc-107323): when the URL Slug in Edit dashboard properties starts with a reserved URL character (? or /), saving succeeds but the post-save redirect lands on a malformed/blank URL on the first render. A manual page reload afterwards works, because the reload uses the stored, backend-sanitized slug.

Root cause. In superset-frontend/src/dashboard/actions/dashboardState.ts, the onUpdateSuccess handler in saveDashboardRequest built the redirect from the raw, locally-submitted slug:

navigateWithState(`/dashboard/${slug || id}/`, { event: 'dashboard_properties_changed' });

The backend sanitizes reserved characters out of the slug before persisting it — BaseDashboardSchema.post_load in superset/dashboards/schemas.py runs re.sub(r"[^\w\-]+", "", ...) — so the persisted slug returned in the PUT /api/v1/dashboard/{id} response can differ from what was submitted. Building the redirect from the raw value produces e.g. /dashboard/?test/, which the router resolves to a slug-less /dashboard/ and renders blank on first paint.

Fix. Build the redirect from the slug in the update response (updatedDashboard.slug), falling back to id when the response carries no slug:

const updatedSlug = updatedDashboard.slug as string | null | undefined;
navigateWithState(`/dashboard/${updatedSlug || id}/`, { event: 'dashboard_properties_changed' });

The Copy / Save as path (onCopySuccess) already redirects on the response id only and is unaffected. The change is one decision point plus regression tests.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Captured in a real dev environment at a fixed 1280×800 viewport. Scenario (identical for both): log in → open the USA Births Names dashboard → Edit dashboard⋯ → Edit properties → set URL Slug to ?testApplySave → observe the address bar on first render (no manual reload). A location.href banner is injected into each still because Playwright screenshots don't include browser chrome.

Before (master) — post-save URL is /dashboard/ with the slug lost; the dashboard renders blank:

Before — post-save URL is slug-less /dashboard/, blank page

Before — rendered result is blank

After (this PR) — post-save URL is the sanitized /dashboard/test/; the dashboard renders correctly:

After — post-save URL is /dashboard/test/, dashboard renders

After — full dashboard renders

Full screen recordings (VP8 WebM): before-master.webm · after-fix.webm. Capture script: capture.mjs.

TESTING INSTRUCTIONS

Manual:

  1. Open any dashboard, enter edit mode, open ⋯ → Edit properties.
  2. Set URL Slug to a value starting with a reserved character, e.g. ?test, and Save.
  3. On master the first render is blank (URL missing the dashboard); with this change the redirect goes to /dashboard/test/ (the sanitized slug) and the dashboard renders. A slug of only reserved characters (e.g. ?) sanitizes to empty and correctly falls back to /dashboard/<id>/.

Automated (superset-frontend):

npm run test -- src/dashboard/actions/dashboardState.test.ts

Two regression tests were added: (a) submitted slug ?test + PUT-response slug test ⇒ redirect /dashboard/test/; (b) PUT-response slug empty/null ⇒ redirect falls back to /dashboard/<id>/. Both fail on master and pass with this change.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
  • Introduces new feature or API
  • Removes existing feature or API

When a dashboard's URL slug in Edit Properties starts with a reserved URL
character (e.g. `?` or `/`), saving succeeded but the post-save redirect
navigated to a malformed/blank URL on first render; a later reload worked
because it used the stored, sanitized slug.

The post-save redirect in `saveDashboardRequest`'s `onUpdateSuccess` handler
built the target from the raw locally-submitted slug. The backend sanitizes
reserved characters out of the slug (`BaseDashboardSchema.post_load` strips
`[^\w\-]`), so the persisted slug returned in the PUT response can differ from
what was submitted. Build the redirect from the response slug, falling back to
the dashboard id when the response has no slug.

Adds regression tests covering the sanitized-slug redirect and the empty-slug
id fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@netlify

netlify Bot commented Aug 6, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit d0cf5df
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a74cb06540d24000834a269
😎 Deploy Preview https://deploy-preview-42853--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@sadpandajoe
sadpandajoe marked this pull request as ready for review August 6, 2026 22:42
@dosubot dosubot Bot added change:frontend Requires changing the frontend dashboard:properties Related to the properties of the Dashboard labels Aug 6, 2026
@sadpandajoe
sadpandajoe requested review from msyavuz and rusackas and a lite review from Copilot and removed request for msyavuz and rusackas August 6, 2026 23: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

Fixes a dashboard post-save redirect bug where the frontend previously built the redirect URL from the raw, locally-submitted slug (which can include reserved URL characters), instead of the backend-sanitized slug returned by the update API response. This ensures the first render after saving lands on the correct dashboard URL.

Changes:

  • Update saveDashboardRequest’s update-success redirect to use updatedDashboard.slug from the PUT response (fallback to id).
  • Add frontend Jest regressions covering “sanitized slug differs from submitted slug” and “no usable slug in response” redirect behavior.

Reviewed changes

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

File Description
superset-frontend/src/dashboard/actions/dashboardState.ts Redirect after dashboard property save uses sanitized slug from PUT response instead of raw submitted slug.
superset-frontend/src/dashboard/actions/dashboardState.test.ts Adds regression tests validating redirect uses response slug and falls back to id when slug is not usable.

Comment on lines +353 to +357
putStub = jest.spyOn(SupersetClient, 'put').mockResolvedValue({
json: {
result: { ...mockDashboardData, id: updatedId, slug: null },
last_modified_time: 0,
},
@bito-code-review

Copy link
Copy Markdown
Contributor

The test case redirects using the id when the PUT response slug is empty in superset-frontend/src/dashboard/actions/dashboardState.test.ts currently mocks the PUT response with slug: null. To accurately test the production bug where the backend sanitizes a submitted slug like ? into an empty string (""), the mock should be updated to return slug: "" instead of slug: null.

This change will ensure the test exercises the logic where updatedSlug becomes an empty string, verifying that the code correctly falls back to the dashboard id for the redirect URL.

superset-frontend/src/dashboard/actions/dashboardState.test.ts

putStub = jest.spyOn(SupersetClient, 'put').mockResolvedValue({
        json: {
          result: { ...mockDashboardData, id: updatedId, slug: '' },
          last_modified_time: 0,
        },
      } as any);

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.73%. Comparing base (de93a19) to head (d0cf5df).
⚠️ Report is 10 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42853      +/-   ##
==========================================
- Coverage   65.73%   65.73%   -0.01%     
==========================================
  Files        2843     2843              
  Lines      162659   162660       +1     
  Branches    37239    37239              
==========================================
  Hits       106921   106921              
- Misses      53645    53646       +1     
  Partials     2093     2093              
Flag Coverage Δ
javascript 72.09% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bito-code-review

bito-code-review Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #c358f3

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: d0cf5df..d0cf5df
    • superset-frontend/src/dashboard/actions/dashboardState.test.ts
    • superset-frontend/src/dashboard/actions/dashboardState.ts
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:frontend Requires changing the frontend dashboard:properties Related to the properties of the Dashboard size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants