Skip to content

feat: replace navbar with the Stacklet design-system sidebar [ENG-8179] - #9

Merged
Ahmore merged 15 commits into
stacklet/integrationfrom
dario/feat/ENG-8179-stacklet-sidebar
Jul 24, 2026
Merged

Ahmore merged 15 commits into
stacklet/integrationfrom
dario/feat/ENG-8179-stacklet-sidebar

Conversation

@Ahmore

@Ahmore Ahmore commented Jul 20, 2026 •

Copy link
Copy Markdown

SUMMARY

Replaces Superset's top navigation with the Stacklet design-system sidebar (V2Sidebar, grouped variant).

Key decisions:

  • @stacklet/ui is a regular npm dependency from CodeArtifact (npm run auth to log in). The package targets React 19, so the fork carries shims: overrides pinning react inside the package, a react/compiler-runtime webpack alias, and jest mocks for the prebuilt ESM.
  • All Stacklet code is isolated in superset-frontend/src/stacklet/; upstream files are touched minimally (App.tsx, menu.tsx, webpack/jest config) to keep rebases cheap.
  • Styling comes from the package's pre-scoped dist/ui.scoped.css inside a .stacklet-ui-scope element
  • The curated menu (Discover / Dashboards / Charts / Data / Settings) is filtered against the backend menu payload, so RBAC keeps working; Favourite/My entries reuse upstream's rison list-filter URLs.
  • Sibling app URLs in the app switcher come from the common bootstrap payload (common.stacklet.urls, injected by the platform — ENG-8219 / stacklet/platform#4166); local dev falls back to the shared dev-platform URLs.

Most of the changed lines are just package-lock.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Screenshot 2026-07-23 at 13 00 55

TESTING INSTRUCTIONS

Test it on my sandbox. I don't have SSO setup on my sandbox so just login with credentials: stacklet-admin/shGttA-9sO7[Xos}[[{&UH1k8u-lHo4o. After login in Console redirect to Superset may not work (it's something with my sandbox, unrelated to this PR, on dev works fine), so just go directly to https://superset.dev.dariusz.sandbox.stacklet.dev/)

ADDITIONAL INFORMATION

  • Has associated issue: ENG-8179
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

🤖 Generated with Claude Code

@Ahmore
Ahmore marked this pull request as ready for review July 23, 2026 10:57
@Ahmore
Ahmore requested a review from a team as a code owner July 23, 2026 10:57
@Ahmore
Ahmore requested review from ephan and squidsoup July 23, 2026 10:57

@ephan ephan left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks Good!

Ahmore and others added 15 commits July 24, 2026 10:53
Adds the Stacklet design-system package as a regular npm dependency,
resolved from the stacklet.client.ui CodeArtifact repository (npm run
auth refreshes the token). superset-frontend/.npmrc scopes only @stacklet
to CodeArtifact and pins the default registry to npmjs so a global
CodeArtifact-wide npmrc cannot break installs.

The package is built for React 19 while Superset runs React 17, hence the
shims: package.json overrides pin react/react-dom inside @stacklet/ui and
align @mui/material for x-data-grid-pro; webpack aliases
react/compiler-runtime to the react-compiler-runtime polyfill; jest maps
@stacklet/ui (prebuilt ESM the suite cannot parse) and @fontsource to
mocks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Renders @stacklet/ui's V2Sidebar (grouped variant) instead of Superset's
top navigation, per Design Kit v2 node 6820-6796: Discover, Dashboards,
Charts, Data and a collapsible Settings section, with the app selector
branded AssetDB. The curated structure is filtered against the backend
menu payload so RBAC keeps working, and Favourite/My entries reuse the
upstream rison list-view filter URLs.

The sidebar tree lives in a .stacklet-ui-scope element styled by the
package's pre-scoped dist/ui.scoped.css (the raw stylesheet would restyle
all of Superset), with react-aria overlays portalled into the same scope.
Active-item resolution feeds the Sidebar a virtual token instead of the
pathname so exactly one entry highlights, query-aware for the filtered
presets. Collapse state and Settings expansion persist in localStorage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The npm ci layer needs a token to resolve @stacklet/ui, passed as a
BuildKit secret so it never lands in a layer; stacklet-image.yml mints it
with aws codeartifact get-authorization-token after the OIDC role
assumption.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CodeArtifact auth, npm 10 requirement, docker-compose backend and the
frontend dev-server workflow, so colleagues can run the fork without
spelunking.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The platform injects its shared URL map into the common bootstrap
payload as stacklet.urls (stacklet/platform#4166); the app switcher now
builds the Console and IaC entries from it. Local development, where
the stock backend injects nothing, falls back to the shared dev
platform URLs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ild [ENG-8179]

npm executes the package's 'preinstall: pnpm dlx only-allow pnpm' during
npm ci; without a pnpm binary the layer fails with exit 127 (works on
dev machines only because pnpm happens to be installed, and only-allow
approves itself when launched through pnpm dlx). Removable once the fork
consumes a @stacklet/ui release without the pnpm-invoking guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…8179]

Carries over two controls dropped from the upstream navbar into the
V2Sidebar user-menu popover: an Info link (navbar_right.user_info_url)
and a Light/Dark/Match-system theme switcher. Log Out is already
rendered by the design-system UserMenu.

The theme switcher (ThemeModeControl) uses useThemeContext and so is
mounted only by the SPA shell, which runs under SupersetThemeProvider;
it is passed to StackletSidebar as themeControl and omitted by the
Flask-AppBuilder menu entrypoint, which has no theme context. It hides
itself when the deployment disallows changing the mode (canSetMode) and
drops 'Match system' when the OS preference can't be read, mirroring the
upstream navbar's theme submenu.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The @stacklet/ui scoped stylesheet keys its dark palette off
`.stacklet-ui-scope[data-theme="dark"]`, but nothing set that attribute,
so the sidebar stayed light while the rest of the app went dark. The
scope element now mirrors the resolved theme: the SPA shell passes the
current mode from the theme context (reactive to in-app switching) and
System mode is resolved via matchMedia; the menu entrypoint, which has no
theme context, falls back to the persisted mode.

Also renames the user-menu 'Info' link to 'User info'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ction [ENG-8179]

Adds the Notifications item per Design Kit v2 (node 6904-6659), between
Database Connections and Action Log, linking to /alert/list/ with the
BellSimple icon. Like the other entries it is gated by URL presence in
the backend menu payload, so it only appears when the ALERT_REPORTS
feature flag exposes Alerts & Reports to the user.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Alerts (/alert/list/) and Reports (/report/list/) are two tabs of the
same Alerts & Reports view, but the Notifications item only targeted
/alert/list/, so switching to Reports dropped the highlight. Nav specs
can now declare extra activePaths, and resolveActiveNavToken matches an
item against its target plus those paths; Notifications lists
/report/list/ so it stays active across both tabs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Use UserCircleIcon (from @stacklet/ui/icons) for the User info entry
  instead of the generic info-circle.
- Give the Theme label the text-label-extra-small-strong style, matching
  the sidebar section labels, and align it with the user-menu buttons'
  content inset (px-md) so it lines up with the User info icon.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sidebar work depended on unreleased @stacklet/ui features (grouped
Sidebar variant, ./icons entry, dist/ui.scoped.css, BellSimple/
UserCircle icons), so the fork ran a locally-packed tarball while
platform-ui#3259 was in review. That PR merged and published 2.15.0;
bump the dependency and lockfile to the real CodeArtifact release. The
Dockerfile still installs pnpm for the package's preinstall guard, which
2.15.0 keeps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…NG-8179]

The sidebar used position:sticky, but its scroll ancestors are all
clamped to the viewport height while page content overflows onto the
window. A sticky element is confined to its containing block, so once the
content scrolled past one viewport the sidebar scrolled away with it.

Pin it with position:fixed (relative to the viewport, independent of
containing-block height) and reserve its width on the content column via
margin-left, tracking the collapsed rail width. Window scroll is
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Ahmore
Ahmore force-pushed the dario/feat/ENG-8179-stacklet-sidebar branch from cd32ad7 to 59483a3 Compare July 24, 2026 08:56
@Ahmore
Ahmore merged commit c64e12b into stacklet/integration Jul 24, 2026
2 checks passed
@Ahmore
Ahmore deleted the dario/feat/ENG-8179-stacklet-sidebar branch July 24, 2026 09:28
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.

2 participants