233 lines
6.7 KiB
JavaScript
233 lines
6.7 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import ChatWindow from './components/ChatWindow';
|
|
import InfoPanel from './components/InfoPanel';
|
|
import Sidebar from './components/Sidebar';
|
|
import HomeView from './components/HomeView';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import { getModelProps } from './api/orchestration';
|
|
|
|
/*** View Panels*** */
|
|
import AllChatsView from './components/AllChatsView';
|
|
import AllProjectsView from './components/AllProjectsView';
|
|
import SettingsView from './components/SettingsView';
|
|
import ProjectView from './components/ProjectView';
|
|
import MemoryView from './components/MemoryView';
|
|
import SummaryView from './components/SummaryView';
|
|
|
|
/**** useHooks **** */
|
|
import { useSession } from './hooks/useSession';
|
|
import { useChat } from './hooks/useChat';
|
|
import { useModels } from './hooks/useModels';
|
|
import { useProjects } from './hooks/useProjects';
|
|
|
|
// Views where back nav makes sense, and where they go back to
|
|
const BACK_MAP = {
|
|
'chat': 'home',
|
|
'all-chats': 'home',
|
|
'all-projects': 'home',
|
|
'settings': 'home',
|
|
'project': 'all-projects',
|
|
'memory': 'settings',
|
|
'summaries': 'chat',
|
|
};
|
|
|
|
export default function App() {
|
|
const [leftOpen, setLeftOpen] = useState(false); // collapsed on home
|
|
const [rightOpen, setRightOpen] = useState(false);
|
|
const { models, selectedModel, setSelectedModel } = useModels();
|
|
const [view, setView] = useState('home');
|
|
const [viewHistory, setViewHistory] = useState([]);
|
|
const [activeProject, setActiveProject] = useState(null);
|
|
const { projects, refreshProjects } = useProjects();
|
|
|
|
// Lifted model props — available to header + SettingsView
|
|
const [modelProps, setModelProps] = useState(null);
|
|
useEffect(() => {
|
|
getModelProps().then(setModelProps).catch(() => {});
|
|
}, []);
|
|
|
|
const {
|
|
sessions,
|
|
setSessions,
|
|
activeSession,
|
|
messages,
|
|
loadingHistory,
|
|
selectSession,
|
|
createSession,
|
|
refreshSessions,
|
|
appendMessage,
|
|
updateLastMessage,
|
|
} = useSession();
|
|
|
|
const {
|
|
sendMessage,
|
|
cancelStream,
|
|
streaming,
|
|
lastTokenCount,
|
|
lastModel,
|
|
useChat,
|
|
} = useChat({ activeSession, appendMessage, updateLastMessage, refreshSessions });
|
|
|
|
function navigate(nextView) {
|
|
setViewHistory(prev => [...prev, view]);
|
|
setView(nextView);
|
|
// Expand sidebar when leaving home
|
|
if (view === 'home') setLeftOpen(true);
|
|
}
|
|
|
|
function goBack() {
|
|
if (viewHistory.length > 0) {
|
|
const prev = viewHistory[viewHistory.length - 1];
|
|
setViewHistory(h => h.slice(0, -1));
|
|
setView(prev);
|
|
if (prev === 'home') setLeftOpen(false);
|
|
} else {
|
|
// Fallback to BACK_MAP
|
|
const dest = BACK_MAP[view] ?? 'home';
|
|
setView(dest);
|
|
if (dest === 'home') setLeftOpen(false);
|
|
}
|
|
}
|
|
|
|
function handleSendMessage(text) {
|
|
sendMessage(text, selectedModel, activeSession?.project_id ?? null);
|
|
}
|
|
|
|
function handleSessionsChange(deletedSession) {
|
|
if (deletedSession?.external_id === activeSession?.external_id) {
|
|
selectSession(null);
|
|
}
|
|
refreshSessions();
|
|
}
|
|
|
|
// Home: create session, navigate to chat, then send after a tick
|
|
function handleHomeSend(text) {
|
|
const newSession = createSession(); // ← capture the returned session
|
|
setViewHistory(prev => [...prev, 'home']);
|
|
setView('chat');
|
|
setLeftOpen(true);
|
|
sendMessage(text, selectedModel, null, newSession); // ← pass directly, no setTimeout needed
|
|
}
|
|
|
|
function handleNewProjectChat(text) {
|
|
const newSession = {
|
|
external_id: uuidv4(),
|
|
metadata: null,
|
|
isNew: true,
|
|
project_id: activeProject?.id ?? null,
|
|
};
|
|
setSessions(prev => [newSession, ...prev]);
|
|
selectSession(newSession);
|
|
setViewHistory(prev => [...prev, view]);
|
|
setView('chat');
|
|
setLeftOpen(true);
|
|
sendMessage(text, selectedModel, activeProject?.id ?? null, newSession); // ← direct, no timeout
|
|
}
|
|
|
|
const canGoBack = view !== 'home';
|
|
|
|
return (
|
|
<div style={{ display: 'flex', height: '100vh', overflow: 'hidden' }}>
|
|
<Sidebar
|
|
sessions={sessions}
|
|
activeSession={activeSession}
|
|
onSelectSession={session => { selectSession(session); navigate('chat'); }}
|
|
onNewChat={() => { createSession(); navigate('chat'); }}
|
|
onNewProject={() => navigate('all-projects')}
|
|
isOpen={leftOpen}
|
|
onToggle={() => setLeftOpen(o => !o)}
|
|
onSessionsChange={handleSessionsChange}
|
|
onNavigate={navigate}
|
|
projects={projects}
|
|
onProjectsChange={refreshProjects}
|
|
onSelectProject={setActiveProject}
|
|
/>
|
|
|
|
{view === 'home' && (
|
|
<HomeView
|
|
onSendMessage={handleHomeSend}
|
|
loadedModel={modelProps?.modelAlias ?? null}
|
|
/>
|
|
)}
|
|
|
|
{view === 'chat' && (
|
|
<ChatWindow
|
|
messages={messages}
|
|
loadingHistory={loadingHistory}
|
|
streaming={streaming}
|
|
activeSession={activeSession}
|
|
onSendMessage={handleSendMessage}
|
|
onCancel={cancelStream}
|
|
onTogglePanel={() => setRightOpen(o => !o)}
|
|
onBack={goBack}
|
|
canGoBack={canGoBack}
|
|
loadedModel={modelProps?.modelAlias ?? null}
|
|
summarising={summarising}
|
|
/>
|
|
)}
|
|
|
|
{view === 'all-chats' && (
|
|
<AllChatsView
|
|
onBack={goBack}
|
|
onSelectSession={session => { selectSession(session); navigate('chat'); }}
|
|
projects={projects}
|
|
/>
|
|
)}
|
|
|
|
{view === 'all-projects' && (
|
|
<AllProjectsView
|
|
onBack={goBack}
|
|
onProjectsChange={refreshProjects}
|
|
onSelectProject={setActiveProject}
|
|
onNavigate={navigate}
|
|
/>
|
|
)}
|
|
|
|
{view === 'settings' && (
|
|
<SettingsView
|
|
onNavigate={navigate}
|
|
onBack={goBack}
|
|
modelProps={modelProps}
|
|
/>
|
|
)}
|
|
|
|
{view === 'project' && activeProject && (
|
|
<ProjectView
|
|
project={activeProject}
|
|
onNavigate={navigate}
|
|
onBack={goBack}
|
|
onSelectSession={selectSession}
|
|
onNewProjectChat={handleNewProjectChat}
|
|
onProjectsChange={refreshProjects} // ← add
|
|
/>
|
|
)}
|
|
|
|
{view === 'memory' && (
|
|
<MemoryView
|
|
onNavigate={navigate}
|
|
onBack={goBack}
|
|
/>
|
|
)}
|
|
|
|
{view === 'summaries' && (
|
|
<SummaryView
|
|
activeSession={activeSession}
|
|
onBack={goBack}
|
|
/>
|
|
)}
|
|
|
|
<InfoPanel
|
|
isOpen={rightOpen}
|
|
onToggle={() => setRightOpen(o => !o)}
|
|
activeSession={activeSession}
|
|
models={models}
|
|
selectedModel={selectedModel}
|
|
onModelChange={setSelectedModel}
|
|
lastModel={lastModel}
|
|
lastTokenCount={lastTokenCount}
|
|
summarising={summarising}
|
|
onViewSummary={() => navigate('summaries')}
|
|
/>
|
|
</div>
|
|
);
|
|
} |