import React, { useState, useContext } from 'react'; import { useForm, ISchema, Schema, useFieldSchema } from '@formily/react'; import { get } from 'lodash'; import { SchemaComponent, SchemaComponentContext, SchemaInitializer, SchemaInitializerItemOptions, InitializerWithSwitch, SchemaInitializerProvider, useSchemaComponentContext, gridRowColWrap, ActionContext, GeneralSchemaDesigner, SchemaSettings, useCompile, } from '@nocobase/client'; import { useTrigger } from '../../triggers'; import { instructions, useAvailableUpstreams, useNodeContext } from '..'; import { useFlowContext } from '../../FlowContext'; import { lang, NAMESPACE } from '../../locale'; import { JOB_STATUS } from '../../constants'; import customForm from './forms/customForm'; function useTriggerInitializers(): SchemaInitializerItemOptions | null { const { workflow } = useFlowContext(); const trigger = useTrigger(); return trigger.useInitializers ? trigger.useInitializers(workflow.config) : null; } const blockTypeNames = { customForm: customForm.title, record: `{{t("Data record", { ns: "${NAMESPACE}" })}}`, }; function SimpleDesigner() { const schema = useFieldSchema(); const title = blockTypeNames[schema['x-designer-props']?.type] ?? '{{t("Block")}}'; const compile = useCompile(); return ( ); } function AddBlockButton(props: any) { const current = useNodeContext(); const nodes = useAvailableUpstreams(current); const triggerInitializers = [useTriggerInitializers()].filter(Boolean); const nodeBlockInitializers = nodes .map((node) => { const instruction = instructions.get(node.type); return instruction?.useInitializers?.(node); }) .filter(Boolean); const dataBlockInitializers = [ ...triggerInitializers, ...(nodeBlockInitializers.length ? [ { key: 'nodes', type: 'subMenu', title: `{{t("Node result", { ns: "${NAMESPACE}" })}}`, children: nodeBlockInitializers, }, ] : []), ].filter(Boolean); const items = [ ...(dataBlockInitializers.length ? [ { type: 'itemGroup', title: '{{t("Data blocks")}}', children: dataBlockInitializers, }, ] : []), { type: 'itemGroup', title: '{{t("Form")}}', children: [ customForm.config.initializer, // { // key: 'createForm', // type: 'item', // title: '{{t("Create record form")}}', // component: CustomFormBlockInitializer, // }, // { // key: 'updateForm', // type: 'item', // title: '{{t("Update record form")}}', // component: CustomFormBlockInitializer, // } ], }, { type: 'itemGroup', title: '{{t("Other blocks")}}', children: [ { type: 'item', title: '{{t("Markdown")}}', component: 'MarkdownBlockInitializer', }, ], }, ] as SchemaInitializerItemOptions[]; return ; } function findSchema(schema, filter, onlyLeaf = false) { const result = []; if (!schema) { return result; } if (filter(schema) && (!onlyLeaf || !schema.properties)) { result.push(schema); return result; } if (schema.properties) { Object.keys(schema.properties).forEach((key) => { result.push(...findSchema(schema.properties[key], filter)); }); } return result; } function SchemaComponentRefreshProvider(props) { const ctx = useSchemaComponentContext(); return ( {props.children} ); } function ActionInitializer({ action, actionProps, ...props }) { return ( ); } function AddActionButton(props) { return ( ); } // NOTE: fake useAction for ui configuration function useSubmit() { // const { values, submit, id: formId } = useForm(); // const formSchema = useFieldSchema(); return { run() {}, }; } function useFlowRecordFromBlock() { return {}; } export function SchemaConfig({ value, onChange }) { const ctx = useContext(SchemaComponentContext); const trigger = useTrigger(); const node = useNodeContext(); const nodes = useAvailableUpstreams(node); const form = useForm(); const { workflow } = useFlowContext(); const nodeInitializers = {}; const nodeComponents = {}; nodes.forEach((item) => { const instruction = instructions.get(item.type); Object.assign(nodeInitializers, instruction.initializers); Object.assign(nodeComponents, instruction.components); }); const schema = new Schema({ properties: { drawer: { type: 'void', title: '{{t("Configure form")}}', 'x-decorator': 'Form', 'x-component': 'Action.Drawer', 'x-component-props': { className: 'nb-action-popup', }, properties: { tabs: { type: 'void', 'x-component': 'Tabs', 'x-component-props': {}, 'x-initializer': 'TabPaneInitializers', 'x-initializer-props': { gridInitializer: 'AddBlockButton', }, properties: value ?? { tab1: { type: 'void', title: `{{t("Manual", { ns: "${NAMESPACE}" })}}`, 'x-component': 'Tabs.TabPane', 'x-designer': 'Tabs.Designer', properties: { grid: { type: 'void', 'x-component': 'Grid', 'x-initializer': 'AddBlockButton', properties: {}, }, }, }, }, }, }, }, }, }); return ( { const forms = {}; const { tabs } = get(schema.toJSON(), 'properties.drawer.properties') as { tabs: ISchema }; const formBlocks: any[] = findSchema(tabs, (item) => item['x-decorator'] === 'FormCollectionProvider'); formBlocks.forEach((formBlock) => { const [formKey] = Object.keys(formBlock.properties); const formSchema = formBlock.properties[formKey]; const fields = findSchema( formSchema.properties.grid, (item) => item['x-component'] === 'CollectionField', true, ); formBlock['x-decorator-props'].collection.fields = fields.map((field) => field['x-interface-options']); forms[formKey] = { type: 'custom', title: formBlock['x-component-props']?.title || formKey, actions: findSchema(formSchema.properties.actions, (item) => item['x-component'] === 'Action').map( (item) => item['x-decorator-props'].value, ), collection: formBlock['x-decorator-props'].collection, }; }); form.setValuesIn('forms', forms); onChange(tabs.properties); }} > ); } export function SchemaConfigButton(props) { const { workflow } = useFlowContext(); const [visible, setVisible] = useState(false); return ( <>
setVisible(true)}> {workflow.executed ? lang('View user interface') : lang('Configure user interface')}
{props.children} ); }