feat(sidebar): replicate WorkBuddy task context menu (TODO 01)
Replace the sidebar delete button with the original task menu: pin/unpin, rename, open in a separate window, open folder, archive and delete. Source: REA ev_f5e9d71a676c453daab40928acfb33aeabae68ba57ffda342380cead7f1a1fe2 (WorkBuddy 5.8.3 task menu, open state) supplies the container/item geometry, the two dividers, danger colour and every item icon. Verified by scripts/verify-task-menu.cjs: 33 assertions in a real isolated Electron app (real preload/IPC/filesystem), including menu geometry, anchor offset, pin/rename/archive persistence, open-folder target and the separate window query. typecheck, test:conversation and build pass.
This commit is contained in:
1 parent
e365e830cf
commit
e335588826
15 files changed
+821
-31
No files matched your search
+34
-2
@@ -93,8 +93,40 @@ async function persist(): Promise<void> {
|
||||
export async function listSessions(): Promise<SessionMeta[]> {
|
||||
const store = await load()
|
||||
return [...store.sessions]
|
||||
.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
.map(({ id, title, createdAt, updatedAt, workspaceId, cwd, modelId, expertId, agentMode: mode, thinkingLevel: level }) => ({ id, title, createdAt, updatedAt, workspaceId, cwd, modelId, expertId, agentMode: agentMode(mode), thinkingLevel: level }))
|
||||
// 置顶任务优先(最近置顶在前),其余按更新时间倒序。
|
||||
.sort((a, b) => Number(b.pinnedAt ?? 0) - Number(a.pinnedAt ?? 0) || b.updatedAt - a.updatedAt)
|
||||
.map(({ id, title, createdAt, updatedAt, workspaceId, cwd, modelId, expertId, agentMode: mode, thinkingLevel: level, pinnedAt, archivedAt }) => ({ id, title, createdAt, updatedAt, workspaceId, cwd, modelId, expertId, agentMode: agentMode(mode), thinkingLevel: level, pinnedAt, archivedAt }))
|
||||
}
|
||||
|
||||
/** 侧栏可见任务:默认排除已归档;`includeArchived` 供归档视图使用。 */
|
||||
export async function listVisibleSessions(includeArchived = false): Promise<SessionMeta[]> {
|
||||
const sessions = await listSessions()
|
||||
return includeArchived ? sessions : sessions.filter((session) => session.archivedAt === undefined)
|
||||
}
|
||||
|
||||
export async function setSessionPinned(sessionId: string, pinned: boolean): Promise<SessionMeta> {
|
||||
const store = await load()
|
||||
const session = store.sessions.find((item) => item.id === sessionId)
|
||||
if (!session) throw new Error('会话不存在')
|
||||
const previous = session.pinnedAt
|
||||
session.pinnedAt = pinned ? Date.now() : undefined
|
||||
try { await persist() } catch (error) { session.pinnedAt = previous; throw error }
|
||||
return meta(session)
|
||||
}
|
||||
|
||||
export async function setSessionArchived(sessionId: string, archived: boolean): Promise<SessionMeta> {
|
||||
const store = await load()
|
||||
const session = store.sessions.find((item) => item.id === sessionId)
|
||||
if (!session) throw new Error('会话不存在')
|
||||
const previous = session.archivedAt
|
||||
session.archivedAt = archived ? Date.now() : undefined
|
||||
try { await persist() } catch (error) { session.archivedAt = previous; throw error }
|
||||
return meta(session)
|
||||
}
|
||||
|
||||
function meta(session: SessionRecord): SessionMeta {
|
||||
const { id, title, createdAt, updatedAt, workspaceId, cwd, modelId, expertId, agentMode: mode, thinkingLevel: level, pinnedAt, archivedAt } = session
|
||||
return { id, title, createdAt, updatedAt, workspaceId, cwd, modelId, expertId, agentMode: agentMode(mode), thinkingLevel: level, pinnedAt, archivedAt }
|
||||
}
|
||||
|
||||
export async function createSession(title = '新对话', context: SessionContext = {}): Promise<SessionMeta> {
|
||||
|
||||
Reference in new issue
Block a user