4.8.5 test fix (#1835)

* faq

* perf: navbar name and fix dataset selector

* feat: app tag

* perf: icon

* fix: update workflow bug

* perf: dataset ui

* perf: menu

* fix: ts

* fix: auth file and app list ui

* app list

* app list

* perf: init api

* update per

* log level
This commit is contained in:
Archer
2024-06-25 10:10:24 +08:00
committed by GitHub
parent d902d29c71
commit 5c8c7fb9f2
50 changed files with 9331 additions and 12025 deletions

View File

@@ -34,7 +34,7 @@ const Navbar = ({ unread }: { unread: number }) => {
activeLink: ['/chat']
},
{
label: t('navbar.Apps'),
label: t('navbar.Studio'),
icon: 'core/app/aiLight',
activeIcon: 'core/app/aiFill',
link: `/app/list`,

View File

@@ -21,7 +21,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
unread: 0
},
{
label: t('navbar.Apps'),
label: t('navbar.Studio'),
icon: 'core/app/aiLight',
activeIcon: 'core/app/aiFill',
link: `/app/list`,

View File

@@ -20,6 +20,7 @@ const PageContainer = ({
overflow={'overlay'}
bg={'myGray.25'}
borderRadius={[0, '16px']}
overflowX={'hidden'}
{...insertProps}
>
{children}

View File

@@ -32,7 +32,7 @@ const PermissionIconText = ({
return PermissionTypeMap[per] ? (
<Flex alignItems={'center'} fontSize={fontSize} {...props}>
<MyIcon name={PermissionTypeMap[per]?.iconLight as any} w={w} />
<Box ml={'2px'} lineHeight={1} fontSize={'xs'}>
<Box ml={'2px'} lineHeight={1}>
{t(PermissionTypeMap[per]?.label)}
</Box>
</Flex>

View File

@@ -63,7 +63,7 @@ const Account = () => {
useQuery(['init'], initUserInfo);
return (
<Box py={[3, '28px']} px={['5vw', '64px']}>
<Box py={[3, '28px']} maxW={['95vw', '1080px']} px={[5, 10]} mx={'auto'}>
{isPc ? (
<Flex justifyContent={'center'}>
<Box flex={'0 0 330px'}>

View File

@@ -170,7 +170,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
</Box>
)}
<Box flex={'1 0 0'} h={'100%'} pb={[4, 0]}>
<Box flex={'1 0 0'} h={'100%'} pb={[4, 0]} overflow={'auto'}>
{currentTab === TabEnum.info && <UserInfo />}
{currentTab === TabEnum.promotion && <Promotion />}
{currentTab === TabEnum.usage && <UsageTable />}

View File

@@ -6,6 +6,7 @@ import { NextAPI } from '@/service/middleware/entry';
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
/*
1. 先读取 HTTP plugin 内容,并找到所有的子plugin,然后事务批量创建,最后修改 inited
@@ -16,19 +17,22 @@ let success = 0;
async function handler(req: NextApiRequest, res: NextApiResponse) {
await authCert({ req, authRoot: true });
const { teamId } = req.body as { teamId?: string };
const total = await MongoPlugin.countDocuments({
inited: { $ne: true }
});
console.log('Total plugin', total);
await initHttp();
await initPlugin();
await initHttp(teamId);
await initPlugin(teamId);
}
async function initHttp(): Promise<any> {
async function initHttp(teamId?: string): Promise<any> {
/* 读取http插件和他的children */
const plugin = await MongoPlugin.findOne({
...(teamId && { teamId }),
type: PluginTypeEnum.folder,
inited: { $ne: true }
}).lean();
@@ -52,7 +56,7 @@ async function initHttp(): Promise<any> {
avatar: plugin.avatar,
intro: plugin.intro,
metadata: plugin.metadata,
version: 'v2',
version: plugin.version,
pluginData: {
apiSchemaStr: plugin.metadata?.apiSchemaStr,
customHeaders: plugin.metadata?.customHeaders
@@ -64,9 +68,10 @@ async function initHttp(): Promise<any> {
/* 批量创建子插件 */
for await (const item of children) {
await MongoApp.create(
const [{ _id: newPluginId }] = await MongoApp.create(
[
{
_id: item._id,
parentId: _id,
teamId: item.teamId,
tmbId: item.tmbId,
@@ -74,7 +79,7 @@ async function initHttp(): Promise<any> {
name: item.name,
avatar: item.avatar,
intro: item.intro,
version: 'v2',
version: plugin.version,
modules: item.modules,
edges: item.edges,
pluginData: {
@@ -85,6 +90,18 @@ async function initHttp(): Promise<any> {
],
{ session }
);
if (item.version === 'v2') {
await MongoAppVersion.create(
[
{
appId: newPluginId,
nodes: item.modules,
edges: item.edges
}
],
{ session }
);
}
}
/* 更新插件信息 */
@@ -115,24 +132,26 @@ async function initHttp(): Promise<any> {
return initHttp();
}
async function initPlugin(): Promise<any> {
async function initPlugin(teamId?: string): Promise<any> {
const plugin = await MongoPlugin.findOne({
...(teamId && { teamId }),
type: PluginTypeEnum.custom,
inited: { $ne: true }
}).lean();
if (!plugin) return;
await mongoSessionRun(async (session) => {
await MongoApp.create(
const [{ _id: newPluginId }] = await MongoApp.create(
[
{
_id: plugin._id,
teamId: plugin.teamId,
tmbId: plugin.tmbId,
type: AppTypeEnum.plugin,
name: plugin.name,
avatar: plugin.avatar,
intro: plugin.intro,
version: 'v2',
version: plugin.version,
modules: plugin.modules,
edges: plugin.edges,
pluginData: {
@@ -143,6 +162,19 @@ async function initPlugin(): Promise<any> {
{ session }
);
if (plugin.version === 'v2') {
await MongoAppVersion.create(
[
{
appId: newPluginId,
nodes: plugin.modules,
edges: plugin.edges
}
],
{ session }
);
}
await MongoPlugin.findOneAndUpdate(
{
_id: plugin._id

View File

@@ -9,6 +9,7 @@ import { DatasetSourceReadTypeEnum } from '@fastgpt/global/core/dataset/constant
import { readDatasetSourceRawText } from '@fastgpt/service/core/dataset/read';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
export type PreviewContextProps = {
type: DatasetSourceReadTypeEnum;
@@ -26,7 +27,13 @@ async function handler(req: ApiRequestProps<PreviewContextProps>, res: NextApiRe
const { teamId } = await (async () => {
if (type === DatasetSourceReadTypeEnum.fileLocal) {
return authFile({ req, authToken: true, authApiKey: true, fileId: sourceId });
return authFile({
req,
authToken: true,
authApiKey: true,
fileId: sourceId,
per: OwnerPermissionVal
});
}
return authCert({ req, authApiKey: true, authToken: true });
})();

View File

@@ -69,7 +69,10 @@ async function handler(
/* temp: get all apps and per */
const [myApps, rpList] = await Promise.all([
MongoApp.find(findAppsQuery, '_id avatar type name intro tmbId pluginData defaultPermission')
MongoApp.find(
findAppsQuery,
'_id avatar type name intro tmbId updateTime pluginData defaultPermission'
)
.sort({
updateTime: -1
})
@@ -101,10 +104,12 @@ async function handler(
return sliceApps.map((app) => ({
_id: app._id,
tmbId: app.tmbId,
avatar: app.avatar,
type: app.type,
name: app.name,
intro: app.intro,
updateTime: app.updateTime,
permission: app.permission,
defaultPermission: app.defaultPermission || AppDefaultPermissionVal,
pluginData: app.pluginData

View File

@@ -48,7 +48,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
...(type && { type }),
...(avatar && { avatar }),
...(intro !== undefined && { intro }),
...(defaultPermission && { defaultPermission }),
...(defaultPermission !== undefined && { defaultPermission }),
...(teamTags && { teamTags }),
...(formatNodes && {
modules: formatNodes

View File

@@ -1,14 +0,0 @@
import type { NextApiRequest } from 'next';
import { authDatasetFile } from '@fastgpt/service/support/permission/dataset/auth';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { NextAPI } from '@/service/middleware/entry';
async function handler(req: NextApiRequest) {
const { fileId } = req.query as { fileId: string };
// 凭证校验
const { file } = await authDatasetFile({ req, authToken: true, fileId, per: ReadPermissionVal });
return file;
}
export default NextAPI(handler);

View File

@@ -1,10 +1,10 @@
import { authDatasetFile } from '@fastgpt/service/support/permission/dataset/auth';
import { DatasetSourceReadTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { rawText2Chunks, readDatasetSourceRawText } from '@fastgpt/service/core/dataset/read';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { NextAPI } from '@/service/middleware/entry';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { OwnerPermissionVal, ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { authFile } from '@fastgpt/service/support/permission/auth/file';
export type PostPreviewFilesChunksProps = {
type: DatasetSourceReadTypeEnum;
@@ -35,12 +35,12 @@ async function handler(
const { teamId } = await (async () => {
if (type === DatasetSourceReadTypeEnum.fileLocal) {
return authDatasetFile({
return authFile({
req,
authToken: true,
authApiKey: true,
fileId: sourceId,
per: ReadPermissionVal
per: OwnerPermissionVal
});
}
return authCert({ req, authApiKey: true, authToken: true });

View File

@@ -11,12 +11,14 @@ import {
ReadPermissionVal
} from '@fastgpt/global/support/permission/constant';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { DatasetDefaultPermission } from '@fastgpt/global/support/permission/dataset/constant';
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
export type GetDatasetListBody = { parentId: ParentIdType; type?: DatasetTypeEnum };
async function handler(req: NextApiRequest) {
const { parentId, type } = req.body as { parentId: ParentIdType; type?: DatasetTypeEnum };
const { parentId, type } = req.body as GetDatasetListBody;
// 凭证校验
const {
teamId,
@@ -28,18 +30,6 @@ async function handler(req: NextApiRequest) {
authApiKey: true,
per: ReadPermissionVal
});
console.log(
'parentId',
parentId,
'type',
type,
'teamId',
teamId,
'tmbId',
tmbId,
'tmbPer',
tmbPer
);
const [myDatasets, rpList] = await Promise.all([
MongoDataset.find({
@@ -85,7 +75,7 @@ async function handler(req: NextApiRequest) {
type: item.type,
permission: item.permission,
vectorModel: getVectorModel(item.vectorModel),
defaultPermission: item.defaultPermission ?? DatasetDefaultPermission
defaultPermission: item.defaultPermission ?? DatasetDefaultPermissionVal
}))
);

View File

@@ -48,7 +48,7 @@ async function handler(req: NextApiRequest) {
...(status && { status }),
...(intro && { intro }),
...(externalReadUrl && { externalReadUrl }),
defaultPermission
...(defaultPermission !== undefined && { defaultPermission })
}
);
}

View File

@@ -34,10 +34,16 @@ const SelectDatasetRender = ({ inputs = [], item, nodeId }: RenderInputProps) =>
onClose: onCloseDatasetSelect
} = useDisclosure();
const selectedDatasetsValue = useMemo(() => {
if (Array.isArray(item.value)) return item.value as SelectedDatasetType;
return [] as SelectedDatasetType;
}, [item.value]);
const selectedDatasets = useMemo(() => {
const value = item.value as SelectedDatasetType;
return allDatasets.filter((dataset) => value?.find((item) => item.datasetId === dataset._id));
}, [allDatasets, item.value]);
return allDatasets.filter((dataset) =>
selectedDatasetsValue?.find((item) => item.datasetId === dataset._id)
);
}, [allDatasets, selectedDatasetsValue]);
useQuery(['loadAllDatasets'], loadAllDatasets);
@@ -95,7 +101,7 @@ const SelectDatasetRender = ({ inputs = [], item, nodeId }: RenderInputProps) =>
{isOpenDatasetSelect && (
<DatasetSelectModal
isOpen={isOpenDatasetSelect}
defaultSelectedDatasets={item.value}
defaultSelectedDatasets={selectedDatasetsValue}
onChange={(e) => {
onChangeNode({
nodeId,
@@ -120,6 +126,7 @@ const SelectDatasetRender = ({ inputs = [], item, nodeId }: RenderInputProps) =>
onCloseDatasetSelect,
onOpenDatasetSelect,
selectedDatasets,
selectedDatasetsValue,
t,
theme.borders.base
]);

View File

@@ -515,18 +515,16 @@ const WorkflowContextProvider = ({
const { nodes } = await getWorkflowStore();
// version preview / debug mode, not save
if (
appDetail.version !== 'v2' ||
historiesDefaultData ||
isSaving ||
nodes.length === 0 ||
edges.length === 0 ||
!!workflowDebugData
)
if (appDetail.version !== 'v2' || historiesDefaultData || isSaving || !!workflowDebugData)
return;
const storeWorkflow = uiWorkflow2StoreWorkflow({ nodes, edges });
// check valid
if (storeWorkflow.nodes.length === 0 || storeWorkflow.edges.length === 0) {
return;
}
try {
await updateAppDetail({
...storeWorkflow,

View File

@@ -1,5 +1,5 @@
import React, { useMemo, useState } from 'react';
import { Box, Grid, Flex, IconButton } from '@chakra-ui/react';
import { Box, Grid, Flex, IconButton, HStack } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { delAppById, putAppById } from '@/web/core/app/api';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
@@ -28,20 +28,22 @@ import {
postUpdateAppCollaborators
} from '@/web/core/app/api/collaborator';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import AppTypeTag from '@/components/core/app/TypeTag';
import AppTypeTag from '@/pages/app/list/components/TypeTag';
const EditResourceModal = dynamic(() => import('@/components/common/Modal/EditResourceModal'));
const ConfigPerModal = dynamic(() => import('@/components/support/permission/ConfigPerModal'));
import type { EditHttpPluginProps } from './HttpPluginEditModal';
import { postCopyApp } from '@/web/core/app/api/app';
import { getTeamMembers } from '@/web/support/user/team/api';
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
const HttpEditModal = dynamic(() => import('./HttpPluginEditModal'));
const ListItem = () => {
const { t } = useTranslation();
const { appT } = useI18n();
const router = useRouter();
const { myApps, loadMyApps, onUpdateApp, setMoveAppId, folderDetail, parentId } =
const { myApps, loadMyApps, onUpdateApp, setMoveAppId, folderDetail, appType } =
useContextSelector(AppListContext, (v) => v);
const [loadingAppId, setLoadingAppId] = useState<string>();
@@ -94,6 +96,10 @@ const ListItem = () => {
successToast: appT('Create copy success')
});
const { data: members = [] } = useRequest2(getTeamMembers, {
manual: false
});
return (
<>
<Grid
@@ -102,196 +108,221 @@ const ListItem = () => {
gridGap={5}
alignItems={'stretch'}
>
{myApps.map((app, index) => (
<MyTooltip
key={app._id}
h="100%"
label={
app.type === AppTypeEnum.folder
? t('common.folder.Open folder')
: app.permission.hasWritePer
? appT('Edit app')
: appT('Go to chat')
}
>
<MyBox
isLoading={loadingAppId === app._id}
lineHeight={1.5}
{myApps.map((app, index) => {
const owner = members.find((v) => v.tmbId === app.tmbId);
return (
<MyTooltip
key={app._id}
h="100%"
py={3}
px={5}
cursor={'pointer'}
border={'base'}
boxShadow={'2'}
bg={'white'}
borderRadius={'md'}
userSelect={'none'}
position={'relative'}
display={'flex'}
flexDirection={'column'}
_hover={{
borderColor: 'primary.300',
boxShadow: '1.5',
'& .more': {
display: 'flex'
},
'& .chat': {
display: 'flex'
}
}}
onClick={() => {
if (app.type === AppTypeEnum.folder || app.type === AppTypeEnum.httpPlugin) {
router.push({
query: {
...router.query,
parentId: app._id
}
});
} else if (app.permission.hasWritePer) {
router.push(`/app/detail?appId=${app._id}`);
} else {
router.push(`/chat?appId=${app._id}`);
}
}}
{...getBoxProps({
dataId: app._id,
isFolder: app.type === AppTypeEnum.folder
})}
label={
app.type === AppTypeEnum.folder
? t('common.folder.Open folder')
: app.permission.hasWritePer
? appT('Edit app')
: appT('Go to chat')
}
>
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={app.avatar} borderRadius={'md'} w={'28px'} />
<Box ml={3}>{app.name}</Box>
{app.permission.hasManagePer && (
<Box
className="more"
position={'absolute'}
top={3.5}
right={4}
display={['', 'none']}
>
<MyMenu
Button={
<IconButton
size={'xsSquare'}
variant={'transparentBase'}
icon={<MyIcon name={'more'} w={'1rem'} />}
aria-label={''}
/>
<MyBox
isLoading={loadingAppId === app._id}
lineHeight={1.5}
h="100%"
pt={4}
pb={3}
px={5}
cursor={'pointer'}
border={'base'}
boxShadow={'2'}
bg={'white'}
borderRadius={'md'}
userSelect={'none'}
position={'relative'}
display={'flex'}
flexDirection={'column'}
_hover={{
borderColor: 'primary.300',
boxShadow: '1.5',
'& .more': {
display: 'flex'
},
'& .time': {
display: ['flex', 'none']
}
}}
onClick={() => {
if (app.type === AppTypeEnum.folder || app.type === AppTypeEnum.httpPlugin) {
router.push({
query: {
...router.query,
parentId: app._id
}
menuList={[
{
children: [
});
} else if (app.permission.hasWritePer) {
router.push(`/app/detail?appId=${app._id}`);
} else {
router.push(`/chat?appId=${app._id}`);
}
}}
{...getBoxProps({
dataId: app._id,
isFolder: app.type === AppTypeEnum.folder
})}
>
{/* <Box position={'absolute'} top={3.5} right={0}>
<AppTypeTag type={app.type} />
</Box> */}
<HStack>
<Avatar src={app.avatar} borderRadius={'md'} w={'1.3rem'} />
<Box flex={'1'} wordBreak={'break-all'}>
{app.name}
</Box>
<Box alignSelf={'flex-start'} mr={'-1.25rem'}>
<AppTypeTag type={app.type} />
</Box>
</HStack>
<Box
flex={'1'}
className={'textEllipsis3'}
my={2}
wordBreak={'break-all'}
fontSize={'mini'}
color={'myGray.600'}
minH={'32px'}
>
{app.intro || '还没写介绍~'}
</Box>
<Flex
h={'24px'}
alignItems={'center'}
justifyContent={'space-between'}
fontSize={'mini'}
color={'myGray.500'}
>
<HStack spacing={3.5}>
{/* {owner && (
<HStack spacing={1}>
<Avatar src={owner.avatar} w={'0.9rem'} />
<Box maxW={'150px'} className="textEllipsis">
{owner.memberName}
</Box>
</HStack>
)} */}
<PermissionIconText defaultPermission={app.defaultPermission} />
</HStack>
<HStack>
{/* <HStack spacing={0.5} className="time">
<MyIcon name={'history'} w={'0.85rem'} />
<Box>{formatTimeToChatTime(app.updateTime)}</Box>
</HStack> */}
{app.permission.hasManagePer && (
<Box className="more" display={['', 'none']}>
<MyMenu
Button={
<IconButton
size={'xsSquare'}
variant={'transparentBase'}
icon={<MyIcon name={'more'} w={'0.8rem'} />}
aria-label={''}
/>
}
menuList={[
{
icon: 'edit',
label: '编辑信息',
onClick: () => {
if (app.type === AppTypeEnum.httpPlugin) {
setEditHttpPlugin({
id: app._id,
name: app.name,
avatar: app.avatar,
intro: app.intro,
pluginData: app.pluginData
});
} else {
setEditedApp({
id: app._id,
avatar: app.avatar,
name: app.name,
intro: app.intro
});
}
}
},
...(folderDetail?.type === AppTypeEnum.httpPlugin
? []
: [
{
icon: 'common/file/move',
label: t('common.folder.Move to'),
onClick: () => setMoveAppId(app._id)
children: [
{
icon: 'edit',
label: '编辑信息',
onClick: () => {
if (app.type === AppTypeEnum.httpPlugin) {
setEditHttpPlugin({
id: app._id,
name: app.name,
avatar: app.avatar,
intro: app.intro,
pluginData: app.pluginData
});
} else {
setEditedApp({
id: app._id,
avatar: app.avatar,
name: app.name,
intro: app.intro
});
}
}
]),
...(app.permission.hasManagePer
},
...(folderDetail?.type === AppTypeEnum.httpPlugin
? []
: [
{
icon: 'common/file/move',
label: t('common.folder.Move to'),
onClick: () => setMoveAppId(app._id)
}
]),
...(app.permission.hasManagePer
? [
{
icon: 'support/team/key',
label: t('permission.Permission'),
onClick: () => setEditPerAppIndex(index)
}
]
: [])
]
},
{
children: [
{
icon: 'copy',
label: appT('Copy one app'),
onClick: () =>
openConfirmCopy(() => onclickCopy({ appId: app._id }))()
}
]
},
{
children: [
{
icon: 'core/chat/chatLight',
label: appT('Go to chat'),
onClick: () => {
router.push(`/chat?appId=${app._id}`);
}
}
]
},
...(app.permission.isOwner
? [
{
icon: 'support/team/key',
label: t('permission.Permission'),
onClick: () => setEditPerAppIndex(index)
children: [
{
type: 'danger' as 'danger',
icon: 'delete',
label: t('common.Delete'),
onClick: () =>
openConfirmDel(
() => onclickDelApp(app._id),
undefined,
app.type === AppTypeEnum.folder
? appT('Confirm delete folder tip')
: appT('Confirm Del App Tip')
)()
}
]
}
]
: [])
]
},
{
children: [
{
icon: 'copy',
label: appT('Copy one app'),
onClick: () =>
openConfirmCopy(() => onclickCopy({ appId: app._id }))()
}
]
},
{
children: [
{
icon: 'core/chat/chatLight',
label: appT('Go to chat'),
onClick: () => {
router.push(`/chat?appId=${app._id}`);
}
}
]
},
...(app.permission.isOwner
? [
{
children: [
{
type: 'danger' as 'danger',
icon: 'delete',
label: t('common.Delete'),
onClick: () =>
openConfirmDel(
() => onclickDelApp(app._id),
undefined,
app.type === AppTypeEnum.folder
? appT('Confirm delete folder tip')
: appT('Confirm Del App Tip')
)()
}
]
}
]
: [])
]}
/>
</Box>
)}
</Flex>
<Box
flex={1}
className={'textEllipsis3'}
py={2}
wordBreak={'break-all'}
fontSize={'mini'}
color={'myGray.600'}
>
{app.intro || '还没写介绍~'}
</Box>
<Flex h={'34px'} alignItems={'flex-end'}>
<Box flex={1}>
<PermissionIconText
defaultPermission={app.defaultPermission}
color={'myGray.600'}
/>
</Box>
<AppTypeTag type={app.type} />
</Flex>
</MyBox>
</MyTooltip>
))}
]}
/>
</Box>
)}
</HStack>
</Flex>
</MyBox>
</MyTooltip>
);
})}
</Grid>
{myApps.length === 0 && <EmptyTip text={'还没有应用,快去创建一个吧!'} pt={'30vh'} />}

View File

@@ -3,7 +3,7 @@ import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import MyTag from '@fastgpt/web/components/common/Tag/index';
import { useI18n } from '@/web/context/I18n';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { Box } from '@chakra-ui/react';
import { Box, Flex } from '@chakra-ui/react';
const AppTypeTag = ({ type }: { type: AppTypeEnum }) => {
const { appT } = useI18n();
@@ -11,19 +11,27 @@ const AppTypeTag = ({ type }: { type: AppTypeEnum }) => {
const map = useRef({
[AppTypeEnum.simple]: {
label: appT('type.Simple bot'),
icon: 'core/app/type/simple'
icon: 'core/app/type/simple',
bg: '#DBF3FF',
color: '#0884DD'
},
[AppTypeEnum.workflow]: {
label: appT('type.Workflow bot'),
icon: 'core/app/type/workflow'
icon: 'core/app/type/workflow',
bg: '#E4E1FC',
color: '#6F5DD7'
},
[AppTypeEnum.plugin]: {
label: appT('type.Plugin'),
icon: 'core/app/type/plugin'
icon: 'core/app/type/plugin',
bg: '#D0F5EE',
color: '#007E7C'
},
[AppTypeEnum.httpPlugin]: {
label: appT('type.Http plugin'),
icon: 'core/app/type/httpPlugin'
icon: 'core/app/type/httpPlugin',
bg: '#FFE4EE',
color: '#E82F72'
},
[AppTypeEnum.folder]: undefined
});
@@ -31,12 +39,20 @@ const AppTypeTag = ({ type }: { type: AppTypeEnum }) => {
const data = map.current[type];
return data ? (
<MyTag type="borderFill" colorSchema="gray">
<MyIcon name={data.icon as any} w={'0.8rem'} color={'myGray.500'} />
<Flex
bg={data.bg}
color={data.color}
py={0.5}
pl={2}
pr={2}
borderLeftRadius={'md'}
whiteSpace={'nowrap'}
>
<MyIcon name={data.icon as any} w={'0.8rem'} />
<Box ml={1} fontSize={'mini'}>
{data.label}
</Box>
</MyTag>
</Flex>
) : null;
};

View File

@@ -11,6 +11,7 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
import { useContextSelector } from 'use-context-selector';
import { DatasetImportContext } from '../Context';
import { importType2ReadType } from '@fastgpt/global/core/dataset/read';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
const PreviewChunks = ({
previewSource,
@@ -25,9 +26,8 @@ const PreviewChunks = ({
(v) => v
);
const { data = [], isLoading } = useQuery(
['previewSource'],
() => {
const { data = [], loading: isLoading } = useRequest2(
async () => {
if (importSource === ImportDataSourceEnum.fileCustom) {
const customSplitChar = processParamsForm.getValues('customSplitChar');
const { chunks } = splitText2Chunks({
@@ -66,12 +66,7 @@ const PreviewChunks = ({
});
},
{
onError(err) {
toast({
status: 'warning',
title: getErrText(err)
});
}
manual: false
}
);

View File

@@ -26,7 +26,7 @@ import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import DefaultPermissionList from '@/components/support/permission/DefaultPerList';
import {
DatasetDefaultPermission,
DatasetDefaultPermissionVal,
DatasetPermissionList
} from '@fastgpt/global/support/permission/dataset/constant';
import MemberManager from '../../component/MemberManager';
@@ -202,10 +202,16 @@ const Info = ({ datasetId }: { datasetId: string }) => {
{datasetDetail.type === DatasetTypeEnum.externalFile && (
<>
<Flex w={'100%'} alignItems={'center'}>
<HStack fontSize={['sm', 'md']} flex={['0 0 90px', '0 0 160px']} w={0}>
<FormLabel
display={'flex'}
flex={['0 0 90px', '0 0 160px']}
w={0}
gap={1}
alignItems={'center'}
>
<Box>{datasetT('External read url')}</Box>
<QuestionTip label={datasetT('External read url tip')} />
</HStack>
</FormLabel>
<Input
flex={[1, '0 0 320px']}
placeholder="https://test.com/read?fileId={{fileId}}"
@@ -246,6 +252,8 @@ const Info = ({ datasetId }: { datasetId: string }) => {
{datasetDetail.permission.hasManagePer && (
<>
<MyDivider my={6} h={'2px'} maxW={'500px'} />
<Flex mt={5} alignItems={'center'} w={'100%'} flexWrap={'wrap'} maxW="500px">
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}>
{commonT('permission.Default permission')}
@@ -253,7 +261,7 @@ const Info = ({ datasetId }: { datasetId: string }) => {
<DefaultPermissionList
w="320px"
per={defaultPermission}
defaultPer={DatasetDefaultPermission}
defaultPer={DatasetDefaultPermissionVal}
onChange={(v) => setValue('defaultPermission', v)}
/>
</Flex>

View File

@@ -20,7 +20,7 @@ import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'
import AIModelSelector from '@/components/Select/AIModelSelector';
import { useI18n } from '@/web/context/I18n';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { DatasetDefaultPermission } from '@fastgpt/global/support/permission/dataset/constant';
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: string }) => {
const { t } = useTranslation();
@@ -40,7 +40,7 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
intro: '',
vectorModel: filterNotHiddenVectorModelList[0].model,
agentModel: datasetModelList[0].model,
defaultPermission: DatasetDefaultPermission
defaultPermission: DatasetDefaultPermissionVal
}
});
const avatar = watch('avatar');

View File

@@ -19,9 +19,9 @@ import { downloadFetch } from '@/web/common/system/utils';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import dynamic from 'next/dynamic';
import { useContextSelector } from 'use-context-selector';
import { DatasetContext } from '../context';
import { DatasetsContext } from '../context';
import {
DatasetDefaultPermission,
DatasetDefaultPermissionVal,
DatasetPermissionList
} from '@fastgpt/global/support/permission/dataset/constant';
import ConfigPerModal from '@/components/support/permission/ConfigPerModal';
@@ -49,16 +49,17 @@ function List() {
editedDataset,
setEditedDataset,
onDelDataset
} = useContextSelector(DatasetContext, (v) => v);
} = useContextSelector(DatasetsContext, (v) => v);
const [editPerDatasetIndex, setEditPerDatasetIndex] = useState<number>();
const { myDatasets, loadMyDatasets } = useDatasetStore();
const [loadingDatasetId, setLoadingDatasetId] = useState<string>();
const { getBoxProps } = useFolderDrag({
activeStyles: {
borderColor: 'primary.600'
},
onDrop: async (dragId: string, targetId: string) => {
setLoading(true);
setLoadingDatasetId(dragId);
try {
await putDatasetById({
id: dragId,
@@ -66,7 +67,7 @@ function List() {
});
refetchDatasets();
} catch (error) {}
setLoading(false);
setLoadingDatasetId(undefined);
}
});
@@ -160,6 +161,7 @@ function List() {
}
>
<MyBox
isLoading={loadingDatasetId === dataset._id}
display={'flex'}
flexDirection={'column'}
py={3}
@@ -254,18 +256,6 @@ function List() {
label: t('Move'),
onClick: () => setMoveDatasetId(dataset._id)
},
...(dataset.type != DatasetTypeEnum.folder
? [
{
icon: 'export',
label: t('Export'),
onClick: () => {
exportDataset(dataset);
}
}
]
: []),
...(dataset.permission.hasManagePer
? [
{
@@ -277,6 +267,21 @@ function List() {
: [])
]
},
...(dataset.type != DatasetTypeEnum.folder
? [
{
children: [
{
icon: 'export',
label: t('Export'),
onClick: () => {
exportDataset(dataset);
}
}
]
}
]
: []),
...(dataset.permission.hasManagePer
? [
{
@@ -361,7 +366,7 @@ function List() {
name={editPerDataset.name}
defaultPer={{
value: editPerDataset.defaultPermission,
defaultValue: DatasetDefaultPermission,
defaultValue: DatasetDefaultPermissionVal,
onChange: async (e) => {
await putDatasetById({
id: editPerDataset._id,

View File

@@ -15,13 +15,12 @@ import { useRouter } from 'next/router';
import React, { useCallback, useState } from 'react';
import { createContext } from 'use-context-selector';
import { useI18n } from '@/web/context/I18n';
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api';
import dynamic from 'next/dynamic';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { DatasetItemType } from '@fastgpt/global/core/dataset/type';
import { EditResourceInfoFormType } from '@/components/common/Modal/EditResourceModal';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'react-i18next';
const MoveModal = dynamic(() => import('@/components/common/folder/MoveModal'));
@@ -39,7 +38,7 @@ export type DatasetContextType = {
onDelDataset: (id: string) => Promise<void>;
};
export const DatasetContext = createContext<DatasetContextType>({
export const DatasetsContext = createContext<DatasetContextType>({
refetchDatasets: () => {},
isFetchingDatasets: false,
setMoveDatasetId: () => {},
@@ -136,7 +135,7 @@ function DatasetContextProvider({ children }: { children: React.ReactNode }) {
};
return (
<DatasetContext.Provider value={contextValue}>
<DatasetsContext.Provider value={contextValue}>
{children}
{!!moveDatasetId && (
<MoveModal
@@ -147,7 +146,7 @@ function DatasetContextProvider({ children }: { children: React.ReactNode }) {
onConfirm={onMoveDataset}
/>
)}
</DatasetContext.Provider>
</DatasetsContext.Provider>
);
}

View File

@@ -7,7 +7,7 @@ import { serviceSideProps } from '@/web/common/utils/i18n';
import ParentPaths from '@/components/common/folder/Path';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import List from './component/List';
import { DatasetContext } from './context';
import { DatasetsContext } from './context';
import DatasetContextProvider from './context';
import { useContextSelector } from 'use-context-selector';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
@@ -22,7 +22,7 @@ import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import FolderSlideCard from '@/components/common/folder/SlideCard';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import {
DatasetDefaultPermission,
DatasetDefaultPermissionVal,
DatasetPermissionList
} from '@fastgpt/global/support/permission/dataset/constant';
import {
@@ -54,7 +54,7 @@ const Dataset = () => {
setEditedDataset,
setMoveDatasetId,
onDelDataset
} = useContextSelector(DatasetContext, (v) => v);
} = useContextSelector(DatasetsContext, (v) => v);
const { userInfo } = useUserStore();
const [editFolderData, setEditFolderData] = useState<EditFolderFormType>();
@@ -68,11 +68,11 @@ const Dataset = () => {
return (
<PageContainer
isLoading={myDatasets.length === 0 && isFetchingDatasets}
insertProps={{ px: [5, '48px'] }}
insertProps={{ px: folderDetail ? [4, 6] : [5, '10'] }}
>
<Flex pt={[8, 10]} pr={folderDetail ? [4, 6] : [4, 10]}>
<Flex pt={[4, 6]}>
<Flex flexGrow={1} flexDirection="column">
<Flex alignItems={'center'} justifyContent={'space-between'}>
<Flex alignItems={'flex-start'} justifyContent={'space-between'}>
<ParentPaths
paths={paths}
FirstPathDom={
@@ -162,7 +162,7 @@ const Dataset = () => {
}
defaultPer={{
value: folderDetail.defaultPermission,
defaultValue: DatasetDefaultPermission,
defaultValue: DatasetDefaultPermissionVal,
onChange: (e) => {
return putDatasetById({
id: folderDetail._id,

View File

@@ -10,7 +10,7 @@ export const defaultApp: AppDetailType = {
type: AppTypeEnum.simple,
avatar: '/icon/logo.svg',
intro: '',
updateTime: Date.now(),
updateTime: new Date(),
modules: [],
chatConfig: {},
teamId: '',

View File

@@ -49,9 +49,10 @@ import type {
PreviewChunksResponse
} from '@/pages/api/core/dataset/file/getPreviewChunks';
import type { readCollectionSourceResponse } from '@/pages/api/core/dataset/collection/read';
import type { GetDatasetListBody } from '@/pages/api/core/dataset/list';
/* ======================== dataset ======================= */
export const getDatasets = (data: { parentId?: ParentIdType; type?: DatasetTypeEnum }) =>
export const getDatasets = (data: GetDatasetListBody) =>
POST<DatasetListItemType[]>(`/core/dataset/list`, data);
/**

View File

@@ -8,7 +8,7 @@ import type {
DatasetCollectionItemType,
DatasetItemType
} from '@fastgpt/global/core/dataset/type.d';
import { DatasetDefaultPermission } from '@fastgpt/global/support/permission/dataset/constant';
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
import { DatasetPermission } from '@fastgpt/global/support/permission/dataset/controller';
export const defaultDatasetDetail: DatasetItemType = {
@@ -26,7 +26,7 @@ export const defaultDatasetDetail: DatasetItemType = {
permission: new DatasetPermission(),
vectorModel: defaultVectorModels[0],
agentModel: defaultQAModels[0],
defaultPermission: DatasetDefaultPermission
defaultPermission: DatasetDefaultPermissionVal
};
export const defaultCollectionDetail: DatasetCollectionItemType = {
@@ -48,7 +48,7 @@ export const defaultCollectionDetail: DatasetCollectionItemType = {
permission: new DatasetPermission(),
vectorModel: defaultVectorModels[0].model,
agentModel: defaultQAModels[0].model,
defaultPermission: DatasetDefaultPermission
defaultPermission: DatasetDefaultPermissionVal
},
parentId: '',
name: '',