Feat: Convert webhook data into the format required by the backend.
This commit is contained in:
parent
4ee310970e
commit
5fd8c2c5a4
16 changed files with 215 additions and 134 deletions
|
|
@ -20,6 +20,7 @@ import { CirclePlus, HelpCircle, Info } from 'lucide-react';
|
||||||
import { useId, useState, type FC, type FormEvent } from 'react';
|
import { useId, useState, type FC, type FormEvent } from 'react';
|
||||||
import { useTranslation } from '../../hooks/use-translation';
|
import { useTranslation } from '../../hooks/use-translation';
|
||||||
import type { NewField, SchemaType } from '../../types/json-schema';
|
import type { NewField, SchemaType } from '../../types/json-schema';
|
||||||
|
import { KeyInputProps } from './interface';
|
||||||
import SchemaTypeSelector from './schema-type-selector';
|
import SchemaTypeSelector from './schema-type-selector';
|
||||||
|
|
||||||
interface AddFieldButtonProps {
|
interface AddFieldButtonProps {
|
||||||
|
|
@ -27,9 +28,10 @@ interface AddFieldButtonProps {
|
||||||
variant?: 'primary' | 'secondary';
|
variant?: 'primary' | 'secondary';
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddFieldButton: FC<AddFieldButtonProps> = ({
|
const AddFieldButton: FC<AddFieldButtonProps & KeyInputProps> = ({
|
||||||
onAddField,
|
onAddField,
|
||||||
variant = 'primary',
|
variant = 'primary',
|
||||||
|
pattern,
|
||||||
}) => {
|
}) => {
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
const [fieldName, setFieldName] = useState('');
|
const [fieldName, setFieldName] = useState('');
|
||||||
|
|
@ -120,6 +122,7 @@ const AddFieldButton: FC<AddFieldButtonProps> = ({
|
||||||
placeholder={t.fieldNamePlaceholder}
|
placeholder={t.fieldNamePlaceholder}
|
||||||
className="font-mono text-sm w-full"
|
className="font-mono text-sm w-full"
|
||||||
required
|
required
|
||||||
|
searchValue={pattern}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { KeyInputProps } from './interface';
|
||||||
|
|
||||||
|
export const KeyInputContext = React.createContext<KeyInputProps>({});
|
||||||
|
|
||||||
|
export function useInputPattern() {
|
||||||
|
const x = useContext(KeyInputContext);
|
||||||
|
return x.pattern;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export type KeyInputProps = { pattern?: RegExp | string };
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
withObjectSchema,
|
withObjectSchema,
|
||||||
} from '../../types/json-schema';
|
} from '../../types/json-schema';
|
||||||
import type { ValidationTreeNode } from '../../types/validation';
|
import type { ValidationTreeNode } from '../../types/validation';
|
||||||
|
import { useInputPattern } from './context';
|
||||||
import TypeDropdown from './type-dropdown';
|
import TypeDropdown from './type-dropdown';
|
||||||
import TypeEditor from './type-editor';
|
import TypeEditor from './type-editor';
|
||||||
|
|
||||||
|
|
@ -54,6 +55,8 @@ export const SchemaPropertyEditor: React.FC<SchemaPropertyEditorProps> = ({
|
||||||
'object' as SchemaType,
|
'object' as SchemaType,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const pattern = useInputPattern();
|
||||||
|
|
||||||
// Update temp values when props change
|
// Update temp values when props change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTempName(name);
|
setTempName(name);
|
||||||
|
|
@ -123,6 +126,7 @@ export const SchemaPropertyEditor: React.FC<SchemaPropertyEditorProps> = ({
|
||||||
className="h-8 text-sm font-medium min-w-[120px] max-w-full z-10"
|
className="h-8 text-sm font-medium min-w-[120px] max-w-full z-10"
|
||||||
autoFocus
|
autoFocus
|
||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
|
searchValue={pattern}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import {
|
||||||
import type { JSONSchema, NewField } from '../../types/json-schema';
|
import type { JSONSchema, NewField } from '../../types/json-schema';
|
||||||
import { asObjectSchema, isBooleanSchema } from '../../types/json-schema';
|
import { asObjectSchema, isBooleanSchema } from '../../types/json-schema';
|
||||||
import AddFieldButton from './add-field-button';
|
import AddFieldButton from './add-field-button';
|
||||||
|
import { KeyInputContext } from './context';
|
||||||
|
import { KeyInputProps } from './interface';
|
||||||
import SchemaFieldList from './schema-field-list';
|
import SchemaFieldList from './schema-field-list';
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
|
@ -17,9 +19,10 @@ export interface SchemaVisualEditorProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
const SchemaVisualEditor: FC<SchemaVisualEditorProps> = ({
|
const SchemaVisualEditor: FC<SchemaVisualEditorProps & KeyInputProps> = ({
|
||||||
schema,
|
schema,
|
||||||
onChange,
|
onChange,
|
||||||
|
pattern,
|
||||||
}) => {
|
}) => {
|
||||||
const t = useTranslation();
|
const t = useTranslation();
|
||||||
// Handle adding a top-level field
|
// Handle adding a top-level field
|
||||||
|
|
@ -121,7 +124,7 @@ const SchemaVisualEditor: FC<SchemaVisualEditorProps> = ({
|
||||||
return (
|
return (
|
||||||
<div className="p-4 h-full flex flex-col overflow-auto jsonjoy">
|
<div className="p-4 h-full flex flex-col overflow-auto jsonjoy">
|
||||||
<div className="mb-6 shrink-0">
|
<div className="mb-6 shrink-0">
|
||||||
<AddFieldButton onAddField={handleAddField} />
|
<AddFieldButton onAddField={handleAddField} pattern={pattern} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grow overflow-auto">
|
<div className="grow overflow-auto">
|
||||||
|
|
@ -131,12 +134,14 @@ const SchemaVisualEditor: FC<SchemaVisualEditorProps> = ({
|
||||||
<p className="text-sm">{t.visualEditorNoFieldsHint2}</p>
|
<p className="text-sm">{t.visualEditorNoFieldsHint2}</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
<KeyInputContext.Provider value={{ pattern }}>
|
||||||
<SchemaFieldList
|
<SchemaFieldList
|
||||||
schema={schema}
|
schema={schema}
|
||||||
onAddField={handleAddField}
|
onAddField={handleAddField}
|
||||||
onEditField={handleEditField}
|
onEditField={handleEditField}
|
||||||
onDeleteField={handleDeleteField}
|
onDeleteField={handleDeleteField}
|
||||||
/>
|
/>
|
||||||
|
</KeyInputContext.Provider>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -193,3 +193,19 @@ export enum SwitchLogicOperator {
|
||||||
And = 'and',
|
And = 'and',
|
||||||
Or = 'or',
|
Or = 'or',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const WebhookAlgorithmList = [
|
||||||
|
'hs256',
|
||||||
|
'hs384',
|
||||||
|
'hs512',
|
||||||
|
'rs256',
|
||||||
|
'rs384',
|
||||||
|
'rs512',
|
||||||
|
'es256',
|
||||||
|
'es384',
|
||||||
|
'es512',
|
||||||
|
'ps256',
|
||||||
|
'ps384',
|
||||||
|
'ps512',
|
||||||
|
'none',
|
||||||
|
] as const;
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,14 @@
|
||||||
import i18n from '@/locales/config';
|
|
||||||
import { BeginId } from '@/pages/agent/constant';
|
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
const prefix = BeginId + '@';
|
|
||||||
|
|
||||||
interface VariableDisplayProps {
|
interface VariableDisplayProps {
|
||||||
content: string;
|
content: string;
|
||||||
getLabel?: (value?: string) => string | ReactNode;
|
getLabel?: (value?: string) => string | ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This component mimics the VariableNode's decorate function from PromptEditor
|
// This component mimics the VariableNode's decorate function from PromptEditor
|
||||||
function VariableNodeDisplay({
|
function VariableNodeDisplay({ label }: { label: ReactNode }) {
|
||||||
value,
|
|
||||||
label,
|
|
||||||
}: {
|
|
||||||
value: string;
|
|
||||||
label: ReactNode;
|
|
||||||
}) {
|
|
||||||
let content: ReactNode = <span className="text-accent-primary">{label}</span>;
|
let content: ReactNode = <span className="text-accent-primary">{label}</span>;
|
||||||
|
|
||||||
if (value.startsWith(prefix)) {
|
|
||||||
content = (
|
|
||||||
<div>
|
|
||||||
<span>{i18n.t(`flow.begin`)}</span> / {content}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className="inline-flex items-center mr-1">{content}</div>;
|
return <div className="inline-flex items-center mr-1">{content}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,11 +45,7 @@ export function VariableDisplay({ content, getLabel }: VariableDisplayProps) {
|
||||||
if (label && label !== variableValue) {
|
if (label && label !== variableValue) {
|
||||||
// If we found a valid label, render as variable node
|
// If we found a valid label, render as variable node
|
||||||
elements.push(
|
elements.push(
|
||||||
<VariableNodeDisplay
|
<VariableNodeDisplay key={`variable-${index}`} label={label} />,
|
||||||
key={`variable-${index}`}
|
|
||||||
value={variableValue}
|
|
||||||
label={label}
|
|
||||||
/>,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// If no label found, keep as original text
|
// If no label found, keep as original text
|
||||||
|
|
|
||||||
|
|
@ -961,3 +961,7 @@ export enum WebhookSecurityAuthType {
|
||||||
Jwt = 'jwt',
|
Jwt = 'jwt',
|
||||||
Hmac = 'hmac',
|
Hmac = 'hmac',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const RateLimitPerList = ['minute', 'hour', 'day'];
|
||||||
|
|
||||||
|
export const WebhookMaxBodySize = ['10MB', '50MB', '100MB', '1000MB'];
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { RAGFlowSelect } from '@/components/ui/select';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
import { FormTooltip } from '@/components/ui/tooltip';
|
import { FormTooltip } from '@/components/ui/tooltip';
|
||||||
|
import { WebhookAlgorithmList } from '@/constants/agent';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { Plus } from 'lucide-react';
|
import { Plus } from 'lucide-react';
|
||||||
|
|
@ -35,11 +36,6 @@ const ModeOptions = [
|
||||||
{ value: AgentDialogueMode.Webhook, label: t('flow.webhook.name') },
|
{ value: AgentDialogueMode.Webhook, label: t('flow.webhook.name') },
|
||||||
];
|
];
|
||||||
|
|
||||||
function BeginForm({ node }: INextOperatorForm) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const values = useValues(node);
|
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
enablePrologue: z.boolean().optional(),
|
enablePrologue: z.boolean().optional(),
|
||||||
prologue: z.string().trim().optional(),
|
prologue: z.string().trim().optional(),
|
||||||
|
|
@ -67,21 +63,33 @@ function BeginForm({ node }: INextOperatorForm) {
|
||||||
per: z.string().optional(),
|
per: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
max_body_size: z.string(),
|
max_body_size: z.string(),
|
||||||
|
jwt: z
|
||||||
|
.object({
|
||||||
|
algorithm: z.string().default(WebhookAlgorithmList[0]).optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
schema: z.record(z.any()).optional(),
|
schema: z.record(z.any()).optional(),
|
||||||
response: z
|
response: z
|
||||||
.object({
|
.object({
|
||||||
status: z.number(),
|
status: z.number(),
|
||||||
headers: z.array(z.object({ key: z.string(), value: z.string() })),
|
headers_template: z.array(
|
||||||
body_template: z.array(
|
|
||||||
z.object({ key: z.string(), value: z.string() }),
|
z.object({ key: z.string(), value: z.string() }),
|
||||||
),
|
),
|
||||||
|
body_template: z.array(z.object({ key: z.string(), value: z.string() })),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
execution_mode: z.string().optional(),
|
execution_mode: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type BeginFormSchemaType = z.infer<typeof FormSchema>;
|
||||||
|
|
||||||
|
function BeginForm({ node }: INextOperatorForm) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const values = useValues(node);
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
defaultValues: values,
|
defaultValues: values,
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
import { AgentDialogueMode } from '../../constant';
|
import {
|
||||||
|
AgentDialogueMode,
|
||||||
|
RateLimitPerList,
|
||||||
|
WebhookExecutionMode,
|
||||||
|
WebhookMaxBodySize,
|
||||||
|
WebhookSecurityAuthType,
|
||||||
|
} from '../../constant';
|
||||||
|
|
||||||
// const WebhookSchema = {
|
// const WebhookSchema = {
|
||||||
// query: {
|
// query: {
|
||||||
|
|
@ -47,11 +53,21 @@ const schema = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initialFormValuesMap = {
|
||||||
|
schema: schema,
|
||||||
|
'security.auth_type': WebhookSecurityAuthType.Basic,
|
||||||
|
'security.rate_limit.per': RateLimitPerList[0],
|
||||||
|
'security.max_body_size': WebhookMaxBodySize[0],
|
||||||
|
execution_mode: WebhookExecutionMode.Immediately,
|
||||||
|
};
|
||||||
|
|
||||||
export function useHandleModeChange(form: UseFormReturn<any>) {
|
export function useHandleModeChange(form: UseFormReturn<any>) {
|
||||||
const handleModeChange = useCallback(
|
const handleModeChange = useCallback(
|
||||||
(mode: AgentDialogueMode) => {
|
(mode: AgentDialogueMode) => {
|
||||||
if (mode === AgentDialogueMode.Webhook) {
|
if (mode === AgentDialogueMode.Webhook) {
|
||||||
form.setValue('schema', schema, { shouldDirty: true });
|
Object.entries(initialFormValuesMap).forEach(([key, value]) => {
|
||||||
|
form.setValue(key, value, { shouldDirty: true });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[form],
|
[form],
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,14 @@
|
||||||
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 { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { WebhookAlgorithmList } from '@/constants/agent';
|
||||||
import { WebhookSecurityAuthType } from '@/pages/agent/constant';
|
import { WebhookSecurityAuthType } from '@/pages/agent/constant';
|
||||||
import { buildOptions } from '@/utils/form';
|
import { buildOptions } from '@/utils/form';
|
||||||
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';
|
||||||
|
|
||||||
const AlgorithmOptions = buildOptions([
|
const AlgorithmOptions = buildOptions(WebhookAlgorithmList);
|
||||||
'hs256',
|
|
||||||
'hs384',
|
|
||||||
'hs512',
|
|
||||||
'rs256',
|
|
||||||
'rs384',
|
|
||||||
'rs512',
|
|
||||||
'es256',
|
|
||||||
'es384',
|
|
||||||
'es512',
|
|
||||||
'ps256',
|
|
||||||
'ps384',
|
|
||||||
'ps512',
|
|
||||||
'none',
|
|
||||||
]);
|
|
||||||
|
|
||||||
const RequiredClaimsOptions = buildOptions(['exp', 'sub']);
|
const RequiredClaimsOptions = buildOptions(['exp', 'sub']);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export function DynamicResponse({
|
||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
tooltip,
|
tooltip,
|
||||||
keyField = 'variable',
|
keyField = 'key',
|
||||||
valueField = 'value',
|
valueField = 'value',
|
||||||
operatorField = 'type',
|
operatorField = 'type',
|
||||||
}: SelectKeysProps) {
|
}: SelectKeysProps) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Collapse } from '@/components/collapse';
|
||||||
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 { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
|
@ -8,8 +9,10 @@ import { buildOptions } from '@/utils/form';
|
||||||
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 {
|
import {
|
||||||
|
RateLimitPerList,
|
||||||
WebhookContentType,
|
WebhookContentType,
|
||||||
WebhookExecutionMode,
|
WebhookExecutionMode,
|
||||||
|
WebhookMaxBodySize,
|
||||||
WebhookMethod,
|
WebhookMethod,
|
||||||
WebhookSecurityAuthType,
|
WebhookSecurityAuthType,
|
||||||
} from '../../../constant';
|
} from '../../../constant';
|
||||||
|
|
@ -20,7 +23,7 @@ import { useShowSchemaDialog } from '../use-show-schema-dialog';
|
||||||
import { Auth } from './auth';
|
import { Auth } from './auth';
|
||||||
import { WebhookResponse } from './response';
|
import { WebhookResponse } from './response';
|
||||||
|
|
||||||
const RateLimitPerOptions = buildOptions(['minute', 'hour', 'day']);
|
const RateLimitPerOptions = buildOptions(RateLimitPerList);
|
||||||
|
|
||||||
export function WebHook() {
|
export function WebHook() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
@ -55,8 +58,8 @@ export function WebHook() {
|
||||||
options={buildOptions(WebhookContentType)}
|
options={buildOptions(WebhookContentType)}
|
||||||
></SelectWithSearch>
|
></SelectWithSearch>
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
<Separator></Separator>
|
<Collapse title={<div>Security</div>}>
|
||||||
<>
|
<section className="space-y-4">
|
||||||
<RAGFlowFormItem
|
<RAGFlowFormItem
|
||||||
name="security.auth_type"
|
name="security.auth_type"
|
||||||
label={t('flow.webhook.authType')}
|
label={t('flow.webhook.authType')}
|
||||||
|
|
@ -82,13 +85,16 @@ export function WebHook() {
|
||||||
name="security.max_body_size"
|
name="security.max_body_size"
|
||||||
label={t('flow.webhook.maxBodySize')}
|
label={t('flow.webhook.maxBodySize')}
|
||||||
>
|
>
|
||||||
<Input></Input>
|
<SelectWithSearch
|
||||||
|
options={buildOptions(WebhookMaxBodySize)}
|
||||||
|
></SelectWithSearch>
|
||||||
</RAGFlowFormItem>
|
</RAGFlowFormItem>
|
||||||
<DynamicStringForm
|
<DynamicStringForm
|
||||||
name="security.ip_whitelist"
|
name="security.ip_whitelist"
|
||||||
label={t('flow.webhook.ipWhitelist')}
|
label={t('flow.webhook.ipWhitelist')}
|
||||||
></DynamicStringForm>
|
></DynamicStringForm>
|
||||||
</>
|
</section>
|
||||||
|
</Collapse>
|
||||||
<RAGFlowFormItem
|
<RAGFlowFormItem
|
||||||
name="schema"
|
name="schema"
|
||||||
label={t('flow.webhook.schema')}
|
label={t('flow.webhook.schema')}
|
||||||
|
|
@ -120,6 +126,7 @@ export function WebHook() {
|
||||||
initialValues={schema}
|
initialValues={schema}
|
||||||
hideModal={hideSchemaDialog}
|
hideModal={hideSchemaDialog}
|
||||||
onOk={handleSchemaDialogOk}
|
onOk={handleSchemaDialogOk}
|
||||||
|
pattern={''}
|
||||||
></SchemaDialog>
|
></SchemaDialog>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { Collapse } from '@/components/collapse';
|
||||||
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Separator } from '@/components/ui/separator';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { DynamicResponse } from './dynamic-response';
|
import { DynamicResponse } from './dynamic-response';
|
||||||
|
|
||||||
|
|
@ -8,8 +8,7 @@ export function WebhookResponse() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Collapse title={<div>Response</div>}>
|
||||||
<Separator></Separator>
|
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<RAGFlowFormItem
|
<RAGFlowFormItem
|
||||||
name={'response.status'}
|
name={'response.status'}
|
||||||
|
|
@ -26,6 +25,6 @@ export function WebhookResponse() {
|
||||||
label={t('flow.webhook.bodyTemplate')}
|
label={t('flow.webhook.bodyTemplate')}
|
||||||
></DynamicResponse>
|
></DynamicResponse>
|
||||||
</section>
|
</section>
|
||||||
</>
|
</Collapse>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import {
|
||||||
JsonSchemaVisualizer,
|
JsonSchemaVisualizer,
|
||||||
SchemaVisualEditor,
|
SchemaVisualEditor,
|
||||||
} from '@/components/jsonjoy-builder';
|
} from '@/components/jsonjoy-builder';
|
||||||
|
import { KeyInputProps } from '@/components/jsonjoy-builder/components/schema-editor/interface';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
|
@ -20,7 +21,8 @@ export function SchemaDialog({
|
||||||
hideModal,
|
hideModal,
|
||||||
onOk,
|
onOk,
|
||||||
initialValues,
|
initialValues,
|
||||||
}: IModalProps<any>) {
|
pattern,
|
||||||
|
}: IModalProps<any> & KeyInputProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [schema, setSchema] = useState<JSONSchema>(initialValues);
|
const [schema, setSchema] = useState<JSONSchema>(initialValues);
|
||||||
|
|
||||||
|
|
@ -36,7 +38,11 @@ export function SchemaDialog({
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<section className="flex overflow-auto">
|
<section className="flex overflow-auto">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<SchemaVisualEditor schema={schema} onChange={setSchema} />
|
<SchemaVisualEditor
|
||||||
|
schema={schema}
|
||||||
|
onChange={setSchema}
|
||||||
|
pattern={pattern}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<JsonSchemaVisualizer schema={schema} onChange={setSchema} />
|
<JsonSchemaVisualizer schema={schema} onChange={setSchema} />
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import {
|
||||||
import pipe from 'lodash/fp/pipe';
|
import pipe from 'lodash/fp/pipe';
|
||||||
import isObject from 'lodash/isObject';
|
import isObject from 'lodash/isObject';
|
||||||
import {
|
import {
|
||||||
|
AgentDialogueMode,
|
||||||
CategorizeAnchorPointPositions,
|
CategorizeAnchorPointPositions,
|
||||||
FileType,
|
FileType,
|
||||||
FileTypeSuffixMap,
|
FileTypeSuffixMap,
|
||||||
|
|
@ -34,6 +35,7 @@ import {
|
||||||
Operator,
|
Operator,
|
||||||
TypesWithArray,
|
TypesWithArray,
|
||||||
} from './constant';
|
} from './constant';
|
||||||
|
import { BeginFormSchemaType } from './form/begin-form';
|
||||||
import { DataOperationsFormSchemaType } from './form/data-operations-form';
|
import { DataOperationsFormSchemaType } from './form/data-operations-form';
|
||||||
import { ExtractorFormSchemaType } from './form/extractor-form';
|
import { ExtractorFormSchemaType } from './form/extractor-form';
|
||||||
import { HierarchicalMergerFormSchemaType } from './form/hierarchical-merger-form';
|
import { HierarchicalMergerFormSchemaType } from './form/hierarchical-merger-form';
|
||||||
|
|
@ -312,6 +314,39 @@ function transformDataOperationsParams(params: DataOperationsFormSchemaType) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function transformArrayToObject(
|
||||||
|
list?: Array<{ key: string; value: string }>,
|
||||||
|
) {
|
||||||
|
if (!Array.isArray(list)) return {};
|
||||||
|
return list?.reduce<Record<string, any>>((pre, cur) => {
|
||||||
|
pre[cur.key] = cur.value;
|
||||||
|
return pre;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformBeginParams(params: BeginFormSchemaType) {
|
||||||
|
if (params.mode === AgentDialogueMode.Webhook) {
|
||||||
|
return {
|
||||||
|
...params,
|
||||||
|
security: {
|
||||||
|
...params.security,
|
||||||
|
ip_whitelist: params.security?.ip_whitelist.map((x) => x.value),
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
...params.response,
|
||||||
|
headers_template: transformArrayToObject(
|
||||||
|
params.response?.headers_template,
|
||||||
|
),
|
||||||
|
body_template: transformArrayToObject(params.response?.body_template),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...params,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// construct a dsl based on the node information of the graph
|
// construct a dsl based on the node information of the graph
|
||||||
export const buildDslComponentsByGraph = (
|
export const buildDslComponentsByGraph = (
|
||||||
nodes: RAGFlowNodeType[],
|
nodes: RAGFlowNodeType[],
|
||||||
|
|
@ -361,6 +396,9 @@ export const buildDslComponentsByGraph = (
|
||||||
case Operator.DataOperations:
|
case Operator.DataOperations:
|
||||||
params = transformDataOperationsParams(params);
|
params = transformDataOperationsParams(params);
|
||||||
break;
|
break;
|
||||||
|
case Operator.Begin:
|
||||||
|
params = transformBeginParams(params);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue