infio-copilot/src/ChatView.tsx
2025-03-23 09:34:44 +08:00

121 lines
3.3 KiB
TypeScript

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ItemView, WorkspaceLeaf } from 'obsidian'
import React from 'react'
import { Root, createRoot } from 'react-dom/client'
import Chat, { ChatProps, ChatRef } from './components/chat-view/Chat'
import { CHAT_VIEW_TYPE } from './constants'
import { AppProvider } from './contexts/AppContext'
import { DarkModeProvider } from './contexts/DarkModeContext'
import { DatabaseProvider } from './contexts/DatabaseContext'
import { DialogProvider } from './contexts/DialogContext'
import { DiffStrategyProvider } from './contexts/DiffStrategyContext'
import { LLMProvider } from './contexts/LLMContext'
import { RAGProvider } from './contexts/RAGContext'
import { SettingsProvider } from './contexts/SettingsContext'
import InfioPlugin from './main'
import { MentionableBlockData } from './types/mentionable'
import { InfioSettings } from './types/settings'
export class ChatView extends ItemView {
private root: Root | null = null
private settings: InfioSettings
private initialChatProps?: ChatProps
private chatRef: React.RefObject<ChatRef> = React.createRef()
constructor(
leaf: WorkspaceLeaf,
private plugin: InfioPlugin,
) {
super(leaf)
this.settings = plugin.settings
this.initialChatProps = plugin.initChatProps
}
getViewType() {
return CHAT_VIEW_TYPE
}
getIcon() {
return 'wand-sparkles'
}
getDisplayText() {
return 'Infio chat'
}
async onOpen() {
await this.render()
// Consume chatProps
this.initialChatProps = undefined
}
async onClose() {
this.root?.unmount()
}
async render() {
if (!this.root) {
this.root = createRoot(this.containerEl.children[1])
}
const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 0, // Immediately garbage collect queries. It prevents memory leak on ChatView close.
},
mutations: {
gcTime: 0, // Immediately garbage collect mutations. It prevents memory leak on ChatView close.
},
},
})
this.root.render(
<AppProvider app={this.app}>
<SettingsProvider
settings={this.settings}
setSettings={(newSettings) => this.plugin.setSettings(newSettings)}
addSettingsChangeListener={(listener) =>
this.plugin.addSettingsListener(listener)
}
>
<DarkModeProvider>
<LLMProvider>
<DatabaseProvider
getDatabaseManager={() => this.plugin.getDbManager()}
>
<DiffStrategyProvider diffStrategy={this.plugin.diffStrategy}>
<RAGProvider getRAGEngine={() => this.plugin.getRAGEngine()}>
<QueryClientProvider client={queryClient}>
<React.StrictMode>
<DialogProvider
container={this.containerEl.children[1] as HTMLElement}
>
<Chat ref={this.chatRef} {...this.initialChatProps} />
</DialogProvider>
</React.StrictMode>
</QueryClientProvider>
</RAGProvider>
</DiffStrategyProvider>
</DatabaseProvider>
</LLMProvider>
</DarkModeProvider>
</SettingsProvider>
</AppProvider>,
)
}
openNewChat(selectedBlock?: MentionableBlockData) {
this.chatRef.current?.openNewChat(selectedBlock)
}
addSelectionToChat(selectedBlock: MentionableBlockData) {
this.chatRef.current?.addSelectionToChat(selectedBlock)
}
focusMessage() {
this.chatRef.current?.focusMessage()
}
}