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(
|
const ToManyNester = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
console.log(props);
|
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { options, field, allowMultiple, allowDissociate } = useAssociationFieldContext<ArrayField>();
|
const { options, field, allowMultiple, allowDissociate } = useAssociationFieldContext<ArrayField>();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -48,7 +48,20 @@ export const findColumnFieldSchema = (fieldSchema, getCollectionJoinField) => {
|
|||||||
getAssociationAppends(fieldSchema);
|
getAssociationAppends(fieldSchema);
|
||||||
return [...childsSchema];
|
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(
|
export const FormItem: any = observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
useEnsureOperatorsValid();
|
useEnsureOperatorsValid();
|
||||||
@ -78,7 +91,8 @@ export const FormItem: any = observer(
|
|||||||
const data = parseVariables(schema.default, { $context: v });
|
const data = parseVariables(schema.default, { $context: v });
|
||||||
iniValues = iniValues.concat(data);
|
iniValues = iniValues.concat(data);
|
||||||
});
|
});
|
||||||
field.setInitialValue?.(_.uniqBy(iniValues, 'id'));
|
const data = _.uniqBy(iniValues, 'id');
|
||||||
|
field.setInitialValue?.(data.length > 0 ? data : [{}]);
|
||||||
} else if (
|
} else if (
|
||||||
collectionField?.interface === 'o2m' &&
|
collectionField?.interface === 'o2m' &&
|
||||||
['SubTable', 'Nester'].includes(schema?.['x-component-props']?.['mode']) // 间接对多
|
['SubTable', 'Nester'].includes(schema?.['x-component-props']?.['mode']) // 间接对多
|
||||||
@ -86,15 +100,19 @@ export const FormItem: any = observer(
|
|||||||
const childrenFieldWithDefault = findColumnFieldSchema(schema, getCollectionJoinField);
|
const childrenFieldWithDefault = findColumnFieldSchema(schema, getCollectionJoinField);
|
||||||
// 子表格/子表单中找出所有belongsTo字段的上下文默认值
|
// 子表格/子表单中找出所有belongsTo字段的上下文默认值
|
||||||
if (childrenFieldWithDefault.length > 0) {
|
if (childrenFieldWithDefault.length > 0) {
|
||||||
const contextData = parseVariables('{{$context}}', variablesCtx);
|
const tableData = parseVariables('{{$context}}', variablesCtx);
|
||||||
const initValues = contextData?.map((v) => {
|
const contextData = {};
|
||||||
const obj = {};
|
// 将数据拍平
|
||||||
childrenFieldWithDefault.forEach((s: any) => {
|
childrenFieldWithDefault?.forEach((s: any) => {
|
||||||
const child = JSON.parse(s);
|
const child = JSON.parse(s);
|
||||||
obj[child.name] = parseVariables(child.default, { $context: v });
|
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);
|
field.setInitialValue?.(initValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ import {
|
|||||||
useGlobalTheme,
|
useGlobalTheme,
|
||||||
useLinkageCollectionFilterOptions,
|
useLinkageCollectionFilterOptions,
|
||||||
useSortFields,
|
useSortFields,
|
||||||
|
useActionContext,
|
||||||
} from '..';
|
} from '..';
|
||||||
import { useTableBlockContext } from '../block-provider';
|
import { useTableBlockContext } from '../block-provider';
|
||||||
import { findFilterTargets, updateFilterTargets } from '../block-provider/hooks';
|
import { findFilterTargets, updateFilterTargets } from '../block-provider/hooks';
|
||||||
@ -1449,6 +1450,7 @@ SchemaSettings.DefaultValue = function DefaultValueConfigure(props) {
|
|||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const actionCtx = useActionContext();
|
||||||
let targetField;
|
let targetField;
|
||||||
const { getField } = useCollection();
|
const { getField } = useCollection();
|
||||||
const { getCollectionJoinField } = useCollectionManager();
|
const { getCollectionJoinField } = useCollectionManager();
|
||||||
@ -1462,10 +1464,10 @@ SchemaSettings.DefaultValue = function DefaultValueConfigure(props) {
|
|||||||
const parentFieldSchema = collectionField?.interface === 'm2o' && findParentFieldSchema(fieldSchema);
|
const parentFieldSchema = collectionField?.interface === 'm2o' && findParentFieldSchema(fieldSchema);
|
||||||
const parentCollectionField = parentFieldSchema && getCollectionJoinField(parentFieldSchema?.['x-collection-field']);
|
const parentCollectionField = parentFieldSchema && getCollectionJoinField(parentFieldSchema?.['x-collection-field']);
|
||||||
const tableCtx = useTableBlockContext();
|
const tableCtx = useTableBlockContext();
|
||||||
const isAllowContextVariable =
|
const isAllowContexVariable =
|
||||||
collectionField?.interface === 'm2m' ||
|
actionCtx?.fieldSchema?.['x-action'] === 'customize:create' &&
|
||||||
(parentCollectionField?.type === 'hasMany' && collectionField?.interface === 'm2o');
|
(collectionField?.interface === 'm2m' ||
|
||||||
|
(parentCollectionField?.type === 'hasMany' && collectionField?.interface === 'm2o'));
|
||||||
return (
|
return (
|
||||||
<SchemaSettings.ModalItem
|
<SchemaSettings.ModalItem
|
||||||
title={t('Set default value')}
|
title={t('Set default value')}
|
||||||
@ -1482,7 +1484,7 @@ SchemaSettings.DefaultValue = function DefaultValueConfigure(props) {
|
|||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
...(fieldSchema?.['x-component-props'] || {}),
|
...(fieldSchema?.['x-component-props'] || {}),
|
||||||
collectionField,
|
collectionField,
|
||||||
contextCollectionName: isAllowContextVariable && tableCtx.collection,
|
contextCollectionName: isAllowContexVariable && tableCtx.collection,
|
||||||
schema: collectionField?.uiSchema,
|
schema: collectionField?.uiSchema,
|
||||||
className: defaultInputStyle,
|
className: defaultInputStyle,
|
||||||
renderSchemaComponent: function Com(props) {
|
renderSchemaComponent: function Com(props) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { CollectionFieldOptions } from '../../collection-manager';
|
import { CollectionFieldOptions } from '../../collection-manager';
|
||||||
import { useCompile, Variable } from '../../schema-component';
|
import { useCompile, Variable } from '../../schema-component';
|
||||||
import { useContextAssociationFields } from './hooks/useContextAssociationFields';
|
import { useContextAssociationFields, useIsSameOrChildCollection } from './hooks/useContextAssociationFields';
|
||||||
import { useUserVariable } from './hooks/useUserVariable';
|
import { useUserVariable } from './hooks/useUserVariable';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -31,7 +31,9 @@ export const VariableInput = (props: Props) => {
|
|||||||
} = props;
|
} = props;
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const userVariable = useUserVariable({ schema, maxDepth: 1 });
|
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 scope = useMemo(() => {
|
||||||
const data = [
|
const data = [
|
||||||
compile({
|
compile({
|
||||||
@ -64,7 +66,7 @@ export const VariableInput = (props: Props) => {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
scope={scope}
|
scope={scope}
|
||||||
style={style}
|
style={style}
|
||||||
changeOnSelect={contextCollectionName !== null}
|
changeOnSelect={isAllowTableContext}
|
||||||
>
|
>
|
||||||
<RenderSchemaComponent value={value} onChange={onChange} />
|
<RenderSchemaComponent value={value} onChange={onChange} />
|
||||||
</Variable.Input>
|
</Variable.Input>
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
import { error } from '@nocobase/utils/client';
|
import { error } from '@nocobase/utils/client';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useCollectionManager, CollectionFieldOptions } from '../../../collection-manager';
|
||||||
import { useCompile, useGetFilterOptions } from '../../../schema-component';
|
import { useCompile, useGetFilterOptions } from '../../../schema-component';
|
||||||
import { FieldOption, Option } from '../type';
|
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 {
|
interface GetOptionsParams {
|
||||||
schema: any;
|
schema: any;
|
||||||
depth: number;
|
depth: number;
|
||||||
@ -15,37 +28,40 @@ interface GetOptionsParams {
|
|||||||
const getChildren = (
|
const getChildren = (
|
||||||
options: FieldOption[],
|
options: FieldOption[],
|
||||||
{ schema, depth, maxDepth, loadChildren, compile }: GetOptionsParams,
|
{ schema, depth, maxDepth, loadChildren, compile }: GetOptionsParams,
|
||||||
|
collectionField,
|
||||||
|
getIsSameOrChildCollection,
|
||||||
): Option[] => {
|
): Option[] => {
|
||||||
const result = options
|
const result = options
|
||||||
.map((option): Option => {
|
.map(
|
||||||
if (!option.target) {
|
(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 {
|
return {
|
||||||
key: option.name,
|
key: option.name,
|
||||||
value: option.name,
|
value: option.name,
|
||||||
label: compile(option.title),
|
label: compile(option.title),
|
||||||
// TODO: 现在是通过组件的名称来过滤能够被选择的选项,这样的坏处是不够精确,后续可以优化
|
disabled: disabled,
|
||||||
// disabled: schema?.['x-component'] !== option.schema?.['x-component'],
|
|
||||||
isLeaf: true,
|
isLeaf: true,
|
||||||
|
field: option,
|
||||||
depth,
|
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);
|
.filter(Boolean);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,15 +69,17 @@ export const useContextAssociationFields = ({
|
|||||||
schema,
|
schema,
|
||||||
maxDepth = 3,
|
maxDepth = 3,
|
||||||
contextCollectionName,
|
contextCollectionName,
|
||||||
|
collectionField,
|
||||||
}: {
|
}: {
|
||||||
schema: any;
|
schema: any;
|
||||||
maxDepth?: number;
|
maxDepth?: number;
|
||||||
contextCollectionName: string;
|
contextCollectionName: string;
|
||||||
|
collectionField: CollectionFieldOptions;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const getFilterOptions = useGetFilterOptions();
|
const getFilterOptions = useGetFilterOptions();
|
||||||
|
const getIsSameOrChildCollection = useIsSameOrChildCollection();
|
||||||
const loadChildren = (option: Option): Promise<void> => {
|
const loadChildren = (option: Option): Promise<void> => {
|
||||||
if (!option.field?.target) {
|
if (!option.field?.target) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@ -87,6 +105,8 @@ export const useContextAssociationFields = ({
|
|||||||
loadChildren,
|
loadChildren,
|
||||||
compile,
|
compile,
|
||||||
},
|
},
|
||||||
|
collectionField,
|
||||||
|
getIsSameOrChildCollection,
|
||||||
) || [];
|
) || [];
|
||||||
|
|
||||||
if (children.length === 0) {
|
if (children.length === 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user