mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-28 00:56:26 +00:00
Perf: delete app tip; fix: can't stop debug. (#2865)
* fix: variables check * remove log * perf: delete app tip * perf: remove node code * fix: can not stop debug * update version * update version intro * fix: per error * perf: apikey manager * Add permission check * update README
This commit is contained in:
@@ -24,7 +24,6 @@ import {
|
||||
putOpenApiKey
|
||||
} from '@/web/support/openapi/api';
|
||||
import type { EditApiKeyProps } from '@/global/support/openapi/api.d';
|
||||
import { useQuery, useMutation } from '@tanstack/react-query';
|
||||
import dayjs from 'dayjs';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
@@ -33,7 +32,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
@@ -61,13 +60,10 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
|
||||
const { ConfirmModal, openConfirm } = useConfirm({
|
||||
type: 'delete',
|
||||
content: t('workflow:delete_api')
|
||||
content: t('common:delete_api')
|
||||
});
|
||||
|
||||
const { mutate: onclickRemove, isLoading: isDeleting } = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
return delOpenApiById(id);
|
||||
},
|
||||
const { runAsync: onclickRemove } = useRequest2(delOpenApiById, {
|
||||
onSuccess() {
|
||||
refetch();
|
||||
}
|
||||
@@ -75,9 +71,12 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
|
||||
const {
|
||||
data: apiKeys = [],
|
||||
isLoading: isGetting,
|
||||
refetch
|
||||
} = useQuery(['getOpenApiKeys', appId], () => getOpenApiKeys({ appId }));
|
||||
loading: isGetting,
|
||||
run: refetch
|
||||
} = useRequest2(() => getOpenApiKeys({ appId }), {
|
||||
manual: false,
|
||||
refreshDeps: [appId]
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setBaseUrl(feConfigs?.customApiDomain || `${location.origin}/api`);
|
||||
@@ -85,7 +84,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
|
||||
return (
|
||||
<MyBox
|
||||
isLoading={isGetting || isDeleting}
|
||||
isLoading={isGetting}
|
||||
display={'flex'}
|
||||
flexDirection={'column'}
|
||||
h={'100%'}
|
||||
|
@@ -52,8 +52,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
}
|
||||
]
|
||||
: []),
|
||||
// ...(feConfigs?.show_pay && userInfo?.team?.permission.hasWritePer
|
||||
...(feConfigs?.show_pay || userInfo?.team?.permission.hasWritePer
|
||||
...(feConfigs?.show_pay && userInfo?.team?.permission.hasManagePer
|
||||
? [
|
||||
{
|
||||
icon: 'support/bill/payRecordLight',
|
||||
@@ -62,8 +61,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
}
|
||||
]
|
||||
: []),
|
||||
|
||||
...(feConfigs?.show_promotion
|
||||
...(feConfigs?.show_promotion && userInfo?.team?.permission.isOwner
|
||||
? [
|
||||
{
|
||||
icon: 'support/account/promotionLight',
|
||||
@@ -72,7 +70,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(userInfo?.team?.permission.hasWritePer
|
||||
...(userInfo?.team?.permission.hasManagePer
|
||||
? [
|
||||
{
|
||||
icon: 'support/outlink/apikeyLight',
|
||||
|
@@ -1,64 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
|
||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
|
||||
import { MongoMemberGroupModel } from '@fastgpt/service/support/permission/memberGroup/memberGroupSchema';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
|
||||
/*
|
||||
1. 给每个 team 创建一个默认的 group
|
||||
*/
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
await authCert({ req, authRoot: true });
|
||||
|
||||
const teamList = await MongoTeam.find({}, '_id');
|
||||
console.log('Total team', teamList.length);
|
||||
let success = 0;
|
||||
|
||||
async function createGroup(teamId: string) {
|
||||
try {
|
||||
await MongoMemberGroupModel.updateOne(
|
||||
{
|
||||
teamId,
|
||||
name: DefaultGroupName
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
teamId: teamId,
|
||||
name: DefaultGroupName
|
||||
}
|
||||
},
|
||||
{
|
||||
upsert: true
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
await delay(500);
|
||||
return createGroup(teamId);
|
||||
}
|
||||
}
|
||||
for await (const team of teamList) {
|
||||
await createGroup(team._id);
|
||||
console.log(++success);
|
||||
}
|
||||
|
||||
jsonRes(res, {
|
||||
message: 'success'
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error
|
||||
});
|
||||
}
|
||||
}
|
@@ -413,32 +413,7 @@ export const useWorkflow = () => {
|
||||
});
|
||||
|
||||
/* node */
|
||||
const handleRemoveNode = useMemoizedFn((nodeId: string) => {
|
||||
// If the node has child nodes, remove the child nodes
|
||||
const childNodes = nodes.filter((n) => n.data.parentNodeId === nodeId);
|
||||
if (childNodes.length > 0) {
|
||||
const childNodeIds = childNodes.map((node) => node.id);
|
||||
const childEdges = edges.filter(
|
||||
(edge) => childNodeIds.includes(edge.source) || childNodeIds.includes(edge.target)
|
||||
);
|
||||
|
||||
onNodesChange(
|
||||
childNodes.map<NodeRemoveChange>((node) => ({
|
||||
type: 'remove',
|
||||
id: node.id
|
||||
}))
|
||||
);
|
||||
onEdgesChange(
|
||||
childEdges.map<EdgeRemoveChange>((edge) => ({
|
||||
type: 'remove',
|
||||
id: edge.id
|
||||
}))
|
||||
);
|
||||
}
|
||||
onNodesChange([{ type: 'remove', id: nodeId }]);
|
||||
|
||||
return;
|
||||
});
|
||||
const handleSelectNode = useMemoizedFn((change: NodeSelectionChange) => {
|
||||
// If the node is not selected and the Ctrl key is pressed, select the node
|
||||
if (change.selected === false && isDowningCtrl) {
|
||||
@@ -618,9 +593,8 @@ export const useWorkflow = () => {
|
||||
|
||||
useKeyPress(['Delete', 'Backspace'], (e) => {
|
||||
if (!mouseInCanvas) return;
|
||||
const selectedNodes = nodes.filter((node) => node.selected);
|
||||
const selectedEdges = edges.filter((edge) => edge.selected);
|
||||
|
||||
const selectedNodes = nodes.filter((node) => node.selected);
|
||||
if (selectedNodes.length > 0) {
|
||||
for (const node of selectedNodes) {
|
||||
if (node.data.forbidDelete) {
|
||||
@@ -631,13 +605,27 @@ export const useWorkflow = () => {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Computed deleted node and its edges
|
||||
const removedNodeId = node.id;
|
||||
handleRemoveNode(removedNodeId);
|
||||
const edgesToRemove = edges.filter(
|
||||
const removedNodeEdges = edges.filter(
|
||||
(edge) => edge.source === removedNodeId || edge.target === removedNodeId
|
||||
);
|
||||
|
||||
const childNodes = nodes.filter((n) => n.data.parentNodeId === removedNodeId);
|
||||
const childNodeIds = childNodes.map((node) => node.id);
|
||||
const childEdges = edges.filter(
|
||||
(edge) => childNodeIds.includes(edge.source) || childNodeIds.includes(edge.target)
|
||||
);
|
||||
|
||||
// Delete
|
||||
onNodesChange(
|
||||
[removedNodeId, ...childNodeIds].map((nodeId) => ({
|
||||
type: 'remove',
|
||||
id: nodeId
|
||||
}))
|
||||
);
|
||||
onEdgesChange(
|
||||
edgesToRemove.map((edge) => ({
|
||||
[...removedNodeEdges, ...childEdges].map((edge) => ({
|
||||
type: 'remove',
|
||||
id: edge.id
|
||||
}))
|
||||
@@ -645,6 +633,8 @@ export const useWorkflow = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete selected edges
|
||||
const selectedEdges = edges.filter((edge) => edge.selected);
|
||||
if (selectedEdges.length > 0) {
|
||||
onEdgesChange(
|
||||
selectedEdges.map((edge) => ({
|
||||
|
@@ -606,10 +606,10 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const onStopNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStopNodeDebug);
|
||||
const onNextNodeDebug = useContextSelector(WorkflowContext, (v) => v.onNextNodeDebug);
|
||||
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
|
||||
const { onChangeNode, onStopNodeDebug, onNextNodeDebug, workflowDebugData } = useContextSelector(
|
||||
WorkflowContext,
|
||||
(v) => v
|
||||
);
|
||||
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: t('common:core.workflow.Confirm stop debug')
|
||||
@@ -741,11 +741,9 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
||||
)}
|
||||
</Card>
|
||||
)}
|
||||
<ConfirmModal />
|
||||
</>
|
||||
) : null;
|
||||
}, [
|
||||
ConfirmModal,
|
||||
debugResult,
|
||||
nodeId,
|
||||
onChangeNode,
|
||||
@@ -753,8 +751,13 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
||||
onStopNodeDebug,
|
||||
openConfirm,
|
||||
t,
|
||||
workflowDebugData?.nextRunNodes
|
||||
workflowDebugData
|
||||
]);
|
||||
|
||||
return <>{RenderStatus}</>;
|
||||
return (
|
||||
<>
|
||||
{RenderStatus}
|
||||
<ConfirmModal />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
@@ -160,7 +160,7 @@ const AppContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
});
|
||||
|
||||
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
|
||||
content: t('app:confirm_del_app_tip'),
|
||||
content: t('app:confirm_del_app_tip', { name: appDetail.name }),
|
||||
type: 'delete'
|
||||
});
|
||||
const { runAsync: deleteApp } = useRequest2(
|
||||
|
@@ -365,7 +365,7 @@ const ListItem = () => {
|
||||
undefined,
|
||||
app.type === AppTypeEnum.folder
|
||||
? t('app:confirm_delete_folder_tip')
|
||||
: t('app:confirm_del_app_tip')
|
||||
: t('app:confirm_del_app_tip', { name: app.name })
|
||||
)()
|
||||
}
|
||||
]
|
||||
|
@@ -82,7 +82,7 @@ const Dataset = () => {
|
||||
|
||||
const RenderSearchInput = useMemo(
|
||||
() => (
|
||||
<InputGroup maxW={['auto', '250px']} pr={[0, 4]}>
|
||||
<InputGroup maxW={['auto', '250px']}>
|
||||
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
|
||||
<MyIcon color={'myGray.600'} name={'common/searchLight'} w={'1rem'} />
|
||||
</InputLeftElement>
|
||||
@@ -100,6 +100,7 @@ const Dataset = () => {
|
||||
),
|
||||
[searchKey, setSearchKey, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<MyBox
|
||||
isLoading={myDatasets.length === 0 && isFetchingDatasets}
|
||||
@@ -110,7 +111,7 @@ const Dataset = () => {
|
||||
>
|
||||
<Flex pt={[4, 6]} pl={3} pr={[3, 10]}>
|
||||
<Flex flexGrow={1} flexDirection="column">
|
||||
<Flex alignItems={'flex-start'} justifyContent={'space-between'}>
|
||||
<Flex alignItems={'center'} justifyContent={'space-between'}>
|
||||
<ParentPaths
|
||||
paths={paths}
|
||||
FirstPathDom={
|
||||
@@ -138,54 +139,56 @@ const Dataset = () => {
|
||||
{isPc && RenderSearchInput}
|
||||
|
||||
{userInfo?.team?.permission.hasWritePer && (
|
||||
<MyMenu
|
||||
offset={[0, 10]}
|
||||
width={120}
|
||||
iconSize="2rem"
|
||||
iconRadius="6px"
|
||||
placement="bottom-end"
|
||||
Button={
|
||||
<Button variant={'primary'} px="0">
|
||||
<Flex alignItems={'center'} px={5}>
|
||||
<AddIcon mr={2} />
|
||||
<Box>{t('common:common.Create New')}</Box>
|
||||
</Flex>
|
||||
</Button>
|
||||
}
|
||||
menuList={[
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: 'core/dataset/commonDatasetColor',
|
||||
label: t('dataset:common_dataset'),
|
||||
description: t('dataset:common_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.dataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/websiteDatasetColor',
|
||||
label: t('dataset:website_dataset'),
|
||||
description: t('dataset:website_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.websiteDataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/externalDatasetColor',
|
||||
label: t('dataset:external_file'),
|
||||
description: t('dataset:external_file_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.externalFile)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: FolderIcon,
|
||||
label: t('common:Folder'),
|
||||
onClick: () => setEditFolderData({})
|
||||
}
|
||||
]
|
||||
<Box pl={[0, 4]}>
|
||||
<MyMenu
|
||||
offset={[0, 10]}
|
||||
width={120}
|
||||
iconSize="2rem"
|
||||
iconRadius="6px"
|
||||
placement="bottom-end"
|
||||
Button={
|
||||
<Button variant={'primary'} px="0">
|
||||
<Flex alignItems={'center'} px={5}>
|
||||
<AddIcon mr={2} />
|
||||
<Box>{t('common:common.Create New')}</Box>
|
||||
</Flex>
|
||||
</Button>
|
||||
}
|
||||
]}
|
||||
/>
|
||||
menuList={[
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: 'core/dataset/commonDatasetColor',
|
||||
label: t('dataset:common_dataset'),
|
||||
description: t('dataset:common_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.dataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/websiteDatasetColor',
|
||||
label: t('dataset:website_dataset'),
|
||||
description: t('dataset:website_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.websiteDataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/externalDatasetColor',
|
||||
label: t('dataset:external_file'),
|
||||
description: t('dataset:external_file_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.externalFile)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: FolderIcon,
|
||||
label: t('common:Folder'),
|
||||
onClick: () => setEditFolderData({})
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
|
Reference in New Issue
Block a user