feat: Run a migration for pinned tabs renamed titles, b=no-bug, c=common

This commit is contained in:
mr. m
2026-01-13 13:31:52 +01:00
parent 902651a196
commit 2b4e46ce4e
5 changed files with 77 additions and 36 deletions

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
index 2a055f0c5f34f0a2667f659185120c07d38f4e41..959e73ab86bdb78203e3aed0c939c1b9acbe4897 100644
index 2a055f0c5f34f0a2667f659185120c07d38f4e41..27f85dc47d66f2f83820e964198832d82bff04c1 100644
--- a/browser/components/sessionstore/SessionStore.sys.mjs
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
@@ -127,6 +127,9 @@ const TAB_EVENTS = [
@@ -235,7 +235,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..959e73ab86bdb78203e3aed0c939c1b9
+ if (tabData.zenIsEmpty) {
+ tab.setAttribute("zen-empty-tab", "true");
+ }
+ if (tabData.zenStaticLabel) {
+ if (typeof tabData.zenStaticLabel === "string") {
+ tab.zenStaticLabel = tabData.zenStaticLabel;
+ }
+ if (tabData.zenHasStaticIcon && tabData.image) {

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..64b6fc581be1791ef9a750e03ab9a91c92325be3 100644
index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..452879acc73898eb28cabae66d2d5692e301f853 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -398,6 +398,7 @@
@@ -191,7 +191,7 @@ index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..64b6fc581be1791ef9a750e03ab9a91c
+ if (!aTab._zenContentsVisible && !aTab._zenChangeLabelFlag && !aTab._labelIsInitialTitle && !gZenWorkspaces.privateWindowOrDisabled) {
+ return false;
+ }
+ aLabel = aTab.zenStaticLabel || aLabel;
+ aLabel = (typeof aTab.zenStaticLabel === "string" && aTab.zenStaticLabel) ? aTab.zenStaticLabel : aLabel;
+ gZenPinnedTabManager.onTabLabelChanged(aTab);
if (!aLabel || aLabel.includes("about:reader?")) {
return false;

View File

@@ -21,7 +21,7 @@ class ZenSessionStore extends nsZenPreloadedFeature {
if (tabData.zenSyncId || tabData.zenPinnedId) {
tab.setAttribute("id", tabData.zenSyncId || tabData.zenPinnedId);
}
if (tabData.zenStaticLabel) {
if (typeof tabData.zenStaticLabel === "string") {
tab.zenStaticLabel = tabData.zenStaticLabel;
}
if (tabData.zenHasStaticIcon && tabData.image) {

View File

@@ -851,6 +851,7 @@
":is(.tabbrowser-tab, .zen-drop-target, .tab-group-label, tab-group[split-view-group])";
let shouldPlayHapticFeedback = false;
let showIndicatorUnderNewTabButton = false;
let dropBefore = false;
let dropElement = event.target.closest(dropZoneSelector);
if (!dropElement) {
if (event.target.classList.contains("zen-workspace-empty-space")) {
@@ -862,7 +863,7 @@
const numPinned = gBrowser.pinnedTabCount - numEssentials;
const tabToUse = event.target.closest(dropZoneSelector);
if (!tabToUse) {
return;
return null;
}
const isPinned = tabToUse.pinned;
const relativeTabs = tabs.slice(
@@ -896,7 +897,7 @@
(!dropElement.pinned || dropElement.hasAttribute("zen-essential"))
) {
this.clearDragOverVisuals();
return;
return null;
}
if (
isTab(dropElement) ||
@@ -913,8 +914,10 @@
Services.prefs.getIntPref("browser.tabs.dragDrop.moveOverThresholdPercent") / 100;
if (overlapPercent > threshold) {
top = Math.round(rect.top + rect.height) + "px";
dropBefore = false;
} else {
top = Math.round(rect.top) + "px";
dropBefore = true;
}
if (indicator.style.top !== top) {
shouldPlayHapticFeedback = true;
@@ -937,12 +940,14 @@
dropElement =
elementToMove(this._tabbrowserTabs.ariaFocusableItems.at(gBrowser._numZenEssentials)) ||
dropElement;
dropBefore = true;
}
}
if (shouldPlayHapticFeedback) {
// eslint-disable-next-line mozilla/valid-services
Services.zen.playHapticFeedback();
}
return [dropBefore, dropElement];
}
#getDragImageOffset(event, tab, draggingTabs) {

View File

@@ -133,6 +133,21 @@ export class nsZenSessionManager {
}
: null,
}));
rows = await db.execute("SELECT * FROM zen_pins ORDER BY position ASC");
data.pins = rows.map((row) => ({
uuid: row.getResultByName("uuid"),
title: row.getResultByName("title"),
url: row.getResultByName("url"),
containerTabId: row.getResultByName("container_id"),
workspaceUuid: row.getResultByName("workspace_uuid"),
position: row.getResultByName("position"),
isEssential: Boolean(row.getResultByName("is_essential")),
isGroup: Boolean(row.getResultByName("is_group")),
parentUuid: row.getResultByName("folder_parent_uuid"),
editedTitle: Boolean(row.getResultByName("edited_title")),
folderIcon: row.getResultByName("folder_icon"),
isFolderCollapsed: Boolean(row.getResultByName("is_folder_collapsed")),
}));
this._migrationData = data;
} catch {
/* ignore errors during migration */
@@ -188,35 +203,7 @@ export class nsZenSessionManager {
// object will always be empty after migration because we haven't
// gotten the opportunity to save the session yet.
if (this._shouldRunMigration) {
this.log("Restoring tabs from Places DB after migration");
if (!this.#sidebar.spaces?.length) {
this.#sidebar = {
...this.#sidebar,
spaces: this._migrationData?.spaces || [],
};
}
// There might be cases where there are no windows in the
// initial state, for example if the user had 'restore previous
// session' disabled before migration. In that case, we try
// to restore the last closed normal window.
if (!initialState?.windows?.length) {
let normalClosedWindow = initialState?._closedWindows?.find(
(win) => !win.isPopup && !win.isTaskbarTab && !win.isPrivate
);
if (normalClosedWindow) {
initialState.windows = [Cu.cloneInto(normalClosedWindow, {})];
this.log("Restoring tabs from last closed normal window");
}
}
for (const winData of initialState?.windows || []) {
winData.spaces = this._migrationData?.spaces || [];
}
// Save the state to the sidebar object so that it gets written
// to the session file.
this.saveState(initialState);
delete this._migrationData;
delete this._shouldRunMigration;
return;
this.#runStateMigration(initialState);
}
// If there are no windows, we create an empty one. By default,
// firefox would create simply a new empty window, but we want
@@ -269,6 +256,55 @@ export class nsZenSessionManager {
this.#sidebarObject.data = data;
}
/**
* Runs the state migration to restore spaces and pinned tabs
* from the Places database into the initial session state.
*
* @param {object} initialState
* The initial session state read from the session file.
*/
#runStateMigration(initialState) {
this.log("Restoring tabs from Places DB after migration");
if (!this.#sidebar.spaces?.length) {
this.#sidebar = {
...this.#sidebar,
spaces: this._migrationData?.spaces || [],
};
}
// There might be cases where there are no windows in the
// initial state, for example if the user had 'restore previous
// session' disabled before migration. In that case, we try
// to restore the last closed normal window.
if (!initialState?.windows?.length) {
let normalClosedWindow = initialState?._closedWindows?.find(
(win) => !win.isPopup && !win.isTaskbarTab && !win.isPrivate
);
if (normalClosedWindow) {
initialState.windows = [Cu.cloneInto(normalClosedWindow, {})];
this.log("Restoring tabs from last closed normal window");
}
}
for (const winData of initialState?.windows || []) {
winData.spaces = this._migrationData?.spaces || [];
if (winData.tabs) {
for (const tabData of winData.tabs) {
let storeId = tabData.zenSyncId || tabData.zenPinnedId;
const pinData = this._migrationData?.pins?.find((pin) => pin.uuid === storeId);
// We need to migrate the static label from the pin data as this information
// was not stored in the session file before.
if (pinData) {
tabData.zenStaticLabel = pinData.editedTitle ? pinData.title : undefined;
}
}
}
}
// Save the state to the sidebar object so that it gets written
// to the session file.
this.saveState(initialState);
delete this._migrationData;
delete this._shouldRunMigration;
}
/**
* Saves the current session state. Collects data and writes to disk.
*