Initial ForgeLM import
This commit is contained in:
commit
a392b9dc60
4296 files changed
+1212675
No files matched your search
@@ -0,0 +1,105 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import Sidebar from "./components/Sidebar";
|
||||
import ChatView from "./components/ChatView";
|
||||
import { useDB } from "./hooks/useDB";
|
||||
import { useModels } from "./hooks/useModels";
|
||||
import { useRuntimeManager } from "./features/runtime/useRuntimeManager";
|
||||
import { useRuntimeReadyModelRefresh } from "./features/runtime/useRuntimeReadyModelRefresh";
|
||||
import type { Chat } from "./lib/types";
|
||||
import "./App.css";
|
||||
|
||||
export default function App() {
|
||||
const { db, ready } = useDB();
|
||||
const [currentChatId, setCurrentChatId] = useState<number | null>(null);
|
||||
const [chats, setChats] = useState<Chat[]>([]);
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
const runtime = useRuntimeManager();
|
||||
const { models, selectedModel, setSelectedModel, status, refresh: refreshModels } = useModels(
|
||||
runtime.connection.serverUrl,
|
||||
runtime.connection.apiKey,
|
||||
Boolean(runtime.connection.serverUrl),
|
||||
);
|
||||
|
||||
useRuntimeReadyModelRefresh(runtime.snapshot.status, refreshModels);
|
||||
|
||||
const loadChats = useCallback(() => {
|
||||
if (!db) return;
|
||||
const rows = db.query<Chat>("SELECT * FROM chats ORDER BY updated_at DESC");
|
||||
setChats(rows);
|
||||
}, [db]);
|
||||
|
||||
useEffect(() => { loadChats(); }, [loadChats]);
|
||||
|
||||
const newChat = useCallback(() => {
|
||||
if (!db) return;
|
||||
const id = db.insert("INSERT INTO chats (title) VALUES ('New Chat')");
|
||||
if (id > 0) {
|
||||
setCurrentChatId(id);
|
||||
setSidebarOpen(false);
|
||||
loadChats();
|
||||
}
|
||||
}, [db, loadChats]);
|
||||
|
||||
const deleteChat = useCallback((id: number) => {
|
||||
if (!db) return;
|
||||
if (!window.confirm("Delete this conversation and all of its messages?")) return;
|
||||
db.run("DELETE FROM chats WHERE id = ?", [id]);
|
||||
if (currentChatId === id) setCurrentChatId(null);
|
||||
setSidebarOpen(false);
|
||||
loadChats();
|
||||
}, [db, currentChatId, loadChats]);
|
||||
|
||||
const handleSelectChat = useCallback((id: number) => {
|
||||
setCurrentChatId(id);
|
||||
setSidebarOpen(false);
|
||||
}, []);
|
||||
|
||||
if (!ready) {
|
||||
return (
|
||||
<div className="app-loading">
|
||||
<div className="loading-spinner" />
|
||||
<span>Initializing…</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`app-layout${sidebarOpen ? " sidebar-open" : ""}`}>
|
||||
<Sidebar
|
||||
chats={chats}
|
||||
currentChatId={currentChatId}
|
||||
onSelectChat={handleSelectChat}
|
||||
onNewChat={newChat}
|
||||
onDeleteChat={deleteChat}
|
||||
models={models}
|
||||
selectedModel={selectedModel}
|
||||
onModelChange={setSelectedModel}
|
||||
status={status}
|
||||
onRefreshModels={refreshModels}
|
||||
runtime={runtime}
|
||||
onCloseMobile={() => setSidebarOpen(false)}
|
||||
/>
|
||||
{sidebarOpen && (
|
||||
<button
|
||||
type="button"
|
||||
className="app-sidebar-backdrop"
|
||||
aria-label="Close navigation"
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
/>
|
||||
)}
|
||||
<div className="app-main">
|
||||
<ChatView
|
||||
db={db!}
|
||||
chatId={currentChatId}
|
||||
server={runtime.connection.serverUrl}
|
||||
apiKey={runtime.connection.apiKey}
|
||||
model={selectedModel}
|
||||
onChatCreated={(id) => { setCurrentChatId(id); loadChats(); setSidebarOpen(false); }}
|
||||
onChatUpdated={loadChats}
|
||||
onOpenSidebar={() => setSidebarOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user