diff --git a/web/src/components/editable-cell.tsx b/web/src/components/editable-cell.tsx new file mode 100644 index 000000000..f8b65cf9f --- /dev/null +++ b/web/src/components/editable-cell.tsx @@ -0,0 +1,103 @@ +import { Form, FormInstance, Input, InputRef } from 'antd'; +import React, { useContext, useEffect, useRef, useState } from 'react'; + +const EditableContext = React.createContext | null>(null); + +interface EditableRowProps { + index: number; +} + +interface Item { + key: string; + name: string; + age: string; + address: string; +} + +export const EditableRow: React.FC = ({ + index, + ...props +}) => { + const [form] = Form.useForm(); + return ( +
+ + + +
+ ); +}; + +interface EditableCellProps { + title: React.ReactNode; + editable: boolean; + children: React.ReactNode; + dataIndex: keyof Item; + record: Item; + handleSave: (record: Item) => void; +} + +export const EditableCell: React.FC = ({ + title, + editable, + children, + dataIndex, + record, + handleSave, + ...restProps +}) => { + const [editing, setEditing] = useState(false); + const inputRef = useRef(null); + const form = useContext(EditableContext)!; + + useEffect(() => { + if (editing) { + inputRef.current!.focus(); + } + }, [editing]); + + const toggleEdit = () => { + setEditing(!editing); + form.setFieldsValue({ [dataIndex]: record[dataIndex] }); + }; + + const save = async () => { + try { + const values = await form.validateFields(); + + toggleEdit(); + handleSave({ ...record, ...values }); + } catch (errInfo) { + console.log('Save failed:', errInfo); + } + }; + + let childNode = children; + + if (editable) { + childNode = editing ? ( + + + + ) : ( +
+ {children} +
+ ); + } + + return {childNode}; +}; diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index c8171190d..6791ac4a9 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -560,6 +560,10 @@ The above is the content you need to summarize.`, createFlow: 'Create a workflow', yes: 'Yes', no: 'No', + key: 'key', + componentId: 'component id', + add: 'Add', + operation: 'operation', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/pages/flow/form-hooks.ts b/web/src/pages/flow/form-hooks.ts index c77a41ece..53c06fb18 100644 --- a/web/src/pages/flow/form-hooks.ts +++ b/web/src/pages/flow/form-hooks.ts @@ -6,6 +6,7 @@ const ExcludedNodesMap = { // exclude some nodes downstream of the classification node [Operator.Categorize]: [Operator.Categorize, Operator.Answer, Operator.Begin], [Operator.Relevant]: [Operator.Begin], + [Operator.Generate]: [Operator.Begin], }; export const useBuildFormSelectOptions = ( diff --git a/web/src/pages/flow/generate-form/dynamic-parameters.tsx b/web/src/pages/flow/generate-form/dynamic-parameters.tsx new file mode 100644 index 000000000..febdf8fd2 --- /dev/null +++ b/web/src/pages/flow/generate-form/dynamic-parameters.tsx @@ -0,0 +1,104 @@ +import { useTranslate } from '@/hooks/commonHooks'; +import { CloseOutlined } from '@ant-design/icons'; +import { Button, Card, Form, Input, Select, Typography } from 'antd'; +import { useUpdateNodeInternals } from 'reactflow'; +import { Operator } from '../constant'; +import { + useBuildFormSelectOptions, + useHandleFormSelectChange, +} from '../form-hooks'; +import { IGenerateParameter } from '../interface'; + +interface IProps { + nodeId?: string; +} + +const DynamicParameters = ({ nodeId }: IProps) => { + const updateNodeInternals = useUpdateNodeInternals(); + const form = Form.useFormInstance(); + const buildCategorizeToOptions = useBuildFormSelectOptions( + Operator.Categorize, + nodeId, + ); + const { handleSelectChange } = useHandleFormSelectChange(nodeId); + const { t } = useTranslate('flow'); + + return ( + <> + + {(fields, { add, remove }) => { + const handleAdd = () => { + const idx = fields.length; + add({ name: `parameter ${idx + 1}` }); + if (nodeId) updateNodeInternals(nodeId); + }; + return ( +
+ {fields.map((field) => ( + { + remove(field.name); + }} + /> + } + > + + + + + + ); + }, + }, + { + title: t('operation'), + dataIndex: 'operation', + width: 20, + key: 'operation', + align: 'center', + render(_, record) { + return ; + }, + }, + ]; + + return ( +
+ + + + styles.editableRow} + /> + + ); +}; + +export default DynamicParameters; diff --git a/web/src/pages/flow/interface.ts b/web/src/pages/flow/interface.ts index 64e187495..87e99871c 100644 --- a/web/src/pages/flow/interface.ts +++ b/web/src/pages/flow/interface.ts @@ -45,6 +45,12 @@ export interface ICategorizeItem { to?: string; } +export interface IGenerateParameter { + id?: string; + key: string; + component_id?: string; +} + export type ICategorizeItemResult = Record< string, Omit