refractor(remote-select): association field data scope merge with original filter conditions (#2118)
* fix: deleting the last field from sub table, the entire table will be deleted * refactor: association select support data scope in sub-table * refactor: locale improve * style: sub-table style improve * refactor: code improve * chore: association field data scope * refactor: code improve * refactor: code improve
This commit is contained in:
		
							parent
							
								
									53a6a6c621
								
							
						
					
					
						commit
						457082ffa1
					
				@ -1,13 +1,18 @@
 | 
				
			|||||||
import { GeneralField } from '@formily/core';
 | 
					import { GeneralField } from '@formily/core';
 | 
				
			||||||
import { useFieldSchema } from '@formily/react';
 | 
					import { useField, useFieldSchema, useForm } from '@formily/react';
 | 
				
			||||||
 | 
					import flat from 'flat';
 | 
				
			||||||
 | 
					import { isString } from 'lodash';
 | 
				
			||||||
import cloneDeep from 'lodash/cloneDeep';
 | 
					import cloneDeep from 'lodash/cloneDeep';
 | 
				
			||||||
import { useCallback, useContext, useMemo } from 'react';
 | 
					import { useCallback, useContext, useMemo } from 'react';
 | 
				
			||||||
 | 
					import { useBlockRequestContext } from '../../../block-provider/BlockProvider';
 | 
				
			||||||
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';
 | 
				
			||||||
import { useRecord } from '../../../record-provider';
 | 
					import { useRecord } from '../../../record-provider';
 | 
				
			||||||
 | 
					import { getInnermostKeyAndValue } from '../../common/utils/uitls';
 | 
				
			||||||
import { useDesignable } from '../../hooks';
 | 
					import { useDesignable } from '../../hooks';
 | 
				
			||||||
import { AssociationFieldContext } from './context';
 | 
					import { AssociationFieldContext } from './context';
 | 
				
			||||||
 | 
					import { extractFilterfield, extractValuesByPattern, generatePattern, parseVariables } from './util';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useInsertSchema = (component) => {
 | 
					export const useInsertSchema = (component) => {
 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
@ -43,9 +48,75 @@ export default function useServiceOptions(props) {
 | 
				
			|||||||
  const { action = 'list', service, fieldNames } = props;
 | 
					  const { action = 'list', service, fieldNames } = props;
 | 
				
			||||||
  const params = service?.params || {};
 | 
					  const params = service?.params || {};
 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
 | 
					  const field = useField();
 | 
				
			||||||
 | 
					  const form = useForm();
 | 
				
			||||||
 | 
					  const ctx = useBlockRequestContext();
 | 
				
			||||||
  const { getField } = useCollection();
 | 
					  const { getField } = useCollection();
 | 
				
			||||||
  const { getCollectionFields, getCollectionJoinField } = useCollectionManager();
 | 
					  const { getCollectionFields, getCollectionJoinField } = useCollectionManager();
 | 
				
			||||||
  const record = useRecord();
 | 
					  const record = useRecord();
 | 
				
			||||||
 | 
					  const parseFilter = useCallback(
 | 
				
			||||||
 | 
					    (rules) => {
 | 
				
			||||||
 | 
					      if (!rules) {
 | 
				
			||||||
 | 
					        return undefined;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (typeof rules === 'string') {
 | 
				
			||||||
 | 
					        return rules;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const type = Object.keys(rules)[0] || '$and';
 | 
				
			||||||
 | 
					      const conditions = rules[type];
 | 
				
			||||||
 | 
					      const results = [];
 | 
				
			||||||
 | 
					      conditions?.forEach((c) => {
 | 
				
			||||||
 | 
					        const jsonlogic = getInnermostKeyAndValue(c);
 | 
				
			||||||
 | 
					        const regex = /{{(.*?)}}/;
 | 
				
			||||||
 | 
					        const matches = jsonlogic.value?.match?.(regex);
 | 
				
			||||||
 | 
					        if (!matches || (!matches[1].includes('$form') && !matches[1].includes('$iteration'))) {
 | 
				
			||||||
 | 
					          results.push(c);
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const associationfield = extractFilterfield(matches[1]);
 | 
				
			||||||
 | 
					        const filterCollectionField = getCollectionJoinField(`${ctx.props.collection}.${associationfield}`);
 | 
				
			||||||
 | 
					        if (['o2m', 'm2m'].includes(filterCollectionField?.interface)) {
 | 
				
			||||||
 | 
					          // 对多子表单
 | 
				
			||||||
 | 
					          const pattern = generatePattern(matches?.[1], associationfield);
 | 
				
			||||||
 | 
					          const parseValue: any = extractValuesByPattern(flat(form.values), pattern);
 | 
				
			||||||
 | 
					          const filters = parseValue.map((v) => {
 | 
				
			||||||
 | 
					            return JSON.parse(JSON.stringify(c).replace(jsonlogic.value, v));
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          results.push({ $or: filters });
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          const variablesCtx = { $form: form.values, $iteration: form.values };
 | 
				
			||||||
 | 
					          let str = matches?.[1];
 | 
				
			||||||
 | 
					          if (str.includes('$iteration')) {
 | 
				
			||||||
 | 
					            const path = field.path.segments.concat([]);
 | 
				
			||||||
 | 
					            path.pop();
 | 
				
			||||||
 | 
					            str = str.replace('$iteration.', `$iteration.${path.join('.')}.`);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          const parseValue = parseVariables(str, variablesCtx);
 | 
				
			||||||
 | 
					          if (Array.isArray(parseValue)) {
 | 
				
			||||||
 | 
					            const filters = parseValue.map((v) => {
 | 
				
			||||||
 | 
					              return JSON.parse(JSON.stringify(c).replace(jsonlogic.value, v));
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            results.push({ $or: filters });
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            const filterObj = JSON.parse(
 | 
				
			||||||
 | 
					              JSON.stringify(c).replace(jsonlogic.value, str.endsWith('id') ? parseValue ?? 0 : parseValue),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            results.push(filterObj);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return { [type]: results };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    [ctx.props?.collection, field.path.segments, form.values, getCollectionJoinField],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const fieldServiceFilter = useMemo(() => {
 | 
				
			||||||
 | 
					    const filterFromSchema = isString(fieldSchema?.['x-component-props']?.service?.params?.filter)
 | 
				
			||||||
 | 
					      ? field.componentProps?.service?.params?.filter
 | 
				
			||||||
 | 
					      : fieldSchema?.['x-component-props']?.service?.params?.filter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return mergeFilter([parseFilter(filterFromSchema) || service?.params?.filter]);
 | 
				
			||||||
 | 
					  }, [field.componentProps?.service?.params?.filter, fieldSchema, parseFilter, service?.params?.filter]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const normalizeValues = useCallback(
 | 
					  const normalizeValues = useCallback(
 | 
				
			||||||
    (obj) => {
 | 
					    (obj) => {
 | 
				
			||||||
@ -85,7 +156,7 @@ export default function useServiceOptions(props) {
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            : null,
 | 
					            : null,
 | 
				
			||||||
          params?.filter,
 | 
					          fieldServiceFilter,
 | 
				
			||||||
        ]),
 | 
					        ]),
 | 
				
			||||||
        isOToAny &&
 | 
					        isOToAny &&
 | 
				
			||||||
        sourceValue !== undefined &&
 | 
					        sourceValue !== undefined &&
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import { ISchema } from '@formily/react';
 | 
				
			|||||||
import { isArr } from '@formily/shared';
 | 
					import { isArr } from '@formily/shared';
 | 
				
			||||||
import { getDefaultFormat, str2moment } from '@nocobase/utils/client';
 | 
					import { getDefaultFormat, str2moment } from '@nocobase/utils/client';
 | 
				
			||||||
import { Tag } from 'antd';
 | 
					import { Tag } from 'antd';
 | 
				
			||||||
 | 
					import { get, isFunction } from 'lodash';
 | 
				
			||||||
import dayjs from 'dayjs';
 | 
					import dayjs from 'dayjs';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { CollectionFieldOptions, useCollectionManager } from '../../../collection-manager';
 | 
					import { CollectionFieldOptions, useCollectionManager } from '../../../collection-manager';
 | 
				
			||||||
@ -93,3 +94,37 @@ export const toValue = (value, placeholder) => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  return value;
 | 
					  return value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const parseVariables = (str: string, ctx) => {
 | 
				
			||||||
 | 
					  if (str) {
 | 
				
			||||||
 | 
					    const result = get(ctx, str);
 | 
				
			||||||
 | 
					    return isFunction(result) ? result() : result;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return str;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export function extractFilterfield(str) {
 | 
				
			||||||
 | 
					  const match = str.match(/^\$form\.([^.[\]]+)/);
 | 
				
			||||||
 | 
					  if (match) {
 | 
				
			||||||
 | 
					    return match[1];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function extractValuesByPattern(obj, pattern) {
 | 
				
			||||||
 | 
					  const regexPattern = new RegExp(pattern.replace(/\*/g, '\\d+'));
 | 
				
			||||||
 | 
					  const result = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const key in obj) {
 | 
				
			||||||
 | 
					    if (regexPattern.test(key)) {
 | 
				
			||||||
 | 
					      const value = obj[key];
 | 
				
			||||||
 | 
					      result.push(value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export function generatePattern(str, fieldName) {
 | 
				
			||||||
 | 
					  const result = str.replace(`$form.${fieldName}.`, `${fieldName}.*.`);
 | 
				
			||||||
 | 
					  return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,14 +6,12 @@ import flat from 'flat';
 | 
				
			|||||||
import _, { uniqBy } from 'lodash';
 | 
					import _, { uniqBy } from 'lodash';
 | 
				
			||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
 | 
					import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
 | 
				
			||||||
import { ResourceActionOptions, useRequest } from '../../../api-client';
 | 
					import { ResourceActionOptions, useRequest } from '../../../api-client';
 | 
				
			||||||
import { useBlockRequestContext } from '../../../block-provider/BlockProvider';
 | 
					 | 
				
			||||||
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 { getInnermostKeyAndValue } from '../../common/utils/uitls';
 | 
					import { getInnermostKeyAndValue } from '../../common/utils/uitls';
 | 
				
			||||||
import { useCompile } from '../../hooks';
 | 
					import { useCompile } from '../../hooks';
 | 
				
			||||||
import { Select, defaultFieldNames } from '../select';
 | 
					import { Select, defaultFieldNames } from '../select';
 | 
				
			||||||
import { ReadPretty } from './ReadPretty';
 | 
					import { ReadPretty } from './ReadPretty';
 | 
				
			||||||
import { extractFilterfield, extractValuesByPattern, generatePattern, parseVariables } from './utils';
 | 
					 | 
				
			||||||
const EMPTY = 'N/A';
 | 
					const EMPTY = 'N/A';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type RemoteSelectProps<P = any> = SelectProps<P, any> & {
 | 
					export type RemoteSelectProps<P = any> = SelectProps<P, any> & {
 | 
				
			||||||
@ -49,7 +47,6 @@ const InternalRemoteSelect = connect(
 | 
				
			|||||||
    const fieldSchema = useFieldSchema();
 | 
					    const fieldSchema = useFieldSchema();
 | 
				
			||||||
    const isQuickAdd = fieldSchema['x-component-props']?.addMode === 'quickAdd';
 | 
					    const isQuickAdd = fieldSchema['x-component-props']?.addMode === 'quickAdd';
 | 
				
			||||||
    const field = useField();
 | 
					    const field = useField();
 | 
				
			||||||
    const ctx = useBlockRequestContext();
 | 
					 | 
				
			||||||
    const { getField } = useCollection();
 | 
					    const { getField } = useCollection();
 | 
				
			||||||
    const searchData = useRef(null);
 | 
					    const searchData = useRef(null);
 | 
				
			||||||
    const { getCollectionJoinField, getInterface } = useCollectionManager();
 | 
					    const { getCollectionJoinField, getInterface } = useCollectionManager();
 | 
				
			||||||
@ -123,70 +120,6 @@ const InternalRemoteSelect = connect(
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      [targetField?.uiSchema, fieldNames],
 | 
					      [targetField?.uiSchema, fieldNames],
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    const parseFilter = useCallback(
 | 
					 | 
				
			||||||
      (rules) => {
 | 
					 | 
				
			||||||
        if (!rules) {
 | 
					 | 
				
			||||||
          return undefined;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (typeof rules === 'string') {
 | 
					 | 
				
			||||||
          return rules;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        const type = Object.keys(rules)[0] || '$and';
 | 
					 | 
				
			||||||
        const conditions = rules[type];
 | 
					 | 
				
			||||||
        const results = [];
 | 
					 | 
				
			||||||
        conditions?.forEach((c) => {
 | 
					 | 
				
			||||||
          const jsonlogic = getInnermostKeyAndValue(c);
 | 
					 | 
				
			||||||
          const regex = /{{(.*?)}}/;
 | 
					 | 
				
			||||||
          const matches = jsonlogic.value?.match?.(regex);
 | 
					 | 
				
			||||||
          if (!matches || (!matches[1].includes('$form') && !matches[1].includes('$iteration'))) {
 | 
					 | 
				
			||||||
            results.push(c);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          const associationfield = extractFilterfield(matches[1]);
 | 
					 | 
				
			||||||
          const filterCollectionField = getCollectionJoinField(`${ctx.props.collection}.${associationfield}`);
 | 
					 | 
				
			||||||
          if (['o2m', 'm2m'].includes(filterCollectionField?.interface)) {
 | 
					 | 
				
			||||||
            // 对多子表单
 | 
					 | 
				
			||||||
            const pattern = generatePattern(matches?.[1], associationfield);
 | 
					 | 
				
			||||||
            const parseValue: any = extractValuesByPattern(flat(form.values), pattern);
 | 
					 | 
				
			||||||
            const filters = parseValue.map((v) => {
 | 
					 | 
				
			||||||
              return JSON.parse(JSON.stringify(c).replace(jsonlogic.value, v));
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
            results.push({ $or: filters });
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            const variablesCtx = { $form: form.values, $iteration: form.values };
 | 
					 | 
				
			||||||
            let str = matches?.[1];
 | 
					 | 
				
			||||||
            if (str.includes('$iteration')) {
 | 
					 | 
				
			||||||
              const path = field.path.segments.concat([]);
 | 
					 | 
				
			||||||
              path.pop();
 | 
					 | 
				
			||||||
              str = str.replace('$iteration.', `$iteration.${path.join('.')}.`);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            const parseValue = parseVariables(str, variablesCtx);
 | 
					 | 
				
			||||||
            if (Array.isArray(parseValue)) {
 | 
					 | 
				
			||||||
              const filters = parseValue.map((v) => {
 | 
					 | 
				
			||||||
                return JSON.parse(JSON.stringify(c).replace(jsonlogic.value, v));
 | 
					 | 
				
			||||||
              });
 | 
					 | 
				
			||||||
              results.push({ $or: filters });
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              const filterObj = JSON.parse(
 | 
					 | 
				
			||||||
                JSON.stringify(c).replace(jsonlogic.value, str.endsWith('id') ? parseValue ?? 0 : parseValue),
 | 
					 | 
				
			||||||
              );
 | 
					 | 
				
			||||||
              results.push(filterObj);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return { [type]: results };
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      [ctx.props?.collection, field.path.segments, form.values, getCollectionJoinField],
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const filter = useMemo(() => {
 | 
					 | 
				
			||||||
      const filterFromSchema = _.isString(fieldSchema?.['x-component-props']?.service?.params?.filter)
 | 
					 | 
				
			||||||
        ? field.componentProps?.service?.params?.filter
 | 
					 | 
				
			||||||
        : fieldSchema?.['x-component-props']?.service?.params?.filter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return mergeFilter([parseFilter(filterFromSchema) || service?.params?.filter]);
 | 
					 | 
				
			||||||
    }, [field.componentProps?.service?.params?.filter, fieldSchema, parseFilter, service?.params?.filter]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { data, run, loading } = useRequest(
 | 
					    const { data, run, loading } = useRequest(
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        action: 'list',
 | 
					        action: 'list',
 | 
				
			||||||
@ -194,8 +127,7 @@ const InternalRemoteSelect = connect(
 | 
				
			|||||||
        params: {
 | 
					        params: {
 | 
				
			||||||
          pageSize: 200,
 | 
					          pageSize: 200,
 | 
				
			||||||
          ...service?.params,
 | 
					          ...service?.params,
 | 
				
			||||||
          // search needs
 | 
					          filter: service?.params?.filter,
 | 
				
			||||||
          filter,
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -243,7 +175,7 @@ const InternalRemoteSelect = connect(
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            : {},
 | 
					            : {},
 | 
				
			||||||
          filter,
 | 
					          service?.params?.filter,
 | 
				
			||||||
        ]),
 | 
					        ]),
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      searchData.current = search;
 | 
					      searchData.current = search;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
import { get, isFunction } from 'lodash';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const parseVariables = (str: string, ctx) => {
 | 
					 | 
				
			||||||
  if (str) {
 | 
					 | 
				
			||||||
    const result = get(ctx, str);
 | 
					 | 
				
			||||||
    return isFunction(result) ? result() : result;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    return str;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
export function extractFilterfield(str) {
 | 
					 | 
				
			||||||
  const match = str.match(/^\$form\.([^.[\]]+)/);
 | 
					 | 
				
			||||||
  if (match) {
 | 
					 | 
				
			||||||
    return match[1];
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return null;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function extractValuesByPattern(obj, pattern) {
 | 
					 | 
				
			||||||
  const regexPattern = new RegExp(pattern.replace(/\*/g, '\\d+'));
 | 
					 | 
				
			||||||
  const result = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (const key in obj) {
 | 
					 | 
				
			||||||
    if (regexPattern.test(key)) {
 | 
					 | 
				
			||||||
      const value = obj[key];
 | 
					 | 
				
			||||||
      result.push(value);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export function generatePattern(str, fieldName) {
 | 
					 | 
				
			||||||
  const result = str.replace(`$form.${fieldName}.`, `${fieldName}.*.`);
 | 
					 | 
				
			||||||
  return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user