feat: add refresh icon to knowledge base items #567

close #567
This commit is contained in:
kangfenmao 2025-01-13 17:42:37 +08:00
parent 662742c958
commit 348d0fb06a
4 changed files with 103 additions and 36 deletions

View File

@ -15,6 +15,7 @@ import {
renameBase, renameBase,
updateBase, updateBase,
updateBases, updateBases,
updateItem as updateItemAction,
updateItemProcessingStatus, updateItemProcessingStatus,
updateNotes updateNotes
} from '@renderer/store/knowledge' } from '@renderer/store/knowledge'
@ -117,7 +118,8 @@ export const useKnowledge = (baseId: string) => {
await db.knowledge_notes.put(updatedNote) await db.knowledge_notes.put(updatedNote)
dispatch(updateNotes({ baseId, item: updatedNote })) dispatch(updateNotes({ baseId, item: updatedNote }))
} }
setTimeout(() => KnowledgeQueue.checkAllBases(), 0) const noteItem = base?.items.find((item) => item.id === noteId)
noteItem && refreshItem(noteItem)
} }
// 获取笔记内容 // 获取笔记内容
@ -125,6 +127,10 @@ export const useKnowledge = (baseId: string) => {
return await db.knowledge_notes.get(noteId) return await db.knowledge_notes.get(noteId)
} }
const updateItem = (item: KnowledgeItem) => {
dispatch(updateItemAction({ baseId, item }))
}
// 移除项目 // 移除项目
const removeItem = async (item: KnowledgeItem) => { const removeItem = async (item: KnowledgeItem) => {
dispatch(removeItemAction({ baseId, item })) dispatch(removeItemAction({ baseId, item }))
@ -138,6 +144,27 @@ export const useKnowledge = (baseId: string) => {
} }
} }
// 刷新项目
const refreshItem = async (item: KnowledgeItem) => {
const status = getProcessingStatus(item.id)
if (status === 'pending' || status === 'processing') {
return
}
if (base && item.uniqueId) {
await window.api.knowledgeBase.remove({ uniqueId: item.uniqueId, base: getKnowledgeBaseParams(base) })
updateItem({
...item,
processingStatus: 'pending',
processingProgress: 0,
processingError: '',
uniqueId: undefined
})
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
}
}
// 更新处理状态 // 更新处理状态
const updateItemStatus = (itemId: string, status: ProcessingStatus, progress?: number, error?: string) => { const updateItemStatus = (itemId: string, status: ProcessingStatus, progress?: number, error?: string) => {
dispatch( dispatch(
@ -238,7 +265,9 @@ export const useKnowledge = (baseId: string) => {
addNote, addNote,
updateNoteContent, updateNoteContent,
getNoteContent, getNoteContent,
updateItem,
updateItemStatus, updateItemStatus,
refreshItem,
getProcessingStatus, getProcessingStatus,
getProcessingItemsByType, getProcessingItemsByType,
clearCompleted, clearCompleted,

View File

@ -6,6 +6,7 @@ import {
GlobalOutlined, GlobalOutlined,
LinkOutlined, LinkOutlined,
PlusOutlined, PlusOutlined,
RedoOutlined,
SearchOutlined SearchOutlined
} from '@ant-design/icons' } from '@ant-design/icons'
import PromptPopup from '@renderer/components/Popups/PromptPopup' import PromptPopup from '@renderer/components/Popups/PromptPopup'
@ -32,30 +33,6 @@ interface KnowledgeContentProps {
const fileTypes = ['.pdf', '.docx', '.pptx', '.xlsx', '.txt', '.md'] const fileTypes = ['.pdf', '.docx', '.pptx', '.xlsx', '.txt', '.md']
const FlexColumn = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
`
const FlexAlignCenter = styled.div`
display: flex;
align-items: center;
gap: 16px;
`
const ClickableSpan = styled.span`
cursor: pointer;
`
const FileIcon = styled(FileTextOutlined)`
font-size: 16px;
`
const BottomSpacer = styled.div`
min-height: 20px;
`
const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => { const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { const {
@ -67,6 +44,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
directoryItems, directoryItems,
addFiles, addFiles,
updateNoteContent, updateNoteContent,
refreshItem,
addUrl, addUrl,
addSitemap, addSitemap,
removeItem, removeItem,
@ -245,7 +223,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
<ClickableSpan onClick={() => window.api.file.openPath(file.path)}>{file.origin_name}</ClickableSpan> <ClickableSpan onClick={() => window.api.file.openPath(file.path)}>{file.origin_name}</ClickableSpan>
</ItemInfo> </ItemInfo>
<FlexAlignCenter> <FlexAlignCenter>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} /> {item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
<StatusIconWrapper>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
</StatusIconWrapper>
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} /> <Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
</FlexAlignCenter> </FlexAlignCenter>
</ItemContent> </ItemContent>
@ -272,7 +253,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
</ClickableSpan> </ClickableSpan>
</ItemInfo> </ItemInfo>
<FlexAlignCenter> <FlexAlignCenter>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} /> {item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
<StatusIconWrapper>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
</StatusIconWrapper>
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} /> <Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
</FlexAlignCenter> </FlexAlignCenter>
</ItemContent> </ItemContent>
@ -299,7 +283,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
</a> </a>
</ItemInfo> </ItemInfo>
<FlexAlignCenter> <FlexAlignCenter>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} /> {item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
<StatusIconWrapper>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
</StatusIconWrapper>
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} /> <Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
</FlexAlignCenter> </FlexAlignCenter>
</ItemContent> </ItemContent>
@ -326,7 +313,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
</a> </a>
</ItemInfo> </ItemInfo>
<FlexAlignCenter> <FlexAlignCenter>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} /> {item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
<StatusIconWrapper>
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
</StatusIconWrapper>
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} /> <Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
</FlexAlignCenter> </FlexAlignCenter>
</ItemContent> </ItemContent>
@ -351,7 +341,9 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
</ItemInfo> </ItemInfo>
<FlexAlignCenter> <FlexAlignCenter>
<Button type="text" onClick={() => handleEditNote(note)} icon={<EditOutlined />} /> <Button type="text" onClick={() => handleEditNote(note)} icon={<EditOutlined />} />
<StatusIcon sourceId={note.id} base={base} getProcessingStatus={getProcessingStatus} /> <StatusIconWrapper>
<StatusIcon sourceId={note.id} base={base} getProcessingStatus={getProcessingStatus} />
</StatusIconWrapper>
<Button type="text" danger onClick={() => removeItem(note)} icon={<DeleteOutlined />} /> <Button type="text" danger onClick={() => removeItem(note)} icon={<DeleteOutlined />} />
</FlexAlignCenter> </FlexAlignCenter>
</ItemContent> </ItemContent>
@ -478,4 +470,42 @@ const ModelInfo = styled.div`
} }
` `
const FlexColumn = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
`
const FlexAlignCenter = styled.div`
display: flex;
align-items: center;
justify-content: center;
`
const ClickableSpan = styled.span`
cursor: pointer;
`
const FileIcon = styled(FileTextOutlined)`
font-size: 16px;
`
const BottomSpacer = styled.div`
min-height: 20px;
`
const StatusIconWrapper = styled.div`
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
padding-top: 2px;
`
const RefreshIcon = styled(RedoOutlined)`
font-size: 15px !important;
color: var(--color-text-2);
`
export default KnowledgeContent export default KnowledgeContent

View File

@ -1,5 +1,4 @@
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons' import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'
import { Center } from '@renderer/components/Layout'
import { KnowledgeBase, ProcessingStatus } from '@renderer/types' import { KnowledgeBase, ProcessingStatus } from '@renderer/types'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
import { FC } from 'react' import { FC } from 'react'
@ -28,9 +27,7 @@ const StatusIcon: FC<StatusIconProps> = ({ sourceId, base, getProcessingStatus }
} }
return ( return (
<Tooltip title={t('knowledge.status_new')} placement="left"> <Tooltip title={t('knowledge.status_new')} placement="left">
<Center style={{ width: '16px', height: '16px' }}> <StatusDot $status="new" />
<StatusDot $status="new" />
</Center>
</Tooltip> </Tooltip>
) )
} }
@ -66,8 +63,8 @@ const StatusIcon: FC<StatusIconProps> = ({ sourceId, base, getProcessingStatus }
} }
const StatusDot = styled.div<{ $status: 'pending' | 'processing' | 'new' }>` const StatusDot = styled.div<{ $status: 'pending' | 'processing' | 'new' }>`
width: 8px; width: 10px;
height: 8px; height: 10px;
border-radius: 50%; border-radius: 50%;
background-color: ${(props) => background-color: ${(props) =>
props.$status === 'pending' ? '#faad14' : props.$status === 'new' ? '#918999' : '#1890ff'}; props.$status === 'pending' ? '#faad14' : props.$status === 'new' ? '#918999' : '#1890ff'};

View File

@ -89,6 +89,16 @@ const knowledgeSlice = createSlice({
} }
}, },
updateItem(state, action: PayloadAction<{ baseId: string; item: KnowledgeItem }>) {
const base = state.bases.find((b) => b.id === action.payload.baseId)
if (base) {
const index = base.items.findIndex((item) => item.id === action.payload.item.id)
if (index !== -1) {
base.items[index] = action.payload.item
}
}
},
addFiles(state, action: PayloadAction<{ baseId: string; items: KnowledgeItem[] }>) { addFiles(state, action: PayloadAction<{ baseId: string; items: KnowledgeItem[] }>) {
const base = state.bases.find((b) => b.id === action.payload.baseId) const base = state.bases.find((b) => b.id === action.payload.baseId)
if (base) { if (base) {
@ -183,6 +193,7 @@ export const {
addFiles, addFiles,
updateNotes, updateNotes,
removeItem, removeItem,
updateItem,
updateItemProcessingStatus, updateItemProcessingStatus,
clearCompletedProcessing, clearCompletedProcessing,
clearAllProcessing, clearAllProcessing,