V4.8.15 feature (#3331)

* feat: add customize toolkit (#3205)

* chaoyang

* fix-auth

* add toolkit

* add order

* plugin usage

* fix

* delete console:

* Fix: Fix fullscreen preview top positioning and improve Markdown rendering logic (#3247)

* 完成任务:修复全屏预览顶部固定问题,优化 Markdown 渲染逻辑

* 有问题修改

* 问题再修改

* 修正问题

* fix: plugin standalone display issue (#3254)

* 4.8.15 test (#3246)

* o1 config

* perf: system plugin code

* 调整系统插件代码。增加html 渲染安全配置。 (#3258)

* perf: base64 picker

* perf: list app or dataset

* perf: plugin config code

* 小窗适配等问题 (#3257)

* 小窗适配等问题

* git问题

* 小窗剩余问题

* feat: system plugin auth and lock version (#3265)

* feat: system plugin auth and lock version

* update comment

* 4.8.15 test (#3267)

* tmp log

* perf: login direct

* perf: iframe html code

* remove log

* fix: plugin standalone display (#3277)

* refactor: 页面拆分&i18n拆分 (#3281)

* refactor: account组件拆成独立页面

* script: 新增i18n json文件创建脚本

* refactor: 页面i18n拆分

* i18n: add en&hant

* 4.8.15 test (#3285)

* tmp log

* remove log

* fix: watch avatar refresh

* perf: i18n code

* fix(plugin): use intro instead of userguide (#3290)

* Universal SSO (#3292)

* tmp log

* remove log

* feat: common oauth

* readme

* perf: sso provider

* remove sso code

* perf: refresh plugins

* feat: add api dataset (#3272)

* add api-dataset

* fix api-dataset

* fix api dataset

* fix ts

* perf: create collection code (#3301)

* tmp log

* remove log

* perf: i18n change

* update version doc

* feat: question guide from chatId

* perf: create collection code

* fix: request api

* fix: request api

* fix: tts auth and response type (#3303)

* perf: md splitter

* fix: tts auth and response type

* fix: api file dataset (#3307)

* perf: api dataset init (#3310)

* perf: collection schema

* perf: api dataset init

* refactor: 团队管理独立页面 (#3302)

* ui: 团队管理独立页面

* 代码优化

* fix

* perf: sync collection and ui check (#3314)

* perf: sync collection

* remove script

* perf: update api server

* perf: api dataset parent

* perf: team ui

* perf: team 18n

* update team ui

* perf: ui check

* perf: i18n

* fix: debug variables & cronjob & system plugin callback load (#3315)

* fix: debug variables & cronjob & system plugin callback load

* fix type

* fix

* fix

* fix: plugin dataset quote;perf: system variables init (#3316)

* fix: plugin dataset quote

* perf: system variables init

* perf: node templates ui;fix: dataset import ui (#3318)

* fix: dataset import ui

* perf: node templates ui

* perf: ui refresh

* feat:套餐改名和套餐跳转配置 (#3309)

* fixing:except Sidebar

* 去除了多余的代码

* 修正了套餐说明的代码

* 修正了误删除的show_git代码

* 修正了名字部分等代码

* 修正了问题,遗留了其他和ui讨论不一致的部分

* 4.8.15 test (#3319)

* remove log

* pref: bill ui

* pref: bill ui

* perf: log

* html渲染文档 (#3270)

* html渲染文档

* 文档有点小问题

* feat: doc (#3322)

* 集合重训练 (#3282)

* rebaser

* 一点补充

* 小问题

* 其他问题修正,删除集合保留文件的参数还没找到...

* reTraining

* delete uesless

* 删除了一行错误代码

* 集合重训练部分

* fixing

* 删除console代码

* feat: navbar item config (#3326)

* perf: custom navbar code;perf: retraining code;feat: api dataset and dataset api doc (#3329)

* feat: api dataset and dataset api doc

* perf: retraining code

* perf: custom navbar code

* fix: ts (#3330)

* fix: ts

* fix: ts

* retraining ui

* perf: api collection filter

* perf: retrining button

---------

Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: Jiangween <145003935+Jiangween@users.noreply.github.com>
Co-authored-by: papapatrick <109422393+Patrickill@users.noreply.github.com>
This commit is contained in:
Archer
2024-12-06 10:56:53 +08:00
committed by GitHub
parent b188544386
commit 1aebe5f185
307 changed files with 7383 additions and 3981 deletions

View File

@@ -0,0 +1,132 @@
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { Box, Flex, HStack, ModalBody } from '@chakra-ui/react';
import Avatar from '@fastgpt/web/components/common/Avatar';
import MyBox from '@fastgpt/web/components/common/MyBox';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyModal from '@fastgpt/web/components/common/MyModal';
import Markdown from '@/components/Markdown';
import { NodeTemplateListItemType } from '@fastgpt/global/core/workflow/type/node';
import { PluginGroupSchemaType } from '@fastgpt/service/core/app/plugin/type';
const PluginCard = ({
item,
groups
}: {
item: NodeTemplateListItemType;
groups: PluginGroupSchemaType[];
}) => {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const [currentPlugin, setCurrentPlugin] = useState<NodeTemplateListItemType | null>(null);
const type = groups.reduce<string | undefined>((acc, group) => {
const foundType = group.groupTypes.find((type) => type.typeId === item.templateType);
return foundType ? foundType.typeName : acc;
}, undefined);
return (
<MyBox
key={item.id}
lineHeight={1.5}
h="100%"
pt={4}
pb={3}
px={4}
border={'base'}
boxShadow={'2'}
bg={'white'}
borderRadius={'10px'}
position={'relative'}
display={'flex'}
flexDirection={'column'}
_hover={{
borderColor: 'primary.300',
boxShadow: '1.5'
}}
>
<HStack>
<Avatar src={item.avatar} borderRadius={'sm'} w={'1.5rem'} h={'1.5rem'} />
<Box flex={'1 0 0'} color={'myGray.900'} fontWeight={500}>
{item.name}
</Box>
<Box mr={'-1rem'}>
<Flex
bg={'myGray.100'}
color={'myGray.600'}
py={0.5}
pl={2}
pr={3}
borderLeftRadius={'sm'}
whiteSpace={'nowrap'}
>
<Box ml={1} fontSize={'mini'}>
{t(type as any)}
</Box>
</Flex>
</Box>
</HStack>
<Box
flex={['1 0 48px', '1 0 56px']}
mt={3}
pr={1}
textAlign={'justify'}
wordBreak={'break-all'}
fontSize={'xs'}
color={'myGray.500'}
>
<Box className={'textEllipsis2'}>{item.intro || t('app:templateMarket.no_intro')}</Box>
</Box>
<Flex w={'full'} fontSize={'mini'}>
<Flex flex={1}>
{item.instructions && (
<Flex
color={'primary.700'}
alignItems={'center'}
gap={1}
cursor={'pointer'}
onClick={() => setCurrentPlugin(item)}
_hover={{ bg: 'myGray.100' }}
>
<MyIcon name={'book'} w={'14px'} />
{t('app:plugin.Instructions')}
</Flex>
)}
</Flex>
<Box color={'myGray.500'}>{`by ${item.author || feConfigs.systemTitle}`}</Box>
</Flex>
{currentPlugin && (
<InstructionModal currentPlugin={currentPlugin} onClose={() => setCurrentPlugin(null)} />
)}
</MyBox>
);
};
const InstructionModal = ({
currentPlugin,
onClose
}: {
currentPlugin: NodeTemplateListItemType;
onClose: () => void;
}) => {
return (
<MyModal
isOpen
iconSrc={currentPlugin.avatar}
title={currentPlugin.name}
onClose={onClose}
minW={'600px'}
>
<ModalBody>
<Box border={'base'} borderRadius={'10px'} p={4} minH={'500px'}>
<Markdown source={currentPlugin.instructions} />
</Box>
</ModalBody>
</MyModal>
);
};
export default React.memo(PluginCard);

View File

@@ -0,0 +1,226 @@
import { serviceSideProps } from '@/web/common/utils/i18n';
import { getPluginGroups, getSystemPlugTemplates } from '@/web/core/app/api/plugin';
import { Box, Flex, Grid, useDisclosure } from '@chakra-ui/react';
import Avatar from '@fastgpt/web/components/common/Avatar';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useMemo, useState } from 'react';
import PluginCard from './components/PluginCard';
import { i18nT } from '@fastgpt/web/i18n/utils';
import { useTranslation } from 'react-i18next';
import { useRouter } from 'next/router';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
import { navbarWidth } from '@/components/Layout';
const Toolkit = () => {
const { t } = useTranslation();
const router = useRouter();
const { isPc } = useSystem();
const { data: plugins = [] } = useRequest2(getSystemPlugTemplates, {
manual: false
});
const { data: pluginGroups = [] } = useRequest2(getPluginGroups, {
manual: false
});
const isOneGroup = pluginGroups.length === 1;
const [search, setSearch] = useState('');
const { isOpen, onOpen, onClose } = useDisclosure();
const { group: selectedGroup = pluginGroups?.[0]?.groupId, type: selectedType = 'all' } =
router.query;
const pluginGroupTypes = useMemo(() => {
const allTypes = [
{
typeId: 'all',
typeName: i18nT('common:common.All')
}
];
const currentTypes =
pluginGroups?.find((group) => group.groupId === selectedGroup)?.groupTypes ?? [];
return [
...allTypes,
...currentTypes.filter((type) =>
plugins.find((plugin) => plugin.templateType === type.typeId)
)
];
}, [pluginGroups, plugins, selectedGroup]);
const currentPlugins = useMemo(() => {
const typeArray = pluginGroupTypes?.map((type) => type.typeId);
return plugins
.filter(
(plugin) =>
(selectedType === 'all' && typeArray?.includes(plugin.templateType)) ||
selectedType === plugin.templateType
)
.filter((plugin) => {
const str = `${plugin.name}${plugin.intro}${plugin.instructions}`;
const regx = new RegExp(search, 'gi');
return regx.test(str);
});
}, [pluginGroupTypes, plugins, selectedType, search]);
return (
<Flex flexDirection={'column'} h={'100%'} overflow={'auto'}>
{/* Mask */}
{!isPc && isOpen && (
<Box
position="fixed"
top={0}
left={0}
right={0}
bottom={0}
bg="blackAlpha.600"
onClick={onClose}
zIndex={99}
/>
)}
{/* Sidebar */}
{(isPc || isOpen) && (
<Box
position={'fixed'}
left={isPc ? navbarWidth : 0}
top={0}
bg={'myGray.25'}
w={['60vw', '200px']}
h={'full'}
borderLeft={'1px solid'}
borderRight={'1px solid'}
borderColor={'myGray.200'}
pt={4}
px={2.5}
pb={2.5}
zIndex={100}
userSelect={'none'}
>
{pluginGroups.map((group) => {
const selected = group.groupId === selectedGroup;
return (
<Box key={group.groupId}>
<Flex
p={2}
mb={0.5}
fontSize={'sm'}
rounded={'md'}
color={'myGray.900'}
{...(!isOneGroup && {
cursor: 'pointer',
_hover: {
bg: 'primary.50'
},
onClick: () => {
router.push({
query: { group: group.groupId, type: 'all' }
});
onClose();
}
})}
>
<Avatar src={group.groupAvatar} w={'1rem'} mr={1.5} color={'primary.600'} />
<Box>{t(group.groupName as any)}</Box>
<Box flex={1} />
{!isOneGroup && (
<MyIcon
color={'myGray.600'}
name={selected ? 'core/chat/chevronDown' : 'core/chat/chevronUp'}
w={'1rem'}
/>
)}
</Flex>
{/* group types */}
{selected &&
pluginGroupTypes.map((type) => {
return (
<Flex
key={type.typeId}
fontSize={'14px'}
fontWeight={500}
rounded={'md'}
py={2}
pl={'30px'}
cursor={'pointer'}
mb={0.5}
_hover={{ bg: 'primary.50' }}
{...(type.typeId === selectedType
? {
bg: 'primary.50',
color: 'primary.600'
}
: {
bg: 'transparent',
color: 'myGray.500'
})}
onClick={() => {
router.push({
query: { group: selectedGroup, type: type.typeId }
});
onClose();
}}
>
{t(type.typeName as any)}
</Flex>
);
})}
</Box>
);
})}
</Box>
)}
<Box ml={[0, '200px']} p={[5, 6]}>
<Flex alignItems={'center'}>
<Flex flex={1} fontSize={'xl'} fontWeight={'medium'} color={'myGray.900'}>
{isPc ? (
<Box>
{t(
pluginGroups?.find((group) => group.groupId === selectedGroup)?.groupName as any
)}
</Box>
) : (
<MyIcon name="menu" w={'20px'} mr={1.5} onClick={onOpen} />
)}
</Flex>
<Box w={['60vw', '260px']}>
<SearchInput
value={search}
bg={'white'}
onChange={(e) => setSearch(e.target.value)}
placeholder={t('common:plugin.Search plugin')}
/>
</Box>
</Flex>
<Grid
gridTemplateColumns={[
'1fr',
'repeat(2,1fr)',
'repeat(2,1fr)',
'repeat(3,1fr)',
'repeat(4,1fr)'
]}
gridGap={4}
alignItems={'stretch'}
py={5}
>
{currentPlugins.map((item) => (
<PluginCard key={item.id} item={item} groups={pluginGroups} />
))}
</Grid>
</Box>
</Flex>
);
};
export default Toolkit;
export async function getServerSideProps(context: any) {
return {
props: {
...(await serviceSideProps(context, ['app', 'user']))
}
};
}