EnxDev opened a new pull request, #44345:
URL: https://github.com/apache/superset/pull/44345
### SUMMARY
Empty tab containers were quietly writing a `null` into
`dashboardState.activeTabs`, which then ended up in the dashboard permalink
request body.
`Tabs.tsx` figures out which tab is active by reading
`component.children[tabIndex]`. If the TABS component has no children, that
read returns `undefined` — but the mount effect dispatched it through
`setActiveTab` anyway, so `findTabsToRestore` merged an `undefined` entry into
`activeTabs`. Since `JSON.stringify` turns `undefined` into `null` inside
arrays, the POST to `/api/v1/dashboard/{id}/permalink` went out looking like
this:
```json
"activeTabs": ["TAB-OTSsSEwZ0", null, "TAB-8l5p-0X1HcVN6DBgYoMy6",
"TAB-Zgq03BIpvp"]
```
The fix is a guard in the effect: if there's no tab id to activate, don't
dispatch. `handleClickTab` already had the same check (`if
(tabIds[tabIndex])`), and `getDefaultActiveTabs` already skips childless
containers, so this was the last path left that could seed an unresolved id.
A couple of things about the original report are worth writing down, because
both look mysterious and both turn out to be the same thing:
- **The position of the `null` moved around** between reproductions. That's
just component mount order — nothing meaningful.
- **Only *some* empty TABS containers triggered it**, and it looked like
nesting depth mattered. It isn't depth, it's mounting: tab content deeper in
the tree isn't mounted until its parent tab is selected, so only containers
present on the initial render ever got the chance to dispatch. Same reason
switching to another tab and back "fixed" it — the array got rebuilt.
**One important note on scope.** This was originally reported as an HTTP
400, and on the reporter's version (6.0.0.30) it is. But the backend half is
already fixed on master: #40969 added `allow_none=True` to the inner
`fields.String` in `DashboardPermalinkStateSchema`, so a `null` entry no longer
gets rejected. **This PR does not fix a 400 on master** — the 400 can't
reproduce here. What it fixes is the frontend defect that puts the `null` there
in the first place, which is still writing junk into permalink state today. If
the 400 itself needs addressing for 6.0.x, that's a backport of #40969, not
this change.
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
Not applicable — no visual change. The difference is in the request payload:
Before:
```json
"activeTabs": ["TAB-OTSsSEwZ0", null, "TAB-8l5p-0X1HcVN6DBgYoMy6"]
```
After:
```json
"activeTabs": ["TAB-OTSsSEwZ0", "TAB-8l5p-0X1HcVN6DBgYoMy6"]
```
### TESTING INSTRUCTIONS
Automated:
```bash
cd superset-frontend
npm run test -- src/dashboard/components/gridComponents/Tabs/Tabs.test.tsx
```
The new test (`A childless TABS component does not register an active tab`)
renders a TABS component with `children: []` and asserts `setActiveTab` is
never called. On unfixed code it fails with `Received number of calls: 1` / `1:
undefined`, which is the bug in one line.
Manual:
1. Build a dashboard with tabs, and inside the tab that's active on load,
drop in a **Tabs** component and delete all of its child tabs so the container
is empty.
2. Save, then open the dashboard fresh via direct URL. Don't click into the
tab first — clicking is the workaround and will mask the issue.
3. Open DevTools → Network, filter Fetch/XHR.
4. `...` → **Share** → **Copy permalink to clipboard**.
5. Check the request payload for `POST /api/v1/dashboard/{id}/permalink`.
`activeTabs` should contain only real tab ids and no `null`.
6. Same check via the inline link icon next to the tab title.
### ADDITIONAL INFORMATION
- [ ] Has associated issue:
- [ ] Required feature flags:
- [ ] Changes UI
- [ ] Includes DB Migration (follow approval process in
[SIP-59](https://github.com/apache/superset/issues/13351))
- [ ] 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
---
Ran `npm run test` over `src/dashboard/components/gridComponents`,
`src/dashboard/reducers`, and `src/dashboard/actions` — 31 suites, 363 tests,
all passing.
A note for reviewers on pre-commit: the `Type-Checking (Frontend)` hook
currently fails on `master` with 116 pre-existing errors in unrelated files.
None are in the files this PR touches, so I left that baseline alone rather
than dragging unrelated fixes into this diff. Every other hook passes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]