mirror of
https://github.com/zen-browser/desktop.git
synced 2026-03-29 11:51:51 +00:00
gh-12740: remove deleted workspace tabs from switch-to-tab (gh-12794)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com> Co-authored-by: mr. m <mr.m@tuta.com>
This commit is contained in:
@@ -13,6 +13,9 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
if (!window.gZenWorkspaces) {
|
||||
return;
|
||||
}
|
||||
this.promiseInitialized = new Promise(resolve => {
|
||||
this._resolveInitialized = resolve;
|
||||
});
|
||||
await this._ensureTable();
|
||||
},
|
||||
|
||||
@@ -54,9 +57,12 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
|
||||
// Create index for changes tracking
|
||||
await db.execute(`
|
||||
CREATE INDEX IF NOT EXISTS idx_bookmarks_workspaces_changes
|
||||
ON zen_bookmarks_workspaces_changes(bookmark_guid, workspace_uuid)
|
||||
`);
|
||||
CREATE INDEX IF NOT EXISTS idx_bookmarks_workspaces_changes
|
||||
ON zen_bookmarks_workspaces_changes(bookmark_guid, workspace_uuid)
|
||||
`);
|
||||
|
||||
this._resolveInitialized();
|
||||
delete this._resolveInitialized;
|
||||
}
|
||||
);
|
||||
},
|
||||
@@ -68,6 +74,7 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
*/
|
||||
async updateLastChangeTimestamp(db) {
|
||||
const now = Date.now();
|
||||
await this.promiseInitialized;
|
||||
await db.execute(
|
||||
`
|
||||
INSERT OR REPLACE INTO moz_meta (key, value)
|
||||
@@ -84,6 +91,7 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
*/
|
||||
async getLastChangeTimestamp() {
|
||||
const db = await this.lazy.PlacesUtils.promiseDBConnection();
|
||||
await this.promiseInitialized;
|
||||
const result = await db.executeCached(`
|
||||
SELECT value FROM moz_meta WHERE key = 'zen_bookmarks_workspaces_last_change'
|
||||
`);
|
||||
@@ -91,16 +99,21 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
},
|
||||
|
||||
async getBookmarkWorkspaces(bookmarkGuid) {
|
||||
await this.promiseInitialized;
|
||||
const db = await this.lazy.PlacesUtils.promiseDBConnection();
|
||||
|
||||
const rows = await db.execute(
|
||||
`
|
||||
let rows = [];
|
||||
try {
|
||||
rows = await db.execute(
|
||||
`
|
||||
SELECT workspace_uuid
|
||||
FROM zen_bookmarks_workspaces
|
||||
WHERE bookmark_guid = :bookmark_guid
|
||||
`,
|
||||
{ bookmark_guid: bookmarkGuid }
|
||||
);
|
||||
{ bookmark_guid: bookmarkGuid }
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Error fetching bookmark workspaces:", e);
|
||||
}
|
||||
|
||||
return rows.map(row => row.getResultByName("workspace_uuid"));
|
||||
},
|
||||
@@ -117,8 +130,8 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
* }
|
||||
*/
|
||||
async getBookmarkGuidsByWorkspace() {
|
||||
await this.promiseInitialized;
|
||||
const db = await this.lazy.PlacesUtils.promiseDBConnection();
|
||||
|
||||
const rows = await db.execute(`
|
||||
SELECT workspace_uuid, GROUP_CONCAT(bookmark_guid) as bookmark_guids
|
||||
FROM zen_bookmarks_workspaces
|
||||
@@ -141,6 +154,7 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
* @returns {Promise<object>} An object mapping bookmark+workspace pairs to their change data.
|
||||
*/
|
||||
async getChangedIDs() {
|
||||
await this.promiseInitialized;
|
||||
const db = await this.lazy.PlacesUtils.promiseDBConnection();
|
||||
const rows = await db.execute(`
|
||||
SELECT bookmark_guid, workspace_uuid, change_type, timestamp
|
||||
@@ -162,6 +176,7 @@ window.ZenWorkspaceBookmarksStorage = {
|
||||
* Clear all recorded changes.
|
||||
*/
|
||||
async clearChangedIDs() {
|
||||
await this.promiseInitialized;
|
||||
await this.lazy.PlacesUtils.withConnectionWrapper(
|
||||
"ZenWorkspaceBookmarksStorage.clearChangedIDs",
|
||||
async db => {
|
||||
|
||||
@@ -1261,12 +1261,23 @@ class nsZenWorkspaces {
|
||||
}
|
||||
|
||||
removeWorkspace(windowID) {
|
||||
let { promise, resolve } = Promise.withResolvers();
|
||||
this.#deleteWorkspaceOwnedTabs(windowID);
|
||||
let workspacesData = this.getWorkspaces();
|
||||
// Remove the workspace from the cache
|
||||
workspacesData = workspacesData.filter(
|
||||
workspace => workspace.uuid !== windowID
|
||||
);
|
||||
window.addEventListener(
|
||||
"ZenWorkspacesUIUpdate",
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
this.#propagateWorkspaceData(workspacesData);
|
||||
gBrowser.tabContainer._invalidateCachedVisibleTabs();
|
||||
return promise;
|
||||
}
|
||||
|
||||
isWorkspaceActive(workspace) {
|
||||
@@ -1472,6 +1483,18 @@ class nsZenWorkspaces {
|
||||
});
|
||||
}
|
||||
|
||||
#deleteWorkspaceOwnedTabs(workspaceID) {
|
||||
const tabs = this.allStoredTabs.filter(
|
||||
tab =>
|
||||
tab.getAttribute("zen-workspace-id") === workspaceID &&
|
||||
!tab.hasAttribute("zen-essential") &&
|
||||
!(tab.hasAttribute("zen-empty-tab") && !tab.group)
|
||||
);
|
||||
gBrowser.removeTabs(tabs, {
|
||||
closeWindowWithLastTab: false,
|
||||
});
|
||||
}
|
||||
|
||||
async unloadWorkspace() {
|
||||
const workspaceId =
|
||||
this.#contextMenuData?.workspaceId || this.activeWorkspace;
|
||||
@@ -1659,7 +1682,7 @@ class nsZenWorkspaces {
|
||||
onInit,
|
||||
previousWorkspace.uuid
|
||||
);
|
||||
if (tabToSelect.linkedBrowser) {
|
||||
if (tabToSelect?.linkedBrowser) {
|
||||
gBrowser.warmupTab(tabToSelect);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
"glance/browser.toml",
|
||||
"live-folders/browser.toml",
|
||||
"pinned/browser.toml",
|
||||
"spaces/browser.toml",
|
||||
"split_view/browser.toml",
|
||||
"tabs/browser.toml",
|
||||
"ub-actions/browser.toml",
|
||||
"urlbar/browser.toml",
|
||||
"welcome/browser.toml",
|
||||
"window_sync/browser.toml",
|
||||
"workspaces/browser.toml",
|
||||
]
|
||||
|
||||
DIRS += [
|
||||
|
||||
@@ -26,7 +26,7 @@ add_task(async function test_Check_Creation() {
|
||||
await gZenWorkspaces.removeWorkspace(gZenWorkspaces.activeWorkspace);
|
||||
const workspacesAfterRemove = gZenWorkspaces.getWorkspaces();
|
||||
Assert.strictEqual(
|
||||
workspacesAfterRemove.workspaces.length,
|
||||
workspacesAfterRemove.length,
|
||||
1,
|
||||
"One workspace should exist."
|
||||
);
|
||||
@@ -4,6 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
add_task(async function test_Issue_10455() {
|
||||
debugger;
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.tabs.closeWindowWithLastTab", true]],
|
||||
});
|
||||
@@ -24,6 +25,7 @@ add_task(async function test_Issue_10455() {
|
||||
});
|
||||
|
||||
add_task(async function test_Issue_10455_Dont_Close() {
|
||||
debugger;
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.tabs.closeWindowWithLastTab", false]],
|
||||
});
|
||||
@@ -1,132 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// verify that workspace unloading works
|
||||
add_task(async function test_UnloadWorkspace_WithMultipleTabs() {
|
||||
const workspaceId =
|
||||
await gZenWorkspaces.createAndSaveWorkspace("Test Workspace 1");
|
||||
const tabs = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
window.gBrowser,
|
||||
`data:text/html,<title>Workspace Tab ${i}</title>`,
|
||||
true,
|
||||
{ skipAnimation: true }
|
||||
);
|
||||
tab.setAttribute("zen-workspace-id", workspaceId);
|
||||
tabs.push(tab);
|
||||
}
|
||||
|
||||
for (const tab of tabs) {
|
||||
ok(!tab.hasAttribute("pending"), "Tab should not be pending before unload");
|
||||
ok(tab.linkedPanel, "Tab should have linked panel before unload");
|
||||
}
|
||||
|
||||
await gZenWorkspaces.unloadWorkspace();
|
||||
|
||||
for (const tab of tabs) {
|
||||
ok(tab.hasAttribute("pending"), "Tab should be pending after unload");
|
||||
ok(!tab.linkedPanel, "Tab should not have linked panel after unload");
|
||||
}
|
||||
|
||||
await gZenWorkspaces.removeWorkspace(workspaceId);
|
||||
});
|
||||
|
||||
// verify that essential tabs are not unloaded
|
||||
add_task(async function test_UnloadWorkspace_WithEssentialTabs() {
|
||||
const workspaceId =
|
||||
await gZenWorkspaces.createAndSaveWorkspace("Test Workspace 2");
|
||||
|
||||
const regularTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
window.gBrowser,
|
||||
"data:text/html,<title>Hi! I am a Regular Tab</title>",
|
||||
true,
|
||||
{ skipAnimation: true }
|
||||
);
|
||||
regularTab.setAttribute("zen-workspace-id", workspaceId);
|
||||
|
||||
const essentialTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
window.gBrowser,
|
||||
"data:text/html,<title>Hi! I am an Essential Tab</title>",
|
||||
true,
|
||||
{ skipAnimation: true }
|
||||
);
|
||||
essentialTab.setAttribute("zen-workspace-id", workspaceId);
|
||||
essentialTab.setAttribute("zen-essential", "true");
|
||||
|
||||
await gZenWorkspaces.unloadWorkspace();
|
||||
|
||||
ok(regularTab.hasAttribute("pending"), "Regular tab should be unloaded");
|
||||
ok(!regularTab.linkedPanel, "Regular tab should not have linked panel");
|
||||
|
||||
ok(
|
||||
!essentialTab.hasAttribute("pending"),
|
||||
"Essential tab should not be unloaded"
|
||||
);
|
||||
ok(essentialTab.linkedPanel, "Essential tab should still have linked panel");
|
||||
|
||||
await gZenWorkspaces.removeWorkspace(workspaceId);
|
||||
});
|
||||
|
||||
// only tabs from the targeted workspace should be unloaded
|
||||
add_task(async function test_UnloadWorkspace_TargetedWorkspaceIsolation() {
|
||||
const inActiveWorkspaceId = await gZenWorkspaces.createAndSaveWorkspace(
|
||||
"Test In-Active Workspace"
|
||||
);
|
||||
const activeWorkspaceId = await gZenWorkspaces.createAndSaveWorkspace(
|
||||
"Test Active Workspace"
|
||||
);
|
||||
|
||||
const inActiveWorkspaceTabs = [];
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
window.gBrowser,
|
||||
`data:text/html,<title>In-Active Workspace Tab ${i}</title>`,
|
||||
true,
|
||||
{ skipAnimation: true }
|
||||
);
|
||||
tab.setAttribute("zen-workspace-id", inActiveWorkspaceId);
|
||||
inActiveWorkspaceTabs.push(tab);
|
||||
}
|
||||
|
||||
const activeWorkspaceTabs = [];
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
window.gBrowser,
|
||||
`data:text/html,<title>Active Workspace Tab ${i}</title>`,
|
||||
true,
|
||||
{ skipAnimation: true }
|
||||
);
|
||||
tab.setAttribute("zen-workspace-id", activeWorkspaceId);
|
||||
activeWorkspaceTabs.push(tab);
|
||||
}
|
||||
|
||||
await gZenWorkspaces.unloadWorkspace(); // this unloads the latest created workspace -> activeWorkspaceId
|
||||
|
||||
for (const tab of activeWorkspaceTabs) {
|
||||
ok(
|
||||
tab.hasAttribute("pending"),
|
||||
"Active workspace tab should be pending after unload"
|
||||
);
|
||||
ok(
|
||||
!tab.linkedPanel,
|
||||
"Active workspace tab should not have linked panel after unload"
|
||||
);
|
||||
}
|
||||
|
||||
for (const tab of inActiveWorkspaceTabs) {
|
||||
ok(
|
||||
!tab.hasAttribute("pending"),
|
||||
"In-Active workspace tab should NOT be pending after unload"
|
||||
);
|
||||
ok(
|
||||
tab.linkedPanel,
|
||||
"In-Active workspace tab should still have linked panel after unload"
|
||||
);
|
||||
}
|
||||
|
||||
await gZenWorkspaces.removeWorkspace(inActiveWorkspaceId);
|
||||
await gZenWorkspaces.removeWorkspace(activeWorkspaceId);
|
||||
});
|
||||
Reference in New Issue
Block a user