chore(ui): login page & workflow page (#3046)

* login page & number input & multirow select & llm select

* workflow

* adjust nodes
This commit is contained in:
heheer
2024-11-04 10:32:38 +08:00
committed by archer
parent e1f5483432
commit 9e8138e55f
71 changed files with 745 additions and 525 deletions

View File

@@ -68,7 +68,9 @@ const SettingLLMModel = ({
<Button
w={'100%'}
justifyContent={'flex-start'}
variant={'whiteBase'}
variant={'whitePrimaryOutline'}
size={'lg'}
fontSize={'sm'}
bg={bg}
_active={{
transform: 'none'
@@ -81,8 +83,9 @@ const SettingLLMModel = ({
w={'18px'}
/>
}
rightIcon={<MyIcon name={'common/select'} w={'1rem'} />}
pl={4}
rightIcon={<MyIcon name={'common/select'} w={'1.2rem'} color={'myGray.500'} />}
px={3}
pr={2}
onClick={onOpenAIChatSetting}
>
<Box flex={1} textAlign={'left'}>

View File

@@ -59,7 +59,9 @@ const FileSelect = ({
return (
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/file'} mr={2} w={'20px'} />
<FormLabel {...labelStyle}>{t('app:file_upload')}</FormLabel>
<FormLabel color={'myGray.600'} {...labelStyle}>
{t('app:file_upload')}
</FormLabel>
<ChatFunctionTip type={'file'} />
<Box flex={1} />
<MyTooltip label={t('app:config_file_upload')}>
@@ -68,6 +70,7 @@ const FileSelect = ({
iconSpacing={1}
size={'sm'}
mr={'-5px'}
color={'myGray.600'}
onClick={onOpen}
>
{formLabel}

View File

@@ -87,7 +87,7 @@ const InputGuideConfig = ({
<Flex alignItems={'center'}>
<MyIcon name={'core/app/inputGuides'} mr={2} w={'20px'} />
<Flex alignItems={'center'}>
<FormLabel>{chatT('input_guide')}</FormLabel>
<FormLabel color={'myGray.600'}>{chatT('input_guide')}</FormLabel>
<ChatFunctionTip type={'inputGuide'} />
</Flex>
<Box flex={1} />
@@ -97,6 +97,7 @@ const InputGuideConfig = ({
iconSpacing={1}
size={'sm'}
mr={'-5px'}
color={'myGray.600'}
onClick={onOpen}
>
{formLabel}

View File

@@ -11,7 +11,7 @@ const QGSwitch = (props: SwitchProps) => {
return (
<Flex alignItems={'center'}>
<MyIcon name={'core/chat/QGFill'} mr={2} w={'20px'} />
<FormLabel>{t('common:core.app.Question Guide')}</FormLabel>
<FormLabel color={'myGray.600'}>{t('common:core.app.Question Guide')}</FormLabel>
<ChatFunctionTip type={'nextQuestion'} />
<Box flex={1} />
<Switch {...props} />

View File

@@ -270,7 +270,7 @@ const ScheduledTriggerConfig = ({
<Flex alignItems={'center'}>
<MyIcon name={'core/app/schedulePlan'} w={'20px'} />
<HStack ml={2} flex={1} spacing={1}>
<FormLabel>{t('common:core.app.Interval timer run')}</FormLabel>
<FormLabel color={'myGray.600'}>{t('common:core.app.Interval timer run')}</FormLabel>
<QuestionTip label={t('common:core.app.Interval timer tip')} />
</HStack>
<MyTooltip label={t('common:core.app.Config schedule plan')}>
@@ -279,6 +279,7 @@ const ScheduledTriggerConfig = ({
iconSpacing={1}
size={'sm'}
mr={'-5px'}
color={'myGray.600'}
onClick={onOpen}
>
{formatLabel}

View File

@@ -82,7 +82,7 @@ const TTSSelect = ({
return (
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/tts'} mr={2} w={'20px'} />
<FormLabel>{t('common:core.app.TTS')}</FormLabel>
<FormLabel color={'myGray.600'}>{t('common:core.app.TTS')}</FormLabel>
<ChatFunctionTip type={'tts'} />
<Box flex={1} />
<MyTooltip label={t('common:core.app.Select TTS')}>
@@ -92,6 +92,7 @@ const TTSSelect = ({
size={'sm'}
mr={'-5px'}
onClick={onOpen}
color={'myGray.600'}
>
{formLabel}
</Button>

View File

@@ -173,7 +173,9 @@ const VariableEdit = ({
{/* Row box */}
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/variable'} w={'20px'} />
<FormLabel ml={2}>{t('common:core.module.Variable')}</FormLabel>
<FormLabel ml={2} color={'myGray.600'}>
{t('common:core.module.Variable')}
</FormLabel>
<ChatFunctionTip type={'variable'} />
<Box flex={1} />
<Button
@@ -181,6 +183,7 @@ const VariableEdit = ({
leftIcon={<SmallAddIcon />}
iconSpacing={1}
size={'sm'}
color={'myGray.600'}
mr={'-5px'}
onClick={() => {
reset(addVariable());
@@ -193,60 +196,96 @@ const VariableEdit = ({
{formatVariables.length > 0 && (
<Box mt={2} borderRadius={'md'} overflow={'hidden'} borderWidth={'1px'} borderBottom="none">
<TableContainer>
<Table>
<Thead>
<Table bg={'white'}>
<Thead h={8}>
<Tr>
<Th
fontSize={'mini'}
borderRadius={'none !important'}
w={'18px !important'}
bg={'myGray.50'}
p={0}
/>
<Th fontSize={'mini'}>{t('workflow:Variable_name')}</Th>
<Th fontSize={'mini'}>{t('app:global_variables_desc')}</Th>
<Th fontSize={'mini'}>{t('common:common.Require Input')}</Th>
<Th fontSize={'mini'} borderRadius={'none !important'}></Th>
px={4}
fontWeight={'medium'}
>
{t('common:core.module.variable.key')}
</Th>
<Th fontSize={'mini'} bg={'myGray.50'} p={0} px={4} fontWeight={'medium'}>
{t('workflow:Variable_name')}
</Th>
<Th fontSize={'mini'} bg={'myGray.50'} p={0} px={4} fontWeight={'medium'}>
{t('common:common.Require Input')}
</Th>
<Th
fontSize={'mini'}
borderRadius={'none !important'}
bg={'myGray.50'}
p={0}
px={4}
fontWeight={'medium'}
>
{t('common:common.Operation')}
</Th>
</Tr>
</Thead>
<Tbody>
{formatVariables.map((item) => (
<Tr key={item.id}>
<Td p={0} pl={3}>
<MyIcon name={item.icon as any} w={'16px'} color={'myGray.500'} />
</Td>
<Td>{item.key}</Td>
<Td
maxW={'200px'}
fontSize={'sm'}
whiteSpace={'pre-wrap'}
wordBreak={'break-all'}
px={0}
p={0}
px={4}
h={8}
color={'myGray.900'}
fontSize={'mini'}
fontWeight={'medium'}
>
{item.description || '-'}
<Flex alignItems={'center'}>
<MyIcon name={item.icon as any} w={'16px'} color={'myGray.400'} mr={2} />
{item.label}
</Flex>
</Td>
<Td>{item.required ? '✔' : '-'}</Td>
<Td>
<MyIcon
mr={3}
name={'common/settingLight'}
w={'16px'}
cursor={'pointer'}
onClick={() => {
const formattedItem = {
...item,
list: item.enums || []
};
reset(formattedItem);
}}
/>
<MyIcon
name={'delete'}
w={'16px'}
cursor={'pointer'}
onClick={() =>
onChange(variables.filter((variable) => variable.id !== item.id))
}
/>
<Td
p={0}
px={4}
h={8}
color={'myGray.900'}
fontSize={'mini'}
fontWeight={'medium'}
>
<Flex alignItems={'center'}>{item.key}</Flex>
</Td>
<Td p={0} px={4} h={8} color={'myGray.900'} fontSize={'mini'}>
<Flex alignItems={'center'}>
{item.required ? (
<MyIcon name={'check'} w={'16px'} color={'myGray.900'} mr={2} />
) : (
''
)}
</Flex>
</Td>
<Td p={0} px={4} h={8} color={'myGray.600'} fontSize={'mini'}>
<Flex alignItems={'center'}>
<MyIcon
mr={3}
name={'common/settingLight'}
w={'16px'}
cursor={'pointer'}
onClick={() => {
const formattedItem = {
...item,
list: item.enums || []
};
reset(formattedItem);
}}
/>
<MyIcon
name={'delete'}
w={'16px'}
cursor={'pointer'}
onClick={() =>
onChange(variables.filter((variable) => variable.id !== item.id))
}
/>
</Flex>
</Td>
</Tr>
))}

View File

@@ -13,17 +13,20 @@ const WelcomeTextConfig = (props: TextareaProps) => {
<>
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/chat'} w={'20px'} />
<FormLabel ml={2}>{t('common:core.app.Welcome Text')}</FormLabel>
<FormLabel ml={2} color={'myGray.600'}>
{t('common:core.app.Welcome Text')}
</FormLabel>
<ChatFunctionTip type={'welcome'} />
</Flex>
<MyTextarea
className="nowheel"
iconSrc={'core/app/simpleMode/chat'}
title={t('common:core.app.Welcome Text')}
mt={2}
mt={1.5}
rows={6}
fontSize={'sm'}
bg={'myGray.50'}
bg={'white'}
minW={'384px'}
placeholder={t('common:core.app.tip.welcomeTextTip')}
autoHeight
minH={100}

View File

@@ -34,7 +34,7 @@ const WhisperConfig = ({
return (
<Flex alignItems={'center'}>
<MyIcon name={'core/app/simpleMode/whisper'} mr={2} w={'20px'} />
<FormLabel>{t('common:core.app.Whisper')}</FormLabel>
<FormLabel color={'myGray.600'}>{t('common:core.app.Whisper')}</FormLabel>
<Box flex={1} />
<MyTooltip label={t('common:core.app.Config whisper')}>
<Button
@@ -42,6 +42,7 @@ const WhisperConfig = ({
iconSpacing={1}
size={'sm'}
mr={'-5px'}
color={'myGray.600'}
onClick={onOpen}
>
{formLabel}

View File

@@ -39,6 +39,7 @@ import { useTranslation } from 'react-i18next';
import { Controller, useForm } from 'react-hook-form';
import MySelect from '@fastgpt/web/components/common/MySelect';
import MyTextarea from '@/components/common/Textarea/MyTextarea';
import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput';
type props = {
value: UserChatItemValueItemType | AIChatItemValueItemType;
@@ -244,25 +245,15 @@ const RenderUserFormInteractive = React.memo(function RenderFormInput({
/>
)}
{input.type === FlowNodeInputTypeEnum.numberInput && (
<NumberInput
step={1}
<MyNumberInput
min={input.min}
max={input.max}
isDisabled={interactive.params.submitted}
bg={'white'}
rounded={'md'}
>
<NumberInputField
bg={'white'}
{...register(input.label, {
required: input.required
})}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
register={register}
name={input.label}
isRequired={input.required}
/>
)}
{input.type === FlowNodeInputTypeEnum.select && (
<Controller

View File

@@ -61,6 +61,7 @@ const DefaultPermissionList = ({
}
}}
fontSize={styles?.fontSize}
fontWeight={styles?.fontWeight}
/>
</Box>
<ConfirmModal />

View File

@@ -145,7 +145,6 @@ const Header = () => {
)}
<Flex
mt={[2, 0]}
py={3}
pl={[2, 4]}
pr={[2, 6]}
borderBottom={'base'}
@@ -163,12 +162,20 @@ const Header = () => {
})}
>
{/* back */}
<MyIcon
name={'common/leftArrowLight'}
w={'1.75rem'}
cursor={'pointer'}
onClick={isPublished ? onBack : onOpenBackConfirm}
/>
<Box
_hover={{
bg: 'myGray.200'
}}
p={0.5}
borderRadius={'sm'}
>
<MyIcon
name={'common/leftArrowLight'}
w={6}
cursor={'pointer'}
onClick={isPublished ? onBack : onOpenBackConfirm}
/>
</Box>
{/* app info */}
<Box ml={1}>

View File

@@ -51,6 +51,7 @@ const RouteTab = () => {
px={2}
py={0.5}
fontWeight={'medium'}
borderRadius={'sm'}
{...(currentTab === tab.id
? {
color: 'primary.700'
@@ -59,8 +60,7 @@ const RouteTab = () => {
color: 'myGray.600',
cursor: 'pointer',
_hover: {
bg: 'myGray.200',
borderRadius: 'md'
bg: 'myGray.200'
},
onClick: () => setCurrentTab(tab.id)
})}

View File

@@ -84,7 +84,7 @@ const AppCard = () => {
>
{appDetail.intro || t('common:core.app.tip.Add a intro to app')}
</Box>
<HStack alignItems={'flex-end'}>
<HStack alignItems={'center'}>
<Button
size={['sm', 'md']}
variant={'whitePrimary'}
@@ -107,7 +107,7 @@ const AppCard = () => {
<MyMenu
Button={
<IconButton
variant={'whiteBase'}
variant={'whitePrimary'}
size={['smSquare', 'mdSquare']}
icon={<MyIcon name={'more'} w={'1rem'} />}
aria-label={''}

View File

@@ -151,7 +151,6 @@ const Header = () => {
)}
<Flex
mt={[2, 0]}
py={3}
pl={[2, 4]}
pr={[2, 6]}
borderBottom={'base'}
@@ -169,12 +168,20 @@ const Header = () => {
})}
>
{/* back */}
<MyIcon
name={'common/leftArrowLight'}
w={'1.75rem'}
cursor={'pointer'}
onClick={isPublished ? onBack : onOpenBackConfirm}
/>
<Box
_hover={{
bg: 'myGray.200'
}}
p={0.5}
borderRadius={'sm'}
>
<MyIcon
name={'common/leftArrowLight'}
w={6}
cursor={'pointer'}
onClick={isPublished ? onBack : onOpenBackConfirm}
/>
</Box>
{/* app info */}
<Box ml={1}>

View File

@@ -16,6 +16,7 @@ import { publishStatusStyle } from '../constants';
import MyPopover from '@fastgpt/web/components/common/MyPopover';
import { fileDownload } from '@/web/common/file/utils';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
import MyBox from '@fastgpt/web/components/common/MyBox';
const ImportSettings = dynamic(() => import('./Flow/ImportSettings'));
@@ -27,97 +28,120 @@ const AppCard = ({
isPublished: boolean;
}) => {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const { appDetail, onOpenInfoEdit, onOpenTeamTagModal, onDelApp, currentTab } =
useContextSelector(AppContext, (v) => v);
const { showHistoryModal } = useContextSelector(WorkflowContext, (v) => v);
const { appDetail, onOpenInfoEdit, onOpenTeamTagModal, onDelApp } = useContextSelector(
AppContext,
(v) => v
);
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
const InfoMenu = useCallback(
({ children }: { children: React.ReactNode }) => {
return (
<MyMenu
width={150}
Button={children}
menuList={[
{
children: [
{
icon: 'edit',
label: t('app:edit_info'),
onClick: onOpenInfoEdit
},
{
icon: 'support/team/key',
label: t('common:common.Role'),
onClick: onOpenInfoEdit
}
]
},
...(!showHistoryModal && currentTab === TabEnum.appEdit
? [
{
children: [
{
label: t('app:import_configs'),
icon: 'common/importLight',
onClick: onOpenImport
},
{
label: ExportPopover({
chatConfig: appDetail.chatConfig,
appName: appDetail.name
}),
menuItemStyles: {
p: 0,
cursor: 'default'
}
}
]
}
]
: []),
...(appDetail.permission.hasWritePer && feConfigs?.show_team_chat
? [
{
children: [
{
icon: 'support/team/memberLight',
label: t('common:common.Team Tags Set'),
onClick: onOpenTeamTagModal
}
]
}
]
: []),
...(appDetail.permission.isOwner
? [
{
children: [
{
type: 'danger' as 'danger',
icon: 'delete',
label: t('common:common.Delete'),
onClick: onDelApp
}
]
}
]
: [])
]}
/>
<MyPopover
placement={'bottom-end'}
hasArrow={false}
offset={[2, 4]}
w={'116px'}
trigger={'hover'}
Trigger={children}
>
{({ onClose }) => (
<Box p={1.5}>
<MyBox
display={'flex'}
size={'md'}
px={1}
py={1.5}
rounded={'4px'}
_hover={{ color: 'primary.600', bg: 'rgba(17, 24, 36, 0.05)' }}
cursor={'pointer'}
onClick={onOpenInfoEdit}
>
<MyIcon name={'edit'} w={'16px'} mr={2} />
<Box fontSize={'sm'}>{t('app:edit_info')}</Box>
</MyBox>
<MyBox
display={'flex'}
size={'md'}
px={1}
py={1.5}
rounded={'4px'}
_hover={{ color: 'primary.600', bg: 'rgba(17, 24, 36, 0.05)' }}
cursor={'pointer'}
onClick={onOpenInfoEdit}
>
<MyIcon name={'support/team/key'} w={'16px'} mr={2} />
<Box fontSize={'sm'}>{t('app:Role_setting')}</Box>
</MyBox>
<Box w={'full'} h={'1px'} bg={'myGray.200'} my={1} />
<MyBox
display={'flex'}
size={'md'}
px={1}
py={1.5}
rounded={'4px'}
_hover={{ color: 'primary.600', bg: 'rgba(17, 24, 36, 0.05)' }}
cursor={'pointer'}
onClick={onOpenImport}
>
<MyIcon name={'common/importLight'} w={'16px'} mr={2} />
<Box fontSize={'sm'}>{t('app:import_configs')}</Box>
</MyBox>
<MyBox
display={'flex'}
size={'md'}
px={1}
py={1.5}
rounded={'4px'}
_hover={{ color: 'primary.600', bg: 'rgba(17, 24, 36, 0.05)' }}
cursor={'pointer'}
>
{ExportPopover({
chatConfig: appDetail.chatConfig,
appName: appDetail.name
})}
</MyBox>
<Box w={'full'} h={'1px'} bg={'myGray.200'} my={1} />
<MyBox
display={'flex'}
size={'md'}
px={1}
py={1.5}
rounded={'4px'}
_hover={{ color: 'primary.600', bg: 'rgba(17, 24, 36, 0.05)' }}
cursor={'pointer'}
onClick={onOpenTeamTagModal}
>
<MyIcon name={'core/dataset/tag'} w={'16px'} mr={2} />
<Box fontSize={'sm'}>{t('app:Team_Tags')}</Box>
</MyBox>
<Box w={'full'} h={'1px'} bg={'myGray.200'} my={1} />
<MyBox
display={'flex'}
size={'md'}
px={1}
py={1.5}
rounded={'4px'}
color={'red.600'}
_hover={{ bg: 'rgba(17, 24, 36, 0.05)' }}
cursor={'pointer'}
onClick={onDelApp}
>
<MyIcon name={'delete'} w={'16px'} mr={2} />
<Box fontSize={'sm'}>{t('common:common.Delete')}</Box>
</MyBox>
</Box>
)}
</MyPopover>
);
},
[
appDetail.chatConfig,
appDetail.name,
appDetail.permission.hasWritePer,
appDetail.permission.isOwner,
currentTab,
feConfigs?.show_team_chat,
showHistoryModal,
onDelApp,
onOpenImport,
onOpenInfoEdit,
@@ -129,21 +153,26 @@ const AppCard = ({
const Render = useMemo(() => {
return (
<HStack>
<InfoMenu>
<Avatar src={appDetail.avatar} w={'1.75rem'} borderRadius={'md'} />
</InfoMenu>
<Avatar src={appDetail.avatar} w={'1.75rem'} borderRadius={'md'} />
<Box>
<InfoMenu>
<HStack spacing={1} cursor={'pointer'}>
<HStack
spacing={1}
cursor={'pointer'}
pl={1}
ml={-1}
borderRadius={'xs'}
_hover={{ bg: 'myGray.150' }}
>
<Box color={'myGray.900'}>{appDetail.name}</Box>
<MyIcon name={'common/select'} w={'1rem'} />
<MyIcon name={'common/select'} w={'1rem'} color={'myGray.500'} />
</HStack>
</InfoMenu>
{showSaveStatus && (
<Flex alignItems={'center'} h={'20px'} fontSize={'mini'} lineHeight={1}>
<Flex alignItems={'center'} fontSize={'mini'} lineHeight={1}>
<MyTag
py={0}
px={0}
px={1}
showDot
bg={'transparent'}
colorSchema={
@@ -211,15 +240,19 @@ function ExportPopover({
return (
<MyPopover
placement={'right-start'}
offset={[0, 0]}
offset={[0, 20]}
hasArrow
trigger={'hover'}
w={'8.6rem'}
Trigger={
<Flex align={'center'} w={'100%'} py={2} px={3}>
<Avatar src={'export'} borderRadius={'sm'} w={'1rem'} mr={3} />
{t('app:export_configs')}
</Flex>
// <Flex align={'center'} w={'100%'} py={2} px={3}>
// <Avatar src={'export'} borderRadius={'sm'} w={'1rem'} mr={3} />
// {t('app:export_configs')}
// </Flex>
<MyBox display={'flex'} size={'md'} rounded={'4px'} cursor={'pointer'}>
<MyIcon name={'export'} w={'16px'} mr={2} />
<Box fontSize={'sm'}>{t('app:export_configs')}</Box>
</MyBox>
}
>
{({ onClose }) => (

View File

@@ -116,13 +116,13 @@ const ButtonEdge = (props: EdgeProps) => {
(edge) => edge.sourceHandle === sourceHandleId && edge.targetHandle === targetHandleId
);
if (!targetEdge) {
if (highlightEdge) return '#3370ff';
if (highlightEdge) return '#487FFF';
return '#94B5FF';
}
// debug mode
const colorMap = {
[RuntimeEdgeStatusEnum.active]: '#39CC83',
[RuntimeEdgeStatusEnum.active]: '#487FFF',
[RuntimeEdgeStatusEnum.waiting]: '#5E8FFF',
[RuntimeEdgeStatusEnum.skipped]: '#8A95A7'
};

View File

@@ -6,10 +6,8 @@ const Container = ({ children, ...props }: BoxProps) => {
return (
<Flex
flexDirection={'column'}
px={4}
mx={2}
mb={2}
py={'10px'}
mx={4}
p={4}
position={'relative'}
bg={'myGray.50'}
border={'1px solid #F0F1F6'}

View File

@@ -4,7 +4,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
const IOTitle = ({ text, ...props }: { text?: 'Input' | 'Output' | string } & StackProps) => {
return (
<HStack fontSize={'md'} alignItems={'center'} fontWeight={'medium'} mb={3} {...props}>
<HStack fontSize={'md'} alignItems={'center'} fontWeight={'medium'} mb={4} {...props}>
<Box w={'3px'} h={'14px'} borderRadius={'13px'} bg={'primary.600'} />
<Box color={'myGray.900'}>{text}</Box>
</HStack>

View File

@@ -290,7 +290,7 @@ export const useWorkflow = () => {
// Loop node size and position
const resetParentNodeSizeAndPosition = useMemoizedFn((rect: Rect, parentId: string) => {
const width = rect.width + 110 > 900 ? rect.width + 110 : 900;
const height = rect.height + 380 > 900 ? rect.height + 380 : 900;
const height = rect.height + 420 > 900 ? rect.height + 420 : 900;
// Update parentNode size and position
onChangeNode({

View File

@@ -80,7 +80,7 @@ const NodeLoopEnd = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
debug: true
}}
>
<Box px={4} pb={4}>
<Box px={4} pb={4} pt={2}>
{inputItem && <Reference item={inputItem} nodeId={nodeId} />}
</Box>
</NodeCard>

View File

@@ -100,7 +100,7 @@ const NodeLoopStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
debug: true
}}
>
<Box px={4} w={'420px'} h={'116px'}>
<Box px={4} pt={2} w={'420px'} h={'116px'}>
{!loopItemInputType ? (
<EmptyTip text={t('workflow:loop_start_tip')} py={0} mt={4} iconSize={'32px'} />
) : (

View File

@@ -99,7 +99,7 @@ const NodeCQNode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
nodeId={nodeId}
handleId={getHandleId(nodeId, 'source', item.key)}
position={Position.Right}
translate={[26, 0]}
translate={[36, 0]}
/>
</Box>
</Box>

View File

@@ -60,7 +60,8 @@ const NodeExtract = ({ data }: NodeProps<FlowNodeItemType>) => {
</Box>
<Button
size={'sm'}
variant={'whitePrimary'}
variant={'ghost'}
color={'myGray.600'}
leftIcon={<AddIcon fontSize={'10px'} />}
onClick={() => setEditExtractField(defaultField)}
>
@@ -78,12 +79,10 @@ const NodeExtract = ({ data }: NodeProps<FlowNodeItemType>) => {
<Table bg={'white'}>
<Thead>
<Tr>
<Th bg={'myGray.50'} borderRadius={'none !important'}>
{t('common:item_name')}
</Th>
<Th bg={'myGray.50'}>{t('common:item_description')}</Th>
<Th bg={'myGray.50'}>{t('common:required')}</Th>
<Th bg={'myGray.50'} borderRadius={'none !important'}></Th>
<Th borderRadius={'none !important'}>{t('common:item_name')}</Th>
<Th>{t('common:item_description')}</Th>
<Th>{t('common:required')}</Th>
<Th borderRadius={'none !important'}></Th>
</Tr>
</Thead>
<Tbody>

View File

@@ -24,7 +24,6 @@ import {
FlowValueTypeMap
} from '@fastgpt/global/core/workflow/node/constant';
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput';
import MySelect from '@fastgpt/web/components/common/MySelect';
import MultipleSelect from '@fastgpt/web/components/common/MySelect/MultipleSelect';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
@@ -35,6 +34,7 @@ import { useTranslation } from 'react-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import DndDrag, { Draggable } from '@fastgpt/web/components/common/DndDrag';
import MyTextarea from '@/components/common/Textarea/MyTextarea';
import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput';
type ListValueType = { id: string; value: string; label: string }[];
@@ -249,8 +249,6 @@ const InputTypeConfig = ({
{t('common:core.module.Max Length')}
</FormLabel>
<MyNumberInput
flex={'1 0 0'}
bg={'myGray.50'}
placeholder={t('common:core.module.Max Length placeholder')}
value={maxLength}
max={50000}
@@ -269,8 +267,6 @@ const InputTypeConfig = ({
{t('common:core.module.Max Value')}
</FormLabel>
<MyNumberInput
flex={'1 0 0'}
bg={'myGray.50'}
value={max}
onChange={(e) => {
// @ts-ignore
@@ -283,8 +279,6 @@ const InputTypeConfig = ({
{t('common:core.module.Min Value')}
</FormLabel>
<MyNumberInput
flex={'1 0 0'}
bg={'myGray.50'}
value={min}
onChange={(e) => {
// @ts-ignore

View File

@@ -35,6 +35,7 @@ const FieldEditModal = dynamic(() => import('./InputEditModal'));
const NodePluginInput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { t } = useTranslation();
const { nodeId, inputs = [], outputs } = data;
console.log(outputs);
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
@@ -141,7 +142,7 @@ const NodePluginInput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
}}
/>
</Container>
{!!outputs.length && (
{!!outputs.filter((output) => output.type !== FlowNodeOutputTypeEnum.hidden).length && (
<Container>
<IOTitle text={t('common:common.Output')} />
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />

View File

@@ -15,7 +15,7 @@ import { WorkflowContext } from '../../context';
const NodeSimple = ({
data,
selected,
minW = '350px',
minW = '524px',
maxW
}: NodeProps<FlowNodeItemType> & { minW?: string | number; maxW?: string | number }) => {
const { t } = useTranslation();

View File

@@ -21,6 +21,7 @@ import WelcomeTextConfig from '@/components/core/app/WelcomeTextConfig';
import FileSelect from '@/components/core/app/FileSelect';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { userFilesInput } from '@fastgpt/global/core/workflow/template/system/workflowStart';
import Container from '../components/Container';
type ComponentProps = {
chatConfig: AppChatConfigType;
@@ -49,7 +50,7 @@ const NodeUserGuide = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
return (
<>
<NodeCard
minW={'300px'}
minW={'420px'}
selected={selected}
menuForbid={{
debug: true,
@@ -58,30 +59,30 @@ const NodeUserGuide = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
}}
{...data}
>
<Box px={4} py={'10px'} position={'relative'} borderRadius={'md'} className="nodrag">
<Container>
<WelcomeText {...componentsProps} />
<Box pt={4}>
<Box mt={2} pt={2}>
<ChatStartVariable {...componentsProps} />
</Box>
<Box mt={3} pt={3} borderTop={'base'}>
<Box mt={3} pt={3} borderTop={'base'} borderColor={'myGray.200'}>
<FileSelectConfig {...componentsProps} />
</Box>
<Box mt={3} pt={3} borderTop={'base'}>
<Box mt={3} pt={3} borderTop={'base'} borderColor={'myGray.200'}>
<TTSGuide {...componentsProps} />
</Box>
<Box mt={3} pt={3} borderTop={'base'}>
<Box mt={3} pt={3} borderTop={'base'} borderColor={'myGray.200'}>
<WhisperGuide {...componentsProps} />
</Box>
<Box mt={3} pt={3} borderTop={'base'}>
<Box mt={3} pt={4} borderTop={'base'} borderColor={'myGray.200'}>
<QuestionGuide {...componentsProps} />
</Box>
<Box mt={3} pt={3} borderTop={'base'}>
<Box mt={4} pt={3} borderTop={'base'} borderColor={'myGray.200'}>
<ScheduledTrigger {...componentsProps} />
</Box>
<Box mt={3} pt={3} borderTop={'base'}>
<Box mt={3} pt={3} borderTop={'base'} borderColor={'myGray.200'}>
<QuestionInputGuide {...componentsProps} />
</Box>
</Box>
</Container>
</NodeCard>
</>
);

View File

@@ -26,7 +26,7 @@ const NodeTools = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />
</Container>
<Box position={'relative'}>
<Box borderBottomLeftRadius={'md'} borderBottomRadius={'md'} overflow={'hidden'}>
<Box mb={-4} borderBottomLeftRadius={'md'} borderBottomRadius={'md'} overflow={'hidden'}>
<Divider
showBorderBottom={false}
icon={<MyIcon name="phoneTabbar/tool" w={'16px'} h={'16px'} />}

View File

@@ -65,7 +65,7 @@ const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
return (
<NodeCard
minW={'240px'}
minW={'420px'}
selected={selected}
menuForbid={{
copy: true,

View File

@@ -5,6 +5,7 @@ import { handleHighLightStyle, sourceCommonStyle, handleConnectedStyle, handleSi
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../../../context';
import MyIcon from '@fastgpt/web/components/common/Icon';
type Props = {
nodeId: string;
@@ -108,9 +109,7 @@ const MySourceHandle = React.memo(function MySourceHandle({
position={position}
isConnectableEnd={false}
>
{showAddIcon && (
<SmallAddIcon pointerEvents={'none'} color={'primary.600'} fontWeight={'bold'} />
)}
{showAddIcon && <MyIcon name={'edgeAdd'} />}
</Handle>
);
}, [handleId, position, showAddIcon, styles, transform]);

View File

@@ -1,4 +1,4 @@
export const primaryColor = '#3370FF';
export const primaryColor = '#487FFF';
export const lowPrimaryColor = '#94B5FF';
export const handleSize = {
width: '18px',

View File

@@ -25,7 +25,6 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useWorkflowUtils } from '../../hooks/useUtils';
import { WholeResponseContent } from '@/components/core/chat/components/WholeResponseModal';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { getDocPath } from '@/web/common/system/doc';
type Props = FlowNodeItemType & {
@@ -149,15 +148,17 @@ const NodeCard = (props: Props) => {
<Box position={'relative'}>
{/* debug */}
{showHeader && (
<Box px={4} py={3}>
<Box px={4} pt={4}>
{/* tool target handle */}
<ToolTargetHandle show={showToolHandle} nodeId={nodeId} />
{/* avatar and name */}
<Flex alignItems={'center'}>
{node?.flowNodeType !== FlowNodeTypeEnum.stopTool && (
<Box
mr={2}
<Flex
alignItems={'center'}
mr={1}
p={1}
cursor={'pointer'}
rounded={'sm'}
_hover={{ bg: 'myGray.200' }}
@@ -172,20 +173,20 @@ const NodeCard = (props: Props) => {
>
<MyIcon
name={!isFolded ? 'core/chat/chevronDown' : 'core/chat/chevronRight'}
w={'24px'}
h={'24px'}
w={'16px'}
h={'16px'}
color={'myGray.500'}
/>
</Box>
</Flex>
)}
<Avatar
src={avatar}
borderRadius={'sm'}
objectFit={'contain'}
w={'30px'}
h={'30px'}
w={'24px'}
h={'24px'}
/>
<Box ml={3} fontSize={'md'} fontWeight={'medium'}>
<Box ml={2} fontSize={'18px'} fontWeight={'medium'} color={'myGray.900'}>
{t(name as any)}
</Box>
<MyIcon
@@ -330,13 +331,16 @@ const NodeCard = (props: Props) => {
maxW={maxW}
minH={minH}
bg={'white'}
borderWidth={'1px'}
borderRadius={'md'}
boxShadow={'1'}
outline={selected ? '2px solid' : '1px solid'}
borderRadius={'lg'}
boxShadow={
'0px 4px 10px 0px rgba(19, 51, 107, 0.10), 0px 0px 1px 0px rgba(19, 51, 107, 0.10)'
}
w={w}
h={h}
_hover={{
boxShadow: '4',
boxShadow:
'0px 12px 16px -4px rgba(19, 51, 107, 0.20), 0px 0px 1px 0px rgba(19, 51, 107, 0.20)',
'& .controller-menu': {
display: 'flex'
},
@@ -351,17 +355,19 @@ const NodeCard = (props: Props) => {
onMouseLeave={() => setHoverNodeId(undefined)}
{...(isError
? {
borderColor: 'red.500',
outlineColor: 'red.500',
onMouseDownCapture: () => onUpdateNodeError(nodeId, false)
}
: {
borderColor: selected ? 'primary.600' : 'borderColor.base'
outlineColor: selected ? 'primary.600' : 'myGray.250'
})}
{...customStyle}
>
<NodeDebugResponse nodeId={nodeId} debugResult={debugResult} />
{Header}
{!isFolded && children}
<Flex flexDirection={'column'} flex={1} my={4} gap={2}>
{!isFolded ? children : <Box h={4} />}
</Flex>
{RenderHandle}
{RenderToolHandle}
@@ -568,31 +574,35 @@ const NodeIntro = React.memo(function NodeIntro({
const Render = useMemo(() => {
return (
<>
<Flex alignItems={'flex-end'} py={1}>
<Box fontSize={'xs'} color={'myGray.600'} flex={'1 0 0'}>
<Flex alignItems={'center'}>
<Box fontSize={'sm'} color={'myGray.500'} flex={'1 0 0'}>
{t(intro as any)}
</Box>
{NodeIsTool && (
<Button
size={'xs'}
variant={'whiteBase'}
onClick={() => {
onOpenIntroModal({
defaultVal: intro,
onSuccess(e) {
onChangeNode({
nodeId,
type: 'attr',
key: 'intro',
value: e
});
}
});
}}
>
{t('common:core.module.Edit intro')}
</Button>
)}
<Flex
p={'7px'}
rounded={'sm'}
alignItems={'center'}
_hover={{
bg: NodeIsTool ? 'myGray.100' : 'transparent'
}}
cursor={NodeIsTool ? 'pointer' : 'default'}
onClick={() => {
if (!NodeIsTool) return;
onOpenIntroModal({
defaultVal: intro,
onSuccess(e) {
onChangeNode({
nodeId,
type: 'attr',
key: 'intro',
value: e
});
}
});
}}
>
<MyIcon name={'edit'} w={'18px'} opacity={NodeIsTool ? 1 : 0} />
</Flex>
</Flex>
<EditIntroModal maxLength={500} />
</>

View File

@@ -9,6 +9,7 @@ import {
} from '@chakra-ui/react';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
import MyIcon from '@fastgpt/web/components/common/Icon';
const NumberInputRender = ({ item, nodeId }: RenderInputProps) => {
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
@@ -19,6 +20,8 @@ const NumberInputRender = ({ item, nodeId }: RenderInputProps) => {
defaultValue={item.value}
min={item.min}
max={item.max}
bg={'white'}
rounded={'md'}
onChange={(e) => {
onChangeNode({
nodeId,
@@ -31,10 +34,31 @@ const NumberInputRender = ({ item, nodeId }: RenderInputProps) => {
});
}}
>
<NumberInputField bg={'white'} px={3} borderRadius={'sm'} />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
<NumberInputField
bg={'white'}
px={3}
rounded={'md'}
_hover={{
borderColor: 'primary.500'
}}
/>
<NumberInputStepper roundedTopRight={'none'}>
<NumberIncrementStepper
borderTopRightRadius={'sm !important'}
_hover={{
bg: 'myGray.100'
}}
>
<MyIcon name={'core/chat/chevronUp'} width={'12px'} />
</NumberIncrementStepper>
<NumberDecrementStepper
borderBottomRightRadius={'sm !important'}
_hover={{
bg: 'myGray.100'
}}
>
<MyIcon name={'core/chat/chevronDown'} width={'12px'} />
</NumberDecrementStepper>
</NumberInputStepper>
</NumberInput>
);

View File

@@ -130,7 +130,7 @@ export const useReference = ({
label: (
<Flex alignItems={'center'}>
<Avatar src={node.avatar} w={'1.25rem'} borderRadius={'xs'} />
<Box ml={1}>{t(node.name as any)}</Box>
<Box ml={2}>{t(node.name as any)}</Box>
</Flex>
),
value: node.nodeId,
@@ -205,7 +205,7 @@ export const ReferSelector = ({
selectItemLabel ? (
<Flex alignItems={'center'}>
{selectItemLabel[0].label}
<MyIcon name={'common/rightArrowLight'} mx={1} w={'14px'}></MyIcon>
<MyIcon name={'core/chat/chevronRight'} mx={1} w={4} />
{selectItemLabel[1].label}
</Flex>
) : (

View File

@@ -302,9 +302,9 @@ const SettingQuotePrompt = (props: RenderInputProps) => {
return (
<>
<Flex className="nodrag" cursor={'default'} alignItems={'center'} position={'relative'}>
<Box position={'relative'} color={'myGray.600'} fontWeight={'medium'}>
<FormLabel position={'relative'} color={'myGray.600'} fontWeight={'medium'}>
{t('common:core.module.Dataset quote.label')}
</Box>
</FormLabel>
<ValueTypeLabel
valueType={WorkflowIOValueTypeEnum.datasetQuote}
valueDesc={datasetQuoteValueDesc}
@@ -320,7 +320,7 @@ const SettingQuotePrompt = (props: RenderInputProps) => {
/>
</MyTooltip>
</Flex>
<Box mt={1}>
<Box mt={3}>
<Reference {...props} />
</Box>

View File

@@ -139,7 +139,7 @@ const RenderOutput = ({
<FormLabel
key={output.key}
required={output.required}
mb={i === renderOutputs.length - 1 ? 0 : 5}
mb={i === renderOutputs.length - 1 ? 0 : 4}
position={'relative'}
>
<OutputLabel nodeId={nodeId} output={output} />

View File

@@ -1,12 +1,7 @@
import React, { useCallback, useMemo, useRef, useState } from 'react';
import React, { useCallback, useMemo, useRef } from 'react';
import {
Box,
Flex,
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
Input,
Button,
ModalBody,
@@ -29,6 +24,8 @@ import { useContextSelector } from 'use-context-selector';
import { DatasetImportContext } from '../Context';
import { useToast } from '@fastgpt/web/hooks/useToast';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean }) {
const { t } = useTranslation();
@@ -127,14 +124,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
<Box>
<Flex alignItems={'center'}>
<Box>{t('dataset:ideal_chunk_length')}</Box>
<MyTooltip label={t('dataset:ideal_chunk_length_tips')}>
<MyIcon
name={'common/questionLight'}
ml={1}
w={'14px'}
color={'myGray.500'}
/>
</MyTooltip>
<QuestionTip label={t('dataset:ideal_chunk_length_tips')} />
</Flex>
<Box
mt={1}
@@ -150,30 +140,18 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
max: maxChunkSize
})}
>
<NumberInput
size={'sm'}
step={100}
<MyNumberInput
name={chunkSizeField}
min={minChunkSize}
max={maxChunkSize}
size={'sm'}
step={100}
value={chunkSize}
onChange={(e) => {
if (e === undefined) return;
setValue(chunkSizeField, +e);
}}
>
<NumberInputField
min={minChunkSize}
max={maxChunkSize}
{...register(chunkSizeField, {
min: minChunkSize,
max: maxChunkSize,
valueAsNumber: true
})}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
/>
</MyTooltip>
</Box>
</Box>
@@ -182,14 +160,9 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
<Box mt={3}>
<Box>
{t('common:core.dataset.import.Custom split char')}
<MyTooltip label={t('common:core.dataset.import.Custom split char Tips')}>
<MyIcon
name={'common/questionLight'}
ml={1}
w={'14px'}
color={'myGray.500'}
/>
</MyTooltip>
<QuestionTip
label={t('common:core.dataset.import.Custom split char Tips')}
/>
</Box>
<Box mt={1}>
<Input

View File

@@ -1,5 +1,5 @@
import React, { useState, Dispatch, useCallback } from 'react';
import { FormControl, Box, Input, Button, useDisclosure } from '@chakra-ui/react';
import React, { Dispatch } from 'react';
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { LoginPageTypeEnum } from '@/web/support/user/login/constants';
import { postFindPassword } from '@/web/support/user/api';
@@ -73,11 +73,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
return (
<>
<Box fontWeight={'bold'} fontSize={'2xl'} textAlign={'center'}>
<Box fontWeight={'medium'} fontSize={'lg'} textAlign={'center'} color={'myGray.900'}>
{t('user:password.retrieved_account', { account: feConfigs?.systemTitle })}
</Box>
<Box
mt={'42px'}
mt={9}
onKeyDown={(e) => {
if (e.keyCode === 13 && !e.shiftKey && !requesting) {
handleSubmit(onclickFindPassword)();
@@ -87,6 +87,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<FormControl isInvalid={!!errors.username}>
<Input
bg={'myGray.50'}
size={'lg'}
placeholder={placeholder}
{...register('username', {
required: t('user:password.email_phone_void'),
@@ -107,6 +108,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
>
<Input
bg={'myGray.50'}
size={'lg'}
flex={1}
maxLength={8}
placeholder={t('user:password.verification_code')}
@@ -120,6 +122,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<Input
bg={'myGray.50'}
type={'password'}
size={'lg'}
placeholder={t('user:password.new_password')}
{...register('password', {
required: t('user:password.password_required'),
@@ -138,6 +141,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<Input
bg={'myGray.50'}
type={'password'}
size={'lg'}
placeholder={t('user:password.confirm')}
{...register('password2', {
validate: (val) =>
@@ -148,9 +152,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<Button
type="submit"
mt={10}
mt={12}
w={'100%'}
size={['md', 'md']}
rounded={['md', 'md']}
h={[10, 10]}
fontWeight={['medium', 'medium']}
colorScheme="blue"
isLoading={requesting}
onClick={handleSubmit(onclickFindPassword)}
@@ -159,9 +166,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
</Button>
<Box
float={'right'}
fontSize="sm"
mt={2}
fontSize="mini"
mt={3}
mb={'50px'}
fontWeight={'medium'}
color={'primary.700'}
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}

View File

@@ -80,7 +80,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
return (
<FormLayout setPageType={setPageType} pageType={LoginPageTypeEnum.passwordLogin}>
<Box
mt={'42px'}
mt={9}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey && !requesting) {
handleSubmit(onclickLogin)();
@@ -90,15 +90,17 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
<FormControl isInvalid={!!errors.username}>
<Input
bg={'myGray.50'}
size={'lg'}
placeholder={placeholder}
{...register('username', {
required: true
})}
></Input>
</FormControl>
<FormControl mt={6} isInvalid={!!errors.password}>
<FormControl mt={7} isInvalid={!!errors.password}>
<Input
bg={'myGray.50'}
size={'lg'}
type={'password'}
placeholder={
isCommunityVersion
@@ -115,13 +117,19 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
></Input>
</FormControl>
{feConfigs?.docUrl && (
<Flex alignItems={'center'} mt={7} fontSize={'mini'}>
<Flex
alignItems={'center'}
mt={7}
fontSize={'mini'}
color={'myGray.700'}
fontWeight={'medium'}
>
{t('login:policy_tip')}
<Link
ml={1}
href={getDocPath('/docs/agreement/terms/')}
target={'_blank'}
color={'primary.500'}
color={'primary.700'}
>
{t('login:terms')}
</Link>
@@ -129,7 +137,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
<Link
href={getDocPath('/docs/agreement/privacy/')}
target={'_blank'}
color={'primary.500'}
color={'primary.700'}
>
{t('login:privacy')}
</Link>
@@ -138,9 +146,11 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
<Button
type="submit"
my={6}
my={5}
w={'100%'}
size={['md', 'md']}
h={[10, 10]}
fontWeight={['medium', 'medium']}
colorScheme="blue"
isLoading={requesting}
onClick={handleSubmit(onclickLogin)}
@@ -148,29 +158,34 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
{t('login:Login')}
</Button>
<Flex align={'center'} justifyContent={'flex-end'} color={'primary.700'}>
<Flex
align={'center'}
justifyContent={'flex-end'}
color={'primary.700'}
fontWeight={'medium'}
>
{feConfigs?.find_password_method && feConfigs.find_password_method.length > 0 && (
<Box
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
onClick={() => setPageType('forgetPassword')}
fontSize="sm"
fontSize="mini"
>
{t('login:forget_password')}
</Box>
)}
{feConfigs?.register_method && feConfigs.register_method.length > 0 && (
<>
<Box mx={3} h={'16px'} w={'1.5px'} bg={'myGray.250'}></Box>
<Flex alignItems={'center'}>
<Box mx={3} h={'12px'} w={'1px'} bg={'myGray.250'}></Box>
<Box
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
onClick={() => setPageType('register')}
fontSize="sm"
fontSize="mini"
>
{t('login:register')}
</Box>
</>
</Flex>
)}
</Flex>
</Box>

View File

@@ -5,7 +5,6 @@ import { Box, Center, Image } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { getWXLoginQR, getWXLoginResult } from '@/web/support/user/api';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useRouter } from 'next/router';
import { useToast } from '@fastgpt/web/hooks/useToast';
import FormLayout from './components/FormLayout';
import { useTranslation } from 'next-i18next';
@@ -40,7 +39,7 @@ const WechatForm = ({ setPageType, loginSuccess }: Props) => {
return (
<FormLayout setPageType={setPageType} pageType={LoginPageTypeEnum.wechat}>
<Box>
<Box w={'full'} textAlign={'center'} pt={5}>
<Box w={'full'} textAlign={'center'} pt={6} fontWeight={'medium'}>
{t('common:support.user.login.wx_qr_login')}
</Box>
<Box p={5} display={'flex'} w={'full'} justifyContent={'center'}>

View File

@@ -8,7 +8,6 @@ import { customAlphabet } from 'nanoid';
import { useRouter } from 'next/router';
import { Dispatch, useRef } from 'react';
import { useTranslation } from 'next-i18next';
import Divider from '@/pages/app/detail/components/WorkflowComponents/Flow/components/Divider';
import I18nLngSelector from '@/components/Select/I18nLngSelector';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 8);
@@ -64,7 +63,7 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
{
label: t('common:support.user.login.Password login'),
provider: LoginPageTypeEnum.passwordLogin,
icon: 'support/account/passwordLogin',
icon: 'support/permission/privateLight',
pageType: LoginPageTypeEnum.passwordLogin
}
]
@@ -77,20 +76,20 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
return (
<Flex flexDirection={'column'} h={'100%'}>
<Flex alignItems={'center'} justify={'space-between'}>
<Flex>
<Flex alignItems={'center'}>
<Flex
w={['48px', '56px']}
h={['48px', '56px']}
w={['42px', '56px']}
h={['42px', '56px']}
bg={'myGray.25'}
borderRadius={'xl'}
borderWidth={'1.5px'}
borderColor={'borderColor.base'}
borderRadius={['semilg', 'lg']}
borderWidth={['1px', '1.5px']}
borderColor={'myGray.200'}
alignItems={'center'}
justifyContent={'center'}
>
<Image src={LOGO_ICON} w={['24px', '28px']} alt={'icon'} />
<Image src={LOGO_ICON} w={['22.5px', '36px']} alt={'icon'} />
</Flex>
<Box ml={3} fontSize={['2xl', '3xl']} fontWeight={'bold'}>
<Box ml={[3, 5]} fontSize={['lg', 'xl']} fontWeight={'bold'} color={'myGray.900'}>
{feConfigs?.systemTitle}
</Box>
</Flex>
@@ -101,26 +100,21 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
<>
<Box flex={1} />
<Box position={'relative'}>
<Divider />
<AbsoluteCenter bg="white" px="4" color={'myGray.500'}>
<Box h={'1px'} bg={'myGray.250'} />
<AbsoluteCenter bg={'white'} px={3} color={'myGray.500'} fontSize={'mini'}>
or
</AbsoluteCenter>
</Box>
<Box mt={8}>
<Box mt={4}>
{oAuthList.map((item) => (
<Box key={item.provider} _notFirst={{ mt: 4 }}>
<Button
variant={'whitePrimary'}
w={'100%'}
h={'42px'}
leftIcon={
<MyIcon
name={item.icon as any}
w={'20px'}
cursor={'pointer'}
color={'myGray.800'}
/>
}
h={'40px'}
borderRadius={'sm'}
fontWeight={'medium'}
leftIcon={<MyIcon name={item.icon as any} w={'20px'} />}
onClick={() => {
item.redirectUrl &&
setLoginStore({
@@ -142,7 +136,8 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
<Button
variant={'whitePrimary'}
w={'100%'}
h={'42px'}
h={'40px'}
borderRadius={'sm'}
leftIcon={<Image alt="" src={feConfigs.sso.icon as any} w="20px" />}
onClick={() => {
feConfigs.sso?.url && router.replace(feConfigs.sso?.url, '_self');

View File

@@ -102,11 +102,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
return (
<>
<Box fontWeight={'bold'} fontSize={'2xl'} textAlign={'center'}>
<Box fontWeight={'medium'} fontSize={'lg'} textAlign={'center'} color={'myGray.900'}>
{t('user:register.register_account', { account: feConfigs?.systemTitle })}
</Box>
<Box
mt={'42px'}
mt={9}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey && !requesting) {
handleSubmit(onclickRegister)();
@@ -116,6 +116,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<FormControl isInvalid={!!errors.username}>
<Input
bg={'myGray.50'}
size={'lg'}
placeholder={placeholder}
{...register('username', {
required: t('user:password.email_phone_void'),
@@ -135,6 +136,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
position={'relative'}
>
<Input
size={'lg'}
bg={'myGray.50'}
flex={1}
maxLength={8}
@@ -148,6 +150,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<FormControl mt={6} isInvalid={!!errors.password}>
<Input
bg={'myGray.50'}
size={'lg'}
type={'password'}
placeholder={t('user:password.new_password')}
{...register('password', {
@@ -166,6 +169,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
<FormControl mt={6} isInvalid={!!errors.password2}>
<Input
bg={'myGray.50'}
size={'lg'}
type={'password'}
placeholder={t('user:password.confirm')}
{...register('password2', {
@@ -176,9 +180,12 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
</FormControl>
<Button
type="submit"
mt={6}
mt={12}
w={'100%'}
size={['md', 'md']}
rounded={['md', 'md']}
h={[10, 10]}
fontWeight={['medium', 'medium']}
colorScheme="blue"
isLoading={requesting}
onClick={handleSubmit(onclickRegister)}
@@ -187,9 +194,10 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
</Button>
<Box
float={'right'}
fontSize="sm"
mt={2}
fontSize="mini"
mt={3}
mb={'50px'}
fontWeight={'medium'}
color={'primary.700'}
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}

View File

@@ -145,7 +145,6 @@ const Login = ({ ChineseRedirectUrl }: { ChineseRedirectUrl: string }) => {
backgroundSize={'cover'}
userSelect={'none'}
h={'100%'}
px={[0, '10vw']}
>
{isPc && (
<Box position={'absolute'} top={'24px'} right={'50px'}>
@@ -154,16 +153,15 @@ const Login = ({ ChineseRedirectUrl }: { ChineseRedirectUrl: string }) => {
)}
<Flex
flexDirection={'column'}
w={['100%', 'auto']}
h={['100%', '700px']}
maxH={['100%', '90vh']}
w={['100%', '556px']}
h={['100%', '677px']}
bg={'white'}
px={['5vw', '88px']}
py={'5vh'}
borderRadius={[0, '24px']}
py={['5vh', '64px']}
borderRadius={[0, '16px']}
boxShadow={[
'',
'0px 0px 1px 0px rgba(19, 51, 107, 0.20), 0px 32px 64px -12px rgba(19, 51, 107, 0.20)'
'0px 32px 64px -12px rgba(19, 51, 107, 0.20), 0px 0px 1px 0px rgba(19, 51, 107, 0.20)'
]}
>
<Box w={['100%', '380px']} flex={'1 0 0'}>
@@ -179,6 +177,8 @@ const Login = ({ ChineseRedirectUrl }: { ChineseRedirectUrl: string }) => {
<Box
mt={8}
color={'primary.700'}
fontSize={'mini'}
fontWeight={'medium'}
cursor={'pointer'}
textAlign={'center'}
onClick={onOpen}

View File

@@ -1,14 +1,4 @@
import {
Box,
Flex,
Grid,
NumberDecrementStepper,
NumberInput,
NumberIncrementStepper,
NumberInputField,
NumberInputStepper,
Button
} from '@chakra-ui/react';
import { Box, Flex, Grid, Button } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import React, { useCallback, useState } from 'react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
@@ -19,6 +9,7 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput';
const ExtraPlan = () => {
const { t } = useTranslation();
@@ -170,22 +161,14 @@ const ExtraPlan = () => {
{t('common:support.wallet.subscription.Month amount')}
</Box>
<Flex alignItems={'center'} mt={1} w={'180px'} position={'relative'}>
<NumberInput size={'sm'} flex={1} step={1} min={1} max={12} position={'relative'}>
<NumberInputField
pr={'30px'}
{...registerDatasetSize('month', {
required: true,
min: 1,
max: 12,
valueAsNumber: true
})}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
<Box position={'absolute'} right={'20px'} color={'myGray.600'} fontSize={'xs'}>
<MyNumberInput
name="month"
register={registerDatasetSize}
min={1}
max={12}
size={'sm'}
/>
<Box position={'absolute'} right={'30px'} color={'myGray.600'} fontSize={'xs'}>
{t('common:common.month')}
</Box>
</Flex>
@@ -195,30 +178,14 @@ const ExtraPlan = () => {
{t('common:support.wallet.subscription.Update extra dataset size')}
</Box>
<Flex alignItems={'center'} mt={1} w={'180px'} position={'relative'}>
<NumberInput
size={'sm'}
flex={1}
<MyNumberInput
name="datasetSize"
register={registerDatasetSize}
min={0}
max={10000}
step={1}
position={'relative'}
>
<NumberInputField
pr={'30px'}
{...registerDatasetSize('datasetSize', {
required: true,
min: 0,
max: 10000,
valueAsNumber: true
})}
step={1}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
<Box position={'absolute'} right={'20px'} color={'myGray.600'} fontSize={'xs'}>
size={'sm'}
/>
<Box position={'absolute'} right={'30px'} color={'myGray.600'} fontSize={'xs'}>
000{t('common:core.dataset.data.unit')}
</Box>
</Flex>
@@ -291,30 +258,14 @@ const ExtraPlan = () => {
position={'relative'}
color={'myGray.500'}
>
<NumberInput
size={'sm'}
flex={1}
<MyNumberInput
name="points"
register={registerDatasetSize}
min={0}
max={10000}
step={1}
position={'relative'}
>
<NumberInputField
pr={'30px'}
step={1}
{...registerExtraPoints('points', {
required: true,
min: 0,
max: 10000,
valueAsNumber: true
})}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
<Box position={'absolute'} right={'20px'} color={'myGray.500'} fontSize={'xs'}>
size={'sm'}
/>
<Box position={'absolute'} right={'30px'} color={'myGray.500'} fontSize={'xs'}>
{'000' + t('common:support.wallet.subscription.point')}
</Box>
</Flex>

View File

@@ -64,7 +64,8 @@ export const useSendCode = ({ type }: { type: `${UserAuthTypeEnum}` }) => {
position={'absolute'}
right={3}
zIndex={1}
fontSize={'sm'}
fontSize={'mini'}
fontWeight={'medium'}
{...styles}
{...(codeCountDown > 0
? {