Drafts
This commit is contained in:
@@ -28,6 +28,7 @@ import { cn } from "@/lib/utils";
|
|||||||
type Provider = "openai" | "anthropic" | "xai";
|
type Provider = "openai" | "anthropic" | "xai";
|
||||||
type AuthMode = "open" | "token";
|
type AuthMode = "open" | "token";
|
||||||
type SidebarSelection = { kind: "chat" | "search"; id: string };
|
type SidebarSelection = { kind: "chat" | "search"; id: string };
|
||||||
|
type DraftSelectionKind = "chat" | "search";
|
||||||
type SidebarItem = SidebarSelection & {
|
type SidebarItem = SidebarSelection & {
|
||||||
title: string;
|
title: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
@@ -132,6 +133,7 @@ export default function App() {
|
|||||||
const [selectedItem, setSelectedItem] = useState<SidebarSelection | null>(null);
|
const [selectedItem, setSelectedItem] = useState<SidebarSelection | null>(null);
|
||||||
const [selectedChat, setSelectedChat] = useState<ChatDetail | null>(null);
|
const [selectedChat, setSelectedChat] = useState<ChatDetail | null>(null);
|
||||||
const [selectedSearch, setSelectedSearch] = useState<SearchDetail | null>(null);
|
const [selectedSearch, setSelectedSearch] = useState<SearchDetail | null>(null);
|
||||||
|
const [draftKind, setDraftKind] = useState<DraftSelectionKind | null>(null);
|
||||||
const [isLoadingCollections, setIsLoadingCollections] = useState(false);
|
const [isLoadingCollections, setIsLoadingCollections] = useState(false);
|
||||||
const [isLoadingSelection, setIsLoadingSelection] = useState(false);
|
const [isLoadingSelection, setIsLoadingSelection] = useState(false);
|
||||||
const [isSending, setIsSending] = useState(false);
|
const [isSending, setIsSending] = useState(false);
|
||||||
@@ -163,6 +165,7 @@ export default function App() {
|
|||||||
setSelectedItem(null);
|
setSelectedItem(null);
|
||||||
setSelectedChat(null);
|
setSelectedChat(null);
|
||||||
setSelectedSearch(null);
|
setSelectedSearch(null);
|
||||||
|
setDraftKind(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshCollections = async (preferredSelection?: SidebarSelection) => {
|
const refreshCollections = async (preferredSelection?: SidebarSelection) => {
|
||||||
@@ -277,9 +280,9 @@ export default function App() {
|
|||||||
}, [isAuthenticated, selectedKey]);
|
}, [isAuthenticated, selectedKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedItem?.kind === "search") return;
|
if (draftKind === "search" || selectedItem?.kind === "search") return;
|
||||||
transcriptEndRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
|
transcriptEndRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
|
||||||
}, [selectedChat?.messages.length, isSending, selectedItem?.kind]);
|
}, [draftKind, selectedChat?.messages.length, isSending, selectedItem?.kind]);
|
||||||
|
|
||||||
const messages = selectedChat?.messages ?? [];
|
const messages = selectedChat?.messages ?? [];
|
||||||
|
|
||||||
@@ -294,6 +297,8 @@ export default function App() {
|
|||||||
}, [searches, selectedItem]);
|
}, [searches, selectedItem]);
|
||||||
|
|
||||||
const selectedTitle = useMemo(() => {
|
const selectedTitle = useMemo(() => {
|
||||||
|
if (draftKind === "chat") return "New chat";
|
||||||
|
if (draftKind === "search") return "New search";
|
||||||
if (!selectedItem) return "Sybil";
|
if (!selectedItem) return "Sybil";
|
||||||
if (selectedItem.kind === "chat") {
|
if (selectedItem.kind === "chat") {
|
||||||
if (selectedChat) return getChatTitle(selectedChat, selectedChat.messages);
|
if (selectedChat) return getChatTitle(selectedChat, selectedChat.messages);
|
||||||
@@ -303,69 +308,34 @@ export default function App() {
|
|||||||
if (selectedSearch) return getSearchTitle(selectedSearch);
|
if (selectedSearch) return getSearchTitle(selectedSearch);
|
||||||
if (selectedSearchSummary) return getSearchTitle(selectedSearchSummary);
|
if (selectedSearchSummary) return getSearchTitle(selectedSearchSummary);
|
||||||
return "New search";
|
return "New search";
|
||||||
}, [selectedChat, selectedChatSummary, selectedItem, selectedSearch, selectedSearchSummary]);
|
}, [draftKind, selectedChat, selectedChatSummary, selectedItem, selectedSearch, selectedSearchSummary]);
|
||||||
|
|
||||||
const isSearchMode = selectedItem?.kind === "search";
|
const isSearchMode = draftKind ? draftKind === "search" : selectedItem?.kind === "search";
|
||||||
const isSearchRunning = isSending && selectedItem?.kind === "search";
|
const isSearchRunning = isSending && selectedItem?.kind === "search";
|
||||||
|
|
||||||
const handleCreateChat = async () => {
|
const handleCreateChat = () => {
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
setDraftKind("chat");
|
||||||
const chat = await createChat();
|
setSelectedItem(null);
|
||||||
setSelectedItem({ kind: "chat", id: chat.id });
|
setSelectedChat(null);
|
||||||
setSelectedChat({
|
setSelectedSearch(null);
|
||||||
id: chat.id,
|
|
||||||
title: chat.title,
|
|
||||||
createdAt: chat.createdAt,
|
|
||||||
updatedAt: chat.updatedAt,
|
|
||||||
messages: [],
|
|
||||||
});
|
|
||||||
setSelectedSearch(null);
|
|
||||||
await refreshCollections({ kind: "chat", id: chat.id });
|
|
||||||
} catch (err) {
|
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
|
||||||
if (message.includes("bearer token")) {
|
|
||||||
handleAuthFailure(message);
|
|
||||||
} else {
|
|
||||||
setError(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateSearch = async () => {
|
const handleCreateSearch = () => {
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
setDraftKind("search");
|
||||||
const search = await createSearch();
|
setSelectedItem(null);
|
||||||
setSelectedItem({ kind: "search", id: search.id });
|
setSelectedChat(null);
|
||||||
setSelectedSearch({
|
setSelectedSearch(null);
|
||||||
id: search.id,
|
|
||||||
title: search.title,
|
|
||||||
query: search.query,
|
|
||||||
createdAt: search.createdAt,
|
|
||||||
updatedAt: search.updatedAt,
|
|
||||||
requestId: null,
|
|
||||||
latencyMs: null,
|
|
||||||
error: null,
|
|
||||||
results: [],
|
|
||||||
});
|
|
||||||
setSelectedChat(null);
|
|
||||||
await refreshCollections({ kind: "search", id: search.id });
|
|
||||||
} catch (err) {
|
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
|
||||||
if (message.includes("bearer token")) {
|
|
||||||
handleAuthFailure(message);
|
|
||||||
} else {
|
|
||||||
setError(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendChat = async (content: string) => {
|
const handleSendChat = async (content: string) => {
|
||||||
let chatId = selectedItem?.kind === "chat" ? selectedItem.id : null;
|
let chatId = draftKind === "chat" ? null : selectedItem?.kind === "chat" ? selectedItem.id : null;
|
||||||
|
|
||||||
if (!chatId) {
|
if (!chatId) {
|
||||||
const chat = await createChat();
|
const chat = await createChat();
|
||||||
chatId = chat.id;
|
chatId = chat.id;
|
||||||
|
setDraftKind(null);
|
||||||
setSelectedItem({ kind: "chat", id: chatId });
|
setSelectedItem({ kind: "chat", id: chatId });
|
||||||
setSelectedChat({
|
setSelectedChat({
|
||||||
id: chat.id,
|
id: chat.id,
|
||||||
@@ -433,11 +403,15 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSendSearch = async (query: string) => {
|
const handleSendSearch = async (query: string) => {
|
||||||
let searchId = selectedItem?.kind === "search" ? selectedItem.id : null;
|
let searchId = draftKind === "search" ? null : selectedItem?.kind === "search" ? selectedItem.id : null;
|
||||||
|
|
||||||
if (!searchId) {
|
if (!searchId) {
|
||||||
const search = await createSearch();
|
const search = await createSearch({
|
||||||
|
query,
|
||||||
|
title: query.slice(0, 80),
|
||||||
|
});
|
||||||
searchId = search.id;
|
searchId = search.id;
|
||||||
|
setDraftKind(null);
|
||||||
setSelectedItem({ kind: "search", id: searchId });
|
setSelectedItem({ kind: "search", id: searchId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,6 +516,7 @@ export default function App() {
|
|||||||
setSelectedItem(null);
|
setSelectedItem(null);
|
||||||
setSelectedChat(null);
|
setSelectedChat(null);
|
||||||
setSelectedSearch(null);
|
setSelectedSearch(null);
|
||||||
|
setDraftKind(null);
|
||||||
setComposer("");
|
setComposer("");
|
||||||
setError(null);
|
setError(null);
|
||||||
};
|
};
|
||||||
@@ -638,7 +613,10 @@ export default function App() {
|
|||||||
"mb-1 w-full rounded-lg px-3 py-2 text-left transition",
|
"mb-1 w-full rounded-lg px-3 py-2 text-left transition",
|
||||||
active ? "bg-slate-700 text-slate-50" : "text-slate-200 hover:bg-slate-800"
|
active ? "bg-slate-700 text-slate-50" : "text-slate-200 hover:bg-slate-800"
|
||||||
)}
|
)}
|
||||||
onClick={() => setSelectedItem({ kind: item.kind, id: item.id })}
|
onClick={() => {
|
||||||
|
setDraftKind(null);
|
||||||
|
setSelectedItem({ kind: item.kind, id: item.id });
|
||||||
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user