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:
parent
e3b0f13923
commit
dcee24a1b0
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user