After Superset.route_base="" (c531185d0a) and the FAB-link migration
(28b845ead4), `url_for` for the core blueprint emits `/dashboard/...`,
`/explore/...`, `/explore_json/...`, `/welcome/...` etc. (no `/superset/`
segment). Likewise the Tag component renders `/all_entities/?id=<id>`,
and rewritePermalinkOrigin substitutes window.location.origin into
backend permalinks at the frontend boundary.
Update test expectations to match:
* Python unit: tests/unit_tests/commands/report/execute_test.py drops
`superset/` from the 12 `dashboard/p/...` expected paths and the
`superset/dashboard/` membership check (kept assertion meaningful
via the existing `dashboard/p/` negative check).
* Python integration: drop `/superset/` from URLs hit by tests and
from URLs asserted against API payloads in core_tests, dashboard_tests,
dashboards/api_tests, event_logger_tests, log_api_tests, security_tests,
strategy_tests, utils_tests, reports/commands_tests,
reports/commands/execute_dashboard_report_tests. Fixed the regex in
test_new_dashboard to match the new Location header shape.
* Jest: ChartList tag-link assertion drops `/superset/`, and
URLShortLinkButton tests assert the rewritten URL
(`${window.location.origin}/123`) the component renders after
rewritePermalinkOrigin, instead of the raw backend `http://fakeurl.com/123`.
These were called out in PROJECT.md as the queued "integration test sweep
for old `/superset/<endpoint>/` shapes" — this commit closes that item.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adversarial review surfaced six classes of subdirectory-deployment gaps not
covered by the existing TDD scaffold. Each is fixed where it lives, with
pinning tests added beside the change:
Helpers
- navigationUtils: drop `//` from the navigation safety regex so
`openInNewTab('//evil.com')` can no longer open a cross-origin tab
- pathUtils.stripAppRoot: greedy strip so an upstream `/superset/superset/x`
payload survives one strip + react-router basename re-prepend
- RedirectWarning.isAllowedScheme: explicit `//` guard; the `new URL(...)`
catch branch was silently allowing protocol-relative URLs through
- SupersetClientClass.getUrl: implement the runtime appRoot dedupe the
project memory was already documenting. Flips the contract test from
pinning the doubled shape under a misleading name to asserting single-
prefix emission with segment-boundary + bare-root coverage
Frontend literals and sinks
- loggerMiddleware: `/superset/log/` -> `/log/` (matches the live route
after `Superset.route_base = ""`); updated three test fixtures
- DatasetPanel: raw `window.open(explore_url)` -> `openInNewTab` with null guard
- RedirectWarning: raw `window.location.href = targetUrl` -> `redirect()`
so the helpers' validation applies
Backend literals and sinks
- Slice.explore_json_url: `/superset/explore_json` -> `/explore_json`
- Database.sql_url: `/superset/sql/<id>/` (route no longer exists) ->
`/sqllab/?dbid=<id>` (the live SQL Lab deep-link)
- tasks/async_queries.result_url: same `/superset/` strip
- initialization Home menu: hardcoded `href="/superset/welcome/"` ->
`f"{app_root}/welcome/"` so it works under any application_root
FAB list-view raw HTML
- dashboard_link / slice_link render raw `<a href=...>` strings, which do
not receive SCRIPT_NAME at render time. Migrated both to `url_for`
(`Superset.dashboard` / `ExploreView.root`) so subdir deployments emit
single-prefix hrefs. The model properties themselves keep their
router-relative shape for frontend callers using ensureAppRoot
Tests
- test_subdirectory_url_for.py grew from 7 to 11 cases pinning
Slice.explore_json_url, Database.sql_url, dashboard_link, and slice_link
under SCRIPT_NAME=/superset
- 82 helper Jest tests + 71 touched component tests green; pre-commit clean
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-4 follow-up to 756458f031. Four user-reported symptoms on /superset/
deployments — blank welcome, blank dashboard edit mode, doubled explore
copy-permalink, JSON 404 on dashboard discard — all trace to round-2
leftovers:
- superset-frontend/src/views/routes.tsx: six SPA routes still hard-coded
the /superset/ prefix on top of <Router basename={applicationRoot()}>.
React Router never matched them post-basename. Drop the prefix on
welcome, file-handler, dashboard/:idOrSlug, explore/p, all_entities,
and tags. isFrontendRoute stripAppRoots its input so menu URLs that
carry the appRoot still resolve.
- Menu.tsx + RightMenu.tsx: SPA-route menu branches handed already-rooted
URLs to <NavLink>/<Link>, doubling them via basename. Mirror the
round-3 brand-link stripAppRoot pattern.
- superset/views/{explore,tags,all_entities}.py: three sibling view
classes still declared route_base = "/superset/...". Mirror
Superset.route_base="".
- superset/models/dashboard.py: Dashboard.url / get_url returned
"/superset/dashboard/<id>/", producing doubled DashboardList row hrefs
that caused the discard-edit 404. Return "/dashboard/<id>/" so
downstream ensureAppRoot-aware consumers prepend exactly once.
- superset/mcp_service/dashboard/{schemas,tool/*}.py: seven sibling
hard-codes of "/superset/dashboard/<id>/" updated identically.
Tests pin shapes for ExplorePermalinkView.permalink, TagModelView.list,
TaggedObjectsModelView.list, Dashboard.get_url, and the MCP dashboard
url emission. routes.test.tsx adds appRoot-prefixed lookup coverage and
documents the dict-lookup-no-pattern-match limitation.
UPDATING.md notes the new sibling route_base moves and the model URL
change alongside the round-2 Superset.route_base entry.
Live Playwright re-validation confirmed all four bugs fixed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-2 follow-up to the TDD scaffold. Two user-visible bugs in QA on
the local /superset deployment:
- Empty dashboard-tab "create a new chart" link opened a 404 tab under
/superset: raw <Typography.Link href="/chart/add?..."> with
target="_blank" bypasses React Router's basename, so the new tab
resolves the absolute path against the document origin without the
application root.
- "Copy permalink" produced /superset/superset/dashboard/p/<key>/ on
the clipboard. The same backend mechanism made the 18 routes on the
`Superset` view class unreachable at request time under subdirectory
deployment (404 for /superset/welcome/, /superset/dashboard/<id>/,
/superset/explore/, etc.).
Frontend:
- Tab.tsx — wrap the create-chart href with `ensureAppRoot()` from
navigationUtils so the application root is applied exactly once and
the new tab lands at the right path.
- New L2 invariant `RAW_HREF_ABSOLUTE_PATH_PATTERN` flags raw
absolute-from-root anchors (`href="/..."`, `href={`/...`}`, etc.) —
the bug class that bypasses both helpers and React Router basename.
Seeded with 7 remaining violator files paired with a
`toEqual([])` stale-allow-list check so each migration commit
shrinks the list in lockstep.
- Tab.subdirectory.test.tsx — empty / /superset / nested-root
regression pins via a jest.mock pattern on applicationRoot().
Backend (breaking change documented in UPDATING.md):
- Override `Superset.route_base = ""` so Flask-AppBuilder's
auto-derived `/superset` prefix no longer compounds with the
SCRIPT_NAME / basename that AppRootMiddleware sets. url_for now
emits single-prefix URLs and the routes are reachable under both
root and subdirectory deployments.
- Pin the new shape with four unit tests covering
Superset.dashboard_permalink (relative + external) and
Superset.welcome, with and without SCRIPT_NAME.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>