form-meta.tsx 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. import { FormRenderProps, FlowNodeJSON, Field, FormMeta } from '@flowgram.ai/free-layout-editor';
  6. import { SubCanvasRender } from '@flowgram.ai/free-container-plugin';
  7. import {
  8. BatchOutputs,
  9. BatchVariableSelector,
  10. createBatchOutputsFormPlugin,
  11. DisplayOutputs,
  12. IFlowRefValue,
  13. IJsonSchema,
  14. provideBatchInputEffect,
  15. } from '@flowgram.ai/form-materials';
  16. import { defaultFormMeta } from '../default-form-meta';
  17. import { useIsSidebar, useNodeRenderContext } from '../../hooks';
  18. import { FormHeader, FormContent, FormItem, Feedback } from '../../form-components';
  19. interface LoopNodeJSON extends FlowNodeJSON {
  20. data: {
  21. loopFor: IFlowRefValue;
  22. };
  23. }
  24. export const LoopFormRender = ({ form }: FormRenderProps<LoopNodeJSON>) => {
  25. const isSidebar = useIsSidebar();
  26. const { readonly } = useNodeRenderContext();
  27. const formHeight = 85;
  28. const loopFor = (
  29. <Field<IFlowRefValue> name={`loopFor`}>
  30. {({ field, fieldState }) => (
  31. <FormItem name={'loopFor'} type={'array'} required>
  32. <BatchVariableSelector
  33. style={{ width: '100%' }}
  34. value={field.value?.content}
  35. onChange={(val) => field.onChange({ type: 'ref', content: val })}
  36. readonly={readonly}
  37. hasError={Object.keys(fieldState?.errors || {}).length > 0}
  38. />
  39. <Feedback errors={fieldState?.errors} />
  40. </FormItem>
  41. )}
  42. </Field>
  43. );
  44. const loopOutputs = (
  45. <Field<Record<string, IFlowRefValue | undefined> | undefined> name={`loopOutputs`}>
  46. {({ field, fieldState }) => (
  47. <FormItem name="loopOutputs" type="object" vertical>
  48. <BatchOutputs
  49. style={{ width: '100%' }}
  50. value={field.value}
  51. onChange={(val) => field.onChange(val)}
  52. readonly={readonly}
  53. hasError={Object.keys(fieldState?.errors || {}).length > 0}
  54. />
  55. <Feedback errors={fieldState?.errors} />
  56. </FormItem>
  57. )}
  58. </Field>
  59. );
  60. if (isSidebar) {
  61. return (
  62. <>
  63. <FormHeader />
  64. <FormContent>
  65. {loopFor}
  66. {loopOutputs}
  67. </FormContent>
  68. </>
  69. );
  70. }
  71. return (
  72. <>
  73. <FormHeader />
  74. <FormContent>
  75. {loopFor}
  76. <SubCanvasRender offsetY={-formHeight} />
  77. <DisplayOutputs displayFromScope />
  78. </FormContent>
  79. </>
  80. );
  81. };
  82. export const formMeta: FormMeta = {
  83. ...defaultFormMeta,
  84. render: LoopFormRender,
  85. effect: {
  86. loopFor: provideBatchInputEffect,
  87. },
  88. plugins: [createBatchOutputsFormPlugin({ outputKey: 'loopOutputs' })],
  89. };