Files
browser-cli/extension/src/commands/groups.ts
T
daniel156161 545abeb515 feat: add performance controls for large browser ops
- Add throttled large-operation handling for tab, group, and session commands.
- Introduce performance profiles, audible-tab aware gentle mode, and job progress tracking.
- Support background session restores with status/cancel commands and lazy placeholders.
- Expose new perf and extension CLI groups plus matching Python SDK methods.
- Preserve pinned tabs during session snapshots and debounce auto-save updates.
- Bump browser-cli and extension versions to 0.10.0 and add pytest-cov to dev deps.
- Add coverage for performance controls, background jobs, lazy restores, and tab metadata.
2026-05-20 22:13:57 +02:00

106 lines
4.3 KiB
TypeScript

// @ts-nocheck
import { buildTabBlocks, getLargeOperationThrottle, resolveGroupId, runLargeOperation, tabInfo, throwIfJobCancelled, updateJobProgress, yieldForLargeOperation } from '../core';
export async function groupList() {
const groups = await chrome.tabGroups.query({});
const all = await chrome.tabs.query({});
return groups.map(g => ({
id: g.id,
title: g.title,
color: g.color,
collapsed: g.collapsed,
windowId: g.windowId,
tabCount: all.filter(t => t.groupId === g.id).length,
}));
}
export async function groupTabs({ groupId }) {
const all = await chrome.tabs.query({});
return all.filter(t => t.groupId === groupId).map(tabInfo);
}
export async function groupCount() {
const groups = await chrome.tabGroups.query({});
return groups.length;
}
export async function groupQuery({ search }) {
const q = search.toLowerCase();
const groups = await chrome.tabGroups.query({});
return groups.filter(g => g.title && g.title.toLowerCase().includes(q));
}
export async function groupClose({ groupId, gentleMode, __job } = {}) {
return runLargeOperation("group.close", async () => {
const tabs = await chrome.tabs.query({});
const groupTabs = tabs.filter(t => t.groupId === groupId);
const tabIds = groupTabs.map(t => t.id);
const throttle = await getLargeOperationThrottle(tabIds.length, gentleMode);
updateJobProgress(__job, { phase: "ungrouping tabs", current: 0, total: tabIds.length });
for (let i = 0; i < tabIds.length; i += throttle.batchSize) {
throwIfJobCancelled(__job);
await chrome.tabs.ungroup(tabIds.slice(i, i + throttle.batchSize));
updateJobProgress(__job, { phase: "ungrouping tabs", current: Math.min(i + throttle.batchSize, tabIds.length), total: tabIds.length });
await yieldForLargeOperation(i + throttle.batchSize, throttle.batchSize, throttle.pauseMs);
}
return { groupId, gentle: throttle.gentle, audible: throttle.audible };
});
}
export async function groupOpen({ name }) {
const tab = await chrome.tabs.create({ active: true });
const groupId = await chrome.tabs.group({ tabIds: [tab.id] });
await chrome.tabGroups.update(groupId, { title: name });
return { id: groupId, name };
}
export async function groupAddTab({ group, url }) {
const groupId = await resolveGroupId(group);
const existingTabs = await chrome.tabs.query({ groupId });
const tab = await chrome.tabs.create({ url: url || "chrome://newtab/", active: true });
await chrome.tabs.group({ tabIds: [tab.id], groupId });
// If a URL was provided, close any blank placeholder tabs left from group creation
if (url) {
const placeholders = existingTabs.filter(t =>
t.url === "chrome://newtab/" || t.url === "about:blank" || t.pendingUrl === "chrome://newtab/"
);
if (placeholders.length) await chrome.tabs.remove(placeholders.map(t => t.id));
}
return { tabId: tab.id, groupId };
}
export async function groupMove({ group, forward, backward }) {
const groupId = await resolveGroupId(group);
const groupInfo = await chrome.tabGroups.get(groupId);
const allTabs = await chrome.tabs.query({ windowId: groupInfo.windowId });
allTabs.sort((a, b) => a.index - b.index);
const blocks = buildTabBlocks(allTabs);
const currentIdx = blocks.findIndex(block => block.groupId === groupId);
if (currentIdx === -1) throw new Error(`No tabs found in group '${group}'`);
const currentBlock = blocks[currentIdx];
const currentLength = currentBlock.tabIds.length;
if (forward) {
const nextBlock = blocks[currentIdx + 1];
if (!nextBlock) return { groupId, moved: false };
const targetIndex =
nextBlock.groupId === null
? currentBlock.startIndex + 1
: nextBlock.endIndex - currentLength + 1;
await chrome.tabGroups.move(groupId, { index: targetIndex });
} else if (backward) {
const previousBlock = blocks[currentIdx - 1];
if (!previousBlock) return { groupId, moved: false };
const targetIndex =
previousBlock.groupId === null
? currentBlock.startIndex - 1
: previousBlock.startIndex;
await chrome.tabGroups.move(groupId, { index: targetIndex });
}
return { groupId, moved: true };
}
// ── Windows ───────────────────────────────────────────────────────────────────