|
|
@ -493,7 +493,7 @@ export default function ChatPage() {
|
|
|
|
<Tabs.Tab value="fact-triggers">Fact Triggers</Tabs.Tab>
|
|
|
|
<Tabs.Tab value="fact-triggers">Fact Triggers</Tabs.Tab>
|
|
|
|
</Tabs.List>
|
|
|
|
</Tabs.List>
|
|
|
|
<Tabs.Panel value="message">
|
|
|
|
<Tabs.Panel value="message">
|
|
|
|
<Messages messages={messages || []} />
|
|
|
|
<Messages />
|
|
|
|
<Textarea
|
|
|
|
<Textarea
|
|
|
|
resize="vertical"
|
|
|
|
resize="vertical"
|
|
|
|
placeholder="Type your message here..."
|
|
|
|
placeholder="Type your message here..."
|
|
|
@ -670,12 +670,92 @@ export default function ChatPage() {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function Messages({
|
|
|
|
function Messages() {
|
|
|
|
messages,
|
|
|
|
|
|
|
|
}: {
|
|
|
|
|
|
|
|
messages: Array<DraftMessage | CommittedMessage>;
|
|
|
|
|
|
|
|
}) {
|
|
|
|
|
|
|
|
const theme = useMantineTheme();
|
|
|
|
const theme = useMantineTheme();
|
|
|
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
const trpc = useTRPC();
|
|
|
|
|
|
|
|
const pageContext = usePageContext();
|
|
|
|
|
|
|
|
const conversationId = pageContext.routeParams.id;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const messagesResult = useQuery(
|
|
|
|
|
|
|
|
trpc.chat.messages.fetchByConversationId.queryOptions({
|
|
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
const messages: Array<DraftMessage | CommittedMessage> | undefined =
|
|
|
|
|
|
|
|
messagesResult.data?.map((m) => ({
|
|
|
|
|
|
|
|
...m,
|
|
|
|
|
|
|
|
parts: m.parts.filter((p) => p.type === "text"),
|
|
|
|
|
|
|
|
})) || [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const deleteMessage = useMutation(
|
|
|
|
|
|
|
|
trpc.chat.messages.deleteOne.mutationOptions({
|
|
|
|
|
|
|
|
onMutate: async ({ id: messageIdToDelete }) => {
|
|
|
|
|
|
|
|
/** Cancel affected queries that may be in-flight: */
|
|
|
|
|
|
|
|
await queryClient.cancelQueries({
|
|
|
|
|
|
|
|
queryKey: trpc.chat.messages.fetchByConversationId.queryKey({
|
|
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Optimistically update the affected queries in react-query's cache: */
|
|
|
|
|
|
|
|
const previousMessages = await queryClient.getQueryData(
|
|
|
|
|
|
|
|
trpc.chat.messages.fetchByConversationId.queryKey({
|
|
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!previousMessages) {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
previousMessages: [],
|
|
|
|
|
|
|
|
newMessages: [],
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const newMessages = previousMessages.filter(
|
|
|
|
|
|
|
|
(m: CommittedMessage) => m.id !== messageIdToDelete
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
queryClient.setQueryData(
|
|
|
|
|
|
|
|
trpc.chat.messages.fetchByConversationId.queryKey({
|
|
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
newMessages
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { previousMessages, newMessages };
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
onSettled: async (data, variables, context) => {
|
|
|
|
|
|
|
|
await queryClient.invalidateQueries({
|
|
|
|
|
|
|
|
queryKey: trpc.chat.messages.fetchByConversationId.queryKey({
|
|
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
onError: async (error, variables, context) => {
|
|
|
|
|
|
|
|
console.error(error);
|
|
|
|
|
|
|
|
if (!context) return;
|
|
|
|
|
|
|
|
queryClient.setQueryData(
|
|
|
|
|
|
|
|
trpc.chat.messages.fetchByConversationId.queryKey({
|
|
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
context.previousMessages
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleDeleteMessage(message: DraftMessage | CommittedMessage) {
|
|
|
|
|
|
|
|
// If the message does not have an id, do nothing
|
|
|
|
|
|
|
|
if (!("id" in message) || !message.id) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Delete the message from the server using the mutation
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
await deleteMessage.mutateAsync({ id: message.id });
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error("Failed to delete message:", error);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<Stack gap="md" justify="flex-start">
|
|
|
|
<Stack gap="md" justify="flex-start">
|
|
|
|
{messages.map((message, index) => (
|
|
|
|
{messages.map((message, index) => (
|
|
|
@ -708,16 +788,17 @@ function Messages({
|
|
|
|
</HoverCard.Target>
|
|
|
|
</HoverCard.Target>
|
|
|
|
<HoverCard.Dropdown>
|
|
|
|
<HoverCard.Dropdown>
|
|
|
|
<ActionIcon.Group>
|
|
|
|
<ActionIcon.Group>
|
|
|
|
<ActionIcon size="lg" variant="filled" color="red">
|
|
|
|
<ActionIcon
|
|
|
|
<IconTrash
|
|
|
|
size="lg"
|
|
|
|
size={16}
|
|
|
|
variant="filled"
|
|
|
|
stroke={1.5}
|
|
|
|
color="red"
|
|
|
|
onClick={(e) => {
|
|
|
|
onClick={(e) => {
|
|
|
|
e.stopPropagation();
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
e.preventDefault();
|
|
|
|
// handleDeleteMessage(message.id);
|
|
|
|
handleDeleteMessage(message);
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
>
|
|
|
|
|
|
|
|
<IconTrash size={16} stroke={1.5} />
|
|
|
|
</ActionIcon>
|
|
|
|
</ActionIcon>
|
|
|
|
</ActionIcon.Group>
|
|
|
|
</ActionIcon.Group>
|
|
|
|
</HoverCard.Dropdown>
|
|
|
|
</HoverCard.Dropdown>
|
|
|
|