fix(variable): compat old variable names (#2889)
* fix(variable): compat old variable names * refactor: remove LocalVariablesProvider
This commit is contained in:
parent
2ec3130f46
commit
cde25ed871
@ -1,17 +1,16 @@
|
|||||||
import { reaction } from '@formily/reactive';
|
import { reaction } from '@formily/reactive';
|
||||||
import { flatten } from '@nocobase/utils/client';
|
import { flatten, getValuesByPath } from '@nocobase/utils/client';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useParseDataScopeFilter } from '../../schema-settings';
|
import { useParseDataScopeFilter } from '../../schema-settings';
|
||||||
import { DEBOUNCE_WAIT } from '../../variables';
|
import { DEBOUNCE_WAIT } from '../../variables';
|
||||||
import { getPath } from '../../variables/utils/getPath';
|
import { getPath } from '../../variables/utils/getPath';
|
||||||
|
import { getVariableName } from '../../variables/utils/getVariableName';
|
||||||
import { isVariable } from '../../variables/utils/isVariable';
|
import { isVariable } from '../../variables/utils/isVariable';
|
||||||
import { useFormBlockContext } from '../FormBlockProvider';
|
|
||||||
|
|
||||||
export function useParsedFilter({ filterOption, currentRecord }: { filterOption: any; currentRecord?: any }) {
|
export function useParsedFilter({ filterOption, currentRecord }: { filterOption: any; currentRecord?: any }) {
|
||||||
const { parseFilter } = useParseDataScopeFilter({ currentRecord });
|
const { parseFilter, findVariable } = useParseDataScopeFilter({ currentRecord });
|
||||||
const [filter, setFilter] = useState({});
|
const [filter, setFilter] = useState({});
|
||||||
const { form } = useFormBlockContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!filterOption) return;
|
if (!filterOption) return;
|
||||||
@ -33,7 +32,19 @@ export function useParsedFilter({ filterOption, currentRecord }: { filterOption:
|
|||||||
if (!isVariable(value)) {
|
if (!isVariable(value)) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
const result = _.get({ $nForm: form?.values }, getPath(value));
|
const variableName = getVariableName(value);
|
||||||
|
const variable = findVariable(variableName);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production' && !variable) {
|
||||||
|
throw new Error(`useParsedFilter: can not find variable ${variableName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = getValuesByPath(
|
||||||
|
{
|
||||||
|
[variableName]: variable?.ctx || {},
|
||||||
|
},
|
||||||
|
getPath(value),
|
||||||
|
);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,6 @@ import {
|
|||||||
IsAllowToSetDefaultValueParams,
|
IsAllowToSetDefaultValueParams,
|
||||||
interfacesOfUnsupportedDefaultValue,
|
interfacesOfUnsupportedDefaultValue,
|
||||||
} from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
} from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
||||||
import { LocalVariablesProvider } from '../../../variables/hooks/useLocalVariables';
|
|
||||||
import { AssociationFieldContext } from './context';
|
import { AssociationFieldContext } from './context';
|
||||||
import { SubFormProvider, useAssociationFieldContext } from './hooks';
|
import { SubFormProvider, useAssociationFieldContext } from './hooks';
|
||||||
|
|
||||||
@ -80,11 +79,9 @@ const ToOneNester = (props) => {
|
|||||||
<FormActiveFieldsProvider name="nester">
|
<FormActiveFieldsProvider name="nester">
|
||||||
<SubFormProvider value={field.value}>
|
<SubFormProvider value={field.value}>
|
||||||
<RecordProvider record={field.value}>
|
<RecordProvider record={field.value}>
|
||||||
<LocalVariablesProvider iterationCtx={field.value}>
|
<DefaultValueProvider isAllowToSetDefaultValue={isAllowToSetDefaultValue}>
|
||||||
<DefaultValueProvider isAllowToSetDefaultValue={isAllowToSetDefaultValue}>
|
<Card bordered={true}>{props.children}</Card>
|
||||||
<Card bordered={true}>{props.children}</Card>
|
</DefaultValueProvider>
|
||||||
</DefaultValueProvider>
|
|
||||||
</LocalVariablesProvider>
|
|
||||||
</RecordProvider>
|
</RecordProvider>
|
||||||
</SubFormProvider>
|
</SubFormProvider>
|
||||||
</FormActiveFieldsProvider>
|
</FormActiveFieldsProvider>
|
||||||
@ -190,17 +187,15 @@ const ToManyNester = observer(
|
|||||||
<FormActiveFieldsProvider name="nester">
|
<FormActiveFieldsProvider name="nester">
|
||||||
<SubFormProvider value={value}>
|
<SubFormProvider value={value}>
|
||||||
<RecordProvider record={value}>
|
<RecordProvider record={value}>
|
||||||
<LocalVariablesProvider iterationCtx={value}>
|
<RecordIndexProvider index={index}>
|
||||||
<RecordIndexProvider index={index}>
|
<DefaultValueProvider isAllowToSetDefaultValue={isAllowToSetDefaultValue}>
|
||||||
<DefaultValueProvider isAllowToSetDefaultValue={isAllowToSetDefaultValue}>
|
<RecursionField
|
||||||
<RecursionField
|
onlyRenderProperties
|
||||||
onlyRenderProperties
|
basePath={field.address.concat(index)}
|
||||||
basePath={field.address.concat(index)}
|
schema={fieldSchema}
|
||||||
schema={fieldSchema}
|
/>
|
||||||
/>
|
</DefaultValueProvider>
|
||||||
</DefaultValueProvider>
|
</RecordIndexProvider>
|
||||||
</RecordIndexProvider>
|
|
||||||
</LocalVariablesProvider>
|
|
||||||
</RecordProvider>
|
</RecordProvider>
|
||||||
</SubFormProvider>
|
</SubFormProvider>
|
||||||
</FormActiveFieldsProvider>
|
</FormActiveFieldsProvider>
|
||||||
|
@ -5,7 +5,6 @@ import { flatten, getValuesByPath } from '@nocobase/utils/client';
|
|||||||
import _, { isString } from 'lodash';
|
import _, { isString } from 'lodash';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { useFormBlockContext } from '../../../block-provider';
|
|
||||||
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
||||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
import { isInFilterFormBlock } from '../../../filter-provider';
|
import { isInFilterFormBlock } from '../../../filter-provider';
|
||||||
@ -13,6 +12,7 @@ import { useRecord } from '../../../record-provider';
|
|||||||
import { useParseDataScopeFilter } from '../../../schema-settings';
|
import { useParseDataScopeFilter } from '../../../schema-settings';
|
||||||
import { DEBOUNCE_WAIT } from '../../../variables';
|
import { DEBOUNCE_WAIT } from '../../../variables';
|
||||||
import { getPath } from '../../../variables/utils/getPath';
|
import { getPath } from '../../../variables/utils/getPath';
|
||||||
|
import { getVariableName } from '../../../variables/utils/getVariableName';
|
||||||
import { isVariable } from '../../../variables/utils/isVariable';
|
import { isVariable } from '../../../variables/utils/isVariable';
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable } from '../../hooks';
|
||||||
import { AssociationFieldContext } from './context';
|
import { AssociationFieldContext } from './context';
|
||||||
@ -48,17 +48,14 @@ export function useAssociationFieldContext<F extends GeneralField>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function useServiceOptions(props) {
|
export default function useServiceOptions(props) {
|
||||||
const { action = 'list', service, fieldNames } = props;
|
const { action = 'list', service } = props;
|
||||||
const params = service?.params || {};
|
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { getField } = useCollection();
|
const { getField } = useCollection();
|
||||||
const { getCollectionJoinField } = useCollectionManager();
|
const { getCollectionJoinField } = useCollectionManager();
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
const { parseFilter } = useParseDataScopeFilter();
|
const { parseFilter, findVariable } = useParseDataScopeFilter();
|
||||||
const [fieldServiceFilter, setFieldServiceFilter] = useState(null);
|
const [fieldServiceFilter, setFieldServiceFilter] = useState(null);
|
||||||
const { form } = useFormBlockContext();
|
|
||||||
const { formValue: subFormValue } = useSubFormValue();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filterFromSchema = isString(fieldSchema?.['x-component-props']?.service?.params?.filter)
|
const filterFromSchema = isString(fieldSchema?.['x-component-props']?.service?.params?.filter)
|
||||||
@ -83,10 +80,16 @@ export default function useServiceOptions(props) {
|
|||||||
if (!isVariable(value)) {
|
if (!isVariable(value)) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
const variableName = getVariableName(value);
|
||||||
|
const variable = findVariable(variableName);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production' && !variable) {
|
||||||
|
throw new Error(`useServiceOptions: can not find variable ${variableName}`);
|
||||||
|
}
|
||||||
|
|
||||||
const result = getValuesByPath(
|
const result = getValuesByPath(
|
||||||
{
|
{
|
||||||
$nForm: form?.values,
|
[variableName]: variable?.ctx || {},
|
||||||
$iteration: subFormValue,
|
|
||||||
},
|
},
|
||||||
getPath(value),
|
getPath(value),
|
||||||
);
|
);
|
||||||
@ -100,39 +103,12 @@ export default function useServiceOptions(props) {
|
|||||||
}, [
|
}, [
|
||||||
field.componentProps?.service?.params?.filter,
|
field.componentProps?.service?.params?.filter,
|
||||||
fieldSchema,
|
fieldSchema,
|
||||||
form?.values,
|
findVariable,
|
||||||
parseFilter,
|
parseFilter,
|
||||||
record,
|
record,
|
||||||
service?.params?.filter,
|
service?.params?.filter,
|
||||||
subFormValue,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const normalizeValues = useCallback(
|
|
||||||
(obj) => {
|
|
||||||
if (obj && typeof obj === 'object') {
|
|
||||||
return obj[fieldNames?.value];
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
[fieldNames?.value],
|
|
||||||
);
|
|
||||||
|
|
||||||
const value = useMemo(() => {
|
|
||||||
if (props.value === undefined || props.value === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result: any[] = null;
|
|
||||||
|
|
||||||
if (Array.isArray(props.value)) {
|
|
||||||
result = props.value.map(normalizeValues);
|
|
||||||
} else {
|
|
||||||
result = [normalizeValues(props.value)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.filter(Boolean);
|
|
||||||
}, [props.value, normalizeValues]);
|
|
||||||
|
|
||||||
const collectionField = useMemo(() => {
|
const collectionField = useMemo(() => {
|
||||||
return getField(fieldSchema.name) || getCollectionJoinField(fieldSchema?.['x-collection-field']);
|
return getField(fieldSchema.name) || getCollectionJoinField(fieldSchema?.['x-collection-field']);
|
||||||
}, [fieldSchema]);
|
}, [fieldSchema]);
|
||||||
|
@ -3,7 +3,7 @@ import { useField, useFieldSchema } from '@formily/react';
|
|||||||
import { reaction } from '@formily/reactive';
|
import { reaction } from '@formily/reactive';
|
||||||
import { getValuesByPath } from '@nocobase/utils/client';
|
import { getValuesByPath } from '@nocobase/utils/client';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { useRecord, useRecordIndex } from '../../../../../src/record-provider';
|
import { useRecord, useRecordIndex } from '../../../../../src/record-provider';
|
||||||
import { useFormBlockType } from '../../../../block-provider/FormBlockProvider';
|
import { useFormBlockType } from '../../../../block-provider/FormBlockProvider';
|
||||||
import { useCollection } from '../../../../collection-manager';
|
import { useCollection } from '../../../../collection-manager';
|
||||||
@ -31,6 +31,20 @@ const useParseDefaultValue = () => {
|
|||||||
const index = useRecordIndex();
|
const index = useRecordIndex();
|
||||||
const { type: formBlockType } = useFormBlockType();
|
const { type: formBlockType } = useFormBlockType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* name: 如 $user
|
||||||
|
*/
|
||||||
|
const findVariable = useCallback(
|
||||||
|
(name: string) => {
|
||||||
|
let result = variables?.getVariable(name);
|
||||||
|
if (!result) {
|
||||||
|
result = localVariables.find((item) => item.name === name);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
[localVariables, variables],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
fieldSchema.default == null ||
|
fieldSchema.default == null ||
|
||||||
@ -94,12 +108,16 @@ const useParseDefaultValue = () => {
|
|||||||
|
|
||||||
if (isVariable(fieldSchema.default)) {
|
if (isVariable(fieldSchema.default)) {
|
||||||
const variableName = getVariableName(fieldSchema.default);
|
const variableName = getVariableName(fieldSchema.default);
|
||||||
const variableValue = localVariables.find((item) => item.name === variableName);
|
const variable = findVariable(variableName);
|
||||||
|
|
||||||
if (variableValue) {
|
if (process.env.NODE_ENV !== 'production' && !variable) {
|
||||||
|
throw new Error(`useParseDefaultValue: can not find variable ${variableName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variable) {
|
||||||
// 实现联动的效果,当依赖的变量变化时(如 `$nForm` 变量),重新解析默认值
|
// 实现联动的效果,当依赖的变量变化时(如 `$nForm` 变量),重新解析默认值
|
||||||
const dispose = reaction(() => {
|
const dispose = reaction(() => {
|
||||||
const obj = { [variableName]: variableValue?.ctx };
|
const obj = { [variableName]: variable?.ctx || {} };
|
||||||
const path = getPath(fieldSchema.default);
|
const path = getPath(fieldSchema.default);
|
||||||
|
|
||||||
// fix https://nocobase.height.app/T-2212
|
// fix https://nocobase.height.app/T-2212
|
||||||
|
@ -22,7 +22,6 @@ import {
|
|||||||
useTableSelectorContext,
|
useTableSelectorContext,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
||||||
import { LocalVariablesProvider } from '../../../variables/hooks/useLocalVariables';
|
|
||||||
import { useToken } from '../__builtins__';
|
import { useToken } from '../__builtins__';
|
||||||
import { SubFormProvider } from '../association-field/hooks';
|
import { SubFormProvider } from '../association-field/hooks';
|
||||||
import { ColumnFieldProvider } from './components/ColumnFieldProvider';
|
import { ColumnFieldProvider } from './components/ColumnFieldProvider';
|
||||||
@ -65,17 +64,15 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
|
|||||||
return (
|
return (
|
||||||
<SubFormProvider value={record}>
|
<SubFormProvider value={record}>
|
||||||
<RecordIndexProvider index={record.__index || index}>
|
<RecordIndexProvider index={record.__index || index}>
|
||||||
<LocalVariablesProvider iterationCtx={record}>
|
<RecordProvider record={record}>
|
||||||
<RecordProvider record={record}>
|
<ColumnFieldProvider schema={s} basePath={field.address.concat(record.__index || index)}>
|
||||||
<ColumnFieldProvider schema={s} basePath={field.address.concat(record.__index || index)}>
|
<RecursionField
|
||||||
<RecursionField
|
basePath={field.address.concat(record.__index || index)}
|
||||||
basePath={field.address.concat(record.__index || index)}
|
schema={s}
|
||||||
schema={s}
|
onlyRenderProperties
|
||||||
onlyRenderProperties
|
/>
|
||||||
/>
|
</ColumnFieldProvider>
|
||||||
</ColumnFieldProvider>
|
</RecordProvider>
|
||||||
</RecordProvider>
|
|
||||||
</LocalVariablesProvider>
|
|
||||||
</RecordIndexProvider>
|
</RecordIndexProvider>
|
||||||
</SubFormProvider>
|
</SubFormProvider>
|
||||||
);
|
);
|
||||||
|
@ -20,6 +20,20 @@ const useParseDataScopeFilter = ({ exclude = defaultExclude, currentRecord }: Pr
|
|||||||
const localVariables = useLocalVariables({ currentRecord });
|
const localVariables = useLocalVariables({ currentRecord });
|
||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* name: 如 $user
|
||||||
|
*/
|
||||||
|
const findVariable = useCallback(
|
||||||
|
(name: string) => {
|
||||||
|
let result = variables?.getVariable(name);
|
||||||
|
if (!result) {
|
||||||
|
result = localVariables.find((item) => item.name === name);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
[localVariables, variables],
|
||||||
|
);
|
||||||
|
|
||||||
const parseFilter = useCallback(
|
const parseFilter = useCallback(
|
||||||
async (filterValue: any) => {
|
async (filterValue: any) => {
|
||||||
const flat = flatten(filterValue, {
|
const flat = flatten(filterValue, {
|
||||||
@ -52,7 +66,7 @@ const useParseDataScopeFilter = ({ exclude = defaultExclude, currentRecord }: Pr
|
|||||||
[exclude, localVariables, variables?.parseVariable],
|
[exclude, localVariables, variables?.parseVariable],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { parseFilter };
|
return { parseFilter, findVariable };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useParseDataScopeFilter;
|
export default useParseDataScopeFilter;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Form } from '@formily/core';
|
import { Form } from '@formily/core';
|
||||||
import React, { useContext, useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useFormBlockContext } from '../../block-provider';
|
import { useFormBlockContext } from '../../block-provider';
|
||||||
import { useCollection } from '../../collection-manager';
|
import { useCollection } from '../../collection-manager';
|
||||||
import { useRecord } from '../../record-provider';
|
import { useRecord } from '../../record-provider';
|
||||||
|
import { useSubFormValue } from '../../schema-component/antd/association-field/hooks';
|
||||||
import { useBlockCollection } from '../../schema-settings/VariableInput/hooks/useBlockCollection';
|
import { useBlockCollection } from '../../schema-settings/VariableInput/hooks/useBlockCollection';
|
||||||
import { VariableOption } from '../types';
|
import { VariableOption } from '../types';
|
||||||
|
|
||||||
@ -12,21 +13,9 @@ interface Props {
|
|||||||
currentForm?: Form;
|
currentForm?: Form;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LocalVariablesContext = React.createContext<{ iterationCtx: Record<string, any> }>(null);
|
|
||||||
|
|
||||||
export const LocalVariablesProvider = ({
|
|
||||||
children,
|
|
||||||
iterationCtx,
|
|
||||||
}: {
|
|
||||||
iterationCtx: Record<string, any>;
|
|
||||||
children: React.ReactNode;
|
|
||||||
}) => {
|
|
||||||
return <LocalVariablesContext.Provider value={{ iterationCtx }}>{children}</LocalVariablesContext.Provider>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const useLocalVariables = (props?: Props) => {
|
const useLocalVariables = (props?: Props) => {
|
||||||
const { name: currentCollectionName } = useCollection();
|
const { name: currentCollectionName } = useCollection();
|
||||||
const { iterationCtx } = useContext(LocalVariablesContext) || {};
|
const { formValue: subFormValue } = useSubFormValue();
|
||||||
let { name } = useBlockCollection();
|
let { name } = useBlockCollection();
|
||||||
let currentRecord = useRecord();
|
let currentRecord = useRecord();
|
||||||
let { form } = useFormBlockContext();
|
let { form } = useFormBlockContext();
|
||||||
@ -86,10 +75,10 @@ const useLocalVariables = (props?: Props) => {
|
|||||||
ctx: form?.values,
|
ctx: form?.values,
|
||||||
collectionName: name,
|
collectionName: name,
|
||||||
},
|
},
|
||||||
iterationCtx && { name: '$iteration', ctx: iterationCtx, collectionName: currentCollectionName },
|
subFormValue && { name: '$iteration', ctx: subFormValue, collectionName: currentCollectionName },
|
||||||
] as VariableOption[]
|
] as VariableOption[]
|
||||||
).filter(Boolean);
|
).filter(Boolean);
|
||||||
}, [currentRecord, name, form?.values, iterationCtx, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中
|
}, [currentRecord, name, form?.values, subFormValue, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useLocalVariables;
|
export default useLocalVariables;
|
||||||
|
Loading…
Reference in New Issue
Block a user