mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-16 20:32:00 +08:00
fix: normalize project session payloads
The sidebar had to understand cursorSessions, codexSessions, and other provider buckets because /api/projects exposed provider-shaped arrays. That leaked backend adapter storage into project state and made frontend behavior drift each time a provider needed another bucket or exception. Return one sessions list with provider metadata instead. Project state, search, and running-session filtering now share one contract, while provider-specific storage remains behind the backend boundary.
This commit is contained in:
@@ -30,10 +30,6 @@ type ProjectApiView = {
|
||||
isArchived: boolean;
|
||||
isStarred: boolean;
|
||||
sessions: [];
|
||||
cursorSessions: [];
|
||||
codexSessions: [];
|
||||
geminiSessions: [];
|
||||
opencodeSessions: [];
|
||||
sessionMeta: {
|
||||
hasMore: false;
|
||||
total: 0;
|
||||
@@ -82,10 +78,6 @@ function mapProjectRowToApiView(projectRow: ProjectRepositoryRow): ProjectApiVie
|
||||
isArchived: Boolean(projectRow.isArchived),
|
||||
isStarred: Boolean(projectRow.isStarred),
|
||||
sessions: [],
|
||||
cursorSessions: [],
|
||||
codexSessions: [],
|
||||
geminiSessions: [],
|
||||
opencodeSessions: [],
|
||||
sessionMeta: {
|
||||
hasMore: false,
|
||||
total: 0,
|
||||
|
||||
@@ -9,13 +9,12 @@ import { AppError } from '@/shared/utils.js';
|
||||
|
||||
type SessionSummary = {
|
||||
id: string;
|
||||
provider: string;
|
||||
summary: string;
|
||||
messageCount: number;
|
||||
lastActivity: string;
|
||||
};
|
||||
|
||||
type SessionsByProvider = Record<'claude' | 'cursor' | 'codex' | 'gemini' | 'opencode', SessionSummary[]>;
|
||||
|
||||
type SessionRepositoryRow = {
|
||||
provider: string;
|
||||
session_id: string;
|
||||
@@ -31,10 +30,6 @@ export type ProjectListItem = {
|
||||
fullPath: string;
|
||||
isStarred: boolean;
|
||||
sessions: SessionSummary[];
|
||||
cursorSessions: SessionSummary[];
|
||||
codexSessions: SessionSummary[];
|
||||
geminiSessions: SessionSummary[];
|
||||
opencodeSessions: SessionSummary[];
|
||||
sessionMeta: {
|
||||
hasMore: boolean;
|
||||
total: number;
|
||||
@@ -64,7 +59,7 @@ type SessionPaginationOptions = {
|
||||
};
|
||||
|
||||
type ProjectSessionsPageResult = {
|
||||
sessionsByProvider: SessionsByProvider;
|
||||
sessions: SessionSummary[];
|
||||
total: number;
|
||||
hasMore: boolean;
|
||||
};
|
||||
@@ -72,10 +67,6 @@ type ProjectSessionsPageResult = {
|
||||
export type ProjectSessionsPageApiView = {
|
||||
projectId: string;
|
||||
sessions: SessionSummary[];
|
||||
cursorSessions: SessionSummary[];
|
||||
codexSessions: SessionSummary[];
|
||||
geminiSessions: SessionSummary[];
|
||||
opencodeSessions: SessionSummary[];
|
||||
sessionMeta: {
|
||||
hasMore: boolean;
|
||||
total: number;
|
||||
@@ -129,39 +120,18 @@ function normalizeSessionPagination(options: SessionPaginationOptions = {}): { l
|
||||
function mapSessionRowToSummary(row: SessionRepositoryRow): SessionSummary {
|
||||
return {
|
||||
id: row.session_id,
|
||||
provider: row.provider,
|
||||
summary: row.custom_name || '',
|
||||
messageCount: 0,
|
||||
lastActivity: row.updated_at ?? row.created_at ?? new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
function bucketSessionRowsByProvider(rows: SessionRepositoryRow[]): SessionsByProvider {
|
||||
const byProvider: SessionsByProvider = {
|
||||
claude: [],
|
||||
cursor: [],
|
||||
codex: [],
|
||||
gemini: [],
|
||||
opencode: [],
|
||||
};
|
||||
|
||||
for (const row of rows) {
|
||||
const provider = row.provider as keyof SessionsByProvider;
|
||||
const bucket = byProvider[provider];
|
||||
if (!bucket) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bucket.push(mapSessionRowToSummary(row));
|
||||
}
|
||||
|
||||
return byProvider;
|
||||
}
|
||||
|
||||
function readProjectSessionsIncludingArchived(projectPath: string): ProjectSessionsPageResult {
|
||||
const rows = sessionsDb.getSessionsByProjectPathIncludingArchived(projectPath) as SessionRepositoryRow[];
|
||||
|
||||
return {
|
||||
sessionsByProvider: bucketSessionRowsByProvider(rows),
|
||||
sessions: rows.map(mapSessionRowToSummary),
|
||||
total: rows.length,
|
||||
hasMore: false,
|
||||
};
|
||||
@@ -183,7 +153,7 @@ function readProjectSessionsPageByPath(
|
||||
const total = sessionsDb.countSessionsByProjectPath(projectPath);
|
||||
|
||||
return {
|
||||
sessionsByProvider: bucketSessionRowsByProvider(rows),
|
||||
sessions: rows.map(mapSessionRowToSummary),
|
||||
total,
|
||||
hasMore: pagination.offset + rows.length < total,
|
||||
};
|
||||
@@ -205,7 +175,7 @@ function broadcastProgress(progress: ProgressUpdate) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all projects from DB and returns provider-bucketed session summaries.
|
||||
* Reads all projects from DB and returns normalized session summaries.
|
||||
*/
|
||||
export async function getProjectsWithSessions(
|
||||
options: GetProjectsWithSessionsOptions = {}
|
||||
@@ -253,11 +223,7 @@ export async function getProjectsWithSessions(
|
||||
displayName,
|
||||
fullPath: projectPath,
|
||||
isStarred: Boolean(row.isStarred),
|
||||
sessions: sessionsPage.sessionsByProvider.claude,
|
||||
cursorSessions: sessionsPage.sessionsByProvider.cursor,
|
||||
codexSessions: sessionsPage.sessionsByProvider.codex,
|
||||
geminiSessions: sessionsPage.sessionsByProvider.gemini,
|
||||
opencodeSessions: sessionsPage.sessionsByProvider.opencode,
|
||||
sessions: sessionsPage.sessions,
|
||||
sessionMeta: {
|
||||
hasMore: sessionsPage.hasMore,
|
||||
total: sessionsPage.total,
|
||||
@@ -310,11 +276,7 @@ export async function getArchivedProjectsWithSessions(
|
||||
fullPath: row.project_path,
|
||||
isStarred: Boolean(row.isStarred),
|
||||
isArchived: true,
|
||||
sessions: sessionsPage.sessionsByProvider.claude,
|
||||
cursorSessions: sessionsPage.sessionsByProvider.cursor,
|
||||
codexSessions: sessionsPage.sessionsByProvider.codex,
|
||||
geminiSessions: sessionsPage.sessionsByProvider.gemini,
|
||||
opencodeSessions: sessionsPage.sessionsByProvider.opencode,
|
||||
sessions: sessionsPage.sessions,
|
||||
sessionMeta: {
|
||||
hasMore: sessionsPage.hasMore,
|
||||
total: sessionsPage.total,
|
||||
@@ -343,11 +305,7 @@ export async function getProjectSessionsPage(
|
||||
const sessionsPage = readProjectSessionsPageByPath(projectRow.project_path, options);
|
||||
return {
|
||||
projectId: projectRow.project_id,
|
||||
sessions: sessionsPage.sessionsByProvider.claude,
|
||||
cursorSessions: sessionsPage.sessionsByProvider.cursor,
|
||||
codexSessions: sessionsPage.sessionsByProvider.codex,
|
||||
geminiSessions: sessionsPage.sessionsByProvider.gemini,
|
||||
opencodeSessions: sessionsPage.sessionsByProvider.opencode,
|
||||
sessions: sessionsPage.sessions,
|
||||
sessionMeta: {
|
||||
hasMore: sessionsPage.hasMore,
|
||||
total: sessionsPage.total,
|
||||
|
||||
Reference in New Issue
Block a user