From 3f6cae33ecce58f58fd39bb19c99f4a397476bf9 Mon Sep 17 00:00:00 2001 From: sheldon66 Date: Sun, 9 Mar 2025 14:47:42 +0800 Subject: [PATCH] feat: introduce VariableProvider --- .../schema-component/antd/variable/Input.tsx | 11 +-- .../antd/variable/VariableFilters.tsx | 69 ++++++++++++++----- .../antd/variable/VariableProvider.tsx | 47 +++++++++++++ .../src/variables/VariablesProvider.tsx | 3 +- packages/core/client/src/variables/types.ts | 20 ++++++ .../json-template-parser/src/parser/index.ts | 2 +- .../src/parser/json-template-parser.ts | 2 + packages/core/utils/src/index.ts | 5 +- 8 files changed, 133 insertions(+), 26 deletions(-) create mode 100644 packages/core/client/src/schema-component/antd/variable/VariableProvider.tsx diff --git a/packages/core/client/src/schema-component/antd/variable/Input.tsx b/packages/core/client/src/schema-component/antd/variable/Input.tsx index 894c7c221e..9f4876af4d 100644 --- a/packages/core/client/src/schema-component/antd/variable/Input.tsx +++ b/packages/core/client/src/schema-component/antd/variable/Input.tsx @@ -35,6 +35,7 @@ import { XButton } from './XButton'; import { useStyles } from './style'; import { Json } from '../input'; import { Filters, Addition, FilterContext } from './VariableFilters'; +import { VariableProvider } from './VariableProvider'; const { Text } = Typography; const JT_VALUE_RE = /^\s*{{\s*([^{}]+)\s*}}\s*$/; @@ -484,11 +485,13 @@ export function Input(props: VariableInputProps) { ); })} - - + + + - {variableText.length > 0 && } - + {variableText.length > 0 && } + + {!disabled ? ( diff --git a/packages/core/client/src/schema-component/antd/variable/VariableFilters.tsx b/packages/core/client/src/schema-component/antd/variable/VariableFilters.tsx index 06e8d199ae..0abc18974e 100644 --- a/packages/core/client/src/schema-component/antd/variable/VariableFilters.tsx +++ b/packages/core/client/src/schema-component/antd/variable/VariableFilters.tsx @@ -17,6 +17,7 @@ import type { MenuProps } from 'antd'; import { SchemaComponent } from '../../core/SchemaComponent'; import { useApp } from '../../../application'; import { useCompile } from '../../hooks'; +import { useVariable } from './VariableProvider'; export function Addition({ variable, onFilterAdd }) { const app = useApp(); @@ -59,15 +60,30 @@ export function Filters({ filters, onFilterChange }) { if (!filterConfig) { return null; } - return ; + const previousFilters = filters.slice(0, index); + return ( + + ); })} ); } -export function Filter({ config, filter, filterId }) { +export function Filter({ config, filter, filterId, previousFilters }) { const [open, setOpen] = useState(false); - + const { value } = useVariable(); + const inputValue = [...previousFilters].reduce((value, filter) => { + return filter.handler(value, ...filter.args); + }, value); + const outputValue = [...previousFilters, filter].reduce((value, filter) => { + return filter.handler(value, ...filter.args); + }, value); const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen); }; @@ -108,16 +124,28 @@ export function Filter({ config, filter, filterId }) { }; const useFormBlockProps = () => { - return { form }; + return { form, layout: 'vertical' }; }; const WithPropOver = ({ children }) => { + const { value } = useVariable(); const schema = { 'x-uid': uid(), type: 'void', - // 'x-component': 'FormV2', - // 'x-use-component-props': 'useFormBlockProps', + 'x-component': 'FormV2', + 'x-use-component-props': 'useFormBlockProps', properties: { + '$input-value': { + type: 'void', + 'x-component': 'Input', + 'x-component-props': { + defaultValue: '{{ inputValue }}', + disabled: true, + }, + 'x-decorator': 'FormItem', + title: tval('Input Value'), + 'x-read-pretty': true, + }, ...Object.fromEntries( config.uiSchema.map((param) => [ param.name, @@ -127,6 +155,17 @@ export function Filter({ config, filter, filterId }) { }, ]), ), + '$return-value': { + type: 'void', + 'x-component': 'Input', + 'x-component-props': { + defaultValue: '{{ outputValue }}', + disabled: true, + }, + 'x-decorator': 'FormItem', + title: tval('Return Value'), + 'x-read-pretty': true, + }, actions: { type: 'void', title: tval('Save'), @@ -153,13 +192,11 @@ export function Filter({ config, filter, filterId }) { open={open} onOpenChange={handleOpenChange} content={ - - - + } trigger={'hover'} > @@ -171,19 +208,19 @@ export function Filter({ config, filter, filterId }) { return ( <> | - - {config.uiSchema ? {Label} : Label} - + {config.uiSchema ? {Label} : Label} ); } type FilterContextType = { + variableName: string; updateFilterParams: (args: { filterId: number; params: any[] }) => any; deleteFilter: (args: { filterId: number }) => any; }; export const FilterContext = React.createContext({ + variableName: '', updateFilterParams: (params: any) => {}, deleteFilter: (params: any) => {}, }); diff --git a/packages/core/client/src/schema-component/antd/variable/VariableProvider.tsx b/packages/core/client/src/schema-component/antd/variable/VariableProvider.tsx new file mode 100644 index 0000000000..9daaf168fc --- /dev/null +++ b/packages/core/client/src/schema-component/antd/variable/VariableProvider.tsx @@ -0,0 +1,47 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; +import { useVariables, useLocalVariables } from '../../../variables'; +import { getPath } from '../../../variables/utils/getPath'; +import { isArray } from 'lodash'; +interface VariableContextValue { + value: any; +} + +interface VariableProviderProps { + variableName: string; + children: React.ReactNode; +} + +const VariableContext = createContext({ value: null }); + +export const useVariable = () => { + const context = useContext(VariableContext); + if (!context) { + throw new Error('useVariable must be used within a VariableProvider'); + } + return context; +}; + +export const VariableProvider: React.FC = ({ variableName, children }) => { + const [value, setValue] = useState(); + const variables = useVariables(); + const localVariables = useLocalVariables(); + isArray(localVariables) ? localVariables : [localVariables]; + useEffect(() => { + async function fetchValue() { + const result = await variables.getVariableValue(variableName, localVariables); + setValue(result.value); + } + fetchValue(); + }, [localVariables, variableName, variables]); + + return {children}; +}; diff --git a/packages/core/client/src/variables/VariablesProvider.tsx b/packages/core/client/src/variables/VariablesProvider.tsx index 2edbaf0fbd..4019bb34f8 100644 --- a/packages/core/client/src/variables/VariablesProvider.tsx +++ b/packages/core/client/src/variables/VariablesProvider.tsx @@ -347,11 +347,12 @@ const VariablesProvider = ({ children, filterVariables }: any) => { parseVariable, registerVariable, getVariable, + getVariableValue: getResult, getCollectionField, removeVariable, filterVariables, }) as VariablesContextType, - [getCollectionField, getVariable, parseVariable, registerVariable, removeVariable, setCtx], + [getCollectionField, getVariable, parseVariable, registerVariable, removeVariable, setCtx, getResult], ); return {children}; diff --git a/packages/core/client/src/variables/types.ts b/packages/core/client/src/variables/types.ts index 2f3eeeb4e2..9612365f2d 100644 --- a/packages/core/client/src/variables/types.ts +++ b/packages/core/client/src/variables/types.ts @@ -82,6 +82,26 @@ export interface VariablesContextType { * @returns 变量的配置 */ getVariable: (variableName: string) => VariableOption; + + /** + * 获取变量的值 + * @param variableName 变量的名称,例如:`$user` + * @returns 变量的配置 + */ + getVariableValue: ( + variablePath: string, + localVariables?: VariableOption[], + options?: { + /** Related fields that need to be included in the first request */ + appends?: string[]; + /** Do not request when the association field is empty */ + doNotRequest?: boolean; + /** + * The operator related to the current field, provided when parsing the default value of the field + */ + fieldOperator?: string | void; + }, + ) => Promise; getCollectionField: ( variableString: string, localVariables?: VariableOption | VariableOption[], diff --git a/packages/core/json-template-parser/src/parser/index.ts b/packages/core/json-template-parser/src/parser/index.ts index ff67548964..b2c2b2398e 100644 --- a/packages/core/json-template-parser/src/parser/index.ts +++ b/packages/core/json-template-parser/src/parser/index.ts @@ -7,4 +7,4 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -export { createJSONTemplateParser, JSONTemplateParser } from './json-template-parser'; +export { createJSONTemplateParser, JSONTemplateParser, parse } from './json-template-parser'; diff --git a/packages/core/json-template-parser/src/parser/json-template-parser.ts b/packages/core/json-template-parser/src/parser/json-template-parser.ts index 1f177dcd37..f86d0eeaed 100644 --- a/packages/core/json-template-parser/src/parser/json-template-parser.ts +++ b/packages/core/json-template-parser/src/parser/json-template-parser.ts @@ -256,3 +256,5 @@ const parser = new JSONTemplateParser(); export function createJSONTemplateParser() { return parser; } + +export const parse = parser.parse; diff --git a/packages/core/utils/src/index.ts b/packages/core/utils/src/index.ts index b2e3258752..2b367b794b 100644 --- a/packages/core/utils/src/index.ts +++ b/packages/core/utils/src/index.ts @@ -9,11 +9,8 @@ import lodash from 'lodash'; import { dayjs } from './dayjs'; -import { createJSONTemplateParser } from '@nocobase/json-template-parser'; -const parser = createJSONTemplateParser(); -const parse = parser.parse; -export { parse }; +export { parse } from '@nocobase/json-template-parser'; export * from './assign'; export * from './collections-graph'; export * from './common';