V4.8.17 feature (#3485)
* feat: add third party account config (#3443) * temp * editor workflow variable style * add team to dispatch * i18n * delete console * change openai account position * fix * fix * fix * fix * fix * 4.8.17 test (#3461) * perf: external provider config * perf: ui * feat: add template config (#3434) * change template position * template config * delete console * delete * fix * fix * perf: Mongo visutal field (#3464) * remve invalid code * perf: team member visutal code * perf: virtual search; perf: search test data * fix: ts * fix: image response headers * perf: template code * perf: auth layout;perf: auto save (#3472) * perf: auth layout * perf: auto save * perf: auto save * fix: template guide display & http input support external variables (#3475) * fix: template guide display * http editor support external workflow variables * perf: auto save;fix: ifelse checker line break; (#3478) * perf: auto save * perf: auto save * fix: ifelse checker line break * perf: doc * perf: doc * fix: update var type error * 4.8.17 test (#3479) * perf: auto save * perf: auto save * perf: template code * 4.8.17 test (#3480) * perf: auto save * perf: auto save * perf: model price model * feat: add react memo * perf: model provider filter * fix: ts (#3481) * perf: auto save * perf: auto save * fix: ts * simple app tool select (#3473) * workflow plugin userguide & simple tool ui * simple tool filter * reuse component * change component to hook * fix * perf: too selector modal (#3484) * perf: auto save * perf: auto save * perf: markdown render * perf: too selector * fix: app version require tmbId * perf: templates refresh * perf: templates refresh * hide auto save error tip * perf: toolkit guide --------- Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
@@ -17,6 +17,8 @@ export enum TabEnum {
|
||||
'bill' = 'bill',
|
||||
'inform' = 'inform',
|
||||
'setting' = 'setting',
|
||||
'thirdParty' = 'thirdParty',
|
||||
'individuation' = 'individuation',
|
||||
'apikey' = 'apikey',
|
||||
'loginout' = 'loginout',
|
||||
'team' = 'team',
|
||||
@@ -70,6 +72,11 @@ const AccountContainer = ({
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
icon: 'common/thirdParty',
|
||||
label: t('account:third_party'),
|
||||
value: TabEnum.thirdParty
|
||||
},
|
||||
{
|
||||
icon: 'common/model',
|
||||
label: t('account:model_provider'),
|
||||
|
||||
@@ -92,7 +92,7 @@ const TeamSelector = ({
|
||||
: []),
|
||||
...teamList
|
||||
];
|
||||
}, [showManage, teamList, router]);
|
||||
}, [showManage, t, teamList, router]);
|
||||
|
||||
return (
|
||||
<Box w={'100%'}>
|
||||
|
||||
@@ -38,10 +38,8 @@ import { formatTime2YMD } from '@fastgpt/global/common/string/time';
|
||||
import { getExtraPlanCardRoute } from '@/web/support/wallet/sub/constants';
|
||||
|
||||
import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList';
|
||||
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
|
||||
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';
|
||||
import AccountContainer from '../components/AccountContainer';
|
||||
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
|
||||
@@ -52,8 +50,6 @@ const StandDetailModal = dynamic(() => import('./components/standardDetailModal'
|
||||
const ConversionModal = dynamic(() => import('./components/ConversionModal'));
|
||||
const UpdatePswModal = dynamic(() => import('./components/UpdatePswModal'));
|
||||
const UpdateNotification = dynamic(() => import('./components/UpdateNotificationModal'));
|
||||
const OpenAIAccountModal = dynamic(() => import('./components/OpenAIAccountModal'));
|
||||
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
||||
const CommunityModal = dynamic(() => import('@/components/CommunityModal'));
|
||||
|
||||
const ModelPriceModal = dynamic(() =>
|
||||
@@ -144,8 +140,7 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
async (data: UserType) => {
|
||||
await updateUserInfo({
|
||||
avatar: data.avatar,
|
||||
timezone: data.timezone,
|
||||
openaiAccount: data.openaiAccount
|
||||
timezone: data.timezone
|
||||
});
|
||||
reset(data);
|
||||
toast({
|
||||
@@ -353,11 +348,6 @@ const PlanUsage = () => {
|
||||
onClose: onCloseStandardModal,
|
||||
onOpen: onOpenStandardModal
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenAiPointsModal,
|
||||
onClose: onCloseAiPointsModal,
|
||||
onOpen: onOpenAiPointsModal
|
||||
} = useDisclosure();
|
||||
|
||||
const planName = useMemo(() => {
|
||||
if (!teamPlanStatus?.standard?.currentSubLevel) return '';
|
||||
@@ -443,9 +433,13 @@ const PlanUsage = () => {
|
||||
<MyIcon mr={2} name={'support/account/plans'} w={'20px'} />
|
||||
{t('account_info:package_and_usage')}
|
||||
</Flex>
|
||||
<Button ml={4} size={'sm'} onClick={onOpenAiPointsModal}>
|
||||
{t('account_info:billing_standard')}
|
||||
</Button>
|
||||
<ModelPriceModal>
|
||||
{({ onOpen }) => (
|
||||
<Button ml={4} size={'sm'} onClick={onOpen}>
|
||||
{t('account_info:billing_standard')}
|
||||
</Button>
|
||||
)}
|
||||
</ModelPriceModal>
|
||||
<Button ml={4} variant={'whitePrimary'} size={'sm'} onClick={onOpenStandardModal}>
|
||||
{t('account_info:package_details')}
|
||||
</Button>
|
||||
@@ -584,14 +578,24 @@ const PlanUsage = () => {
|
||||
</Box>
|
||||
</Box>
|
||||
{isOpenStandardModal && <StandDetailModal onClose={onCloseStandardModal} />}
|
||||
{isOpenAiPointsModal && <ModelPriceModal onClose={onCloseAiPointsModal} />}
|
||||
</Box>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const ButtonStyles = {
|
||||
bg: 'white',
|
||||
py: 3,
|
||||
px: 6,
|
||||
border: 'sm',
|
||||
borderWidth: '1.5px',
|
||||
borderRadius: 'md',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none' as any,
|
||||
fontSize: 'sm'
|
||||
};
|
||||
const Other = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
const { feConfigs } = useSystemStore();
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystem();
|
||||
@@ -600,56 +604,16 @@ const Other = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
const { reset } = useForm<UserUpdateParams>({
|
||||
defaultValues: userInfo as UserType
|
||||
});
|
||||
const { isOpen: isOpenLaf, onClose: onCloseLaf, onOpen: onOpenLaf } = useDisclosure();
|
||||
const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure();
|
||||
|
||||
const onclickSave = useCallback(
|
||||
async (data: UserType) => {
|
||||
await updateUserInfo({
|
||||
avatar: data.avatar,
|
||||
timezone: data.timezone,
|
||||
openaiAccount: data.openaiAccount
|
||||
});
|
||||
reset(data);
|
||||
toast({
|
||||
title: t('account_info:update_success_tip'),
|
||||
status: 'success'
|
||||
});
|
||||
},
|
||||
[reset, t, toast, updateUserInfo]
|
||||
);
|
||||
|
||||
const buttonStyles = useRef<FlexProps>({
|
||||
bg: 'white',
|
||||
py: 3,
|
||||
px: 6,
|
||||
border: theme.borders.sm,
|
||||
borderWidth: '1.5px',
|
||||
borderRadius: 'md',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
fontSize: 'sm'
|
||||
});
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid gridGap={4} mt={3}>
|
||||
{feConfigs?.docUrl && (
|
||||
<Link
|
||||
bg={'white'}
|
||||
href={getDocPath('/docs/intro')}
|
||||
target="_blank"
|
||||
display={'flex'}
|
||||
py={3}
|
||||
px={6}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
alignItems={'center'}
|
||||
userSelect={'none'}
|
||||
textDecoration={'none !important'}
|
||||
fontSize={'sm'}
|
||||
{...ButtonStyles}
|
||||
>
|
||||
<MyIcon name={'common/courseLight'} w={'18px'} color={'myGray.600'} />
|
||||
<Box ml={2} flex={1}>
|
||||
@@ -662,76 +626,22 @@ const Other = ({ onOpenContact }: { onOpenContact: () => void }) => {
|
||||
feConfigs?.navbarItems
|
||||
?.filter((item) => item.isActive)
|
||||
.map((item) => (
|
||||
<Flex
|
||||
key={item.id}
|
||||
{...buttonStyles.current}
|
||||
onClick={() => window.open(item.url, '_blank')}
|
||||
>
|
||||
<Flex key={item.id} {...ButtonStyles} onClick={() => window.open(item.url, '_blank')}>
|
||||
<Avatar src={item.avatar} w={'18px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{item.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
|
||||
{feConfigs?.lafEnv && userInfo?.team.role === TeamMemberRoleEnum.owner && (
|
||||
<Flex {...buttonStyles.current} onClick={onOpenLaf}>
|
||||
<MyImage src="/imgs/workflow/laf.png" w={'18px'} alt="laf" />
|
||||
<Box ml={2} flex={1}>
|
||||
{'laf' + t('account_info:account_duplicate')}
|
||||
</Box>
|
||||
<Box
|
||||
w={'9px'}
|
||||
h={'9px'}
|
||||
borderRadius={'50%'}
|
||||
bg={userInfo?.team.lafAccount?.token ? '#67c13b' : 'myGray.500'}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{feConfigs?.show_openai_account && (
|
||||
<Flex {...buttonStyles.current} onClick={onOpenOpenai}>
|
||||
<MyIcon name={'common/openai'} w={'18px'} color={'myGray.600'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{'OpenAI / OneAPI' + t('account_info:account_duplicate')}
|
||||
</Box>
|
||||
<Box
|
||||
w={'9px'}
|
||||
h={'9px'}
|
||||
borderRadius={'50%'}
|
||||
bg={userInfo?.openaiAccount?.key ? '#67c13b' : 'myGray.500'}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
{feConfigs?.concatMd && (
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
justifyContent={'flex-start'}
|
||||
leftIcon={<MyIcon name={'modal/concat'} w={'18px'} color={'myGray.600'} />}
|
||||
onClick={onOpenContact}
|
||||
h={'48px'}
|
||||
fontSize={'sm'}
|
||||
>
|
||||
{t('account_info:contact_us')}
|
||||
</Button>
|
||||
<Flex onClick={onOpenContact} {...ButtonStyles}>
|
||||
<MyIcon name={'modal/concat'} w={'18px'} color={'myGray.600'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('account_info:contact_us')}
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
{isOpenLaf && userInfo && (
|
||||
<LafAccountModal defaultData={userInfo?.team.lafAccount} onClose={onCloseLaf} />
|
||||
)}
|
||||
{isOpenOpenai && userInfo && (
|
||||
<OpenAIAccountModal
|
||||
defaultData={userInfo?.openaiAccount}
|
||||
onSuccess={(data) =>
|
||||
onclickSave({
|
||||
...userInfo,
|
||||
openaiAccount: data
|
||||
})
|
||||
}
|
||||
onClose={onCloseOpenai}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -130,7 +130,7 @@ const Team = () => {
|
||||
<Flex align={'center'} ml={6}>
|
||||
<TeamSelector height={'28px'} />
|
||||
</Flex>
|
||||
{userInfo?.team.role === TeamMemberRoleEnum.owner && (
|
||||
{userInfo?.team?.role === TeamMemberRoleEnum.owner && (
|
||||
<Flex align={'center'} justify={'center'} ml={2} p={'0.44rem'}>
|
||||
<MyIcon
|
||||
name="edit"
|
||||
|
||||
@@ -3,41 +3,51 @@ import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/rea
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import type { UserType } from '@fastgpt/global/support/user/type.d';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import type { OpenaiAccountType } from '@fastgpt/global/support/user/team/type';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { putUpdateTeam } from '@/web/support/user/team/api';
|
||||
|
||||
const OpenAIAccountModal = ({
|
||||
defaultData,
|
||||
onSuccess,
|
||||
onClose
|
||||
}: {
|
||||
defaultData: UserType['openaiAccount'];
|
||||
onSuccess: (e: UserType['openaiAccount']) => Promise<any>;
|
||||
defaultData?: OpenaiAccountType;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { userInfo, initUserInfo } = useUserStore();
|
||||
const { register, handleSubmit } = useForm({
|
||||
defaultValues: defaultData
|
||||
});
|
||||
|
||||
const { mutate: onSubmit, isLoading } = useRequest({
|
||||
mutationFn: async (data: UserType['openaiAccount']) => onSuccess(data),
|
||||
onSuccess(res) {
|
||||
onClose();
|
||||
const { runAsync: onSubmit, loading } = useRequest2(
|
||||
async (data: OpenaiAccountType) => {
|
||||
if (!userInfo?.team.teamId) return;
|
||||
return putUpdateTeam({
|
||||
openaiAccount: data
|
||||
});
|
||||
},
|
||||
errorToast: t('account_info:openai_account_setting_exception')
|
||||
});
|
||||
{
|
||||
onSuccess: () => {
|
||||
initUserInfo();
|
||||
onClose();
|
||||
},
|
||||
successToast: t('common:common.Update Success'),
|
||||
errorToast: t('common:common.Update Failed')
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
iconSrc="common/openai"
|
||||
title={t('account_info:openai_account_configuration')}
|
||||
title={t('account_thirdParty:openai_account_configuration')}
|
||||
>
|
||||
<ModalBody>
|
||||
<Box fontSize={'sm'} color={'myGray.500'}>
|
||||
{t('account_info:open_api_notice')}
|
||||
{t('account_thirdParty:open_api_notice')}
|
||||
</Box>
|
||||
<Flex alignItems={'center'} mt={5}>
|
||||
<Box flex={'0 0 65px'}>API Key:</Box>
|
||||
@@ -48,16 +58,16 @@ const OpenAIAccountModal = ({
|
||||
<Input
|
||||
flex={1}
|
||||
{...register('baseUrl')}
|
||||
placeholder={t('account_info:request_address_notice')}
|
||||
></Input>
|
||||
placeholder={t('account_thirdParty:request_address_notice')}
|
||||
/>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button mr={3} variant={'whiteBase'} onClick={onClose}>
|
||||
{t('account_info:cancel')}
|
||||
{t('common:common.Cancel')}
|
||||
</Button>
|
||||
<Button isLoading={isLoading} onClick={handleSubmit((data) => onSubmit(data))}>
|
||||
{t('account_info:confirm')}
|
||||
<Button isLoading={loading} onClick={handleSubmit(onSubmit)}>
|
||||
{t('common:common.Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
81
projects/app/src/pages/account/thirdParty/components/WorkflowVariableModal.tsx
vendored
Normal file
81
projects/app/src/pages/account/thirdParty/components/WorkflowVariableModal.tsx
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Box, Button, Flex, Input, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import React from 'react';
|
||||
import { ThirdPartyAccountType } from '../index';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { putUpdateTeam } from '@/web/support/user/team/api';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
|
||||
const WorkflowVariableModal = ({
|
||||
defaultData,
|
||||
onClose
|
||||
}: {
|
||||
defaultData: ThirdPartyAccountType;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { userInfo, initUserInfo } = useUserStore();
|
||||
|
||||
const { register, handleSubmit } = useForm({
|
||||
defaultValues: {
|
||||
value: '',
|
||||
key: defaultData.key || ''
|
||||
}
|
||||
});
|
||||
|
||||
const { runAsync: onSubmit, loading } = useRequest2(
|
||||
async (data: { key: string; value: string }) => {
|
||||
if (!userInfo?.team.teamId) return;
|
||||
|
||||
await putUpdateTeam({
|
||||
externalWorkflowVariable: data
|
||||
});
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
initUserInfo();
|
||||
onClose();
|
||||
},
|
||||
successToast: t('common:common.Update Success'),
|
||||
errorToast: t('common:common.Update Failed')
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<MyModal title={`${defaultData.name} 配置`} iconSrc={'edit'} iconColor={'primary.600'}>
|
||||
<ModalBody w={'420px'}>
|
||||
<Box fontSize={'14px'} color={'myGray.900'}>
|
||||
{defaultData.intro}
|
||||
</Box>
|
||||
<Box h={'1px'} bg={'myGray.150'} my={4}></Box>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box fontSize={'14px'} color={'myGray.900'} fontWeight={'medium'}>
|
||||
{t('common:core.workflow.value')}
|
||||
</Box>
|
||||
<Input
|
||||
ml={8}
|
||||
bg={'myGray.50'}
|
||||
placeholder={t('account_thirdParty:value_placeholder')}
|
||||
flex={1}
|
||||
{...register('value')}
|
||||
/>
|
||||
</Flex>
|
||||
<Box mt={1} color={'myGray.500'} fontSize={'xs'}>
|
||||
{t('account_thirdParty:value_not_return_tip')}
|
||||
</Box>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button mr={3} variant={'whiteBase'} onClick={onClose}>
|
||||
{t('common:common.Cancel')}
|
||||
</Button>
|
||||
<Button isLoading={loading} onClick={handleSubmit(onSubmit)}>
|
||||
{t('common:common.Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(WorkflowVariableModal);
|
||||
263
projects/app/src/pages/account/thirdParty/index.tsx
vendored
Normal file
263
projects/app/src/pages/account/thirdParty/index.tsx
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
import AccountContainer from '../components/AccountContainer';
|
||||
import { Box, Flex, Grid, Progress, useDisclosure } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useState, useMemo } from 'react';
|
||||
import WorkflowVariableModal from './components/WorkflowVariableModal';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { serviceSideProps } from '@fastgpt/web/common/system/nextjs';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { GET } from '@/web/common/api/request';
|
||||
import type { checkUsageResponse } from '@/pages/api/support/user/team/thirtdParty/checkUsage';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
|
||||
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
||||
const OpenAIAccountModal = dynamic(() => import('./components/OpenAIAccountModal'));
|
||||
|
||||
export type ThirdPartyAccountType = {
|
||||
name: string;
|
||||
icon: string;
|
||||
iconColor?: string;
|
||||
key?: string;
|
||||
intro: string;
|
||||
onClick?: () => void;
|
||||
isOpen?: boolean;
|
||||
active: boolean;
|
||||
usage?: {
|
||||
used: number;
|
||||
total: number;
|
||||
};
|
||||
};
|
||||
|
||||
const ThirdParty = () => {
|
||||
const { t } = useTranslation();
|
||||
const { feConfigs } = useSystemStore();
|
||||
const { toast } = useToast();
|
||||
const { isOpen: isOpenLaf, onClose: onCloseLaf, onOpen: onOpenLaf } = useDisclosure();
|
||||
const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure();
|
||||
|
||||
const [workflowVariable, setWorkflowVariable] = useState<ThirdPartyAccountType>();
|
||||
|
||||
const { userInfo } = useUserStore();
|
||||
|
||||
const isOwner = userInfo?.team?.role === TeamMemberRoleEnum.owner;
|
||||
|
||||
const defaultAccountList: ThirdPartyAccountType[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
name: t('account_thirdParty:laf_account'),
|
||||
icon: 'support/account/laf',
|
||||
intro: t('common:support.user.Laf account intro'),
|
||||
onClick: onOpenLaf,
|
||||
isOpen: !!feConfigs?.lafEnv,
|
||||
active: !!userInfo?.team?.lafAccount?.appid
|
||||
},
|
||||
{
|
||||
name: t('account_thirdParty:openai_account_configuration'),
|
||||
iconColor: 'black',
|
||||
icon: 'common/openai',
|
||||
intro: t('account_thirdParty:open_api_notice'),
|
||||
onClick: onOpenOpenai,
|
||||
isOpen: feConfigs?.show_openai_account,
|
||||
active: userInfo?.team?.openaiAccount?.key !== undefined
|
||||
}
|
||||
],
|
||||
[
|
||||
feConfigs?.lafEnv,
|
||||
feConfigs?.show_openai_account,
|
||||
onOpenLaf,
|
||||
onOpenOpenai,
|
||||
t,
|
||||
userInfo?.team?.lafAccount?.appid,
|
||||
userInfo?.team?.openaiAccount?.key
|
||||
]
|
||||
);
|
||||
|
||||
const { data: workflowVariables = [], loading } = useRequest2(
|
||||
async (): Promise<ThirdPartyAccountType[]> => {
|
||||
return Promise.all(
|
||||
(feConfigs?.externalProviderWorkflowVariables || []).map(async (item) => {
|
||||
const usage = await (async () => {
|
||||
try {
|
||||
return await GET<checkUsageResponse>('/support/user/team/thirtdParty/checkUsage', {
|
||||
key: item.key
|
||||
});
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
})();
|
||||
|
||||
const account = {
|
||||
key: item.key,
|
||||
name: item.name,
|
||||
active: userInfo?.team?.externalWorkflowVariables?.[item.key] !== undefined,
|
||||
icon: 'common/variable',
|
||||
iconColor: 'primary.600',
|
||||
intro: item.intro || t('account_thirdParty:no_intro')
|
||||
};
|
||||
|
||||
return {
|
||||
...account,
|
||||
usage,
|
||||
onClick: () => setWorkflowVariable(account),
|
||||
isOpen: item.isOpen
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
{
|
||||
manual: false,
|
||||
refreshDeps: [
|
||||
feConfigs?.externalProviderWorkflowVariables,
|
||||
userInfo?.team?.externalWorkflowVariables
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
const accountList = useMemo(
|
||||
() => [...defaultAccountList, ...workflowVariables],
|
||||
[defaultAccountList, workflowVariables]
|
||||
);
|
||||
|
||||
return (
|
||||
<AccountContainer>
|
||||
<MyBox isLoading={loading} px={[4, 8]} py={[4, 6]} bg={'white'} h={'full'}>
|
||||
<Flex>
|
||||
<MyIcon name={'common/thirdParty'} w={'24px'} color={'myGray.900'} />
|
||||
<Box ml={3}>
|
||||
<Box fontSize={'md'} color={'myGray.900'}>
|
||||
{t('account_thirdParty:third_party_account')}
|
||||
</Box>
|
||||
<Box fontSize={'mini'} color={'myGray.500'}>
|
||||
{t('account_thirdParty:third_party_account_desc')}
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Grid
|
||||
gridTemplateColumns={[
|
||||
'1fr',
|
||||
'repeat(2,1fr)',
|
||||
'repeat(3,1fr)',
|
||||
'repeat(3,1fr)',
|
||||
'repeat(4,1fr)'
|
||||
]}
|
||||
gridGap={4}
|
||||
alignItems={'stretch'}
|
||||
mt={5}
|
||||
pb={5}
|
||||
>
|
||||
{accountList
|
||||
.filter((item) => item.isOpen)
|
||||
.map((item) => (
|
||||
<Flex
|
||||
key={item.name}
|
||||
flexDirection={'column'}
|
||||
border={'1px solid'}
|
||||
borderColor={'myGray.200'}
|
||||
pt={4}
|
||||
px={5}
|
||||
borderRadius={'10px'}
|
||||
h={'146px'}
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
borderColor: 'primary.600'
|
||||
}}
|
||||
onClick={
|
||||
isOwner
|
||||
? item.onClick
|
||||
: () =>
|
||||
toast({
|
||||
title: t('account_thirdParty:error.no_permission'),
|
||||
status: 'warning'
|
||||
})
|
||||
}
|
||||
position={'relative'}
|
||||
>
|
||||
<Flex>
|
||||
<MyIcon name={item.icon as any} w={'24px'} color={item.iconColor} />
|
||||
<Box ml={2} flex={1} fontWeight={'medium'} fontSize={'16px'} color={'myGray.900'}>
|
||||
{item.name}
|
||||
</Box>
|
||||
<Box
|
||||
color={item.active ? 'green.600' : 'myGray.700'}
|
||||
bg={item.active ? 'green.50' : 'myGray.100'}
|
||||
px={2}
|
||||
py={1}
|
||||
borderRadius={'sm'}
|
||||
fontSize={'10px'}
|
||||
>
|
||||
{item.active
|
||||
? t('account_thirdParty:configured')
|
||||
: t('account_thirdParty:not_configured')}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Box
|
||||
className="textEllipsis2"
|
||||
mt={3}
|
||||
fontSize={'mini'}
|
||||
color={'myGray.500'}
|
||||
lineHeight={'18px'}
|
||||
>
|
||||
{item.intro}
|
||||
</Box>
|
||||
<Box flex={1} />
|
||||
{item.active && item.usage && (
|
||||
<Box w={'full'} mb={4}>
|
||||
<Flex fontSize={'mini'} color={'myGray.500'}>
|
||||
<Box>{t('account_thirdParty:usage')}</Box>
|
||||
{item.usage?.total ? (
|
||||
<Box ml={1}>
|
||||
{item.usage.used}/{item.usage.total}
|
||||
</Box>
|
||||
) : (
|
||||
<Box ml={1}>{t('account_thirdParty:unavailable')}</Box>
|
||||
)}
|
||||
</Flex>
|
||||
<Box mt={1} w={'full'}>
|
||||
<Progress
|
||||
size={'sm'}
|
||||
value={(item.usage.used / item.usage.total) * 100}
|
||||
colorScheme={'blue'}
|
||||
borderRadius={'md'}
|
||||
borderWidth={'1px'}
|
||||
borderColor={'low'}
|
||||
isAnimated
|
||||
hasStripe
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
))}
|
||||
</Grid>
|
||||
</MyBox>
|
||||
|
||||
{isOpenLaf && userInfo && (
|
||||
<LafAccountModal defaultData={userInfo?.team?.lafAccount} onClose={onCloseLaf} />
|
||||
)}
|
||||
{isOpenOpenai && userInfo && (
|
||||
<OpenAIAccountModal defaultData={userInfo?.team?.openaiAccount} onClose={onCloseOpenai} />
|
||||
)}
|
||||
{workflowVariable && (
|
||||
<WorkflowVariableModal
|
||||
defaultData={workflowVariable}
|
||||
onClose={() => setWorkflowVariable(undefined)}
|
||||
/>
|
||||
)}
|
||||
</AccountContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getServerSideProps(content: any) {
|
||||
return {
|
||||
props: {
|
||||
...(await serviceSideProps(content, ['account', 'account_thirdParty']))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default ThirdParty;
|
||||
Reference in New Issue
Block a user