Feat: Display mode at the begin node #10427 (#12326)

### What problem does this PR solve?

Feat: Display mode at the begin node #10427
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-12-30 19:53:24 +08:00
committed by GitHub
parent a7e466142d
commit 348265afc1
3 changed files with 94 additions and 52 deletions

View File

@ -1,16 +1,18 @@
import { IBeginNode } from '@/interfaces/database/flow'; import { BaseNode } from '@/interfaces/database/flow';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { NodeProps, Position } from '@xyflow/react'; import { NodeProps, Position } from '@xyflow/react';
import get from 'lodash/get'; import get from 'lodash/get';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
AgentDialogueMode,
BeginQueryType, BeginQueryType,
BeginQueryTypeIconMap, BeginQueryTypeIconMap,
NodeHandleId, NodeHandleId,
Operator, Operator,
} from '../../constant'; } from '../../constant';
import { BeginQuery } from '../../interface'; import { BeginFormSchemaType } from '../../form/begin-form/schema';
import { useBuildWebhookUrl } from '../../hooks/use-build-webhook-url';
import OperatorIcon from '../../operator-icon'; import OperatorIcon from '../../operator-icon';
import { LabelCard } from './card'; import { LabelCard } from './card';
import { CommonHandle } from './handle'; import { CommonHandle } from './handle';
@ -18,10 +20,19 @@ import { RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import { NodeWrapper } from './node-wrapper'; import { NodeWrapper } from './node-wrapper';
// TODO: do not allow other nodes to connect to this node function InnerBeginNode({
function InnerBeginNode({ data, id, selected }: NodeProps<IBeginNode>) { data,
id,
selected,
}: NodeProps<BaseNode<BeginFormSchemaType>>) {
const { t } = useTranslation(); const { t } = useTranslation();
const inputs: Record<string, BeginQuery> = get(data, 'form.inputs', {}); const inputs = get(data, 'form.inputs', {});
const mode = data.form?.mode;
const isWebhookMode = mode === AgentDialogueMode.Webhook;
const url = useBuildWebhookUrl();
return ( return (
<NodeWrapper selected={selected} id={id}> <NodeWrapper selected={selected} id={id}>
@ -40,23 +51,38 @@ function InnerBeginNode({ data, id, selected }: NodeProps<IBeginNode>) {
{t(`flow.begin`)} {t(`flow.begin`)}
</div> </div>
</section> </section>
<section className={cn(styles.generateParameters, 'flex gap-2 flex-col')}> <div className="text-accent-primary mt-2 p-1 bg-bg-accent w-fit rounded-sm text-xs">
{Object.entries(inputs).map(([key, val], idx) => { {t(`flow.${isWebhookMode ? 'webhook.name' : mode}`)}
const Icon = BeginQueryTypeIconMap[val.type as BeginQueryType]; </div>
return ( {isWebhookMode ? (
<LabelCard key={idx} className={cn('flex gap-1.5 items-center')}> <LabelCard className="mt-2 flex gap-1 items-center">
<Icon className="size-3.5" /> <span className="font-bold">URL</span>
<label htmlFor="" className="text-accent-primary text-sm italic"> <span className="flex-1 truncate">{url}</span>
{key} </LabelCard>
</label> ) : (
<LabelCard className="py-0.5 truncate flex-1"> <section
{val.name} className={cn(styles.generateParameters, 'flex gap-2 flex-col')}
>
{Object.entries(inputs).map(([key, val], idx) => {
const Icon = BeginQueryTypeIconMap[val.type as BeginQueryType];
return (
<LabelCard key={idx} className={cn('flex gap-1.5 items-center')}>
<Icon className="size-3.5" />
<label
htmlFor=""
className="text-accent-primary text-sm italic"
>
{key}
</label>
<LabelCard className="py-0.5 truncate flex-1">
{val.name}
</LabelCard>
<span className="flex-1">{val.optional ? 'Yes' : 'No'}</span>
</LabelCard> </LabelCard>
<span className="flex-1">{val.optional ? 'Yes' : 'No'}</span> );
</LabelCard> })}
); </section>
})} )}
</section>
</NodeWrapper> </NodeWrapper>
); );
} }

View File

