mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-01 17:02:29 -07:00
feat(ui): build interactive session browser component (#13351)
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user