/** * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates * SPDX-License-Identifier: MIT */ import React, { useMemo, useState } from 'react'; import { IJsonSchema, JsonSchemaTypeManager, useTypeManager } from '@flowgram.ai/json-schema'; import { I18n } from '@flowgram.ai/editor'; import { Button, Checkbox, IconButton } from '@douyinfe/semi-ui'; import { IconExpand, IconShrink, IconPlus, IconChevronDown, IconChevronRight, IconMinus, } from '@douyinfe/semi-icons'; import { InjectTypeSelector } from '@/components/type-selector'; import { BlurInput } from '@/components/blur-input'; import { ConfigType, PropertyValueType } from './types'; import { IconAddChildren } from './icon'; import { usePropertiesEdit } from './hooks'; import { DefaultValue } from './default-value'; import './styles.css'; const DEFAULT = { type: 'object' }; function getSchemaDefaultValue( typeManager: JsonSchemaTypeManager, schema: Partial | undefined ) { if (schema?.type === 'object') { return '{}'; } if (schema?.type === 'array') { return '[]'; } return typeManager.getDefaultValue(schema || {}); } export function JsonSchemaEditor(props: { value?: IJsonSchema; onChange?: (value: IJsonSchema) => void; config?: ConfigType; className?: string; readonly?: boolean; }) { const { value = DEFAULT, config = {}, onChange: onChangeProps, readonly } = props; const { propertyList, onAddProperty, onRemoveProperty, onEditProperty } = usePropertiesEdit( value, onChangeProps ); return (
{propertyList.map((_property) => ( { onEditProperty(_property.key!, _v); }} onRemove={() => { onRemoveProperty(_property.key!); }} /> ))}
); } function PropertyEdit(props: { value?: PropertyValueType; config?: ConfigType; onChange?: (value: PropertyValueType) => void; onRemove?: () => void; readonly?: boolean; $isLast?: boolean; $level?: number; // 添加层级属性 }) { const { value, config, readonly, $level = 0, onChange: onChangeProps, onRemove, $isLast } = props; const [expand, setExpand] = useState(false); const [collapse, setCollapse] = useState(false); const typeManager = useTypeManager() as JsonSchemaTypeManager; const { name, type, items, default: defaultValue, description, isPropertyRequired } = value || {}; const typeSelectorValue = useMemo(() => ({ type, items }), [type, items]); const { propertyList, canAddField, onAddProperty, onRemoveProperty, onEditProperty } = usePropertiesEdit(value, onChangeProps); const onChange = (key: string, _value: any) => { onChangeProps?.({ ...(value || {}), [key]: _value, }); }; const showCollapse = canAddField && propertyList.length > 0; return ( <>
0 ? 'show-line' : ''} ${ $isLast ? 'is-last' : '' } ${showCollapse ? 'show-collapse' : ''}`} > {showCollapse && (
setCollapse((_collapse) => !_collapse)} > {collapse ? : }
)}
onChange('name', value)} />
{ const nextTypeSchema = _value || {}; onChangeProps?.({ ...(value || {}), ...nextTypeSchema, default: getSchemaDefaultValue(typeManager, nextTypeSchema), }); }} />
onChange('isPropertyRequired', e.target.checked)} />
: } onClick={() => { setExpand((_expand) => !_expand); }} /> {canAddField && ( } onClick={() => { onAddProperty(); setCollapse(true); }} /> )} } onClick={onRemove} />
{expand && (
{config?.descTitle ?? I18n.t('Description')}
onChange('description', value)} placeholder={ config?.descPlaceholder ?? I18n.t('Help LLM to understand the property') } /> {$level === 0 && ( <>
{config?.defaultValueTitle ?? I18n.t('Default Value')}
onChange('default', value)} />
)}
)}
{showCollapse && (
{propertyList.map((_property, index) => ( { onEditProperty(_property.key!, _v); }} onRemove={() => { onRemoveProperty(_property.key!); }} $isLast={index === propertyList.length - 1} /> ))}
)}
); }