feat(ui): build interactive session browser component (#13351)

This commit is contained in:
bl-ue
2025-11-21 09:16:56 -07:00
committed by GitHub
parent 3370644ffe
commit b97661553f
9 changed files with 1907 additions and 604 deletions

View File

@@ -4,11 +4,110 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { useState, useCallback } from 'react';
import type { HistoryItemWithoutId } from '../types.js';
import type { ConversationRecord } from '@google/gemini-cli-core';
import * as fs from 'node:fs/promises';
import path from 'node:path';
import type {
Config,
ConversationRecord,
ResumedSessionData,
} from '@google/gemini-cli-core';
import type { Part } from '@google/genai';
import { partListUnionToString } from '@google/gemini-cli-core';
import type { SessionInfo } from '../../utils/sessionUtils.js';
import { MessageType, ToolCallStatus } from '../types.js';
export const useSessionBrowser = (
config: Config,
onLoadHistory: (
uiHistory: HistoryItemWithoutId[],
clientHistory: Array<{ role: 'user' | 'model'; parts: Part[] }>,
resumedSessionData: ResumedSessionData,
) => void,
) => {
const [isSessionBrowserOpen, setIsSessionBrowserOpen] = useState(false);
return {
isSessionBrowserOpen,
openSessionBrowser: useCallback(() => {
setIsSessionBrowserOpen(true);
}, []),
closeSessionBrowser: useCallback(() => {
setIsSessionBrowserOpen(false);
}, []),
/**
* Loads a conversation by ID, and reinitializes the chat recording service with it.
*/
handleResumeSession: useCallback(
async (session: SessionInfo) => {
try {
const chatsDir = path.join(
config.storage.getProjectTempDir(),
'chats',
);
const fileName = session.fileName;
const originalFilePath = path.join(chatsDir, fileName);
// Load up the conversation.
const conversation: ConversationRecord = JSON.parse(
await fs.readFile(originalFilePath, 'utf8'),
);
// Use the old session's ID to continue it.
const existingSessionId = conversation.sessionId;
config.setSessionId(existingSessionId);
const resumedSessionData = {
conversation,
filePath: originalFilePath,
};
// We've loaded it; tell the UI about it.
setIsSessionBrowserOpen(false);
const historyData = convertSessionToHistoryFormats(
conversation.messages,
);
onLoadHistory(
historyData.uiHistory,
historyData.clientHistory,
resumedSessionData,
);
} catch (error) {
console.error('Error resuming session:', error);
setIsSessionBrowserOpen(false);
}
},
[config, onLoadHistory],
),
/**
* Deletes a session by ID using the ChatRecordingService.
*/
handleDeleteSession: useCallback(
(session: SessionInfo) => {
try {
const chatRecordingService = config
.getGeminiClient()
?.getChatRecordingService();
if (chatRecordingService) {
chatRecordingService.deleteSession(session.id);
}
} catch (error) {
console.error('Error deleting session:', error);
throw error;
}
},
[config],
),
};
};
/**
* Converts session/conversation data into UI history and Gemini client history formats.
*/