gh-12740: remove deleted workspace tabs from switch-to-tab#12794
gh-12740: remove deleted workspace tabs from switch-to-tab#12794mr-cheffy merged 8 commits intozen-browser:devfrom
Conversation
src/zen/spaces/ZenSpaceManager.mjs
Outdated
| workspace => workspace.uuid !== windowID | ||
| ); | ||
| this.#propagateWorkspaceData(workspacesData); | ||
| this._allStoredTabs = null; |
There was a problem hiding this comment.
line 1271 is not redundant in all cases
the redundant one is more likely the clear inside #deleteWorkspaceOwnedTabs(), not the one in removeWorkspace()
There was a problem hiding this comment.
These are some cases where i found it useful:
-
The workspace is deleted but it has no workspace-owned tabs left.
In that case#deleteWorkspaceOwnedTabs()may do nothing, so no tab-close-driven cache invalidation happens. ButallStoredTabsis still stale because the workspace container set changed. -
The workspace only had tabs that are excluded from deletion logic.
Example: no normal workspace-owned tabs, only essentials/empty-tab edge cases. The workspace still disappears from the workspace UI/container model, so the cached tab walk can still be stale. -
You move tab deletion out of
removeWorkspace()or it happens later/asynchronously.
Then line 1271 becomes the only immediate invalidation at the time workspace data is changed.
Why this matters:
allStoredTabsis built by walking workspace containers, not justgBrowser.tabs.removeWorkspace()changes workspace data and leads to workspace container removal.- If no lower-level tab invalidation fires, the memoized cache can point at the old container-derived state.
So:
- if real tab removal definitely happens first, line 1271 may be redundant
- if workspace metadata/UI can change without guaranteed tab-removal invalidation, line 1271 is still useful
There was a problem hiding this comment.
Sorry, better to use gBrowser.tabContainer._invalidateCachedVisibleTabs();
There was a problem hiding this comment.
I tracked down why this._allStoredTabs = null originally looked like the fix.
What made it confusing is that there are actually two delete paths with different behavior:
- deleting the currently active workspace
- deleting a different workspace while staying in the current one
Deleting the active workspace worked because the removal code was using gBrowser.tabs, and in Zen that effectively reflects the active workspace strip. So the tabs from the workspace being deleted were present in that enumeration and got removed.
Deleting a different workspace failed because its tabs were not part of that same gBrowser.tabs view, so #deleteWorkspaceOwnedTabs() could miss them entirely. That is why stale Switch to Tab entries remained.
I initially thought this._allStoredTabs = null was the right fix because clearing that cache made the stale results disappear in practice. After tracing it further, the real issue was not the open-tabs/urlbar unregister path, and not moz_openpages_temp either; those were being cleaned up correctly on workspace deletion. The actual problem was that the delete path was enumerating tabs from an active-workspace-scoped source.
So the fix here is to use allStoredTabs for workspace-owned tab deletion, since that walks tabs across workspace containers instead of only what gBrowser.tabs currently exposes for the active space. I also updated the test to cover deleting a workspace from another workspace, since that was the failing branch.
src/zen/spaces/ZenSpaceManager.mjs
Outdated
| workspace => workspace.uuid !== windowID | ||
| ); | ||
| this.#propagateWorkspaceData(workspacesData); | ||
| this._allStoredTabs = null; |
| removeNonWorkspaceTabs(); | ||
| }); | ||
|
|
||
| add_task(async function test_DeleteWorkspace_RemovesWorkspaceOwnedTabs() { |
There was a problem hiding this comment.
This test is a bit useless, i'd just check if TabRemove event is being fired for every tab and TabGroupRemoved
There was a problem hiding this comment.
Updated the test to cover the actual removal lifecycle instead of only checking the final tab state. It now waits for the relevant TabClose events and TabGroupRemoved, then asserts the workspace-owned tabs are gone. The updated coverage is in browser_workspace_unload.js.
src/zen/spaces/ZenSpaceManager.mjs
Outdated
| tab => | ||
| tab.getAttribute("zen-workspace-id") === workspaceID && | ||
| !tab.hasAttribute("zen-essential") && | ||
| !tab.hasAttribute("zen-empty-tab") |
There was a problem hiding this comment.
!tab.hasAttribute("zen-empty-tab") not needed here AFAIK. At least i'd do (!tab.hasAttribute("zen-empty-tab") && !tab.group) so it also removes empty tabs of the folders and therefor, remove the folder its self
There was a problem hiding this comment.
Fixed this by handling workspace folders explicitly during workspace deletion instead of trying to fold zen-empty-tab handling into the normal tab filter. removeWorkspace() now deletes workspace folders first, which also clears the folder empty-tab path, and then removes the remaining workspace-owned tabs. I also extended the test to cover a folder case in browser_workspace_unload.js. The deletion change is in ZenSpaceManager.mjs.
There was a problem hiding this comment.
Important
I verified the workspace-deletion change in isolation and the updated deletion test passes.
I still couldn’t get a clean full-file run, but this does not look introduced by this PR: the same file already fails on a full origin/dev checkout, and it fails more broadly there. The main issue is unload tests not fully unloading tabs (pending stays false / linkedPanel still exists), which then leaves unexpected tabs behind at the end of the run.
Because of that, I used a temporary local .only() only to confirm the new deletion behavior independently, then removed it afterward.
src/zen/spaces/ZenSpaceManager.mjs
Outdated
| workspace => workspace.uuid !== windowID | ||
| ); | ||
| this.#propagateWorkspaceData(workspacesData); | ||
| this._allStoredTabs = null; |
There was a problem hiding this comment.
Sorry, better to use gBrowser.tabContainer._invalidateCachedVisibleTabs();
…kspace folders and improve workspace switching tests
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Vedaant Rajoo <vedaant12345@gmail.com>
|
You haven't ran the tests you created, have you? |
Summary
Fixes #12740 by removing workspace-owned tabs through the normal tab close path when a
workspace is deleted.
Previously, deleting a workspace only removed the workspace metadata/UI. Tabs that
still belonged to that workspace could remain alive in the browser tab model, which
allowed stale
Switch Tabresults to continue appearing in the urlbar.What changed
Why this approach
The stale urlbar result was a symptom of the tabs not actually being closed. The safest
fix is to delete those tabs through the normal
gBrowser.removeTabs(...)path so theusual browser and Zen cleanup runs, instead of trying to manually refresh urlbar state
afterward.
Notes
creating unrealistic workspace state by mutating attributes directly