Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
b4604860
authored
Sep 11, 2023
by
Archer
Committed by
GitHub
Sep 11, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: move dataset (#277)
parent
ae2887e9
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
424 additions
and
60 deletions
+424
-60
client/public/locales/en/common.json
+5
-0
client/public/locales/zh/common.json
+5
-0
client/src/api/plugins/kb.ts
+3
-2
client/src/api/request/kb.d.ts
+1
-0
client/src/components/Icon/icons/light/move.svg
+2
-0
client/src/components/Icon/icons/light/rightArrow.svg
+2
-1
client/src/components/Icon/index.tsx
+2
-1
client/src/components/MyMenu/index.tsx
+5
-2
client/src/hooks/useEditInfo.tsx
+2
-1
client/src/pages/api/plugins/kb/list.ts
+4
-2
client/src/pages/api/plugins/kb/update.ts
+6
-3
client/src/pages/app/detail/components/KBSelectModal.tsx
+8
-2
client/src/pages/components/Hero.tsx
+37
-8
client/src/pages/kb/detail/components/FileCard.tsx
+1
-1
client/src/pages/kb/list/component/MoveModal.tsx
+181
-0
client/src/pages/kb/list/index.tsx
+133
-34
client/src/store/dataset.ts
+27
-3
No files found.
client/public/locales/en/common.json
View file @
b4604860
...
...
@@ -5,7 +5,9 @@
"Create New"
:
"Create"
,
"Dataset"
:
"Dataset"
,
"Folder"
:
"Folder"
,
"Move"
:
"Move"
,
"Name"
:
"Name"
,
"Rename"
:
"Rename"
,
"Running"
:
"Running"
,
"Select value is empty"
:
"Select value is empty"
,
"UnKnow"
:
"UnKnow"
,
...
...
@@ -163,6 +165,7 @@
},
"kb"
:
{
"Chunk Length"
:
"Chunk Length"
,
"Confirm move the folder"
:
"Confirm Move"
,
"Confirm to delete the file"
:
"Are you sure to delete the file and all its data?"
,
"Create Folder"
:
"Create Folder"
,
"Delete Dataset Error"
:
"Delete dataset failed"
,
...
...
@@ -171,7 +174,9 @@
"Filename"
:
"Filename"
,
"Files"
:
"{{total}} Files"
,
"Folder Name"
:
"Input folder name"
,
"Move Failed"
:
"Move Failed"
,
"My Dataset"
:
"My Dataset"
,
"No Folder"
:
"No Folder"
,
"Other Data"
:
"Other Data"
,
"Select Dataset"
:
"Select Dataset"
,
"Select Folder"
:
"Enter folder"
,
...
...
client/public/locales/zh/common.json
View file @
b4604860
...
...
@@ -5,7 +5,9 @@
"Create New"
:
"新建"
,
"Dataset"
:
"知识库"
,
"Folder"
:
"文件夹"
,
"Move"
:
"移动"
,
"Name"
:
"名称"
,
"Rename"
:
"重命名"
,
"Running"
:
"运行中"
,
"Select value is empty"
:
"选择的内容为空"
,
"UnKnow"
:
"未知"
,
...
...
@@ -163,6 +165,7 @@
},
"kb"
:
{
"Chunk Length"
:
"数据总量"
,
"Confirm move the folder"
:
"确认移动到该目录"
,
"Confirm to delete the file"
:
"确认删除该文件及其所有数据?"
,
"Create Folder"
:
"创建文件夹"
,
"Delete Dataset Error"
:
"删除知识库异常"
,
...
...
@@ -171,7 +174,9 @@
"Filename"
:
"文件名"
,
"Files"
:
"文件: {{total}}个"
,
"Folder Name"
:
"输入文件夹名称"
,
"Move Failed"
:
"移动出现错误~"
,
"My Dataset"
:
"我的知识库"
,
"No Folder"
:
"没有子目录了~"
,
"Other Data"
:
"其他数据"
,
"Select Dataset"
:
"选择该知识库"
,
"Select Folder"
:
"进入文件夹"
,
...
...
client/src/api/plugins/kb.ts
View file @
b4604860
...
...
@@ -19,10 +19,11 @@ import {
import
{
Props
as
UpdateDataProps
}
from
'@/pages/api/openapi/kb/updateData'
;
import
type
{
KbUpdateParams
,
CreateKbParams
,
GetKbDataListProps
}
from
'../request/kb'
;
import
{
QuoteItemType
}
from
'@/types/chat'
;
import
{
KbTypeEnum
}
from
'@/constants/kb'
;
/* knowledge base */
export
const
getKbList
=
(
parentId
?:
string
)
=>
GET
<
KbListItemType
[]
>
(
`/plugins/kb/list`
,
{
parentId
}
);
export
const
getKbList
=
(
data
:
{
parentId
?:
string
;
type
?:
`
${
KbTypeEnum
}
`
}
)
=>
GET
<
KbListItemType
[]
>
(
`/plugins/kb/list`
,
data
);
export
const
getAllDataset
=
()
=>
GET
<
KbListItemType
[]
>
(
`/plugins/kb/allDataset`
);
export
const
getKbPaths
=
(
parentId
?:
string
)
=>
...
...
client/src/api/request/kb.d.ts
View file @
b4604860
...
...
@@ -3,6 +3,7 @@ import type { RequestPaging } from '@/types';
export
type
KbUpdateParams
=
{
id
:
string
;
parentId
?:
string
;
tags
?:
string
;
name
?:
string
;
avatar
?:
string
;
...
...
client/src/components/Icon/icons/light/move.svg
0 → 100644
View file @
b4604860
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t=
"1694403033666"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"4053"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"64"
height=
"64"
><path
d=
"M1016.32 494.08l-143.872-143.36c-9.728-9.728-26.112-9.728-35.84 0-9.728 9.728-9.728 26.112 0 35.84L936.96 486.4h-399.36V87.04l99.84 100.352c9.728 9.728 26.112 9.728 35.84 0 9.728-9.728 9.728-26.112 0-35.84l-143.36-143.872c-9.728-9.728-26.112-9.728-35.84 0l-143.36 143.872c-9.728 9.728-9.728 26.112 0 35.84 9.728 9.728 26.112 9.728 35.84 0L486.4 87.04v399.36H87.04l100.352-99.84c9.728-9.728 9.728-26.112 0-35.84-9.728-9.728-26.112-9.728-35.84 0l-143.872 143.36c-9.728 9.728-9.728 26.112 0 35.84l143.872 143.36c9.728 9.728 26.112 9.728 35.84 0 9.728-9.728 9.728-26.112 0-35.84L87.04 537.6h399.36v399.36l-99.84-100.352c-9.728-9.728-26.112-9.728-35.84 0-9.728 9.728-9.728 26.112 0 35.84l143.36 143.872c9.728 9.728 26.112 9.728 35.84 0l143.36-143.872c9.728-9.728 9.728-26.112 0-35.84-9.728-9.728-26.112-9.728-35.84 0L537.6 936.96v-399.36h399.36l-100.352 99.84c-9.728 9.728-9.728 26.112 0 35.84 9.728 9.728 26.112 9.728 35.84 0l143.872-143.36c10.24-9.728 10.24-26.112 0-35.84z"
p-id=
"4054"
></path></svg>
\ No newline at end of file
client/src/components/Icon/icons/light/rightArrow.svg
View file @
b4604860
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
>
<svg
viewBox=
"0 0 24 24"
>
<path
d=
"M8.3 5.7a1 1 0 011.4-1.4l7.71 7.7-7.7 7.7a1 1 0 11-1.42-1.4l6.3-6.3-6.3-6.3z"
fill-rule=
"nonzero"
></path>
</svg>
\ No newline at end of file
client/src/components/Icon/index.tsx
View file @
b4604860
...
...
@@ -83,7 +83,8 @@ const map = {
retryLight
:
require
(
'./icons/light/retry.svg'
).
default
,
rightArrowLight
:
require
(
'./icons/light/rightArrow.svg'
).
default
,
searchLight
:
require
(
'./icons/light/search.svg'
).
default
,
plusFill
:
require
(
'./icons/fill/plus.svg'
).
default
plusFill
:
require
(
'./icons/fill/plus.svg'
).
default
,
moveLight
:
require
(
'./icons/light/move.svg'
).
default
};
export
type
IconName
=
keyof
typeof
map
;
...
...
client/src/components/MyMenu/index.tsx
View file @
b4604860
...
...
@@ -8,7 +8,7 @@ interface Props {
menuList
:
{
isActive
?:
boolean
;
child
:
React
.
ReactNode
;
onClick
:
()
=>
void
;
onClick
:
()
=>
any
;
}[];
}
...
...
@@ -37,7 +37,10 @@ const MyMenu = ({ width, offset = [0, 10], Button, menuList }: Props) => {
<
MenuItem
key=
{
i
}
{
...
menuItemStyles
}
onClick=
{
item
.
onClick
}
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
item
.
onClick
&&
item
.
onClick
();
}
}
color=
{
item
.
isActive
?
'hover.blue'
:
''
}
>
{
item
.
child
}
...
...
client/src/hooks/useEditInfo.tsx
View file @
b4604860
import
React
,
{
useCallback
,
useRef
,
useState
}
from
'react'
;
import
React
,
{
useCallback
,
useRef
}
from
'react'
;
import
{
ModalFooter
,
ModalBody
,
Input
,
useDisclosure
,
Button
}
from
'@chakra-ui/react'
;
import
MyModal
from
'@/components/MyModal'
;
...
...
@@ -39,6 +39,7 @@ export const useEditInfo = ({
try
{
const
val
=
inputRef
.
current
.
value
;
await
onSuccessCb
.
current
?.(
val
);
onClose
();
}
catch
(
err
)
{
onErrorCb
.
current
?.(
err
);
...
...
client/src/pages/api/plugins/kb/list.ts
View file @
b4604860
...
...
@@ -4,10 +4,11 @@ import { connectToDatabase, KB } from '@/service/mongo';
import
{
authUser
}
from
'@/service/utils/auth'
;
import
{
getVectorModel
}
from
'@/service/utils/data'
;
import
{
KbListItemType
}
from
'@/types/plugin'
;
import
{
KbTypeEnum
}
from
'@/constants/kb'
;
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
const
{
parentId
}
=
req
.
query
as
{
parentId
:
string
};
const
{
parentId
,
type
}
=
req
.
query
as
{
parentId
?:
string
;
type
?:
`
${
KbTypeEnum
}
`
};
// 凭证校验
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
...
...
@@ -15,7 +16,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const
kbList
=
await
KB
.
find
({
userId
,
parentId
:
parentId
||
null
...(
parentId
!==
undefined
&&
{
parentId
:
parentId
||
null
}),
...(
type
&&
{
type
})
}).
sort
({
updateTime
:
-
1
});
const
data
=
await
Promise
.
all
(
...
...
client/src/pages/api/plugins/kb/update.ts
View file @
b4604860
...
...
@@ -6,9 +6,9 @@ import type { KbUpdateParams } from '@/api/request/kb';
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
const
{
id
,
name
,
avatar
,
tags
=
''
}
=
req
.
body
as
KbUpdateParams
;
const
{
id
,
parentId
,
name
,
avatar
,
tags
}
=
req
.
body
as
KbUpdateParams
;
if
(
!
id
||
!
name
)
{
if
(
!
id
)
{
throw
new
Error
(
'缺少参数'
);
}
...
...
@@ -23,9 +23,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
userId
},
{
...(
parentId
!==
undefined
&&
{
parentId
:
parentId
||
null
}),
...(
name
&&
{
name
}),
...(
avatar
&&
{
avatar
}),
tags
:
tags
.
split
(
' '
).
filter
((
item
)
=>
item
)
...(
typeof
tags
===
'string'
&&
{
tags
:
tags
.
split
(
' '
).
filter
((
item
)
=>
item
)
})
}
);
...
...
client/src/pages/app/detail/components/KBSelectModal.tsx
View file @
b4604860
...
...
@@ -83,7 +83,13 @@ export const KBSelectModal = ({
<
Flex
flexDirection=
{
'column'
}
h=
{
[
'90vh'
,
'auto'
]
}
>
<
ModalHeader
>
{
!!
parentId
?
(
<
Flex
flex=
{
1
}
>
<
Flex
flex=
{
1
}
userSelect=
{
'none'
}
fontSize=
{
[
'sm'
,
'lg'
]
}
fontWeight=
{
'normal'
}
color=
{
'myGray.900'
}
>
{
paths
.
map
((
item
,
i
)
=>
(
<
Flex
key=
{
item
.
parentId
}
mr=
{
2
}
alignItems=
{
'center'
}
>
<
Box
...
...
@@ -106,7 +112,7 @@ export const KBSelectModal = ({
{
item
.
parentName
}
</
Box
>
{
i
!==
paths
.
length
-
1
&&
(
<
MyIcon
name=
{
'rightArrowLight'
}
color=
{
'myGray.500'
}
/>
<
MyIcon
name=
{
'rightArrowLight'
}
color=
{
'myGray.500'
}
w=
{
[
'18px'
,
'24px'
]
}
/>
)
}
</
Flex
>
))
}
...
...
client/src/pages/components/Hero.tsx
View file @
b4604860
import
{
Box
,
Flex
,
Button
,
Image
}
from
'@chakra-ui/react'
;
import
React
from
'react'
;
import
React
,
{
useState
}
from
'react'
;
import
{
useTranslation
}
from
'react-i18next'
;
import
{
feConfigs
}
from
'@/store/static'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
MyIcon
from
'@/components/Icon'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
const
Hero
=
()
=>
{
const
router
=
useRouter
();
const
{
toast
}
=
useToast
();
const
{
t
}
=
useTranslation
();
const
{
isPc
,
gitStar
}
=
useGlobalStore
();
const
[
showVideo
,
setShowVide
]
=
useState
(
false
);
return
(
<
Flex
flexDirection=
{
'column'
}
pt=
{
[
'24px'
,
'50px'
]
}
alignItems=
{
'center'
}
userSelect=
{
'none'
}
>
...
...
@@ -62,6 +61,7 @@ const Hero = () => {
mx=
{
[
'-10%'
,
'auto'
]
}
maxW=
{
[
'120%'
,
'1000px'
]
}
alt=
""
draggable=
{
false
}
/>
<
MyIcon
name=
{
'playFill'
}
...
...
@@ -72,13 +72,42 @@ const Hero = () => {
top=
{
'50%'
}
color=
{
'#363c42b8'
}
transform=
{
[
'translate(-50%,5px)'
,
'translate(-50%,40px)'
]
}
onClick=
{
()
=>
{
toast
({
title
:
'录制中~'
});
}
}
onClick=
{
()
=>
setShowVide
(
true
)
}
/>
</
Box
>
{
showVideo
&&
(
<
Flex
position=
{
'fixed'
}
zIndex=
{
99
}
top=
{
0
}
left=
{
0
}
right=
{
0
}
bottom=
{
0
}
alignItems=
{
'center'
}
justifyContent=
{
'center'
}
bg=
{
'rgba(255,255,255,0.4)'
}
onClick=
{
()
=>
setShowVide
(
false
)
}
>
<
Box
w=
{
[
'100vw'
,
'50%'
]
}
borderRadius=
{
'lg'
}
overflow=
{
'hidden'
}
onClick=
{
(
e
)
=>
e
.
preventDefault
()
}
>
<
video
style=
{
{
margin
:
'auto'
}
}
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
}
}
src=
{
'https://otnvvf-imgs.oss.laf.run/fastgpt.mp4'
}
controls
autoPlay
/>
</
Box
>
</
Flex
>
)
}
</
Flex
>
);
};
...
...
client/src/pages/kb/detail/components/FileCard.tsx
View file @
b4604860
...
...
@@ -145,7 +145,7 @@ const FileCard = ({ kbId }: { kbId: string }) => {
cursor=
{
'pointer'
}
title=
{
'点击查看数据详情'
}
onClick=
{
()
=>
router
.
push
({
router
.
replace
({
query
:
{
kbId
,
fileId
:
file
.
id
,
...
...
client/src/pages/kb/list/component/MoveModal.tsx
0 → 100644
View file @
b4604860
import
React
,
{
useMemo
,
useState
}
from
'react'
;
import
{
Card
,
Flex
,
Box
,
Button
,
ModalBody
,
ModalHeader
,
ModalFooter
,
useTheme
,
Grid
}
from
'@chakra-ui/react'
;
import
{
getKbPaths
}
from
'@/api/plugins/kb'
;
import
Avatar
from
'@/components/Avatar'
;
import
MyTooltip
from
'@/components/MyTooltip'
;
import
MyModal
from
'@/components/MyModal'
;
import
MyIcon
from
'@/components/Icon'
;
import
{
KbTypeEnum
}
from
'@/constants/kb'
;
import
{
useTranslation
}
from
'react-i18next'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
getKbList
,
putKbById
}
from
'@/api/plugins/kb'
;
import
{
useRequest
}
from
'@/hooks/useRequest'
;
const
MoveModal
=
({
onClose
,
onSuccess
,
moveDataId
}:
{
onClose
:
()
=>
void
;
onSuccess
:
()
=>
void
;
moveDataId
:
string
;
})
=>
{
const
{
t
}
=
useTranslation
();
const
theme
=
useTheme
();
const
[
parentId
,
setParentId
]
=
useState
<
string
>
(
''
);
const
{
data
}
=
useQuery
([
'getKbList'
,
parentId
],
()
=>
{
return
Promise
.
all
([
getKbList
({
parentId
,
type
:
'folder'
}),
getKbPaths
(
parentId
)]);
});
const
paths
=
useMemo
(
()
=>
[
{
parentId
:
''
,
parentName
:
t
(
'kb.My Dataset'
)
},
...(
data
?.[
1
]
||
[])
],
[
data
,
t
]
);
const
folderList
=
useMemo
(
()
=>
(
data
?.[
0
]
||
[]).
filter
((
item
)
=>
item
.
_id
!==
moveDataId
),
[
moveDataId
,
data
]
);
const
{
mutate
,
isLoading
}
=
useRequest
({
mutationFn
:
()
=>
putKbById
({
id
:
moveDataId
,
parentId
}),
onSuccess
,
errorToast
:
t
(
'kb.Move Failed'
)
});
return
(
<
MyModal
isOpen=
{
true
}
maxW=
{
[
'90vw'
,
'800px'
]
}
w=
{
'800px'
}
onClose=
{
onClose
}
>
<
Flex
flexDirection=
{
'column'
}
h=
{
[
'90vh'
,
'auto'
]
}
>
<
ModalHeader
>
{
!!
parentId
?
(
<
Flex
flex=
{
1
}
userSelect=
{
'none'
}
fontSize=
{
[
'sm'
,
'lg'
]
}
fontWeight=
{
'normal'
}
>
{
paths
.
map
((
item
,
i
)
=>
(
<
Flex
key=
{
item
.
parentId
}
mr=
{
2
}
alignItems=
{
'center'
}
>
<
Box
borderRadius=
{
'md'
}
{
...
(
i
===
paths
.
length
-
1
?
{
cursor
:
'
default
'
}
:
{
cursor
:
'
pointer
',
_hover
:
{
color
:
'
myBlue
.
600'
},
onClick
:
()
=
>
{
setParentId
(
item
.
parentId
);
}
})}
>
{
item
.
parentName
}
</
Box
>
{
i
!==
paths
.
length
-
1
&&
(
<
MyIcon
name=
{
'rightArrowLight'
}
color=
{
'myGray.500'
}
w=
{
[
'18px'
,
'24px'
]
}
/>
)
}
</
Flex
>
))
}
</
Flex
>
)
:
(
<
Box
>
我的知识库
</
Box
>
)
}
</
ModalHeader
>
<
ModalBody
flex=
{
[
'1 0 0'
,
'0 0 auto'
]
}
maxH=
{
'80vh'
}
overflowY=
{
'auto'
}
display=
{
'grid'
}
userSelect=
{
'none'
}
>
<
Grid
gridTemplateColumns=
{
[
'repeat(1,1fr)'
,
'repeat(2,1fr)'
,
'repeat(3,1fr)'
]
}
gridGap=
{
3
}
>
{
folderList
.
map
((
item
)
=>
(()
=>
{
return
(
<
MyTooltip
key=
{
item
.
_id
}
label=
{
item
.
type
===
KbTypeEnum
.
dataset
?
t
(
'kb.Select Dataset'
)
:
t
(
'kb.Select Folder'
)
}
>
<
Card
p=
{
3
}
border=
{
theme
.
borders
.
base
}
boxShadow=
{
'sm'
}
h=
{
'80px'
}
cursor=
{
'pointer'
}
_hover=
{
{
boxShadow
:
'md'
}
}
onClick=
{
()
=>
{
setParentId
(
item
.
_id
);
}
}
>
<
Flex
alignItems=
{
'center'
}
h=
{
'38px'
}
>
<
Avatar
src=
{
item
.
avatar
}
w=
{
[
'24px'
,
'28px'
]
}
></
Avatar
>
<
Box
className=
"textEllipsis"
ml=
{
3
}
fontWeight=
{
'bold'
}
fontSize=
{
[
'md'
,
'lg'
,
'xl'
]
}
>
{
item
.
name
}
</
Box
>
</
Flex
>
<
Flex
justifyContent=
{
'flex-end'
}
alignItems=
{
'center'
}
fontSize=
{
'sm'
}
>
{
item
.
type
===
KbTypeEnum
.
folder
?
(
<
Box
color=
{
'myGray.500'
}
>
{
t
(
'Folder'
)
}
</
Box
>
)
:
(
<>
<
MyIcon
mr=
{
1
}
name=
"kbTest"
w=
{
'12px'
}
/>
<
Box
color=
{
'myGray.500'
}
>
{
item
.
vectorModel
.
name
}
</
Box
>
</>
)
}
</
Flex
>
</
Card
>
</
MyTooltip
>
);
})()
)
}
</
Grid
>
{
folderList
.
length
===
0
&&
(
<
Flex
mt=
{
5
}
flexDirection=
{
'column'
}
alignItems=
{
'center'
}
>
<
MyIcon
name=
"empty"
w=
{
'48px'
}
h=
{
'48px'
}
color=
{
'transparent'
}
/>
<
Box
mt=
{
2
}
color=
{
'myGray.500'
}
>
{
t
(
'kb.No Folder'
)
}
</
Box
>
</
Flex
>
)
}
</
ModalBody
>
<
ModalFooter
>
<
Button
isLoading=
{
isLoading
}
onClick=
{
mutate
}
>
{
t
(
'kb.Confirm move the folder'
)
}
</
Button
>
</
ModalFooter
>
</
Flex
>
</
MyModal
>
);
};
export
default
MoveModal
;
client/src/pages/kb/list/index.tsx
View file @
b4604860
import
React
,
{
use
Callback
,
use
Memo
,
useRef
,
useState
}
from
'react'
;
import
React
,
{
useMemo
,
useRef
,
useState
}
from
'react'
;
import
{
Box
,
Flex
,
...
...
@@ -6,7 +6,6 @@ import {
useTheme
,
useDisclosure
,
Card
,
IconButton
,
MenuButton
,
Image
}
from
'@chakra-ui/react'
;
...
...
@@ -16,8 +15,7 @@ import PageContainer from '@/components/PageContainer';
import
{
useConfirm
}
from
'@/hooks/useConfirm'
;
import
{
AddIcon
}
from
'@chakra-ui/icons'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
delKbById
,
getKbPaths
}
from
'@/api/plugins/kb'
;
import
{
delKbById
,
getKbPaths
,
putKbById
}
from
'@/api/plugins/kb'
;
import
{
useTranslation
}
from
'react-i18next'
;
import
Avatar
from
'@/components/Avatar'
;
import
MyIcon
from
'@/components/Icon'
;
...
...
@@ -28,16 +26,17 @@ import Tag from '@/components/Tag';
import
MyMenu
from
'@/components/MyMenu'
;
import
{
useRequest
}
from
'@/hooks/useRequest'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useEditInfo
}
from
'@/hooks/useEditInfo'
;
const
CreateModal
=
dynamic
(()
=>
import
(
'./component/CreateModal'
),
{
ssr
:
false
});
const
EditFolderModal
=
dynamic
(()
=>
import
(
'./component/EditFolderModal'
),
{
ssr
:
false
});
const
MoveModal
=
dynamic
(()
=>
import
(
'./component/MoveModal'
),
{
ssr
:
false
});
const
Kb
=
()
=>
{
const
{
t
}
=
useTranslation
();
const
theme
=
useTheme
();
const
router
=
useRouter
();
const
{
parentId
}
=
router
.
query
as
{
parentId
:
string
};
const
{
toast
}
=
useToast
();
const
{
setLoading
}
=
useGlobalStore
();
const
DeleteTipsMap
=
useRef
({
...
...
@@ -49,7 +48,13 @@ const Kb = () => {
title
:
t
(
'common.Delete Warning'
),
content
:
''
});
const
{
myKbList
,
loadKbList
,
setKbList
}
=
useDatasetStore
();
const
{
myKbList
,
loadKbList
,
setKbList
,
updateDataset
}
=
useDatasetStore
();
const
{
onOpenModal
:
onOpenTitleModal
,
EditModal
:
EditTitleModal
}
=
useEditInfo
({
title
:
t
(
'Rename'
)
});
const
[
moveDataId
,
setMoveDataId
]
=
useState
<
string
>
();
const
[
dragStartId
,
setDragStartId
]
=
useState
<
string
>
();
const
[
dragTargetId
,
setDragTargetId
]
=
useState
<
string
>
();
const
{
isOpen
:
isOpenCreateModal
,
...
...
@@ -102,8 +107,8 @@ const Kb = () => {
{
paths
.
map
((
item
,
i
)
=>
(
<
Flex
key=
{
item
.
parentId
}
mr=
{
2
}
alignItems=
{
'center'
}
>
<
Box
fontSize=
{
'lg'
}
px=
{
2
}
fontSize=
{
[
'sm'
,
'lg'
]
}
px=
{
[
0
,
2
]
}
py=
{
1
}
borderRadius=
{
'md'
}
{
...
(
i
===
paths
.
length
-
1
...
...
@@ -126,7 +131,9 @@ const Kb = () => {
>
{
item
.
parentName
}
</
Box
>
{
i
!==
paths
.
length
-
1
&&
<
MyIcon
name=
{
'rightArrowLight'
}
color=
{
'myGray.500'
}
/>
}
{
i
!==
paths
.
length
-
1
&&
(
<
MyIcon
name=
{
'rightArrowLight'
}
color=
{
'myGray.500'
}
w=
{
[
'18px'
,
'24px'
]
}
/>
)
}
</
Flex
>
))
}
</
Flex
>
...
...
@@ -184,6 +191,7 @@ const Kb = () => {
p=
{
5
}
gridTemplateColumns=
{
[
'1fr'
,
'repeat(3,1fr)'
,
'repeat(4,1fr)'
,
'repeat(5,1fr)'
]
}
gridGap=
{
5
}
userSelect=
{
'none'
}
>
{
myKbList
.
map
((
kb
)
=>
(
<
Card
...
...
@@ -196,8 +204,36 @@ const Kb = () => {
h=
{
'130px'
}
border=
{
theme
.
borders
.
md
}
boxShadow=
{
'none'
}
userSelect=
{
'none'
}
position=
{
'relative'
}
data
-
drag
-
id=
{
kb
.
type
===
KbTypeEnum
.
folder
?
kb
.
_id
:
undefined
}
borderColor=
{
dragTargetId
===
kb
.
_id
?
'myBlue.600'
:
''
}
draggable
onDragStart=
{
(
e
)
=>
{
setDragStartId
(
kb
.
_id
);
}
}
onDragOver=
{
(
e
)
=>
{
e
.
preventDefault
();
const
targetId
=
e
.
currentTarget
.
getAttribute
(
'data-drag-id'
);
if
(
!
targetId
)
return
;
KbTypeEnum
.
folder
&&
setDragTargetId
(
targetId
);
}
}
onDragLeave=
{
(
e
)
=>
{
e
.
preventDefault
();
setDragTargetId
(
undefined
);
}
}
onDrop=
{
async
(
e
)
=>
{
e
.
preventDefault
();
if
(
!
dragTargetId
||
!
dragStartId
||
dragTargetId
===
dragStartId
)
return
;
// update parentId
try
{
await
putKbById
({
id
:
dragStartId
,
parentId
:
dragTargetId
});
refetch
();
}
catch
(
error
)
{}
setDragTargetId
(
undefined
);
}
}
_hover=
{
{
boxShadow
:
'1px 1px 10px rgba(0,0,0,0.2)'
,
borderColor
:
'transparent'
,
...
...
@@ -223,33 +259,85 @@ const Kb = () => {
}
}
}
>
<
MyMenu
offset=
{
[
-
30
,
10
]
}
width=
{
120
}
Button=
{
<
MenuButton
position=
{
'absolute'
}
top=
{
3
}
right=
{
3
}
w=
{
'22px'
}
h=
{
'22px'
}
borderRadius=
{
'md'
}
_hover=
{
{
color
:
'myBlue.600'
,
'& .icon'
:
{
bg
:
'myGray.100'
}
}
}
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
}
}
>
<
MyIcon
className=
"icon"
name=
{
'more'
}
h=
{
'16px'
}
w=
{
'16px'
}
px=
{
1
}
py=
{
1
}
borderRadius=
{
'md'
}
cursor=
{
'pointer'
}
/>
</
MenuButton
>
}
menuList=
{
[
{
child
:
(
<
Flex
alignItems=
{
'center'
}
>
<
MyIcon
name=
{
'edit'
}
w=
{
'14px'
}
mr=
{
2
}
/>
{
t
(
'Rename'
)
}
</
Flex
>
),
onClick
:
()
=>
onOpenTitleModal
({
defaultVal
:
kb
.
name
,
onSuccess
:
(
val
)
=>
{
if
(
val
===
kb
.
name
||
!
val
)
return
;
updateDataset
({
id
:
kb
.
_id
,
name
:
val
});
}
})
},
{
child
:
(
<
Flex
alignItems=
{
'center'
}
>
<
MyIcon
name=
{
'moveLight'
}
w=
{
'14px'
}
mr=
{
2
}
/>
{
t
(
'Move'
)
}
</
Flex
>
),
onClick
:
()
=>
setMoveDataId
(
kb
.
_id
)
},
{
child
:
(
<
Flex
alignItems=
{
'center'
}
>
<
MyIcon
name=
{
'delete'
}
w=
{
'14px'
}
mr=
{
2
}
/>
{
t
(
'common.Delete'
)
}
</
Flex
>
),
onClick
:
()
=>
{
openConfirm
(
()
=>
onclickDelKb
(
kb
.
_id
),
undefined
,
DeleteTipsMap
.
current
[
kb
.
type
]
)();
}
}
]
}
/>
<
Flex
alignItems=
{
'center'
}
h=
{
'38px'
}
>
<
Avatar
src=
{
kb
.
avatar
}
borderRadius=
{
'lg'
}
w=
{
'28px'
}
/>
<
Box
ml=
{
3
}
>
{
kb
.
name
}
</
Box
>
<
IconButton
className=
"delete"
position=
{
'absolute'
}
top=
{
4
}
right=
{
4
}
size=
{
'sm'
}
icon=
{
<
MyIcon
name=
{
'delete'
}
w=
{
'14px'
}
/>
}
variant=
{
'base'
}
borderRadius=
{
'md'
}
aria
-
label=
{
'delete'
}
display=
{
[
''
,
'none'
]
}
_hover=
{
{
bg
:
'red.100'
}
}
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
openConfirm
(
()
=>
onclickDelKb
(
kb
.
_id
),
undefined
,
DeleteTipsMap
.
current
[
kb
.
type
]
)();
}
}
/>
</
Flex
>
<
Box
flex=
{
'1 0 0'
}
overflow=
{
'hidden'
}
pt=
{
2
}
>
<
Flex
>
...
...
@@ -282,6 +370,7 @@ const Kb = () => {
</
Flex
>
)
}
<
ConfirmModal
/>
<
EditTitleModal
/>
{
isOpenCreateModal
&&
<
CreateModal
onClose=
{
onCloseCreateModal
}
parentId=
{
parentId
}
/>
}
{
!!
editFolderData
&&
(
<
EditFolderModal
...
...
@@ -291,6 +380,16 @@ const Kb = () => {
{
...
editFolderData
}
/>
)
}
{
!!
moveDataId
&&
(
<
MoveModal
moveDataId=
{
moveDataId
}
onClose=
{
()
=>
setMoveDataId
(
''
)
}
onSuccess=
{
()
=>
{
refetch
();
setMoveDataId
(
''
);
}
}
/>
)
}
</
PageContainer
>
);
};
...
...
client/src/store/dataset.ts
View file @
b4604860
...
...
@@ -3,8 +3,9 @@ import { devtools, persist } from 'zustand/middleware';
import
{
immer
}
from
'zustand/middleware/immer'
;
import
{
type
KbTestItemType
}
from
'@/types/plugin'
;
import
type
{
KbItemType
,
KbListItemType
}
from
'@/types/plugin'
;
import
{
getKbList
,
getKbById
,
getAllDataset
}
from
'@/api/plugins/kb'
;
import
{
getKbList
,
getKbById
,
getAllDataset
,
putKbById
}
from
'@/api/plugins/kb'
;
import
{
defaultKbDetail
}
from
'@/constants/kb'
;
import
{
KbUpdateParams
}
from
'@/api/request/kb'
;
type
State
=
{
datasets
:
KbListItemType
[];
...
...
@@ -14,6 +15,7 @@ type State = {
setKbList
(
val
:
KbListItemType
[]):
void
;
kbDetail
:
KbItemType
;
getKbDetail
:
(
id
:
string
,
init
?:
boolean
)
=>
Promise
<
KbItemType
>
;
updateDataset
:
(
data
:
KbUpdateParams
)
=>
Promise
<
any
>
;
kbTestList
:
KbTestItemType
[];
pushKbTestItem
:
(
data
:
KbTestItemType
)
=>
void
;
...
...
@@ -34,8 +36,8 @@ export const useDatasetStore = create<State>()(
return
res
;
},
myKbList
:
[],
async
loadKbList
(
parentId
)
{
const
res
=
await
getKbList
(
parentId
);
async
loadKbList
(
parentId
=
''
)
{
const
res
=
await
getKbList
(
{
parentId
}
);
set
((
state
)
=>
{
state
.
myKbList
=
res
;
});
...
...
@@ -58,6 +60,28 @@ export const useDatasetStore = create<State>()(
return
data
;
},
async
updateDataset
(
data
)
{
if
(
get
().
kbDetail
.
_id
===
data
.
id
)
{
set
((
state
)
=>
{
state
.
kbDetail
=
{
...
state
.
kbDetail
,
...
data
};
});
}
set
((
state
)
=>
{
state
.
myKbList
=
state
.
myKbList
=
state
.
myKbList
.
map
((
item
)
=>
item
.
_id
===
data
.
id
?
{
...
item
,
...
data
,
tags
:
data
.
tags
?.
split
(
' '
)
||
[]
}
:
item
);
});
await
putKbById
(
data
);
},
kbTestList
:
[],
pushKbTestItem
(
data
)
{
set
((
state
)
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment