update, use json database replace pglite, for sync
This commit is contained in:
@@ -4,20 +4,19 @@ import { InitialEditorStateType } from '@lexical/react/LexicalComposer'
|
||||
import { $getRoot, $insertNodes, LexicalEditor } from 'lexical'
|
||||
import { Pencil, Search, Trash2 } from 'lucide-react'
|
||||
import { Notice } from 'obsidian'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
// import { v4 as uuidv4 } from 'uuid'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
import { lexicalNodeToPlainText } from '../../components/chat-view/chat-input/utils/editor-state-to-plain-text'
|
||||
import { useDatabase } from '../../contexts/DatabaseContext'
|
||||
import { DBManager } from '../../database/database-manager'
|
||||
import { TemplateContent } from '../../database/schema'
|
||||
import { useCommands } from '../../hooks/use-commands'
|
||||
|
||||
import LexicalContentEditable from './chat-input/LexicalContentEditable'
|
||||
|
||||
|
||||
export interface QuickCommand {
|
||||
id: string
|
||||
name: string
|
||||
content: TemplateContent
|
||||
contentText: string
|
||||
createdAt: Date | undefined
|
||||
updatedAt: Date | undefined
|
||||
}
|
||||
@@ -29,30 +28,12 @@ const CommandsView = (
|
||||
selectedSerializedNodes?: BaseSerializedNode[]
|
||||
}
|
||||
) => {
|
||||
const [commands, setCommands] = useState<QuickCommand[]>([])
|
||||
|
||||
const { getDatabaseManager } = useDatabase()
|
||||
const getManager = useCallback(async (): Promise<DBManager> => {
|
||||
return await getDatabaseManager()
|
||||
}, [getDatabaseManager])
|
||||
|
||||
// init get all commands
|
||||
const fetchCommands = useCallback(async () => {
|
||||
const dbManager = await getManager()
|
||||
dbManager.getCommandManager().getAllCommands((rows) => {
|
||||
setCommands(rows.map((row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
content: row.content,
|
||||
createdAt: row.createdAt,
|
||||
updatedAt: row.updatedAt,
|
||||
})))
|
||||
})
|
||||
}, [getManager])
|
||||
|
||||
useEffect(() => {
|
||||
void fetchCommands()
|
||||
}, [fetchCommands])
|
||||
const {
|
||||
createCommand,
|
||||
deleteCommand,
|
||||
updateCommand,
|
||||
commandList,
|
||||
} = useCommands()
|
||||
|
||||
// new command name
|
||||
const [newCommandName, setNewCommandName] = useState('')
|
||||
@@ -66,13 +47,13 @@ const CommandsView = (
|
||||
const nameInputRefs = useRef<Map<string, HTMLInputElement>>(new Map())
|
||||
const contentEditorRefs = useRef<Map<string, LexicalEditor>>(new Map())
|
||||
|
||||
// 为每个正在编辑的命令创建refs
|
||||
// create refs for each command
|
||||
const commandEditRefs = useRef<Map<string, {
|
||||
editorRef: React.RefObject<LexicalEditor>,
|
||||
contentEditableRef: React.RefObject<HTMLDivElement>
|
||||
}>>(new Map());
|
||||
|
||||
// 获取或创建命令编辑refs
|
||||
// get or create command edit refs
|
||||
const getCommandEditRefs = useCallback((id: string) => {
|
||||
if (!commandEditRefs.current.has(id)) {
|
||||
commandEditRefs.current.set(id, {
|
||||
@@ -94,7 +75,7 @@ const CommandsView = (
|
||||
return refs;
|
||||
}, []);
|
||||
|
||||
// 当编辑状态改变时更新refs
|
||||
// update command edit refs when editing command id changes
|
||||
useEffect(() => {
|
||||
if (editingCommandId) {
|
||||
const refs = getCommandEditRefs(editingCommandId);
|
||||
@@ -133,25 +114,20 @@ const CommandsView = (
|
||||
new Notice('Please enter a name for your template')
|
||||
return
|
||||
}
|
||||
const dbManager = await getManager()
|
||||
dbManager.getCommandManager().createCommand({
|
||||
name: newCommandName,
|
||||
content: { nodes },
|
||||
})
|
||||
|
||||
await createCommand(newCommandName, { nodes })
|
||||
|
||||
// clear editor content
|
||||
editorRef.current.update(() => {
|
||||
const root = $getRoot()
|
||||
root.clear()
|
||||
})
|
||||
|
||||
setNewCommandName('')
|
||||
}
|
||||
|
||||
// delete command
|
||||
const handleDeleteCommand = async (id: string) => {
|
||||
const dbManager = await getManager()
|
||||
await dbManager.getCommandManager().deleteCommand(id)
|
||||
await deleteCommand(id)
|
||||
}
|
||||
|
||||
// edit command
|
||||
@@ -173,11 +149,11 @@ const CommandsView = (
|
||||
new Notice('Please enter a content for your template')
|
||||
return
|
||||
}
|
||||
const dbManager = await getManager()
|
||||
await dbManager.getCommandManager().updateCommand(id, {
|
||||
name: nameInput.value,
|
||||
content: { nodes },
|
||||
})
|
||||
await updateCommand(
|
||||
id,
|
||||
nameInput.value,
|
||||
{ nodes },
|
||||
)
|
||||
setEditingCommandId(null)
|
||||
}
|
||||
|
||||
@@ -187,11 +163,16 @@ const CommandsView = (
|
||||
}
|
||||
|
||||
// filter commands list
|
||||
const filteredCommands = commands.filter(
|
||||
command =>
|
||||
command.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
command.content.nodes.map(lexicalNodeToPlainText).join('').toLowerCase().includes(searchTerm.toLowerCase())
|
||||
)
|
||||
const filteredCommands = useMemo(() => {
|
||||
if (!searchTerm.trim()) {
|
||||
return commandList;
|
||||
}
|
||||
return commandList.filter(
|
||||
command =>
|
||||
command.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
command.contentText.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
}, [commandList, searchTerm]);
|
||||
|
||||
const getCommandEditorState = (commandContent: TemplateContent): InitialEditorStateType => {
|
||||
return (editor: LexicalEditor) => {
|
||||
@@ -287,7 +268,7 @@ const CommandsView = (
|
||||
// view mode
|
||||
<div className="infio-commands-view-mode">
|
||||
<div className="infio-commands-name">{command.name}</div>
|
||||
<div className="infio-commands-content">{command.content.nodes.map(lexicalNodeToPlainText).join('')}</div>
|
||||
<div className="infio-commands-content">{command.contentText}</div>
|
||||
<div className="infio-commands-actions">
|
||||
<button
|
||||
onClick={() => handleEditCommand(command)}
|
||||
|
||||
@@ -242,7 +242,7 @@ export function ModelSelect() {
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value)
|
||||
setSelectedIndex(0)
|
||||
// 确保下一个渲染循环中仍然聚焦在输入框
|
||||
// Ensure the input is focused in the next render cycle
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus()
|
||||
}, 0)
|
||||
@@ -292,7 +292,7 @@ export function ModelSelect() {
|
||||
value={searchTerm}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value)
|
||||
// 确保下一个渲染循环中仍然聚焦在输入框
|
||||
// ensure the input is focused in the next render cycle
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus()
|
||||
}, 0)
|
||||
@@ -350,7 +350,7 @@ export function ModelSelect() {
|
||||
</DropdownMenu.Root>
|
||||
<style>
|
||||
{`
|
||||
/* 模型项样式 */
|
||||
/* Model item styles */
|
||||
.infio-llm-setting-model-item {
|
||||
display: block;
|
||||
padding: 0;
|
||||
@@ -366,7 +366,7 @@ export function ModelSelect() {
|
||||
border-left: 3px solid var(--interactive-accent);
|
||||
}
|
||||
|
||||
/* 文本溢出处理 */
|
||||
/* Text overflow handling */
|
||||
.infio-model-item-text-wrapper {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -379,7 +379,7 @@ export function ModelSelect() {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* 高亮样式 - 使用紫色而不是主题色 */
|
||||
/* Highlighted text style - use purple instead of theme color */
|
||||
.infio-llm-setting-model-item-highlight {
|
||||
display: inline;
|
||||
color: #9370DB;
|
||||
@@ -389,7 +389,7 @@ export function ModelSelect() {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* 搜索容器 */
|
||||
/* Search container */
|
||||
.infio-llm-setting-search-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -399,7 +399,7 @@ export function ModelSelect() {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
/* 提供商选择器容器 */
|
||||
/* Provider selector container */
|
||||
.infio-llm-setting-provider-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -408,9 +408,7 @@ export function ModelSelect() {
|
||||
width: 26%;
|
||||
}
|
||||
|
||||
/* 移除提供商选择箭头 */
|
||||
|
||||
/* 提供商选择器 */
|
||||
/* Provider selector */
|
||||
.infio-llm-setting-provider-switch {
|
||||
width: 100% !important;
|
||||
margin: 0;
|
||||
@@ -435,7 +433,7 @@ export function ModelSelect() {
|
||||
box-shadow: 0 0 0 2px rgba(var(--interactive-accent-rgb), 0.2);
|
||||
}
|
||||
|
||||
/* 搜索框容器 */
|
||||
/* Search container */
|
||||
.infio-search-input-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -443,10 +441,8 @@ export function ModelSelect() {
|
||||
flex: 1 1 auto;
|
||||
width: 74%;
|
||||
}
|
||||
|
||||
/* 移除搜索图标 */
|
||||
|
||||
/* 搜索输入框 */
|
||||
|
||||
/* Search input */
|
||||
.infio-llm-setting-item-search {
|
||||
width: 100% !important;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
@@ -469,7 +465,7 @@ export function ModelSelect() {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* 下拉菜单容器 */
|
||||
/* Dropdown menu container */
|
||||
.infio-llm-setting-combobox-dropdown {
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
|
||||
Reference in New Issue
Block a user