Commit b41b5411 by siigure Committed by GitHub

Fix/playground-visibility-config-layout (#7135)

* fix: enhance Playground visibility configuration with new grid layout and switch components

* refactor: update layout and styling for various components to improve responsiveness and usability

* perf: ui

* perf: tool response none

* doc

* doc

* hide auth switch in community version

---------

Co-authored-by: archer <545436317@qq.com>
parent c44a1a73
......@@ -21,6 +21,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initSandboxArchive' \
5. 支持通过模型生成对话标题,需配置 `CHAT_TITLE_MODEL` 变量。
6. 调整 Skill Edit 编辑交互。
7. HTTP 节点支持返回完整错误对象。
8. agent 模式知识库搜索,支持权限过滤。
## ⚙️ 优化
......@@ -29,11 +30,13 @@ curl --location --request POST 'https://{{host}}/api/admin/initSandboxArchive' \
3. 移除所有内置 LLM 请求中的 `temperature` 和 `max_tokens`,避免部分模型不兼容。
4. 知识库训练出现错误时的提示,同时支持一键全部重试。
5. 过滤掉无效的知识库引用角标。
6. 工具运行空响应时候,自动补充 "none",避免部分模型报错。
## 🐛 修复
1. 修复 S3 私有对象 key 未绑定已鉴权资源时可能导致的跨资源文件访问风险。
2. 工作流工具,array 和 object 类型,工具调用参数 schema 异常。
3. 发布渠道 - 门户,UI 偏移。
## 代码优化
......
......@@ -285,7 +285,7 @@
"content/self-host/upgrading/4-15/41504.en.mdx": "2026-06-10T19:02:59+08:00",
"content/self-host/upgrading/4-15/41504.mdx": "2026-06-15T23:34:43+08:00",
"content/self-host/upgrading/4-15/41505.en.mdx": "2026-06-12T20:47:04+08:00",
"content/self-host/upgrading/4-15/41505.mdx": "2026-06-17T18:19:09+08:00",
"content/self-host/upgrading/4-15/41505.mdx": "2026-06-18T14:56:07+08:00",
"content/self-host/upgrading/outdated/40.en.mdx": "2026-04-26T21:08:47+08:00",
"content/self-host/upgrading/outdated/40.mdx": "2026-04-26T21:08:47+08:00",
"content/self-host/upgrading/outdated/41.en.mdx": "2026-04-26T21:08:47+08:00",
......
......@@ -10,3 +10,4 @@ export * from './plan/updateTool';
export * from './stop';
export * from './tools';
export * from './loop/unified';
export * from './utils';
......@@ -23,6 +23,7 @@ import type {
import { AgentUsageModuleName } from '../constants';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { batchRun } from '@fastgpt/global/common/system/utils';
import { normalizeToolResponseContent } from '../utils';
type RunAgentCallProps<TChildrenResponse = unknown> = {
maxRunAgentTimes: number;
......@@ -233,7 +234,7 @@ export const runAgentLoop = async <TChildrenResponse = unknown>({
item.role === 'tool' && item.tool_call_id === childrenInteractiveParams.toolParams.toolCallId
? {
...item,
content: response
content: normalizeToolResponseContent(response)
}
: item
);
......@@ -461,7 +462,7 @@ export const runAgentLoop = async <TChildrenResponse = unknown>({
const { toolFinalResponse, toolResponseCompress } = await (async () => {
if (skipResponseCompress) {
return {
toolFinalResponse: response
toolFinalResponse: normalizeToolResponseContent(response)
};
}
......@@ -475,12 +476,13 @@ export const runAgentLoop = async <TChildrenResponse = unknown>({
userKey
});
const { compressed: compressed_context, usage: compressionUsage } = compressionResult;
const normalizedCompressedContext = normalizeToolResponseContent(compressed_context);
if (compressionUsage) {
usagePush([compressionUsage]);
return {
toolFinalResponse: compressed_context,
toolFinalResponse: normalizedCompressedContext,
toolResponseCompress: {
response: compressed_context,
response: normalizedCompressedContext,
usage: compressionUsage,
requestIds: compressionResult.requestIds ?? [],
seconds: +((Date.now() - compressStartTime) / 1000).toFixed(2)
......@@ -489,7 +491,7 @@ export const runAgentLoop = async <TChildrenResponse = unknown>({
}
return {
toolFinalResponse: compressed_context
toolFinalResponse: normalizedCompressedContext
};
})();
......
......@@ -11,6 +11,7 @@ import { parsePlanAskToolCall } from '../plan/parser';
import { applyPlanUpdate } from '../plan/state';
import { runStopGate } from '../stop';
import { getToolsForUnifiedLoop, normalizeToolCatalog } from '../tools';
import { normalizeToolResponseContent } from '../utils';
import type {
AgentLoopRuntime,
AgentLoopToolExecutionResult,
......@@ -163,7 +164,7 @@ export const runUnifiedAgentLoop = async ({
{
role: ChatCompletionRequestMessageRoleEnum.Tool,
tool_call_id: input.pendingMainContext.askToolCallId,
content: input.userAnswer || ''
content: normalizeToolResponseContent(input.userAnswer)
} as ChatCompletionMessageParam
]
: buildInitialMessages({ input, hasRuntimeTools });
......
/**
* 规范化会写入 LLM tool message 的工具响应。
* OpenAI 兼容接口通常不接受空 tool content;undefined 和空字符串统一兜底为 none。
*/
export const normalizeToolResponseContent = (response?: string) =>
response === '' || response === undefined ? 'none' : response;
......@@ -440,6 +440,115 @@ describe('runAgentLoop with mocked createLLMResponse', () => {
});
});
it('normalizes empty tool response to none before feeding the next LLM request', async () => {
const onRunTool = vi.fn(async () => ({
response: '',
assistantMessages: [],
usages: []
}));
mockCreateLLMResponseQueue(createLLMResponseMock, [
toolCall({
id: 'call_search',
name: 'search',
args: {
q: 'FastGPT'
}
}),
text({ requestId: 'req_final', content: 'final answer' })
]);
const result = await runAgentLoop({
maxRunAgentTimes: 5,
body: {
model: 'gpt-4',
stream: true,
messages: [
{
role: ChatCompletionRequestMessageRoleEnum.User,
content: 'search FastGPT'
}
],
tools: [searchTool]
},
usagePush: vi.fn(),
isAborted: () => false,
onRunTool,
onRunInteractiveTool: vi.fn()
});
expect(createLLMResponseMock.mock.calls[1][0].body.messages).toContainEqual({
role: 'tool',
tool_call_id: 'call_search',
content: 'none'
});
expect(result.assistantMessages).toContainEqual({
role: 'tool',
tool_call_id: 'call_search',
content: 'none'
});
});
it('normalizes empty compressed tool response to none', async () => {
compressToolResponseMock.mockImplementation(async () => ({
compressed: ''
}));
const onAfterToolCall = vi.fn();
const onRunTool = vi.fn(async () => ({
response: 'raw response',
assistantMessages: [],
usages: []
}));
mockCreateLLMResponseQueue(createLLMResponseMock, [
toolCall({
id: 'call_search',
name: 'search',
args: {
q: 'FastGPT'
}
}),
text({ requestId: 'req_final', content: 'final answer' })
]);
const result = await runAgentLoop({
maxRunAgentTimes: 5,
body: {
model: 'gpt-4',
stream: true,
messages: [
{
role: ChatCompletionRequestMessageRoleEnum.User,
content: 'search FastGPT'
}
],
tools: [searchTool]
},
usagePush: vi.fn(),
isAborted: () => false,
onRunTool,
onRunInteractiveTool: vi.fn(),
onAfterToolCall
});
expect(onAfterToolCall).toHaveBeenCalledWith(
expect.objectContaining({
call: expect.objectContaining({ id: 'call_search' }),
response: 'none'
})
);
expect(createLLMResponseMock.mock.calls[1][0].body.messages).toContainEqual({
role: 'tool',
tool_call_id: 'call_search',
content: 'none'
});
expect(result.assistantMessages).toContainEqual({
role: 'tool',
tool_call_id: 'call_search',
content: 'none'
});
});
it('passes reasoning effort into context and tool response compression', async () => {
compressRequestMessagesMock.mockImplementation(async ({ messages }) => ({
messages
......
......@@ -787,6 +787,51 @@ describe('runUnifiedAgentLoop', () => {
expect(createLLMResponseMock).toHaveBeenCalledTimes(2);
});
it('normalizes empty ask_agent resume answer to none in tool message', async () => {
mockCreateLLMResponseQueue(createLLMResponseMock, [
text({
requestId: 'req_after_resume',
content: 'continued after empty answer'
})
]);
await runUnifiedAgentLoop({
runtime: createRuntime(),
input: {
messages: [],
pendingMainContext: {
messages: [
{
role: ChatCompletionRequestMessageRoleEnum.User,
content: 'Need clarification'
},
{
role: ChatCompletionRequestMessageRoleEnum.Assistant,
tool_calls: [
{
id: 'call_ask',
type: 'function',
function: {
name: 'ask_agent',
arguments: '{}'
}
}
]
}
],
askToolCallId: 'call_ask'
},
userAnswer: ''
}
});
expect(createLLMResponseMock.mock.calls[0][0].body.messages).toContainEqual({
role: 'tool',
tool_call_id: 'call_ask',
content: 'none'
});
});
it('keeps runtime-tool plan-update requirements across ask_agent resume', async () => {
mockCreateLLMResponseQueue(createLLMResponseMock, [
toolCall({
......
......@@ -438,6 +438,7 @@ const EditForm = ({
<MyIcon name={'core/app/simpleMode/dataset'} w={'20px'} />
<FormLabel ml={2}>{t('app:dataset')}</FormLabel>
</Flex>
{feConfigs?.isPlus && (
<Flex alignItems={'center'} mr={2}>
<Box fontSize={'sm'} color={'myGray.600'} whiteSpace={'nowrap'}>
{t('workflow:auth_tmb_id')}
......@@ -458,6 +459,7 @@ const EditForm = ({
}}
/>
</Flex>
)}
<Button
variant={'transparentBase'}
leftIcon={<MyIcon name={'edit'} w={'14px'} />}
......
......@@ -64,7 +64,7 @@ const AgentEdit = () => {
);
return (
<Flex h={'100%'} flexDirection={'column'} px={[3, 0]} pr={[3, 3]}>
<Flex h={'100%'} minH={0} flexDirection={'column'} px={[3, 0]} pr={[3, 3]}>
<Header
appForm={appForm}
forbiddenSaveSnapshot={forbiddenSaveSnapshot}
......@@ -78,7 +78,15 @@ const AgentEdit = () => {
{currentTab === TabEnum.appEdit ? (
<Edit appForm={appForm} setAppForm={setAppForm} setPast={setPast} />
) : (
<Box flex={'1 0 0'} h={0} mt={[4, 0]} mb={[2, 4]}>
<Box
flex={'1 0 0'}
h={0}
minH={0}
overflowY={'auto'}
overflowX={'hidden'}
mt={[4, 0]}
mb={[2, 4]}
>
{currentTab === TabEnum.publish && <PublishChannel />}
{currentTab === TabEnum.logs && <Logs />}
</Box>
......
......@@ -320,6 +320,7 @@ const EditForm = ({
<MyIcon name={'core/app/simpleMode/dataset'} w={'20px'} />
<FormLabel ml={2}>{t('app:dataset')}</FormLabel>
</Flex>
{feConfigs?.isPlus && (
<Flex alignItems={'center'} mr={2}>
<Box fontSize={'sm'} color={'myGray.600'} whiteSpace={'nowrap'}>
{t('workflow:auth_tmb_id')}
......@@ -340,6 +341,7 @@ const EditForm = ({
}}
/>
</Flex>
)}
<Button
variant={'transparentBase'}
leftIcon={<MyIcon name={'edit'} w={'14px'} />}
......
......@@ -2,7 +2,6 @@ import React, { useState } from 'react';
import Header from '../FormComponent/Header';
import { useContextSelector } from 'use-context-selector';
import { AppContext, TabEnum } from '../../context';
import dynamic from 'next/dynamic';
import { Box, Flex } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useSimpleAppSnapshots } from '../FormComponent/useSnapshots';
......@@ -70,7 +69,7 @@ const SimpleEdit = () => {
);
return (
<Flex h={'100%'} flexDirection={'column'} px={[3, 0]} pr={[3, 3]}>
<Flex h={'100%'} minH={0} flexDirection={'column'} px={[3, 0]} pr={[3, 3]}>
<Header
appForm={appForm}
forbiddenSaveSnapshot={forbiddenSaveSnapshot}
......@@ -84,7 +83,17 @@ const SimpleEdit = () => {
{currentTab === TabEnum.appEdit ? (
<Edit appForm={appForm} setAppForm={setAppForm} setPast={setPast} />
) : (
<Box flex={'1 0 0'} h={0} mt={[4, 0]} mb={[2, 4]} bg={'white'} borderRadius={'lg'}>
<Box
flex={'1 0 0'}
h={0}
minH={0}
overflowY={'auto'}
overflowX={'hidden'}
mt={[4, 0]}
mb={[2, 4]}
bg={'white'}
borderRadius={'lg'}
>
{currentTab === TabEnum.publish && <PublishChannel />}
{currentTab === TabEnum.logs && <Logs />}
</Box>
......
......@@ -56,7 +56,17 @@ const WorkflowEdit = () => {
{currentTab === TabEnum.appEdit ? (
<Flow />
) : (
<Flex flexDirection={'column'} h={'100%'} mt={'72px'} px={4} pb={4} bg={'white'}>
<Flex
flexDirection={'column'}
flex={1}
minH={0}
mt={'72px'}
px={4}
pb={4}
bg={'white'}
overflowY={'auto'}
overflowX={'hidden'}
>
{currentTab === TabEnum.publish && <PublishChannel />}
{currentTab === TabEnum.logs && <Logs />}
</Flex>
......
import React, { useMemo } from 'react';
import { Box, Flex, Switch } from '@chakra-ui/react';
import { Box, Flex, Grid, Switch } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useForm, useWatch } from 'react-hook-form';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
......@@ -35,7 +35,6 @@ const PlaygroundVisibilityConfig = ({ appId }: { appId: string }) => {
const showFullText = useWatch({ control, name: 'showFullText' });
const canDownloadSource = useWatch({ control, name: 'canDownloadSource' });
const showRunningStatus = useWatch({ control, name: 'showRunningStatus' });
const showSkillReferences = useWatch({ control, name: 'showSkillReferences' });
const showWholeResponse = useWatch({ control, name: 'showWholeResponse' });
const playgroundLink = useMemo(() => {
......@@ -76,8 +75,14 @@ const PlaygroundVisibilityConfig = ({ appId }: { appId: string }) => {
await saveConfig(values);
};
const visibilityItemGridProps = {
templateColumns: { base: 'minmax(0, 1fr) auto', sm: '140px auto' } as const,
columnGap: '28px' as const,
alignItems: 'center' as const
};
return (
<Flex flexDirection="column" h="100%">
<Flex flexDirection="column">
<Box fontSize={'sm'} fontWeight={'medium'} color={'myGray.900'} mb={3}>
{t('app:publish.playground_link')}
</Box>
......@@ -112,41 +117,54 @@ const PlaygroundVisibilityConfig = ({ appId }: { appId: string }) => {
{t('publish:private_config')}
</Box>
<Flex flexDirection="column" gap={4} mt={4}>
<Flex gap={4} flexWrap={'wrap'}>
<Flex alignItems={'center'}>
<FormLabel fontSize={'12px'} flex={'0 0 127px'}>
<Grid
mt={4}
w={'100%'}
templateColumns={{ base: '1fr', sm: 'repeat(3, 1fr)' }}
columnGap={6}
rowGap={4}
pb={4}
>
<Grid {...visibilityItemGridProps}>
<FormLabel fontSize={'12px'} mb={0} whiteSpace={{ base: 'normal', sm: 'nowrap' }}>
{t('publish:show_node')}
</FormLabel>
<Switch
flexShrink={0}
{...register('showRunningStatus', {
onChange: autoSave
})}
isChecked={showRunningStatus}
/>
</Flex>
<Flex alignItems={'center'}>
<Flex alignItems={'center'} flex={'0 0 127px'}>
<FormLabel fontSize={'12px'}>{t('app:publish.show_whole_response')}</FormLabel>
<QuestionTip ml={1} label={t('app:publish.show_whole_response_tip')} />
</Grid>
<Grid {...visibilityItemGridProps}>
<Flex alignItems={'center'} gap={1}>
<FormLabel fontSize={'12px'} mb={0} whiteSpace={{ base: 'normal', sm: 'nowrap' }}>
{t('app:publish.show_whole_response')}
</FormLabel>
<QuestionTip label={t('app:publish.show_whole_response_tip')} />
</Flex>
<Switch
flexShrink={0}
{...register('showWholeResponse', {
onChange: autoSave
})}
isChecked={showWholeResponse}
/>
</Flex>
</Flex>
<Flex gap={4} flexWrap={'wrap'}>
<Flex alignItems={'center'}>
<Flex alignItems={'center'} flex={'0 0 127px'}>
<FormLabel fontSize={'12px'}>
</Grid>
<Box display={{ base: 'none', sm: 'block' }} />
<Grid {...visibilityItemGridProps}>
<Flex alignItems={'center'} gap={1}>
<FormLabel fontSize={'12px'} mb={0} whiteSpace={{ base: 'normal', sm: 'nowrap' }}>
{t('common:support.outlink.share.Response Quote')}
</FormLabel>
<QuestionTip ml={1} label={t('common:support.outlink.share.Response Quote tips')} />
<QuestionTip label={t('common:support.outlink.share.Response Quote tips')} />
</Flex>
<Switch
flexShrink={0}
{...register('showCite', {
onChange(e) {
if (!e.target.checked) {
......@@ -158,13 +176,17 @@ const PlaygroundVisibilityConfig = ({ appId }: { appId: string }) => {
})}
isChecked={showCite}
/>
</Flex>
<Flex alignItems={'center'}>
<Flex alignItems={'center'} flex={'0 0 127px'}>
<FormLabel fontSize={'12px'}>{t('common:core.app.share.Show full text')}</FormLabel>
<QuestionTip ml={1} label={t('common:support.outlink.share.Show full text tips')} />
</Grid>
<Grid {...visibilityItemGridProps}>
<Flex alignItems={'center'} gap={1}>
<FormLabel fontSize={'12px'} mb={0} whiteSpace={{ base: 'normal', sm: 'nowrap' }}>
{t('common:core.app.share.Show full text')}
</FormLabel>
<QuestionTip label={t('common:support.outlink.share.Show full text tips')} />
</Flex>
<Switch
flexShrink={0}
{...register('showFullText', {
onChange(e) {
if (!e.target.checked) {
......@@ -177,15 +199,17 @@ const PlaygroundVisibilityConfig = ({ appId }: { appId: string }) => {
})}
isChecked={showFullText}
/>
</Flex>
<Flex alignItems={'center'}>
<Flex alignItems={'center'} flex={'0 0 127px'}>
<FormLabel fontSize={'12px'} fontWeight={'medium'}>
</Grid>
<Grid {...visibilityItemGridProps}>
<Flex alignItems={'center'} gap={1}>
<FormLabel fontSize={'12px'} mb={0} whiteSpace={{ base: 'normal', sm: 'nowrap' }}>
{t('common:core.app.share.Download source')}
</FormLabel>
<QuestionTip ml={1} label={t('common:support.outlink.share.Download source tips')} />
<QuestionTip label={t('common:support.outlink.share.Download source tips')} />
</Flex>
<Switch
flexShrink={0}
{...register('canDownloadSource', {
onChange(e) {
if (e.target.checked) {
......@@ -197,28 +221,8 @@ const PlaygroundVisibilityConfig = ({ appId }: { appId: string }) => {
})}
isChecked={canDownloadSource}
/>
</Flex>
</Flex>
<Flex gap={4} flexWrap={'wrap'}>
<Flex alignItems={'center'}>
<Flex alignItems={'center'} flex={'0 0 127px'}>
<FormLabel fontSize={'12px'}>{t('publish:show_skill_reference')}</FormLabel>
<QuestionTip ml={1} label={t('publish:show_skill_reference_tips')} />
</Flex>
<Switch
{...register('showSkillReferences', {
onChange(e) {
if (e.target.checked) {
setValue('showRunningStatus', true);
}
autoSave();
}
})}
isChecked={showSkillReferences}
/>
</Flex>
</Flex>
</Flex>
</Grid>
</Grid>
</Flex>
);
};
......
import React, { useRef, useState } from 'react';
import { Box, Flex } from '@chakra-ui/react';
import React, { useMemo, useState } from 'react';
import { Box } from '@chakra-ui/react';
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
import dynamic from 'next/dynamic';
......@@ -31,7 +31,8 @@ const OutLink = () => {
const appId = useContextSelector(AppContext, (v) => v.appId);
const publishList = useRef([
const publishList = useMemo(
() => [
{
icon: '/imgs/modal/shareFill.svg',
title: t('common:core.app.Share link'),
......@@ -111,18 +112,14 @@ const OutLink = () => {
value: PublishChannelEnum.playground,
isProFn: false
}
]);
],
[t, feConfigs, userInfo?.tags]
);
const [linkType, setLinkType] = useState<PublishChannelEnum>(PublishChannelEnum.share);
return (
<Box
display={['block', 'flex']}
overflowY={'auto'}
overflowX={'hidden'}
h={'100%'}
flexDirection={'column'}
>
<Box>
<Box mx={[4, 8]} py={[4, 6]} borderBottom={'1px solid'} borderColor={'myGray.150'}>
<MyRadio
gridTemplateColumns={[
......@@ -133,10 +130,10 @@ const OutLink = () => {
'repeat(4, 1fr)'
]}
iconSize={'20px'}
list={publishList.current}
list={publishList}
value={linkType}
onChange={(e) => {
const config = publishList.current.find((v) => v.value === e)!;
const config = publishList.find((v) => v.value === e)!;
if (!feConfigs.isPlus && config.isProFn) {
toast({
status: 'warning',
......@@ -149,7 +146,7 @@ const OutLink = () => {
/>
</Box>
<Flex flexDirection={'column'} mt={2} px={[4, 8]} py={[4, 6]} flex={1}>
<Box mt={2} px={[4, 8]} py={[4, 6]}>
{linkType === PublishChannelEnum.share && (
<Link appId={appId} type={PublishChannelEnum.share} />
)}
......@@ -160,7 +157,7 @@ const OutLink = () => {
{linkType === PublishChannelEnum.officialAccount && <OffiAccount appId={appId} />}
{linkType === PublishChannelEnum.wechat && <Wechat appId={appId} />}
{linkType === PublishChannelEnum.playground && <Playground appId={appId} />}
</Flex>
</Box>
</Box>
);
};
......
......@@ -62,7 +62,17 @@ const WorkflowEdit = () => {
{currentTab === TabEnum.appEdit ? (
<Flow />
) : (
<Flex flexDirection={'column'} h={'100%'} mt={'72px'} px={4} pb={4} bg={'white'}>
<Flex
flexDirection={'column'}
flex={1}
minH={0}
mt={'72px'}
px={4}
pb={4}
bg={'white'}
overflowY={'auto'}
overflowX={'hidden'}
>
{currentTab === TabEnum.publish && <PublishChannel />}
{currentTab === TabEnum.logs && <Logs />}
</Flex>
......
......@@ -845,7 +845,7 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
<Box mb={5}>
<Flex className="nodrag" cursor={'default'} alignItems={'center'}>
<FormLabel color={'myGray.600'}>{t('common:core.dataset.Dataset')}</FormLabel>
{authTmbIdInput && (
{feConfigs?.isPlus && authTmbIdInput && (
<Flex ml={2} alignItems={'center'}>
<Box fontSize={'sm'} color={'myGray.600'} whiteSpace={'nowrap'}>
{t('workflow:auth_tmb_id')}
......
......@@ -11,6 +11,7 @@ import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { WorkflowActionsContext } from '@/pageComponents/app/detail/WorkflowComponents/context/workflowActionsContext';
import DatasetCard from '@/components/core/app/DatasetCard';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
......@@ -133,6 +134,7 @@ export const SwitchAuthTmb = React.memo(function SwitchAuthTmb({
nodeId
}: RenderInputProps) {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const onChangeNode = useContextSelector(WorkflowActionsContext, (v) => v.onChangeNode);
const authTmbIdInput = useMemo(
......@@ -140,7 +142,7 @@ export const SwitchAuthTmb = React.memo(function SwitchAuthTmb({
[inputs]
);
return authTmbIdInput ? (
return feConfigs?.isPlus && authTmbIdInput ? (
<Flex alignItems={'center'}>
<Box fontSize={'sm'}>{t('workflow:auth_tmb_id')}</Box>
<QuestionTip label={t('workflow:auth_tmb_id_tip')} />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment