refactor: table select record restricted the usage association field (#2338)

* refactor: table select recordrestricted the usage association field

* refactor: table select recordrestricted the usage action

* refactor: code improve

* refactor: code improve

* fix: code improve

* refactor: code improve
This commit is contained in:
katherinehhh 2023-08-04 15:20:06 +08:00 committed by GitHub
parent e3b0f13923
commit dcee24a1b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 39 deletions

View File

@ -29,7 +29,6 @@ const ToOneNester = (props) => {
const ToManyNester = observer(
(props) => {
console.log(props);
const fieldSchema = useFieldSchema();
const { options, field, allowMultiple, allowDissociate } = useAssociationFieldContext<ArrayField>();
const { t } = useTranslation();

View File

@ -48,7 +48,20 @@ export const findColumnFieldSchema = (fieldSchema, getCollectionJoinField) => {
getAssociationAppends(fieldSchema);
return [...childsSchema];
};
function transformData(inputData) {
const transformedData = [];
const keys = Object.keys(inputData) || [];
const values: any[] = Object.values(inputData) || [];
for (let i = 0; i < values[0]?.length; i++) {
const newObj = {};
keys.forEach((key, index) => {
newObj[key] = values[index][i];
});
transformedData.push(newObj);
}
return transformedData;
}
export const FormItem: any = observer(
(props: any) => {
useEnsureOperatorsValid();
@ -78,7 +91,8 @@ export const FormItem: any = observer(
const data = parseVariables(schema.default, { $context: v });
iniValues = iniValues.concat(data);
});
field.setInitialValue?.(_.uniqBy(iniValues, 'id'));
const data = _.uniqBy(iniValues, 'id');
field.setInitialValue?.(data.length > 0 ? data : [{}]);
} else if (
collectionField?.interface === 'o2m' &&
['SubTable', 'Nester'].includes(schema?.['x-component-props']?.['mode']) // 间接对多
@ -86,15 +100,19 @@ export const FormItem: any = observer(
const childrenFieldWithDefault = findColumnFieldSchema(schema, getCollectionJoinField);
// 子表格/子表单中找出所有belongsTo字段的上下文默认值
if (childrenFieldWithDefault.length > 0) {
const contextData = parseVariables('{{$context}}', variablesCtx);
const initValues = contextData?.map((v) => {
const obj = {};
childrenFieldWithDefault.forEach((s: any) => {
const child = JSON.parse(s);
obj[child.name] = parseVariables(child.default, { $context: v });
const tableData = parseVariables('{{$context}}', variablesCtx);
const contextData = {};
// 将数据拍平
childrenFieldWithDefault?.forEach((s: any) => {
const child = JSON.parse(s);
tableData?.map((v) => {
contextData[child.name] = _.uniqBy(
(contextData[child.name] || []).concat(parseVariables(child.default, { $context: v })),
'id',
);
});
return obj;
});
const initValues = transformData(contextData);
field.setInitialValue?.(initValues);
}
}

View File

@ -57,6 +57,7 @@ import {
useGlobalTheme,
useLinkageCollectionFilterOptions,
useSortFields,
useActionContext,
} from '..';
import { useTableBlockContext } from '../block-provider';
import { findFilterTargets, updateFilterTargets } from '../block-provider/hooks';
@ -1449,6 +1450,7 @@ SchemaSettings.DefaultValue = function DefaultValueConfigure(props) {
const field = useField<Field>();
const { dn } = useDesignable();
const { t } = useTranslation();
const actionCtx = useActionContext();
let targetField;
const { getField } = useCollection();
const { getCollectionJoinField } = useCollectionManager();
@ -1462,10 +1464,10 @@ SchemaSettings.DefaultValue = function DefaultValueConfigure(props) {
const parentFieldSchema = collectionField?.interface === 'm2o' && findParentFieldSchema(fieldSchema);
const parentCollectionField = parentFieldSchema && getCollectionJoinField(parentFieldSchema?.['x-collection-field']);
const tableCtx = useTableBlockContext();
const isAllowContextVariable =
collectionField?.interface === 'm2m' ||
(parentCollectionField?.type === 'hasMany' && collectionField?.interface === 'm2o');
const isAllowContexVariable =
actionCtx?.fieldSchema?.['x-action'] === 'customize:create' &&
(collectionField?.interface === 'm2m' ||
(parentCollectionField?.type === 'hasMany' && collectionField?.interface === 'm2o'));
return (
<SchemaSettings.ModalItem
title={t('Set default value')}
@ -1482,7 +1484,7 @@ SchemaSettings.DefaultValue = function DefaultValueConfigure(props) {
'x-component-props': {
...(fieldSchema?.['x-component-props'] || {}),
collectionField,
contextCollectionName: isAllowContextVariable && tableCtx.collection,
contextCollectionName: isAllowContexVariable && tableCtx.collection,
schema: collectionField?.uiSchema,
className: defaultInputStyle,
renderSchemaComponent: function Com(props) {

View File

@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { CollectionFieldOptions } from '../../collection-manager';
import { useCompile, Variable } from '../../schema-component';
import { useContextAssociationFields } from './hooks/useContextAssociationFields';
import { useContextAssociationFields, useIsSameOrChildCollection } from './hooks/useContextAssociationFields';
import { useUserVariable } from './hooks/useUserVariable';
type Props = {
@ -31,7 +31,9 @@ export const VariableInput = (props: Props) => {
} = props;
const compile = useCompile();
const userVariable = useUserVariable({ schema, maxDepth: 1 });
const contextVariable = useContextAssociationFields({ schema, maxDepth: 2, contextCollectionName });
const contextVariable = useContextAssociationFields({ schema, maxDepth: 2, contextCollectionName, collectionField });
const getIsSameOrChildCollection = useIsSameOrChildCollection();
const isAllowTableContext = getIsSameOrChildCollection(contextCollectionName, collectionField?.target);
const scope = useMemo(() => {
const data = [
compile({
@ -64,7 +66,7 @@ export const VariableInput = (props: Props) => {
onChange={onChange}
scope={scope}
style={style}
changeOnSelect={contextCollectionName !== null}
changeOnSelect={isAllowTableContext}
>
<RenderSchemaComponent value={value} onChange={onChange} />
</Variable.Input>

View File

@ -1,9 +1,22 @@
import { error } from '@nocobase/utils/client';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useCollectionManager, CollectionFieldOptions } from '../../../collection-manager';
import { useCompile, useGetFilterOptions } from '../../../schema-component';
import { FieldOption, Option } from '../type';
export const useIsSameOrChildCollection = () => {
const { getChildrenCollections } = useCollectionManager();
return (contextCollection, targetCollection) => {
console.log(contextCollection, targetCollection);
if (contextCollection === targetCollection) {
return true;
}
const childrens = getChildrenCollections(targetCollection);
return childrens?.some((v) => v.name === contextCollection);
};
};
interface GetOptionsParams {
schema: any;
depth: number;
@ -15,37 +28,40 @@ interface GetOptionsParams {
const getChildren = (
options: FieldOption[],
{ schema, depth, maxDepth, loadChildren, compile }: GetOptionsParams,
collectionField,
getIsSameOrChildCollection,
): Option[] => {
const result = options
.map((option): Option => {
if (!option.target) {
.map(
(option): Option => {
const disabled = !getIsSameOrChildCollection(option.target, collectionField?.target);
if (!option.target) {
return {
key: option.name,
value: option.name,
label: compile(option.title),
disabled: disabled,
isLeaf: true,
depth,
};
}
if (depth >= maxDepth) {
return null;
}
return {
key: option.name,
value: option.name,
label: compile(option.title),
// TODO: 现在是通过组件的名称来过滤能够被选择的选项,这样的坏处是不够精确,后续可以优化
// disabled: schema?.['x-component'] !== option.schema?.['x-component'],
disabled: disabled,
isLeaf: true,
field: option,
depth,
loadChildren,
};
}
if (depth >= maxDepth) {
return null;
}
return {
key: option.name,
value: option.name,
label: compile(option.title),
isLeaf: true,
field: option,
depth,
loadChildren,
};
})
},
)
.filter(Boolean);
return result;
};
@ -53,15 +69,17 @@ export const useContextAssociationFields = ({
schema,
maxDepth = 3,
contextCollectionName,
collectionField,
}: {
schema: any;
maxDepth?: number;
contextCollectionName: string;
collectionField: CollectionFieldOptions;
}) => {
const { t } = useTranslation();
const compile = useCompile();
const getFilterOptions = useGetFilterOptions();
const getIsSameOrChildCollection = useIsSameOrChildCollection();
const loadChildren = (option: Option): Promise<void> => {
if (!option.field?.target) {
return new Promise((resolve) => {
@ -87,6 +105,8 @@ export const useContextAssociationFields = ({
loadChildren,
compile,
},
collectionField,
getIsSameOrChildCollection,
) || [];
if (children.length === 0) {