@ -3,13 +3,16 @@ import { CopyToClipboardWithText } from '@/components/copy-to-clipboard';
import NumberInput from '@/components/originui/number-input'; import NumberInput from '@/components/originui/number-input';
import { SelectWithSearch } from '@/components/originui/select-with-search'; import { SelectWithSearch } from '@/components/originui/select-with-search';
import { RAGFlowFormItem } from '@/components/ragflow-form'; import { RAGFlowFormItem } from '@/components/ragflow-form';
import { Label } from '@/components/ui/label';
import { MultiSelect } from '@/components/ui/multi-select'; import { MultiSelect } from '@/components/ui/multi-select';
import { Separator } from '@/components/ui/separator';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { useBuildWebhookUrl } from '@/pages/agent/hooks/use-build-webhook-url';
import { buildOptions } from '@/utils/form'; import { buildOptions } from '@/utils/form';
import { upperFirst } from 'lodash';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useFormContext, useWatch } from 'react-hook-form'; import { useFormContext, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useParams } from 'umi';
import { import {
RateLimitPerList, RateLimitPerList,
WebhookMaxBodySize, WebhookMaxBodySize,
@ -22,7 +25,10 @@ import { Auth } from './auth';
import { WebhookRequestSchema } from './request-schema'; import { WebhookRequestSchema } from './request-schema';
import { WebhookResponse } from './response'; import { WebhookResponse } from './response';
const RateLimitPerOptions = buildOptions(RateLimitPerList); const RateLimitPerOptions = RateLimitPerList.map((x) => ({
value: x,
label: upperFirst(x),
}));
const RequestLimitMap = { const RequestLimitMap = {
[WebhookRateLimitPer.Second]: 100, [WebhookRateLimitPer.Second]: 100,
@ -33,7 +39,6 @@ const RequestLimitMap = {
export function WebHook() { export function WebHook() {
const { t } = useTranslation(); const { t } = useTranslation();
const { id } = useParams();
const form = useFormContext(); const form = useFormContext();
const rateLimitPer = useWatch({ const rateLimitPer = useWatch({
@ -45,7 +50,7 @@ export function WebHook() {
return RequestLimitMap[rateLimitPer as keyof typeof RequestLimitMap] ?? 100; return RequestLimitMap[rateLimitPer as keyof typeof RequestLimitMap] ?? 100;
}, []); }, []);
const text = `${location.protocol}//${location.host}/api/v1/webhook/${id}`; const text = useBuildWebhookUrl();
return ( return (
<> <>
@ -74,33 +79,36 @@ export function WebHook() {
></SelectWithSearch> ></SelectWithSearch>
</RAGFlowFormItem> </RAGFlowFormItem>
<Auth></Auth> <Auth></Auth>
<RAGFlowFormItem <section>
name="security.rate_limit.limit" <Label>{t('flow.webhook.limit')}</Label>
label={t('flow.webhook.limit')} <div className="flex items-center mt-1 gap-2">
> <RAGFlowFormItem
<NumberInput name="security.rate_limit.limit"
max={getLimitRateLimitPerMax(rateLimitPer)} className="flex-1"
className="w-full" >
></NumberInput> <NumberInput
</RAGFlowFormItem> max={getLimitRateLimitPerMax(rateLimitPer)}
<RAGFlowFormItem className="w-full"
name="security.rate_limit.per" ></NumberInput>
label={t('flow.webhook.per')} </RAGFlowFormItem>
> <Separator className="w-2" />
{(field) => ( <RAGFlowFormItem name="security.rate_limit.per">
<SelectWithSearch {(field) => (
options={RateLimitPerOptions} <SelectWithSearch
value={field.value} options={RateLimitPerOptions}
onChange={(val) => { value={field.value}
field.onChange(val); onChange={(val) => {
form.setValue( field.onChange(val);
'security.rate_limit.limit', form.setValue(
getLimitRateLimitPerMax(val), 'security.rate_limit.limit',
); getLimitRateLimitPerMax(val),
}} );
></SelectWithSearch> }}
)} ></SelectWithSearch>
</RAGFlowFormItem> )}
</RAGFlowFormItem>
</div>
</section>
<RAGFlowFormItem <RAGFlowFormItem
name="security.max_body_size" name="security.max_body_size"
label={t('flow.webhook.maxBodySize')} label={t('flow.webhook.maxBodySize')}

View File

@ -0,0 +1,8 @@
import { useParams } from 'umi';
export function useBuildWebhookUrl() {
const { id } = useParams();
const text = `${location.protocol}//${location.host}/api/v1/webhook/${id}`;
return text;
}