mirror of
https://github.com/zen-browser/components.git
synced 2025-07-08 14:39:58 +02:00
feat(workspaces): Store workspaces in a database
This commit introduces a new `ZenWorkspacesStorage` class to handle the persistence of workspaces in a database. The previous implementation used JSON files, but this approach brings several advantages, including: - Improved performance and scalability - Easier data management and synchronization - Enhanced security and data integrity This change removes the reliance on JSON files and streamlines workspace management, leading to a more robust and reliable system.
This commit is contained in:
parent
2ea7024eea
commit
de8a857549
2 changed files with 106 additions and 28 deletions
|
@ -19,6 +19,7 @@ var ZenWorkspaces = new class extends ZenMultiWindowFeature {
|
||||||
this._expandWorkspacesStrip.bind(this)
|
this._expandWorkspacesStrip.bind(this)
|
||||||
);
|
);
|
||||||
ChromeUtils.defineLazyGetter(this, 'tabContainer', () => document.getElementById('tabbrowser-tabs'));
|
ChromeUtils.defineLazyGetter(this, 'tabContainer', () => document.getElementById('tabbrowser-tabs'));
|
||||||
|
await ZenWorkspacesStorage.init();
|
||||||
await this.initializeWorkspaces();
|
await this.initializeWorkspaces();
|
||||||
console.info('ZenWorkspaces: ZenWorkspaces initialized');
|
console.info('ZenWorkspaces: ZenWorkspaces initialized');
|
||||||
}
|
}
|
||||||
|
@ -57,10 +58,7 @@ var ZenWorkspaces = new class extends ZenMultiWindowFeature {
|
||||||
|
|
||||||
async _workspaces() {
|
async _workspaces() {
|
||||||
if (!this._workspaceCache) {
|
if (!this._workspaceCache) {
|
||||||
this._workspaceCache = await IOUtils.readJSON(this._storeFile);
|
this._workspaceCache = { workspaces: await ZenWorkspacesStorage.getWorkspaces() };
|
||||||
if (!this._workspaceCache.workspaces) {
|
|
||||||
this._workspaceCache.workspaces = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this._workspaceCache;
|
return this._workspaceCache;
|
||||||
}
|
}
|
||||||
|
@ -171,42 +169,34 @@ var ZenWorkspaces = new class extends ZenMultiWindowFeature {
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveWorkspace(workspaceData) {
|
async saveWorkspace(workspaceData) {
|
||||||
let json = await IOUtils.readJSON(this._storeFile);
|
await ZenWorkspacesStorage.saveWorkspace(workspaceData);
|
||||||
if (typeof json.workspaces === 'undefined') {
|
|
||||||
json.workspaces = [];
|
|
||||||
}
|
|
||||||
let existing = json.workspaces.findIndex((workspace) => workspace.uuid === workspaceData.uuid);
|
|
||||||
if (existing >= 0) {
|
|
||||||
json.workspaces[existing] = workspaceData;
|
|
||||||
} else {
|
|
||||||
json.workspaces.push(workspaceData);
|
|
||||||
}
|
|
||||||
console.info('ZenWorkspaces: Saving workspace', workspaceData);
|
|
||||||
await IOUtils.writeJSON(this._storeFile, json);
|
|
||||||
this._workspaceCache = null;
|
this._workspaceCache = null;
|
||||||
|
|
||||||
await this._updateWorkspacesChangeContextMenu();
|
await this._updateWorkspacesChangeContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeWorkspace(windowID) {
|
async removeWorkspace(windowID) {
|
||||||
let json = await this._workspaces();
|
|
||||||
console.info('ZenWorkspaces: Removing workspace', windowID);
|
console.info('ZenWorkspaces: Removing workspace', windowID);
|
||||||
await this.changeWorkspace(json.workspaces.find((workspace) => workspace.uuid !== windowID));
|
await this.changeWorkspace(json.workspaces.find((workspace) => workspace.uuid !== windowID));
|
||||||
this._deleteAllTabsInWorkspace(windowID);
|
this._deleteAllTabsInWorkspace(windowID);
|
||||||
delete this._lastSelectedWorkspaceTabs[windowID];
|
delete this._lastSelectedWorkspaceTabs[windowID];
|
||||||
json.workspaces = json.workspaces.filter((workspace) => workspace.uuid !== windowID);
|
await ZenWorkspacesStorage.removeWorkspace(windowID);
|
||||||
await this.unsafeSaveWorkspaces(json);
|
this._workspaceCache = null;
|
||||||
await this._propagateWorkspaceData();
|
await this._propagateWorkspaceData();
|
||||||
await this._updateWorkspacesChangeContextMenu();
|
await this._updateWorkspacesChangeContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveWorkspaces() {
|
async saveWorkspaces() {
|
||||||
await IOUtils.writeJSON(this._storeFile, await this._workspaces());
|
const workspaces = await this._workspaces();
|
||||||
|
for (const workspace of workspaces.workspaces) {
|
||||||
|
await ZenWorkspacesStorage.saveWorkspace(workspace);
|
||||||
|
}
|
||||||
this._workspaceCache = null;
|
this._workspaceCache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async unsafeSaveWorkspaces(workspaces) {
|
async unsafeSaveWorkspaces(workspaces) {
|
||||||
await IOUtils.writeJSON(this._storeFile, workspaces);
|
for (const workspace of workspaces.workspaces) {
|
||||||
|
await ZenWorkspacesStorage.saveWorkspace(workspace);
|
||||||
|
}
|
||||||
this._workspaceCache = workspaces;
|
this._workspaceCache = workspaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,6 +614,8 @@ var ZenWorkspaces = new class extends ZenMultiWindowFeature {
|
||||||
|
|
||||||
browser.document.getElementById('tabbrowser-tabs')._positionPinnedTabs();
|
browser.document.getElementById('tabbrowser-tabs')._positionPinnedTabs();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await ZenWorkspacesStorage.setActiveWorkspace(window.uuid);
|
||||||
await this.saveWorkspaces();
|
await this.saveWorkspaces();
|
||||||
await this._propagateWorkspaceData();
|
await this._propagateWorkspaceData();
|
||||||
}
|
}
|
||||||
|
@ -757,11 +749,8 @@ var ZenWorkspaces = new class extends ZenMultiWindowFeature {
|
||||||
}
|
}
|
||||||
|
|
||||||
async setDefaultWorkspace() {
|
async setDefaultWorkspace() {
|
||||||
let workspaces = await this._workspaces();
|
await ZenWorkspacesStorage.setDefaultWorkspace(this._contextMenuId);
|
||||||
for (let workspace of workspaces.workspaces) {
|
this._workspaceCache = null;
|
||||||
workspace.default = workspace.uuid === this._contextMenuId;
|
|
||||||
}
|
|
||||||
await this.unsafeSaveWorkspaces(workspaces);
|
|
||||||
await this._propagateWorkspaceData();
|
await this._propagateWorkspaceData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
89
src/ZenWorkspacesStorage.mjs
Normal file
89
src/ZenWorkspacesStorage.mjs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
var ZenWorkspacesStorage = {
|
||||||
|
async init() {
|
||||||
|
console.log('ZenWorkspacesStorage: Initializing...');
|
||||||
|
await this._ensureTable();
|
||||||
|
},
|
||||||
|
|
||||||
|
async _ensureTable() {
|
||||||
|
await PlacesUtils.withConnectionWrapper("ZenWorkspacesStorage._ensureTable", async db => {
|
||||||
|
await db.execute(`
|
||||||
|
CREATE TABLE IF NOT EXISTS moz_workspaces (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
uuid TEXT UNIQUE NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
icon TEXT,
|
||||||
|
is_default INTEGER NOT NULL DEFAULT 0,
|
||||||
|
is_active INTEGER NOT NULL DEFAULT 0,
|
||||||
|
container_id INTEGER,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveWorkspace(workspace) {
|
||||||
|
await PlacesUtils.withConnectionWrapper("ZenWorkspacesStorage.saveWorkspace", async db => {
|
||||||
|
const now = Date.now();
|
||||||
|
await db.executeCached(`
|
||||||
|
INSERT OR REPLACE INTO moz_workspaces (
|
||||||
|
uuid, name, icon, is_default, is_active, container_id, created_at, updated_at
|
||||||
|
) VALUES (
|
||||||
|
:uuid, :name, :icon, :is_default, :is_active, :container_id,
|
||||||
|
COALESCE((SELECT created_at FROM moz_workspaces WHERE uuid = :uuid), :now),
|
||||||
|
:now
|
||||||
|
)
|
||||||
|
`, {
|
||||||
|
uuid: workspace.uuid,
|
||||||
|
name: workspace.name,
|
||||||
|
icon: workspace.icon || null,
|
||||||
|
is_default: workspace.default ? 1 : 0,
|
||||||
|
is_active: workspace.used ? 1 : 0,
|
||||||
|
container_id: workspace.containerTabId || null,
|
||||||
|
now
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async getWorkspaces() {
|
||||||
|
const db = await PlacesUtils.promiseDBConnection();
|
||||||
|
const rows = await db.execute(`
|
||||||
|
SELECT * FROM moz_workspaces ORDER BY created_at ASC
|
||||||
|
`);
|
||||||
|
|
||||||
|
return rows.map(row => ({
|
||||||
|
uuid: row.getResultByName("uuid"),
|
||||||
|
name: row.getResultByName("name"),
|
||||||
|
icon: row.getResultByName("icon"),
|
||||||
|
default: !!row.getResultByName("is_default"),
|
||||||
|
used: !!row.getResultByName("is_active"),
|
||||||
|
containerTabId: row.getResultByName("container_id")
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
async removeWorkspace(uuid) {
|
||||||
|
await PlacesUtils.withConnectionWrapper("ZenWorkspacesStorage.removeWorkspace", async db => {
|
||||||
|
await db.execute(`
|
||||||
|
DELETE FROM moz_workspaces WHERE uuid = :uuid
|
||||||
|
`, { uuid });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async setActiveWorkspace(uuid) {
|
||||||
|
await PlacesUtils.withConnectionWrapper("ZenWorkspacesStorage.setActiveWorkspace", async db => {
|
||||||
|
await db.executeTransaction(async function() {
|
||||||
|
await db.execute(`UPDATE moz_workspaces SET is_active = 0`);
|
||||||
|
await db.execute(`UPDATE moz_workspaces SET is_active = 1 WHERE uuid = :uuid`, { uuid });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async setDefaultWorkspace(uuid) {
|
||||||
|
await PlacesUtils.withConnectionWrapper("ZenWorkspacesStorage.setDefaultWorkspace", async db => {
|
||||||
|
await db.executeTransaction(async function() {
|
||||||
|
await db.execute(`UPDATE moz_workspaces SET is_default = 0`);
|
||||||
|
await db.execute(`UPDATE moz_workspaces SET is_default = 1 WHERE uuid = :uuid`, { uuid });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue