refactor: 跟踪上游,(refactor: change useProps to x-use-component-props (#3853)) (#629)

Reviewed-on: daoyoucloud/tachycode#629
Co-authored-by: bai.jingfeng <bai.jingfeng@foxmail.com>
Co-committed-by: bai.jingfeng <bai.jingfeng@foxmail.com>
This commit is contained in:
bai.jingfeng 2024-04-08 17:09:14 +08:00 committed by sealday
parent bab77e28ac
commit 799603f9f2
94 changed files with 796 additions and 1036 deletions

View File

@ -1,262 +0,0 @@
import { ISchema } from '@nocobase/schema';
import { uid } from '@nocobase/schema';
import { useRoleResourceValues } from './useRoleResourceValues';
import { useSaveRoleResourceAction } from './useSaveRoleResourceAction';
const collection = {
name: 'collections',
targetKey: 'name',
filterTargetKey: 'name',
fields: [
{
type: 'integer',
name: 'title',
interface: 'input',
uiSchema: {
title: '{{t("Collection display name")}}',
type: 'number',
'x-component': 'Input',
required: true,
} as ISchema,
},
{
type: 'string',
name: 'name',
interface: 'input',
uiSchema: {
title: '{{t("Collection name")}}',
type: 'string',
'x-component': 'Input',
} as ISchema,
},
{
type: 'string',
name: 'type',
interface: 'input',
uiSchema: {
title: '{{t("Resource type")}}',
type: 'string',
'x-component': 'Select',
enum: [
{ label: '{{t("Collection")}}', value: 'collection', color: 'green' },
{ label: '{{t("Association")}}', value: 'association', color: 'blue' },
],
} as ISchema,
},
{
type: 'string',
name: 'usingConfig',
interface: 'input',
uiSchema: {
title: '{{t("Permission policy")}}',
type: 'string',
'x-component': 'Select',
enum: [
{ label: '{{t("Individual")}}', value: 'resourceAction', color: 'orange' },
{ label: '{{t("General")}}', value: 'strategy', color: 'default' },
],
} as ISchema,
},
{
type: 'hasMany',
name: 'fields',
target: 'fields',
collectionName: 'collections',
sourceKey: 'name',
targetKey: 'name',
uiSchema: {},
},
],
};
export const roleCollectionsSchema: ISchema = {
type: 'void',
'x-decorator': 'ResourceActionProvider',
'x-decorator-props': {
collection,
association: {
sourceKey: 'name',
targetKey: 'name',
},
resourceName: 'roles.collections',
request: {
resource: 'roles.collections',
action: 'list',
params: {
pageSize: 20,
filter: { hidden: { $isFalsy: true } },
sort: ['sort'],
appends: [],
},
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
},
properties: {
filter: {
type: 'void',
title: '{{ t("Filter") }}',
default: {
$and: [{ title: { $includes: '' } }, { name: { $includes: '' } }],
},
'x-action': 'filter',
'x-component': 'Filter.Action',
'x-component-props': {
icon: 'FilterOutlined',
useProps: '{{ cm.useFilterActionProps }}',
},
'x-align': 'left',
},
},
},
table1: {
type: 'void',
'x-uid': 'input',
'x-component': 'Table.Void',
'x-component-props': {
rowKey: 'name',
// rowSelection: {
// type: 'checkbox',
// },
useDataSource: '{{ cm.useDataSourceFromRAC }}',
},
properties: {
column0: {
type: 'void',
'x-decorator': 'Table.Column.Decorator',
'x-component': 'Table.Column',
properties: {
title: {
type: 'number',
'x-component': 'CollectionField',
'x-read-pretty': true,
},
},
},
// column1: {
// type: 'void',
// 'x-decorator': 'Table.Column.Decorator',
// 'x-component': 'Table.Column',
// properties: {
// type: {
// type: 'string',
// 'x-component': 'CollectionField',
// 'x-read-pretty': true,
// },
// },
// },
column2: {
type: 'void',
'x-decorator': 'Table.Column.Decorator',
'x-component': 'Table.Column',
properties: {
name: {
type: 'string',
'x-component': 'CollectionField',
'x-read-pretty': true,
},
},
},
column3: {
type: 'void',
'x-decorator': 'Table.Column.Decorator',
'x-component': 'Table.Column',
properties: {
usingConfig: {
type: 'string',
'x-component': 'CollectionField',
'x-read-pretty': true,
},
},
},
column4: {
type: 'void',
title: '{{t("Actions")}}',
'x-component': 'Table.Column',
properties: {
actions: {
type: 'void',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
properties: {
configure: {
type: 'void',
title: '{{t("Configure")}}',
'x-component': 'Action.Link',
'x-component-props': {
type: 'primary',
},
properties: {
drawer: {
type: 'void',
'x-component': 'Action.Drawer',
'x-decorator': 'Form',
'x-decorator-props': {
useValues: useRoleResourceValues,
},
title: '{{t("Configure permission")}}',
properties: {
usingActionsConfig: {
title: '{{t("Permission policy")}}',
'x-component': 'Radio.Group',
'x-decorator': 'FormItem',
default: false,
enum: [
{ value: false, label: '{{t("General")}}' },
{ value: true, label: '{{t("Individual")}}' },
],
'x-reactions': {
target: 'actions',
fulfill: {
state: {
hidden: '{{!$self.value}}',
},
},
},
},
actions: {
'x-component': 'RolesResourcesActions',
'x-decorator': 'FormItem',
},
footer: {
type: 'void',
'x-component': 'Action.Drawer.Footer',
properties: {
cancel: {
title: '{{t("Cancel")}}',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ cm.useCancelAction }}',
},
},
submit: {
title: '{{t("Submit")}}',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: useSaveRoleResourceAction,
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
};

View File

@ -5,7 +5,6 @@ import { useEffect } from 'react';
import { useRequest } from '../../../api-client'; import { useRequest } from '../../../api-client';
import { useRecord } from '../../../record-provider'; import { useRecord } from '../../../record-provider';
import { useActionContext } from '../../../schema-component'; import { useActionContext } from '../../../schema-component';
import { roleCollectionsSchema } from './roleCollections';
const collection = { const collection = {
name: 'roles', name: 'roles',

View File

@ -124,9 +124,7 @@ export const scopesSchema: ISchema = {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': useFormBlockProps,
useProps: useFormBlockProps,
},
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
@ -139,15 +137,17 @@ export const scopesSchema: ISchema = {
name: 'filter', name: 'filter',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ctx = useContext(RoleResourceCollectionContext);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useFilterOptions(ctx.name);
return {
options,
};
},
'x-component-props': { 'x-component-props': {
dynamicComponent: VariableInput, dynamicComponent: VariableInput,
useProps() {
const ctx = useContext(RoleResourceCollectionContext);
const options = useFilterOptions(ctx.name);
return {
options,
};
},
}, },
}, },
actions: { actions: {
@ -164,10 +164,10 @@ export const scopesSchema: ISchema = {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCreateActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useCreateActionProps }}',
}, },
}, },
}, },
@ -185,12 +185,12 @@ export const scopesSchema: ISchema = {
value: { value: {
type: 'array', type: 'array',
'x-component': 'TableV2.Selector', 'x-component': 'TableV2.Selector',
'x-use-component-props': 'useTableSelectorProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableSelectorProps }}',
}, },
properties: { properties: {
column1: { column1: {
@ -252,9 +252,7 @@ export const scopesSchema: ISchema = {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
@ -267,15 +265,17 @@ export const scopesSchema: ISchema = {
name: 'filter', name: 'filter',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ctx = useContext(RoleResourceCollectionContext);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useFilterOptions(ctx.name);
return {
options,
};
},
'x-component-props': { 'x-component-props': {
dynamicComponent: VariableInput, dynamicComponent: VariableInput,
useProps() {
const ctx = useContext(RoleResourceCollectionContext);
const options = useFilterOptions(ctx.name);
return {
options,
};
},
}, },
}, },
actions: { actions: {
@ -292,10 +292,10 @@ export const scopesSchema: ISchema = {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useUpdateActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useUpdateActionProps }}',
}, },
}, },
}, },
@ -313,13 +313,13 @@ export const scopesSchema: ISchema = {
'x-action': 'destroy', 'x-action': 'destroy',
'x-decorator': 'ACLActionProvider', 'x-decorator': 'ACLActionProvider',
'x-component': 'Action.Link', 'x-component': 'Action.Link',
'x-use-component-props': 'useDestroyActionProps',
'x-component-props': { 'x-component-props': {
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
confirm: { confirm: {
title: "{{t('Delete record')}}", title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}", content: "{{t('Are you sure you want to delete it?')}}",
}, },
useProps: '{{ useDestroyActionProps }}',
}, },
}, },
}, },
@ -343,10 +343,10 @@ export const scopesSchema: ISchema = {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'usePickActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ usePickActionProps }}',
}, },
}, },
}, },

View File

@ -1,6 +1,7 @@
import { useExpressionScope } from '@nocobase/schema'; import { useExpressionScope } from '@nocobase/schema';
import React, { ComponentType, useMemo } from 'react'; import React, { ComponentType, useMemo } from 'react';
import { useDesignable } from '../../schema-component'; import { useDesignable } from '../../schema-component';
import _ from 'lodash';
const useDefaultSchemaProps = () => undefined; const useDefaultSchemaProps = () => undefined;
@ -28,14 +29,35 @@ export function withDynamicSchemaProps<T = any>(Component: any, options: WithSch
} }
}, [dn]); }, [dn]);
const useSchemaProps = useMemo(() => { const useSchemaProps = useMemo(() => {
let res = undefined; const getHook = (str: string, scope: Record<string, any>, allText: string) => {
if (useComponentPropsStr) { let res = undefined;
res = scope[useComponentPropsStr]; if (_.isFunction(str)) {
if (!res) { res = str;
console.error(`${useComponentPropsStr} is not registered`); } else {
res = scope[str];
if (!res) {
console.error(`${allText} is not registered`);
}
} }
return res || useDefaultSchemaProps;
};
if (!useComponentPropsStr) {
return useDefaultSchemaProps;
} }
return res || useDefaultSchemaProps;
if (_.isFunction(useComponentPropsStr)) {
return useComponentPropsStr;
}
const pathList = useComponentPropsStr.split('.');
let result;
for (const item of pathList) {
result = getHook(item, result || scope, useComponentPropsStr);
}
return result;
}, [scope, useComponentPropsStr]); }, [scope, useComponentPropsStr]);
const schemaProps = useSchemaProps(props); const schemaProps = useSchemaProps(props);
@ -43,6 +65,7 @@ export function withDynamicSchemaProps<T = any>(Component: any, options: WithSch
return { ...props, ...schemaProps }; return { ...props, ...schemaProps };
}, [schemaProps, props]); }, [schemaProps, props]);
// @ts-ignore
return <Component {...memoProps}>{props.children}</Component>; return <Component {...memoProps}>{props.children}</Component>;
}; };

View File

@ -50,11 +50,11 @@ export class SubTableFieldInterface extends CollectionFieldInterface {
type: 'array', type: 'array',
'x-initializer': 'table:configureColumns', 'x-initializer': 'table:configureColumns',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableFieldProps',
'x-component-props': { 'x-component-props': {
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableFieldProps }}',
}, },
}, },
}, },

View File

@ -15,13 +15,13 @@ export const BulkDestroyActionInitializer = (props) => {
'x-acl-action-props': { 'x-acl-action-props': {
skipScopeCheck: true, skipScopeCheck: true,
}, },
'x-use-component-props': 'useBulkDestroyActionProps',
'x-component-props': { 'x-component-props': {
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
confirm: { confirm: {
title: "{{t('Delete record')}}", title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}", content: "{{t('Are you sure you want to delete it?')}}",
}, },
useProps: '{{ useBulkDestroyActionProps }}',
}, },
'x-action-settings': { 'x-action-settings': {
triggerWorkflows: [], triggerWorkflows: [],

View File

@ -7,6 +7,7 @@ export const DestroyActionInitializer = (props) => {
title: '{{ t("Delete") }}', title: '{{ t("Delete") }}',
'x-action': 'destroy', 'x-action': 'destroy',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useDestroyActionProps',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:delete', 'x-settings': 'actionSettings:delete',
'x-component-props': { 'x-component-props': {
@ -15,7 +16,6 @@ export const DestroyActionInitializer = (props) => {
title: "{{t('Delete record')}}", title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}", content: "{{t('Are you sure you want to delete it?')}}",
}, },
useProps: '{{ useDestroyActionProps }}',
}, },
'x-action-settings': { 'x-action-settings': {
triggerWorkflows: [], triggerWorkflows: [],

View File

@ -7,6 +7,7 @@ export const DisassociateActionInitializer = (props) => {
title: '{{ t("Disassociate") }}', title: '{{ t("Disassociate") }}',
'x-action': 'disassociate', 'x-action': 'disassociate',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useDisassociateActionProps',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:disassociate', 'x-settings': 'actionSettings:disassociate',
'x-component-props': { 'x-component-props': {
@ -15,7 +16,6 @@ export const DisassociateActionInitializer = (props) => {
title: "{{t('Disassociate record')}}", title: "{{t('Disassociate record')}}",
content: "{{t('Are you sure you want to disassociate it?')}}", content: "{{t('Are you sure you want to disassociate it?')}}",
}, },
useProps: '{{ useDisassociateActionProps }}',
}, },
'x-action-settings': { 'x-action-settings': {
triggerWorkflows: [], triggerWorkflows: [],

View File

@ -10,9 +10,9 @@ export const FilterActionInitializer = (props) => {
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:filter', 'x-settings': 'actionSettings:filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ useFilterActionProps }}',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;

View File

@ -6,11 +6,11 @@ export const RefreshActionInitializer = (props) => {
title: '{{ t("Refresh") }}', title: '{{ t("Refresh") }}',
'x-action': 'refresh', 'x-action': 'refresh',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useRefreshActionProps',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:refresh', 'x-settings': 'actionSettings:refresh',
'x-component-props': { 'x-component-props': {
icon: 'ReloadOutlined', icon: 'ReloadOutlined',
useProps: '{{ useRefreshActionProps }}',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;

View File

@ -7,6 +7,7 @@ export const SaveRecordActionInitializer = () => {
title: '{{ t("Save record") }}', title: '{{ t("Save record") }}',
'x-action': 'customize:save', 'x-action': 'customize:save',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCreateActionProps',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:saveRecord', 'x-settings': 'actionSettings:saveRecord',
'x-designer-props': { 'x-designer-props': {
@ -23,9 +24,6 @@ export const SaveRecordActionInitializer = () => {
}, },
triggerWorkflows: [], triggerWorkflows: [],
}, },
'x-component-props': {
useProps: '{{ useCreateActionProps }}',
},
}; };
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();

View File

@ -6,12 +6,12 @@ export const CreateSubmitActionInitializer = (props) => {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCreateActionProps',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:createSubmit', 'x-settings': 'actionSettings:createSubmit',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useCreateActionProps }}',
}, },
'x-action-settings': { 'x-action-settings': {
triggerWorkflows: [], triggerWorkflows: [],

View File

@ -7,13 +7,13 @@ export const UpdateSubmitActionInitializer = (props) => {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useUpdateActionProps',
// 'x-designer': 'Action.Designer', // 'x-designer': 'Action.Designer',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:updateSubmit', 'x-settings': 'actionSettings:updateSubmit',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useUpdateActionProps }}',
}, },
'x-action-settings': { 'x-action-settings': {
triggerWorkflows: [], triggerWorkflows: [],

View File

@ -6,6 +6,7 @@ export const UpdateRecordActionInitializer = (props) => {
const schema = { const schema = {
title: '{{ t("Update record") }}', title: '{{ t("Update record") }}',
'x-component': props?.['x-component'] || 'Action.Link', 'x-component': props?.['x-component'] || 'Action.Link',
'x-use-component-props': 'useCustomizeUpdateActionProps',
'x-action': 'customize:update', 'x-action': 'customize:update',
'x-decorator': 'ACLActionProvider', 'x-decorator': 'ACLActionProvider',
'x-acl-action': 'update', 'x-acl-action': 'update',
@ -21,9 +22,6 @@ export const UpdateRecordActionInitializer = (props) => {
}, },
triggerWorkflows: [], triggerWorkflows: [],
}, },
'x-component-props': {
useProps: '{{ useCustomizeUpdateActionProps }}',
},
}; };
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();

View File

@ -80,7 +80,7 @@ export const filterCollapseItemFieldSettings = new SchemaSettings({
checked: field.componentProps.defaultCollapse, checked: field.componentProps.defaultCollapse,
onChange: (v) => { onChange: (v) => {
field.componentProps.defaultCollapse = v; field.componentProps.defaultCollapse = v;
fieldSchema['x-component-props']['defaultCollapse'] = v; _.set(fieldSchema, 'x-component-props.defaultCollapse', v);
dn.emit('patch', { dn.emit('patch', {
schema: { schema: {
['x-uid']: fieldSchema['x-uid'], ['x-uid']: fieldSchema['x-uid'],

View File

@ -19,7 +19,6 @@ export const associationFilterFilterBlockInitializer = new SchemaInitializer({
title: '{{t("Association fields")}}', title: '{{t("Association fields")}}',
useChildren() { useChildren() {
const associatedFields = useAssociatedFields(); const associatedFields = useAssociatedFields();
const useProps = '{{useAssociationFilterBlockProps}}';
const children = associatedFields.map((field) => ({ const children = associatedFields.map((field) => ({
name: field.key, name: field.key,
title: field.uiSchema?.title, title: field.uiSchema?.title,
@ -32,11 +31,11 @@ export const associationFilterFilterBlockInitializer = new SchemaInitializer({
'x-toolbar': 'CollapseItemSchemaToolbar', 'x-toolbar': 'CollapseItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterCollapseItem', 'x-settings': 'fieldSettings:FilterCollapseItem',
'x-component': 'AssociationFilter.Item', 'x-component': 'AssociationFilter.Item',
'x-use-component-props': 'useAssociationFilterBlockProps',
'x-component-props': { 'x-component-props': {
fieldNames: { fieldNames: {
label: field.targetKey || 'id', label: field.targetKey || 'id',
}, },
useProps,
}, },
properties: {}, properties: {},
}, },
@ -96,7 +95,6 @@ export const filterCollapseItemInitializer_deprecated = new CompatibleSchemaInit
title: '{{t("Association fields")}}', title: '{{t("Association fields")}}',
useChildren() { useChildren() {
const associatedFields = useAssociatedFields(); const associatedFields = useAssociatedFields();
const useProps = '{{useAssociationFilterBlockProps}}';
const cm = useCollectionManager_deprecated(); const cm = useCollectionManager_deprecated();
const children = associatedFields.map((field) => ({ const children = associatedFields.map((field) => ({
name: field.key, name: field.key,
@ -110,11 +108,11 @@ export const filterCollapseItemInitializer_deprecated = new CompatibleSchemaInit
'x-toolbar': 'CollapseItemSchemaToolbar', 'x-toolbar': 'CollapseItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterCollapseItem', 'x-settings': 'fieldSettings:FilterCollapseItem',
'x-component': 'AssociationFilter.Item', 'x-component': 'AssociationFilter.Item',
'x-use-component-props': 'useAssociationFilterBlockProps',
'x-component-props': { 'x-component-props': {
fieldNames: { fieldNames: {
label: cm.getCollection(field.target)?.getPrimaryKey() || 'id', label: cm.getCollection(field.target)?.getPrimaryKey() || 'id',
}, },
useProps,
}, },
properties: {}, properties: {},
}, },
@ -129,7 +127,6 @@ export const filterCollapseItemInitializer_deprecated = new CompatibleSchemaInit
hideIfNoChildren: true, hideIfNoChildren: true,
useChildren() { useChildren() {
const optionalList = useOptionalFieldList(); const optionalList = useOptionalFieldList();
const useProps = '{{useAssociationFilterBlockProps}}';
const optionalChildren = optionalList.map((field) => ({ const optionalChildren = optionalList.map((field) => ({
name: field.key, name: field.key,
title: field.uiSchema.title, title: field.uiSchema.title,
@ -143,11 +140,11 @@ export const filterCollapseItemInitializer_deprecated = new CompatibleSchemaInit
'x-toolbar': 'CollapseItemSchemaToolbar', 'x-toolbar': 'CollapseItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterCollapseItem', 'x-settings': 'fieldSettings:FilterCollapseItem',
'x-component': 'AssociationFilter.Item', 'x-component': 'AssociationFilter.Item',
'x-use-component-props': 'useAssociationFilterBlockProps',
'x-component-props': { 'x-component-props': {
fieldNames: { fieldNames: {
label: field.name, label: field.name,
}, },
useProps,
}, },
properties: {}, properties: {},
}, },
@ -172,7 +169,6 @@ export const filterCollapseItemInitializer = new CompatibleSchemaInitializer(
title: '{{t("Association fields")}}', title: '{{t("Association fields")}}',
useChildren() { useChildren() {
const associatedFields = useAssociatedFields(); const associatedFields = useAssociatedFields();
const useProps = '{{useAssociationFilterBlockProps}}';
const cm = useCollectionManager_deprecated(); const cm = useCollectionManager_deprecated();
const children = associatedFields.map((field) => ({ const children = associatedFields.map((field) => ({
name: field.key, name: field.key,
@ -186,11 +182,11 @@ export const filterCollapseItemInitializer = new CompatibleSchemaInitializer(
'x-toolbar': 'CollapseItemSchemaToolbar', 'x-toolbar': 'CollapseItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterCollapseItem', 'x-settings': 'fieldSettings:FilterCollapseItem',
'x-component': 'AssociationFilter.Item', 'x-component': 'AssociationFilter.Item',
'x-use-component-props': 'useAssociationFilterBlockProps',
'x-component-props': { 'x-component-props': {
fieldNames: { fieldNames: {
label: cm.getCollection(field.target)?.getPrimaryKey() || 'id', label: cm.getCollection(field.target)?.getPrimaryKey() || 'id',
}, },
useProps,
}, },
properties: {}, properties: {},
}, },
@ -205,7 +201,6 @@ export const filterCollapseItemInitializer = new CompatibleSchemaInitializer(
hideIfNoChildren: true, hideIfNoChildren: true,
useChildren() { useChildren() {
const optionalList = useOptionalFieldList(); const optionalList = useOptionalFieldList();
const useProps = '{{useAssociationFilterBlockProps}}';
const optionalChildren = optionalList.map((field) => ({ const optionalChildren = optionalList.map((field) => ({
name: field.key, name: field.key,
title: field.uiSchema.title, title: field.uiSchema.title,
@ -219,11 +214,11 @@ export const filterCollapseItemInitializer = new CompatibleSchemaInitializer(
'x-toolbar': 'CollapseItemSchemaToolbar', 'x-toolbar': 'CollapseItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterCollapseItem', 'x-settings': 'fieldSettings:FilterCollapseItem',
'x-component': 'AssociationFilter.Item', 'x-component': 'AssociationFilter.Item',
'x-use-component-props': 'useAssociationFilterBlockProps',
'x-component-props': { 'x-component-props': {
fieldNames: { fieldNames: {
label: field.name, label: field.name,
}, },
useProps,
}, },
properties: {}, properties: {},
}, },

View File

@ -3,12 +3,13 @@ import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import Action from './Action'; import Action from './Action';
import { ComposedAction } from './types'; import { ComposedAction } from './types';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export const ActionLink: ComposedAction = observer( export const ActionLink: ComposedAction = withDynamicSchemaProps(
(props: any) => { observer((props: any) => {
return ( return (
<Action {...props} component={props.component || 'a'} className={classnames('nb-action-link', props.className)} /> <Action {...props} component={props.component || 'a'} className={classnames('nb-action-link', props.className)} />
); );
}, }),
{ displayName: 'ActionLink' }, { displayName: 'ActionLink' },
); );

View File

@ -26,9 +26,10 @@ import { useA } from './hooks';
import { useGetAriaLabelOfAction } from './hooks/useGetAriaLabelOfAction'; import { useGetAriaLabelOfAction } from './hooks/useGetAriaLabelOfAction';
import { ComposedAction } from './types'; import { ComposedAction } from './types';
import { linkageAction } from './utils'; import { linkageAction } from './utils';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export const Action: ComposedAction = observer( export const Action: ComposedAction = withDynamicSchemaProps(
(props: any) => { observer((props: any) => {
const { const {
popover, popover,
confirm, confirm,
@ -47,7 +48,7 @@ export const Action: ComposedAction = observer(
/** 如果为 true 则说明该按钮是树表格的 Add child 按钮 */ /** 如果为 true 则说明该按钮是树表格的 Add child 按钮 */
addChild, addChild,
...others ...others
} = useProps(props); } = useProps(props); // 新版 UISchema1.0 之后)中已经废弃了 useProps这里之所以继续保留是为了兼容旧版的 UISchema
const aclCtx = useACLActionParamsContext(); const aclCtx = useACLActionParamsContext();
const { wrapSSR, componentCls, hashId } = useStyles(); const { wrapSSR, componentCls, hashId } = useStyles();
const { t } = useTranslation(); const { t } = useTranslation();
@ -181,7 +182,7 @@ export const Action: ComposedAction = observer(
} }
return wrapSSR(result); return wrapSSR(result);
}, }),
{ displayName: 'Action' }, { displayName: 'Action' },
); );

View File

@ -3,6 +3,7 @@ import { ISchema, observer, useField, useFieldSchema } from '@nocobase/schema';
import { Action, SchemaComponent, SchemaComponentProvider, useActionContext } from '@nocobase/client'; import { Action, SchemaComponent, SchemaComponentProvider, useActionContext } from '@nocobase/client';
import { Radio } from 'antd'; import { Radio } from 'antd';
import React, { useRef } from 'react'; import React, { useRef } from 'react';
import _ from 'lodash';
const useCloseAction = () => { const useCloseAction = () => {
const { setVisible } = useActionContext(); const { setVisible } = useActionContext();
@ -25,7 +26,7 @@ const Editable = observer(
value={field.componentProps.openMode} value={field.componentProps.openMode}
onChange={(e) => { onChange={(e) => {
field.componentProps.openMode = e.target.value; field.componentProps.openMode = e.target.value;
schema['x-component-props']['openMode'] = e.target.value; _.set(schema, 'x-component-props.openMode', e.target.value);
}} }}
> >
<Radio.Button value="drawer">Drawer</Radio.Button> <Radio.Button value="drawer">Drawer</Radio.Button>

View File

@ -145,8 +145,8 @@ const InternalFileManager = (props) => {
<FileSelector <FileSelector
value={options} value={options}
multiple={multiple} multiple={multiple}
quickUpload={fieldSchema['x-component-props'].quickUpload !== false} quickUpload={fieldSchema['x-component-props']?.quickUpload !== false}
selectFile={fieldSchema['x-component-props'].selectFile !== false} selectFile={fieldSchema['x-component-props']?.selectFile !== false}
action={`${collectionField?.target}:create`} action={`${collectionField?.target}:create`}
onSelect={handleSelect} onSelect={handleSelect}
onRemove={handleRemove} onRemove={handleRemove}

View File

@ -71,13 +71,13 @@ export default {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'usePickActionProps',
// 'x-designer': 'Action.Designer', // 'x-designer': 'Action.Designer',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:submit', 'x-settings': 'actionSettings:submit',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ usePickActionProps }}',
}, },
}, },
}, },

View File

@ -19,7 +19,6 @@ export const associationFilterInitializer = new SchemaInitializer({
title: '{{t("Association fields")}}', title: '{{t("Association fields")}}',
useChildren() { useChildren() {
const associatedFields = useAssociatedFields(); const associatedFields = useAssociatedFields();
const useProps = '{{useAssociationFilterProps}}';
const children: SchemaInitializerItemType[] = associatedFields.map((field) => ({ const children: SchemaInitializerItemType[] = associatedFields.map((field) => ({
type: 'item', type: 'item',
name: field.key, name: field.key,
@ -33,11 +32,11 @@ export const associationFilterInitializer = new SchemaInitializer({
'x-toolbar': 'CollapseItemSchemaToolbar', 'x-toolbar': 'CollapseItemSchemaToolbar',
'x-settings': 'fieldSettings:FilterCollapseItem', 'x-settings': 'fieldSettings:FilterCollapseItem',
'x-component': 'AssociationFilter.Item', 'x-component': 'AssociationFilter.Item',
'x-use-component-props': 'useAssociationFilterProps',
'x-component-props': { 'x-component-props': {
fieldNames: { fieldNames: {
label: field.targetKey || 'id', label: field.targetKey || 'id',
}, },
useProps,
}, },
properties: {}, properties: {},
}, },

View File

@ -95,7 +95,7 @@ export const AssociationFilterItemDesigner = (props) => {
checked={field.componentProps.defaultCollapse} checked={field.componentProps.defaultCollapse}
onChange={(v) => { onChange={(v) => {
field.componentProps.defaultCollapse = v; field.componentProps.defaultCollapse = v;
fieldSchema['x-component-props']['defaultCollapse'] = v; _.set(fieldSchema, 'x-component-props.defaultCollapse', v);
dn.emit('patch', { dn.emit('patch', {
schema: { schema: {
['x-uid']: fieldSchema['x-uid'], ['x-uid']: fieldSchema['x-uid'],

View File

@ -10,148 +10,152 @@ import { EllipsisWithTooltip } from '../input';
import { getLabelFormatValue, useLabelUiSchema } from '../record-picker'; import { getLabelFormatValue, useLabelUiSchema } from '../record-picker';
import { AssociationFilter } from './AssociationFilter'; import { AssociationFilter } from './AssociationFilter';
import useStyles from './AssociationFilter.Item.style'; import useStyles from './AssociationFilter.Item.style';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
const { Panel } = Collapse; const { Panel } = Collapse;
export const AssociationFilterItem = (props) => { export const AssociationFilterItem = withDynamicSchemaProps(
const { wrapSSR, componentCls, hashId } = useStyles(); (props) => {
const { token } = useToken(); const { wrapSSR, componentCls, hashId } = useStyles();
const collectionField = AssociationFilter.useAssociationField(); const { token } = useToken();
const collectionField = AssociationFilter.useAssociationField();
// 把一些可定制的状态通过 hook 提取出去了,为了兼容之前添加的 Table 区块,这里加了个默认值 // 把一些可定制的状态通过 hook 提取出去了,为了兼容之前添加的 Table 区块,这里加了个默认值
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const Designer = useDesigner(); const Designer = useDesigner();
const compile = useCompile(); const compile = useCompile();
const { const {
list, list,
onSelected, onSelected,
handleSearchInput: _handleSearchInput, handleSearchInput: _handleSearchInput,
params, params,
run, run,
valueKey: _valueKey, valueKey: _valueKey,
labelKey: _labelKey, labelKey: _labelKey,
defaultCollapse, defaultCollapse,
} = useProps(props); } = useProps(props);
const [searchVisible, setSearchVisible] = useState(false); const [searchVisible, setSearchVisible] = useState(false);
const defaultActiveKeyCollapse = useMemo<React.Key[]>( const defaultActiveKeyCollapse = useMemo<React.Key[]>(
() => (defaultCollapse && collectionField?.name ? [collectionField.name] : []), () => (defaultCollapse && collectionField?.name ? [collectionField.name] : []),
[], [],
); );
const valueKey = _valueKey || collectionField?.targetKey || 'id'; const valueKey = _valueKey || collectionField?.targetKey || 'id';
const labelKey = _labelKey || fieldSchema['x-component-props']?.fieldNames?.label || valueKey; const labelKey = _labelKey || fieldSchema['x-component-props']?.fieldNames?.label || valueKey;
const fieldNames = { const fieldNames = {
title: labelKey || valueKey, title: labelKey || valueKey,
key: valueKey, key: valueKey,
}; };
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]); const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]); const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true); const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);
const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.title || 'label'); const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.title || 'label');
if (!collectionField) { if (!collectionField) {
return null; return null;
}
const onExpand = (expandedKeysValue: React.Key[]) => {
setExpandedKeys(expandedKeysValue);
setAutoExpandParent(false);
};
const onSelect = (selectedKeysValue: React.Key[]) => {
setSelectedKeys(selectedKeysValue);
onSelected(selectedKeysValue);
};
const handleSearchToggle = (e: MouseEvent) => {
const filter = params?.[0]?.filter;
if (searchVisible || filter) {
run({
...params?.[0],
filter: undefined,
});
} }
setSearchVisible(!searchVisible);
e.stopPropagation();
};
const handleSearchClick = (e: MouseEvent) => { const onExpand = (expandedKeysValue: React.Key[]) => {
e.stopPropagation(); setExpandedKeys(expandedKeysValue);
}; setAutoExpandParent(false);
};
const handleSearchInput = (e: ChangeEvent<any>) => { const onSelect = (selectedKeysValue: React.Key[]) => {
_handleSearchInput(e); setSelectedKeys(selectedKeysValue);
}; onSelected(selectedKeysValue);
};
const title = fieldSchema.title ?? collectionField?.uiSchema?.title; const handleSearchToggle = (e: MouseEvent) => {
const filter = params?.[0]?.filter;
if (searchVisible || filter) {
run({
...params?.[0],
filter: undefined,
});
}
setSearchVisible(!searchVisible);
e.stopPropagation();
};
return wrapSSR( const handleSearchClick = (e: MouseEvent) => {
<SortableItem className={cls(componentCls, hashId, 'nb-block-item', props.className, 'SortableItem')}> e.stopPropagation();
<Designer /> };
<Collapse defaultActiveKey={defaultActiveKeyCollapse} ghost expandIcon={searchVisible ? () => null : undefined}>
<Panel const handleSearchInput = (e: ChangeEvent<any>) => {
className="Panel" _handleSearchInput(e);
header={ };
<Row
className="headerRow" const title = fieldSchema.title ?? collectionField?.uiSchema?.title;
style={{
borderBottom: searchVisible ? `1px solid ${token.colorBorder}` : 'none', return wrapSSR(
}} <SortableItem className={cls(componentCls, hashId, 'nb-block-item', props.className, 'SortableItem')}>
gutter={5} <Designer />
> <Collapse defaultActiveKey={defaultActiveKeyCollapse} ghost expandIcon={searchVisible ? () => null : undefined}>
<Col title={compile(title)} className="headerCol"> <Panel
{searchVisible ? ( className="Panel"
<Input header={
bordered={false} <Row
autoFocus className="headerRow"
placeholder="Search..."
className="search"
onClick={handleSearchClick}
onChange={handleSearchInput}
/>
) : (
compile(title)
)}
</Col>
<Col
style={{ style={{
flex: '0 0 auto', borderBottom: searchVisible ? `1px solid ${token.colorBorder}` : 'none',
}} }}
gutter={5}
> >
{searchVisible ? ( <Col title={compile(title)} className="headerCol">
<CloseOutlined className="CloseOutlined" onClick={handleSearchToggle} /> {searchVisible ? (
) : ( <Input
<SearchOutlined className="SearchOutlined" onClick={handleSearchToggle} /> bordered={false}
)} autoFocus
</Col> placeholder="Search..."
</Row> className="search"
} onClick={handleSearchClick}
key={defaultActiveKeyCollapse[0]} onChange={handleSearchInput}
> />
<Tree ) : (
className="Tree" compile(title)
onExpand={onExpand} )}
expandedKeys={expandedKeys} </Col>
autoExpandParent={autoExpandParent} <Col
treeData={list} style={{
onSelect={onSelect} flex: '0 0 auto',
fieldNames={fieldNames} }}
titleRender={(node) => { >
return ( {searchVisible ? (
<EllipsisWithTooltip ellipsis> <CloseOutlined className="CloseOutlined" onClick={handleSearchToggle} />
{getLabelFormatValue(labelUiSchema, compile(node[labelKey]))} ) : (
</EllipsisWithTooltip> <SearchOutlined className="SearchOutlined" onClick={handleSearchToggle} />
); )}
}} </Col>
selectedKeys={selectedKeys} </Row>
blockNode }
/> key={defaultActiveKeyCollapse[0]}
</Panel> >
</Collapse> <Tree
</SortableItem>, className="Tree"
); onExpand={onExpand}
}; expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
treeData={list}
onSelect={onSelect}
fieldNames={fieldNames}
titleRender={(node) => {
return (
<EllipsisWithTooltip ellipsis>
{getLabelFormatValue(labelUiSchema, compile(node[labelKey]))}
</EllipsisWithTooltip>
);
}}
selectedKeys={selectedKeys}
blockNode
/>
</Panel>
</Collapse>
</SortableItem>,
);
},
{ displayName: 'AssociationFilterItem' },
);

View File

@ -8,15 +8,18 @@ import { FilterAction } from './FilterAction';
import { FilterGroup } from './FilterGroup'; import { FilterGroup } from './FilterGroup';
import { SaveDefaultValue } from './SaveDefaultValue'; import { SaveDefaultValue } from './SaveDefaultValue';
import { FilterContext } from './context'; import { FilterContext } from './context';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
const useDef = (options) => { const useDef = (options) => {
const field = useField<ObjectFieldModel>(); const field = useField<ObjectFieldModel>();
return useRequest(() => Promise.resolve({ data: field.dataSource }), options); return useRequest(() => Promise.resolve({ data: field.dataSource }), options);
}; };
export const Filter: any = observer( export const Filter: any = withDynamicSchemaProps(
(props: any) => { observer((props: any) => {
const { useDataSource = useDef } = props; const { useDataSource = useDef } = props;
// 新版 UISchema1.0 之后)中已经废弃了 useProps这里之所以继续保留是为了兼容旧版的 UISchema
const { options, dynamicComponent, className, collectionName } = useProps(props); const { options, dynamicComponent, className, collectionName } = useProps(props);
const field = useField<ObjectFieldModel>(); const field = useField<ObjectFieldModel>();
const fieldSchema: any = useFieldSchema(); const fieldSchema: any = useFieldSchema();
@ -47,7 +50,7 @@ export const Filter: any = observer(
</FilterContext.Provider> </FilterContext.Provider>
</div> </div>
); );
}, }),
{ displayName: 'Filter' }, { displayName: 'Filter' },
); );

View File

@ -10,18 +10,21 @@ import { useDesignable } from '../../hooks';
import { useProps } from '../../hooks/useProps'; import { useProps } from '../../hooks/useProps';
import { Action } from '../action'; import { Action } from '../action';
import { StablePopover } from '../popover'; import { StablePopover } from '../popover';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export const FilterActionContext = createContext<any>(null); export const FilterActionContext = createContext<any>(null);
FilterActionContext.displayName = 'FilterActionContext'; FilterActionContext.displayName = 'FilterActionContext';
export const FilterAction = observer( export const FilterAction = withDynamicSchemaProps(
(props: any) => { observer((props: any) => {
const { t } = useTranslation(); const { t } = useTranslation();
const field = useField<Field>(); const field = useField<Field>();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { designable, dn } = useDesignable(); const { designable, dn } = useDesignable();
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const form = useMemo<Form>(() => props.form || createForm(), []); const form = useMemo<Form>(() => props.form || createForm(), []);
// 新版 UISchema1.0 之后)中已经废弃了 useProps这里之所以继续保留是为了兼容旧版的 UISchema
const { options, onSubmit, onReset, ...others } = useProps(props); const { options, onSubmit, onReset, ...others } = useProps(props);
const onOpenChange = useCallback((visible: boolean): void => { const onOpenChange = useCallback((visible: boolean): void => {
setVisible(visible); setVisible(visible);
@ -93,7 +96,7 @@ export const FilterAction = observer(
</StablePopover> </StablePopover>
</FilterActionContext.Provider> </FilterActionContext.Provider>
); );
}, }),
{ displayName: 'FilterAction' }, { displayName: 'FilterAction' },
); );

View File

@ -60,14 +60,14 @@ const schema: any = {
name: 'filter', name: 'filter',
type: 'object', type: 'object',
'x-component': 'Filter', 'x-component': 'Filter',
'x-component-props': { 'x-use-component-props': () => {
useProps: () => { // eslint-disable-next-line react-hooks/rules-of-hooks
const { name } = useCollection_deprecated(); const { name } = useCollection_deprecated();
const options = useFilterOptions(name); // eslint-disable-next-line react-hooks/rules-of-hooks
return { const options = useFilterOptions(name);
options, return {
}; options,
}, };
}, },
}, },
}, },

View File

@ -74,9 +74,7 @@ const schema: ISchema = {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
nickname: { nickname: {
type: 'string', type: 'string',

View File

@ -51,9 +51,7 @@ const schema: ISchema = {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-read-pretty': true, 'x-read-pretty': true,
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
grid: { grid: {
type: 'void', type: 'void',

View File

@ -9,6 +9,7 @@ import {
SchemaSettingsRemove, SchemaSettingsRemove,
} from '../../../schema-settings'; } from '../../../schema-settings';
import { useCompile, useDesignable } from '../../hooks'; import { useCompile, useDesignable } from '../../hooks';
import _ from 'lodash';
const validateJSON = { const validateJSON = {
validator: `{{(value, rule)=> { validator: `{{(value, rule)=> {
@ -94,9 +95,9 @@ export const G2PlotDesigner = () => {
} else { } else {
field.componentProps.config = conf; field.componentProps.config = conf;
} }
fieldSchema.title = title; _.set(fieldSchema, 'title', title);
fieldSchema['x-component-props']['plot'] = plot; _.set(fieldSchema, 'x-component-props.plot', plot);
fieldSchema['x-component-props']['config'] = JSON.parse(config); _.set(fieldSchema, 'x-component-props.config', JSON.parse(config));
dn.emit('patch', { dn.emit('patch', {
schema: { schema: {
title, title,

View File

@ -9,6 +9,7 @@ import { useFormBlockType } from '../../../block-provider';
import { DndContext } from '../../common/dnd-context'; import { DndContext } from '../../common/dnd-context';
import { useToken } from '../__builtins__'; import { useToken } from '../__builtins__';
import useStyles from './Grid.style'; import useStyles from './Grid.style';
import _ from 'lodash';
const GridRowContext = createContext<any>({}); const GridRowContext = createContext<any>({});
GridRowContext.displayName = 'GridRowContext'; GridRowContext.displayName = 'GridRowContext';
@ -124,8 +125,8 @@ const ColDivider = (props) => {
el.parentElement.clientWidth el.parentElement.clientWidth
).toFixed(2); ).toFixed(2);
prevSchema['x-component-props']['width'] = preWidth; _.set(prevSchema, 'x-component-props.width', preWidth);
nextSchema['x-component-props']['width'] = nextWidth; _.set(nextSchema, 'x-component-props.width', nextWidth);
dn.emit('batchPatch', { dn.emit('batchPatch', {
schemas: [ schemas: [
{ {

View File

@ -92,12 +92,12 @@ const schema: ISchema = {
value: { value: {
type: 'array', type: 'array',
'x-component': 'TableV2.Selector', 'x-component': 'TableV2.Selector',
'x-use-component-props': 'useTableSelectorProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableSelectorProps }}',
}, },
properties: { properties: {
column1: { column1: {
@ -129,10 +129,10 @@ const schema: ISchema = {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'usePickActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ usePickActionProps }}',
}, },
}, },
}, },

View File

@ -21,6 +21,7 @@ import { SchemaSettingsDataScope } from '../../../schema-settings/SchemaSettings
import { isPatternDisabled } from '../../../schema-settings/isPatternDisabled'; import { isPatternDisabled } from '../../../schema-settings/isPatternDisabled';
import { SchemaSettingsDateFormat } from '../../../schema-settings/SchemaSettingsDateFormat'; import { SchemaSettingsDateFormat } from '../../../schema-settings/SchemaSettingsDateFormat';
import { SchemaSettingsSortingRule } from '../../../schema-settings/SchemaSettingsSortingRule'; import { SchemaSettingsSortingRule } from '../../../schema-settings/SchemaSettingsSortingRule';
import _ from 'lodash';
export const useLabelFields = (collectionName?: any) => { export const useLabelFields = (collectionName?: any) => {
// 需要在组件顶层调用 // 需要在组件顶层调用
@ -232,11 +233,11 @@ export const TableColumnDesigner = (props) => {
value={fieldNames?.['label']} value={fieldNames?.['label']}
onChange={(label) => { onChange={(label) => {
const fieldNames = { const fieldNames = {
...collectionField?.uiSchema?.['x-component-props']['fieldNames'], ...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'],
...fieldSchema?.['x-component-props']?.['fieldNames'], ...fieldSchema?.['x-component-props']?.['fieldNames'],
label, label,
}; };
fieldSchema['x-component-props']['fieldNames'] = fieldNames; _.set(fieldSchema, 'x-component-props.fieldNames', fieldNames);
const path = field.path?.splice(field.path?.length - 1, 1); const path = field.path?.splice(field.path?.length - 1, 1);
field.form.query(`${path.concat(`*.` + fieldSchema.name)}`).forEach((f) => { field.form.query(`${path.concat(`*.` + fieldSchema.name)}`).forEach((f) => {
f.componentProps.fieldNames = fieldNames; f.componentProps.fieldNames = fieldNames;

View File

@ -99,9 +99,7 @@ const formSchema: ISchema = {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
id: { id: {
type: 'string', type: 'string',
@ -157,12 +155,12 @@ const schema: ISchema = {
type: 'array', type: 'array',
title: `编辑模式`, title: `编辑模式`,
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableBlockProps }}',
}, },
properties: { properties: {
column1: { column1: {

View File

@ -10,6 +10,7 @@ import {
} from '../../../schema-settings'; } from '../../../schema-settings';
import { useCompile, useDesignable } from '../../hooks'; import { useCompile, useDesignable } from '../../hooks';
import { useActionContext } from '../action'; import { useActionContext } from '../action';
import _ from 'lodash';
const useLabelFields = (collectionName?: any) => { const useLabelFields = (collectionName?: any) => {
const compile = useCompile(); const compile = useCompile();
@ -122,10 +123,10 @@ export const TableColumnDesigner = (props) => {
value={fieldSchema?.['x-component-props']?.['fieldNames']?.['label']} value={fieldSchema?.['x-component-props']?.['fieldNames']?.['label']}
onChange={(label) => { onChange={(label) => {
const fieldNames = { const fieldNames = {
...fieldSchema['x-component-props']['fieldNames'], ...fieldSchema['x-component-props']?.['fieldNames'],
label, label,
}; };
fieldSchema['x-component-props']['fieldNames'] = fieldNames; _.set(fieldSchema, 'x-component-props.fieldNames', fieldNames);
field.query(`.*.${fieldSchema.name}`).take((f) => { field.query(`.*.${fieldSchema.name}`).take((f) => {
f.componentProps.fieldNames = fieldNames; f.componentProps.fieldNames = fieldNames;
}); });

View File

@ -11,6 +11,8 @@ import { ReadPretty } from './ReadPretty';
import { isImage, isPdf, toArr, toFileList, toItem, toValue, useUploadProps } from './shared'; import { isImage, isPdf, toArr, toFileList, toItem, toValue, useUploadProps } from './shared';
import { useStyles } from './style'; import { useStyles } from './style';
import type { ComposedUpload, DraggerProps, DraggerV2Props, UploadProps } from './type'; import type { ComposedUpload, DraggerProps, DraggerV2Props, UploadProps } from './type';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useProps } from '../../hooks/useProps';
export const Upload: ComposedUpload = connect( export const Upload: ComposedUpload = connect(
(props: UploadProps) => { (props: UploadProps) => {
@ -299,42 +301,44 @@ Upload.Dragger = connect(
}), }),
); );
Upload.DraggerV2 = connect( Upload.DraggerV2 = withDynamicSchemaProps(
(props: DraggerV2Props) => { connect(
const { t } = useTranslation(); (props: DraggerV2Props) => {
const defaultTitle = t('Click or drag file to this area to upload'); const { t } = useTranslation();
const defaultSubTitle = t('Support for a single or bulk upload, file size should not exceed') + ` 10MB`; const defaultTitle = t('Click or drag file to this area to upload');
const { title = defaultTitle, subTitle = defaultSubTitle, useProps } = props; const defaultSubTitle = t('Support for a single or bulk upload, file size should not exceed') + ` 10MB`;
const extraProps: Record<string, any> = useProps?.() || {}; const { title = defaultTitle, subTitle = defaultSubTitle, ...extraProps } = useProps(props);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const { wrapSSR, hashId, componentCls: prefixCls } = useStyles(); const { wrapSSR, hashId, componentCls: prefixCls } = useStyles();
const handleChange = (fileList: any[] = []) => { const handleChange = (fileList: any[] = []) => {
const { onChange } = extraProps; const { onChange } = extraProps;
onChange?.(fileList); onChange?.(fileList);
if (fileList.some((file) => file.status === 'uploading')) { if (fileList.some((file) => file.status === 'uploading')) {
setLoading(true); setLoading(true);
} else { } else {
setLoading(false); setLoading(false);
} }
}; };
return wrapSSR( return wrapSSR(
<div className={cls(`${prefixCls}-dragger`, hashId)}> <div className={cls(`${prefixCls}-dragger`, hashId)}>
<AntdUpload.Dragger {...useUploadProps({ ...props, ...extraProps, onChange: handleChange })}> <AntdUpload.Dragger {...useUploadProps({ ...props, ...extraProps, onChange: handleChange })}>
<p className={`${prefixCls}-drag-icon`}> <p className={`${prefixCls}-drag-icon`}>
{loading ? <LoadingOutlined style={{ fontSize: 36 }} spin /> : <InboxOutlined />} {loading ? <LoadingOutlined style={{ fontSize: 36 }} spin /> : <InboxOutlined />}
</p> </p>
<p className={`${prefixCls}-text`}>{title}</p> <p className={`${prefixCls}-text`}>{title}</p>
<p className={`${prefixCls}-hint`}>{subTitle}</p> <p className={`${prefixCls}-hint`}>{subTitle}</p>
</AntdUpload.Dragger> </AntdUpload.Dragger>
</div>, </div>,
); );
}, },
mapProps({ mapProps({
value: 'fileList', value: 'fileList',
}), }),
),
{ displayName: 'Upload.DraggerV2' },
); );
export default Upload; export default Upload;

View File

@ -22,6 +22,7 @@ export type DraggerV2Props = Omit<AntdDraggerProps, 'onChange'> & {
title?: string; title?: string;
subTitle?: string; subTitle?: string;
children?: React.ReactNode; children?: React.ReactNode;
/** @deprecated */
useProps?: () => any; useProps?: () => any;
}; };

View File

@ -7,11 +7,11 @@ export const CreateFilterActionInitializer = (props) => {
title: '{{ t("Filter") }}', title: '{{ t("Filter") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useFilterBlockActionProps',
'x-designer': 'Action.Designer', 'x-designer': 'Action.Designer',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useFilterBlockActionProps }}',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;

View File

@ -6,10 +6,8 @@ export const CreateResetActionInitializer = (props) => {
const schema = { const schema = {
title: '{{ t("Reset") }}', title: '{{ t("Reset") }}',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useResetBlockActionProps',
'x-designer': 'Action.Designer', 'x-designer': 'Action.Designer',
'x-component-props': {
useProps: '{{ useResetBlockActionProps }}',
},
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;
}; };

View File

@ -39,13 +39,13 @@ export const SelectActionInitializer = (props) => {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'usePickActionProps',
// 'x-designer': 'Action.Designer', // 'x-designer': 'Action.Designer',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:submit', 'x-settings': 'actionSettings:submit',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ usePickActionProps }}',
}, },
}, },
}, },

View File

@ -13,7 +13,6 @@ export const SubmitActionInitializer = (props) => {
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
// useProps: '{{ bp.useSubmitActionProps }}',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;

View File

@ -965,6 +965,12 @@ export const useCollectionDataSourceItems = ({
return noAssociationMenu; return noAssociationMenu;
}; };
/**
* @deprecated
* 使 createDetailsUISchema createDetailsWithPaginationUISchema
* @param options
* @returns
*/
export const createDetailsBlockSchema = (options: { export const createDetailsBlockSchema = (options: {
collection: string; collection: string;
dataSource: string; dataSource: string;
@ -1015,10 +1021,8 @@ export const createDetailsBlockSchema = (options: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
'x-component': 'Details', 'x-component': 'Details',
'x-use-component-props': 'useDetailsBlockProps',
'x-read-pretty': true, 'x-read-pretty': true,
'x-component-props': {
useProps: '{{ useDetailsBlockProps }}',
},
properties: { properties: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
@ -1042,9 +1046,7 @@ export const createDetailsBlockSchema = (options: {
pagination: { pagination: {
type: 'void', type: 'void',
'x-component': 'Pagination', 'x-component': 'Pagination',
'x-component-props': { 'x-use-component-props': 'useDetailsPaginationProps',
useProps: '{{ useDetailsPaginationProps }}',
},
}, },
} }
: {}), : {}),
@ -1117,9 +1119,7 @@ export const createFormBlockSchema = (options: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
@ -1185,10 +1185,8 @@ export const createReadPrettyFormBlockSchema = (options) => {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-use-component-props': 'useFormBlockProps',
'x-read-pretty': true, 'x-read-pretty': true,
'x-component-props': {
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
@ -1273,12 +1271,12 @@ export const createTableBlockSchema = (options) => {
type: 'array', type: 'array',
'x-initializer': tableColumnInitializers ?? 'table:configureColumns', 'x-initializer': tableColumnInitializers ?? 'table:configureColumns',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableBlockProps }}',
}, },
properties: { properties: {
actions: { actions: {

View File

@ -7,7 +7,7 @@ import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useCollectionManager_deprecated } from '../../collection-manager'; import { useCollectionManager_deprecated } from '../../collection-manager';
import { mergeFilter } from '../../filter-provider/utils'; import { mergeFilter } from '../../filter-provider/utils';
import { SchemaComponent, SchemaComponentContext, removeNullCondition } from '../../schema-component'; import { SchemaComponent, SchemaComponentContext, removeNullCondition, useProps } from '../../schema-component';
import { ITemplate } from '../../schema-component/antd/form-v2/Templates'; import { ITemplate } from '../../schema-component/antd/form-v2/Templates';
import { VariableInput } from '../VariableInput'; import { VariableInput } from '../VariableInput';
import { AsDefaultTemplate } from './components/AsDefaultTemplate'; import { AsDefaultTemplate } from './components/AsDefaultTemplate';
@ -15,6 +15,7 @@ import { ArrayCollapse } from './components/DataTemplateTitle';
import { getSelectedIdFilter } from './components/Designer'; import { getSelectedIdFilter } from './components/Designer';
import { useCollectionState } from './hooks/useCollectionState'; import { useCollectionState } from './hooks/useCollectionState';
import { useSyncFromForm } from './utils'; import { useSyncFromForm } from './utils';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
const Tree = connect( const Tree = connect(
AntdTree, AntdTree,
@ -38,232 +39,235 @@ export const compatibleDataId = (data, config?) => {
}); });
}; };
export const FormDataTemplates = observer( export const FormDataTemplates = withDynamicSchemaProps(
(props: any) => { observer(
const { useProps, formSchema, designerCtx } = props; (props: any) => {
const { defaultValues, collectionName } = useProps(); // 新版 UISchema1.0 之后)中已经废弃了 useProps这里之所以继续保留是为了兼容旧版的 UISchema
const { const { formSchema, designerCtx, defaultValues, collectionName } = useProps(props);
collectionList, const {
getEnableFieldTree, collectionList,
getOnLoadData,
getOnCheck,
getScopeDataSource,
useTitleFieldDataSource,
} = useCollectionState(collectionName);
const { getCollection, getCollectionField } = useCollectionManager_deprecated();
const { t } = useTranslation();
// 不要在后面的数组中依赖 defaultValues否则会因为 defaultValues 的变化导致 activeData 响应性丢失
const activeData = useMemo<ITemplate>(
() =>
observable(
{ ...defaultValues, items: compatibleDataId(defaultValues?.items || [], defaultValues?.config) } || {
items: [],
display: true,
config: { [collectionName]: { titleField: '', filter: {} } },
},
),
[],
);
const getTargetField = (collectionName: string) => {
const collection = getCollection(collectionName);
return getCollectionField(
`${collectionName}.${activeData?.config[collectionName]?.titleField || collection?.titleField || 'id'}`,
);
};
const getFieldNames = (collectionName: string) => {
const collection = getCollection(collectionName);
return {
label: getLabel(activeData.config?.[collectionName]?.titleField || collection?.titleField || 'id'),
value: 'id',
};
};
const getFilter = (collectionName: string, value: any) => {
const filter = activeData.config?.[collectionName]?.filter;
return _.isEmpty(filter) ? {} : removeNullCondition(mergeFilter([filter, getSelectedIdFilter(value)], '$or'));
};
const components = useMemo(() => ({ ArrayCollapse }), []);
const scope = useMemo(
() => ({
getEnableFieldTree, getEnableFieldTree,
getTargetField,
getFieldNames,
getFilter,
getResource,
getOnLoadData, getOnLoadData,
getOnCheck, getOnCheck,
collectionName,
getScopeDataSource, getScopeDataSource,
useTitleFieldDataSource, useTitleFieldDataSource,
}), } = useCollectionState(collectionName);
[], const { getCollection, getCollectionField } = useCollectionManager_deprecated();
); const { t } = useTranslation();
const schema = useMemo( // 不要在后面的数组中依赖 defaultValues否则会因为 defaultValues 的变化导致 activeData 响应性丢失
() => ({ const activeData = useMemo<ITemplate>(
type: 'object', () =>
properties: { observable(
items: { { ...defaultValues, items: compatibleDataId(defaultValues?.items || [], defaultValues?.config) } || {
type: 'array', items: [],
default: activeData?.items, display: true,
'x-component': 'ArrayCollapse', config: { [collectionName]: { titleField: '', filter: {} } },
'x-decorator': 'FormItem',
'x-component-props': {
accordion: true,
}, },
),
[],
);
const getTargetField = (collectionName: string) => {
const collection = getCollection(collectionName);
return getCollectionField(
`${collectionName}.${activeData?.config[collectionName]?.titleField || collection?.titleField || 'id'}`,
);
};
const getFieldNames = (collectionName: string) => {
const collection = getCollection(collectionName);
return {
label: getLabel(activeData.config?.[collectionName]?.titleField || collection?.titleField || 'id'),
value: 'id',
};
};
const getFilter = (collectionName: string, value: any) => {
const filter = activeData.config?.[collectionName]?.filter;
return _.isEmpty(filter) ? {} : removeNullCondition(mergeFilter([filter, getSelectedIdFilter(value)], '$or'));
};
const components = useMemo(() => ({ ArrayCollapse }), []);
const scope = useMemo(
() => ({
getEnableFieldTree,
getTargetField,
getFieldNames,
getFilter,
getResource,
getOnLoadData,
getOnCheck,
collectionName,
getScopeDataSource,
useTitleFieldDataSource,
}),
[],
);
const schema = useMemo(
() => ({
type: 'object',
properties: {
items: { items: {
type: 'object', type: 'array',
'x-component': 'ArrayCollapse.CollapsePanel', default: activeData?.items,
'x-component': 'ArrayCollapse',
'x-decorator': 'FormItem',
'x-component-props': { 'x-component-props': {
extra: [<AsDefaultTemplate key="0" />], accordion: true,
}, },
properties: { items: {
layout: { type: 'object',
type: 'void', 'x-component': 'ArrayCollapse.CollapsePanel',
'x-component': 'FormLayout', 'x-component-props': {
'x-component-props': { extra: [<AsDefaultTemplate key="0" />],
layout: 'vertical', },
}, properties: {
properties: { layout: {
collection: { type: 'void',
type: 'string', 'x-component': 'FormLayout',
title: '{{ t("Collection") }}', 'x-component-props': {
required: true, layout: 'vertical',
description: t('If collection inherits, choose inherited collections as templates'),
default: '{{ collectionName }}',
'x-display': collectionList.length > 1 ? 'visible' : 'hidden',
'x-decorator': 'FormItem',
'x-component': 'Select',
'x-component-props': {
options: collectionList,
},
}, },
dataScope: { properties: {
type: 'object', collection: {
title: '{{ t("Assign data scope for the template") }}', type: 'string',
'x-decorator': 'FormItem', title: '{{ t("Collection") }}',
'x-component': 'Filter', required: true,
'x-component-props': { description: t('If collection inherits, choose inherited collections as templates'),
dynamicComponent: VariableInput, default: '{{ collectionName }}',
}, 'x-display': collectionList.length > 1 ? 'visible' : 'hidden',
'x-decorator-props': { 'x-decorator': 'FormItem',
style: { 'x-component': 'Select',
marginBottom: '0px', 'x-component-props': {
options: collectionList,
}, },
}, },
required: true, dataScope: {
'x-reactions': [ type: 'object',
{ title: '{{ t("Assign data scope for the template") }}',
dependencies: ['.collection'], 'x-decorator': 'FormItem',
fulfill: { 'x-component': 'Filter',
state: { 'x-component-props': {
disabled: '{{ !$deps[0] }}', dynamicComponent: VariableInput,
}, },
schema: { 'x-decorator-props': {
enum: '{{ getScopeDataSource($deps[0]) }}', style: {
}, marginBottom: '0px',
}, },
}, },
], required: true,
}, 'x-reactions': [
titleField: { {
type: 'string', dependencies: ['.collection'],
'x-decorator': 'FormItem', fulfill: {
title: '{{ t("Title field") }}', state: {
'x-component': 'Select', disabled: '{{ !$deps[0] }}',
required: true, },
'x-reactions': '{{useTitleFieldDataSource}}', schema: {
}, enum: '{{ getScopeDataSource($deps[0]) }}',
syncFromForm: {
type: 'void',
title: '{{ t("Sync from form fields") }}',
'x-component': 'Action.Link',
'x-component-props': {
type: 'primary',
style: { float: 'right', position: 'relative', zIndex: 1200 },
useAction: () => useSyncFromForm(formSchema),
},
},
fields: {
type: 'array',
title: '{{ t("Data fields") }}',
required: true,
description: t('Only the selected fields will be used as the initialization data for the form'),
'x-decorator': 'FormItem',
'x-component': Tree,
'x-component-props': {
treeData: [],
checkable: true,
checkStrictly: true,
selectable: false,
loadData: '{{ getOnLoadData($self) }}',
onCheck: '{{ getOnCheck($self) }}',
rootStyle: {
padding: '8px 0',
border: '1px solid #d9d9d9',
borderRadius: '2px',
maxHeight: '30vh',
overflow: 'auto',
margin: '2px 0',
},
},
'x-reactions': [
{
dependencies: ['.collection'],
fulfill: {
state: {
disabled: '{{ !$deps[0] }}',
componentProps: {
treeData: '{{ getEnableFieldTree($deps[0], $self) }}',
}, },
}, },
}, },
],
},
titleField: {
type: 'string',
'x-decorator': 'FormItem',
title: '{{ t("Title field") }}',
'x-component': 'Select',
required: true,
'x-reactions': '{{useTitleFieldDataSource}}',
},
syncFromForm: {
type: 'void',
title: '{{ t("Sync from form fields") }}',
'x-component': 'Action.Link',
'x-component-props': {
type: 'primary',
style: { float: 'right', position: 'relative', zIndex: 1200 },
useAction: () => useSyncFromForm(formSchema),
}, },
], },
fields: {
type: 'array',
title: '{{ t("Data fields") }}',
required: true,
description: t('Only the selected fields will be used as the initialization data for the form'),
'x-decorator': 'FormItem',
'x-component': Tree,
'x-component-props': {
treeData: [],
checkable: true,
checkStrictly: true,
selectable: false,
loadData: '{{ getOnLoadData($self) }}',
onCheck: '{{ getOnCheck($self) }}',
rootStyle: {
padding: '8px 0',
border: '1px solid #d9d9d9',
borderRadius: '2px',
maxHeight: '30vh',
overflow: 'auto',
margin: '2px 0',
},
},
'x-reactions': [
{
dependencies: ['.collection'],
fulfill: {
state: {
disabled: '{{ !$deps[0] }}',
componentProps: {
treeData: '{{ getEnableFieldTree($deps[0], $self) }}',
},
},
},
},
],
},
}, },
}, },
remove: {
type: 'void',
'x-component': 'ArrayCollapse.Remove',
},
moveUp: {
type: 'void',
'x-component': 'ArrayCollapse.MoveUp',
},
moveDown: {
type: 'void',
'x-component': 'ArrayCollapse.MoveDown',
},
}, },
remove: { },
properties: {
add: {
type: 'void', type: 'void',
'x-component': 'ArrayCollapse.Remove', title: '{{ t("Add template") }}',
}, 'x-component': 'ArrayCollapse.Addition',
moveUp: {
type: 'void',
'x-component': 'ArrayCollapse.MoveUp',
},
moveDown: {
type: 'void',
'x-component': 'ArrayCollapse.MoveDown',
}, },
}, },
}, },
properties: { display: {
add: { type: 'boolean',
type: 'void', 'x-content': '{{ t("Display data template selector") }}',
title: '{{ t("Add template") }}', default: activeData?.display !== false,
'x-component': 'ArrayCollapse.Addition', 'x-decorator': 'FormItem',
}, 'x-component': 'Checkbox',
}, },
}, },
display: { }),
type: 'boolean', [],
'x-content': '{{ t("Display data template selector") }}', );
default: activeData?.display !== false,
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
}),
[],
);
return ( return (
<SchemaComponentContext.Provider value={{ ...designerCtx, designable: true }}> <SchemaComponentContext.Provider value={{ ...designerCtx, designable: true }}>
<SchemaComponent components={components} scope={scope} schema={schema} /> <SchemaComponent components={components} scope={scope} schema={schema} />
</SchemaComponentContext.Provider> </SchemaComponentContext.Provider>
); );
}, },
{ displayName: 'FormDataTemplates' },
),
{ displayName: 'FormDataTemplates' }, { displayName: 'FormDataTemplates' },
); );

View File

@ -184,7 +184,7 @@ export const useSyncFromForm = (fieldSchema, collection?, callBack?) => {
selectFields.add(path); selectFields.add(path);
} }
if (collectionfield && (isAssociationField || isAssociationSubfield) && s['x-component'] !== 'TableField') { if (collectionfield && (isAssociationField || isAssociationSubfield) && s['x-component'] !== 'TableField') {
formData.add({ name: path, fieldMode: s['x-component-props']['mode'] || 'Select' }); formData.add({ name: path, fieldMode: s['x-component-props']?.['mode'] || 'Select' });
if (['Nester', 'SubTable'].includes(s['x-component-props']?.mode)) { if (['Nester', 'SubTable'].includes(s['x-component-props']?.mode)) {
const bufPrefix = prefix && prefix !== '' ? prefix + '.' + s.name : s.name; const bufPrefix = prefix && prefix !== '' ? prefix + '.' + s.name : s.name;
getAssociationAppends(s, bufPrefix); getAssociationAppends(s, bufPrefix);

View File

@ -2,12 +2,12 @@ import { observer, useForm } from '@nocobase/schema';
import { action } from '@nocobase/schema'; import { action } from '@nocobase/schema';
import React from 'react'; import React from 'react';
import { useCollectionManager_deprecated } from '../../collection-manager'; import { useCollectionManager_deprecated } from '../../collection-manager';
import { SchemaComponent, useCompile } from '../../schema-component'; import { SchemaComponent, useCompile, useProps } from '../../schema-component';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
export const EnableChildCollections = observer( export const EnableChildCollections = withDynamicSchemaProps(
(props: any) => { observer((props: any) => {
const { useProps } = props; const { defaultValues, collectionName } = useProps(props);
const { defaultValues, collectionName } = useProps();
const form = useForm(); const form = useForm();
const compile = useCompile(); const compile = useCompile();
const { getChildrenCollections } = useCollectionManager_deprecated(); const { getChildrenCollections } = useCollectionManager_deprecated();
@ -105,6 +105,6 @@ export const EnableChildCollections = observer(
scope={{ useAsyncDataSource, loadData }} scope={{ useAsyncDataSource, loadData }}
/> />
); );
}, }),
{ displayName: 'EnableChildCollections' }, { displayName: 'EnableChildCollections' },
); );

View File

@ -10,6 +10,9 @@ import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FormButtonLinkageRuleAction, FormFieldLinkageRuleAction } from './LinkageRuleAction'; import { FormButtonLinkageRuleAction, FormFieldLinkageRuleAction } from './LinkageRuleAction';
import { RemoveActionContext } from './context'; import { RemoveActionContext } from './context';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
import { useProps } from '../../schema-component/hooks/useProps';
export const LinkageRuleActions = observer( export const LinkageRuleActions = observer(
(props: any): any => { (props: any): any => {
const { type, linkageOptions } = props; const { type, linkageOptions } = props;
@ -32,38 +35,41 @@ export const LinkageRuleActions = observer(
); );
interface LinkageRuleActionGroupProps { interface LinkageRuleActionGroupProps {
useProps: () => { type: 'button' | 'field';
type: 'button' | 'field'; linkageOptions: any;
linkageOptions: any; collectionName: string;
collectionName: string;
};
} }
export const LinkageRuleActionGroup = (props: LinkageRuleActionGroupProps) => { export const LinkageRuleActionGroup = withDynamicSchemaProps(
const { t } = useTranslation(); (props: LinkageRuleActionGroupProps) => {
const field = useField<VoidField>(); const { t } = useTranslation();
const logic = 'actions'; const field = useField<VoidField>();
const { type, linkageOptions, collectionName } = props.useProps(); const logic = 'actions';
const style = useMemo(() => ({ marginLeft: 10 }), []); // 新版 UISchema1.0 之后)中已经废弃了 useProps这里之所以继续保留是为了兼容旧版的 UISchema
const components = useMemo( const { type, linkageOptions, collectionName } = useProps(props);
() => [LinkageRuleActions, { type, linkageOptions, collectionName }],
[collectionName, linkageOptions, type],
);
const spaceStyle = useMemo(() => ({ marginTop: 8, marginBottom: 8 }), []);
const onClick = useCallback(() => {
const f = field.query('.actions').take() as ArrayFieldModel;
const items = f.value || [];
items.push({});
f.value = items;
}, [field]);
return ( const style = useMemo(() => ({ marginLeft: 10 }), []);
<div style={style}> const components = useMemo(
<ArrayField name={logic} component={components} disabled={false} /> () => [LinkageRuleActions, { type, linkageOptions, collectionName }],
<Space size={16} style={spaceStyle}> [collectionName, linkageOptions, type],
<a onClick={onClick}>{t('Add property')}</a> );
</Space> const spaceStyle = useMemo(() => ({ marginTop: 8, marginBottom: 8 }), []);
</div> const onClick = useCallback(() => {
); const f = field.query('.actions').take() as ArrayFieldModel;
}; const items = f.value || [];
items.push({});
f.value = items;
}, [field]);
return (
<div style={style}>
<ArrayField name={logic} component={components} disabled={false} />
<Space size={16} style={spaceStyle}>
<a onClick={onClick}>{t('Add property')}</a>
</Space>
</div>
);
},
{ displayName: 'LinkageRuleActionGroup' },
);

View File

@ -6,7 +6,7 @@ import { FormBlockContext } from '../../block-provider';
import { useCollectionManager_deprecated } from '../../collection-manager'; import { useCollectionManager_deprecated } from '../../collection-manager';
import { useCollectionParentRecordData } from '../../data-source/collection-record/CollectionRecordProvider'; import { useCollectionParentRecordData } from '../../data-source/collection-record/CollectionRecordProvider';
import { RecordProvider } from '../../record-provider'; import { RecordProvider } from '../../record-provider';
import { SchemaComponent } from '../../schema-component'; import { SchemaComponent, useProps } from '../../schema-component';
import { DynamicComponentProps } from '../../schema-component/antd/filter/DynamicComponent'; import { DynamicComponentProps } from '../../schema-component/antd/filter/DynamicComponent';
import { FilterContext } from '../../schema-component/antd/filter/context'; import { FilterContext } from '../../schema-component/antd/filter/context';
import { VariableOption, VariablesContextType } from '../../variables/types'; import { VariableOption, VariablesContextType } from '../../variables/types';
@ -14,6 +14,7 @@ import { VariableInput, getShouldChange } from '../VariableInput/VariableInput';
import { LinkageRuleActionGroup } from './LinkageRuleActionGroup'; import { LinkageRuleActionGroup } from './LinkageRuleActionGroup';
import { EnableLinkage } from './components/EnableLinkage'; import { EnableLinkage } from './components/EnableLinkage';
import { ArrayCollapse } from './components/LinkageHeader'; import { ArrayCollapse } from './components/LinkageHeader';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
interface usePropsReturn { interface usePropsReturn {
options: any; options: any;
@ -30,16 +31,23 @@ interface usePropsReturn {
} }
interface Props { interface Props {
useProps: () => usePropsReturn;
dynamicComponent: any; dynamicComponent: any;
} }
export const FormLinkageRules = observer( export const FormLinkageRules = withDynamicSchemaProps(
(props: Props) => { observer((props: Props) => {
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const { useProps, dynamicComponent } = props; const {
const { options, defaultValues, collectionName, form, formBlockType, variables, localVariables, record } = options,
useProps(); defaultValues,
collectionName,
form,
formBlockType,
variables,
localVariables,
record,
dynamicComponent,
} = useProps(props);
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated(); const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
const parentRecordData = useCollectionParentRecordData(); const parentRecordData = useCollectionParentRecordData();
@ -80,18 +88,18 @@ export const FormLinkageRules = observer(
}, },
condition: { condition: {
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
return {
options,
className: css`
position: relative;
width: 100%;
margin-left: 10px;
`,
};
},
'x-component-props': { 'x-component-props': {
collectionName, collectionName,
useProps() {
return {
options,
className: css`
position: relative;
width: 100%;
margin-left: 10px;
`,
};
},
dynamicComponent: (props: DynamicComponentProps) => { dynamicComponent: (props: DynamicComponentProps) => {
const { collectionField } = props; const { collectionField } = props;
return ( return (
@ -175,6 +183,6 @@ export const FormLinkageRules = observer(
</RecordProvider> </RecordProvider>
</FormBlockContext.Provider> </FormBlockContext.Provider>
); );
}, }),
{ displayName: 'FormLinkageRules' }, { displayName: 'FormLinkageRules' },
); );

View File

@ -1245,22 +1245,22 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) {
properties: { properties: {
fieldReaction: { fieldReaction: {
'x-component': FormLinkageRules, 'x-component': FormLinkageRules,
'x-component-props': { 'x-use-component-props': () => {
useProps: () => { // eslint-disable-next-line react-hooks/rules-of-hooks
const options = useLinkageCollectionFilterOptions(collectionName); const options = useLinkageCollectionFilterOptions(collectionName);
return { return {
options, options,
defaultValues: gridSchema?.['x-linkage-rules'] || fieldSchema?.['x-linkage-rules'], defaultValues: gridSchema?.['x-linkage-rules'] || fieldSchema?.['x-linkage-rules'],
type, type,
linkageOptions: useLinkageCollectionFieldOptions(collectionName), // eslint-disable-next-line react-hooks/rules-of-hooks
collectionName, linkageOptions: useLinkageCollectionFieldOptions(collectionName),
form, collectionName,
variables, form,
localVariables, variables,
record, localVariables,
formBlockType, record,
}; formBlockType,
}, };
}, },
}, },
}, },
@ -1274,7 +1274,7 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) {
for (const rule of v.fieldReaction.rules) { for (const rule of v.fieldReaction.rules) {
rules.push(_.pickBy(rule, _.identity)); rules.push(_.pickBy(rule, _.identity));
} }
const templateId = gridSchema['x-component'] === 'BlockTemplate' && gridSchema['x-component-props'].templateId; const templateId = gridSchema['x-component'] === 'BlockTemplate' && gridSchema['x-component-props']?.templateId;
const uid = (templateId && getTemplateById(templateId).uid) || gridSchema['x-uid']; const uid = (templateId && getTemplateById(templateId).uid) || gridSchema['x-uid'];
const schema = { const schema = {
['x-uid']: uid, ['x-uid']: uid,
@ -1332,15 +1332,15 @@ export const SchemaSettingsDataTemplates = function DataTemplates(props) {
fieldReaction: { fieldReaction: {
'x-decorator': (props) => <FlagProvider {...props} isInFormDataTemplate />, 'x-decorator': (props) => <FlagProvider {...props} isInFormDataTemplate />,
'x-component': FormDataTemplates, 'x-component': FormDataTemplates,
'x-use-component-props': () => {
return {
defaultValues: templateData,
collectionName,
};
},
'x-component-props': { 'x-component-props': {
designerCtx, designerCtx,
formSchema, formSchema,
useProps: () => {
return {
defaultValues: templateData,
collectionName,
};
},
}, },
}, },
}, },
@ -1395,13 +1395,11 @@ export function SchemaSettingsEnableChildCollections(props) {
properties: { properties: {
enableChildren: { enableChildren: {
'x-component': EnableChildCollections, 'x-component': EnableChildCollections,
'x-component-props': { 'x-use-component-props': () => {
useProps: () => { return {
return { defaultValues: fieldSchema?.['x-enable-children'],
defaultValues: fieldSchema?.['x-enable-children'], collectionName,
collectionName, };
};
},
}, },
}, },
allowAddToCurrent: { allowAddToCurrent: {

View File

@ -140,7 +140,7 @@ export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props:
} }
if (collectionField?.uiSchema['x-component'] === 'Checkbox') { if (collectionField?.uiSchema['x-component'] === 'Checkbox') {
s['x-component-props'].defaultChecked = defaultValue; _.set(s, 'x-component-props.defaultChecked', defaultValue);
// 在这里如果不设置 type 为 void会导致设置的默认值不生效 // 在这里如果不设置 type 为 void会导致设置的默认值不生效
// 但是我不知道为什么必须要设置为 void // 但是我不知道为什么必须要设置为 void

View File

@ -72,13 +72,13 @@ export const uiSchemaTemplatesSchema: ISchema = {
title: '{{ t("Delete") }}', title: '{{ t("Delete") }}',
'x-action': 'destroy', 'x-action': 'destroy',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': useBulkDestroyTemplateProps,
'x-component-props': { 'x-component-props': {
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
confirm: { confirm: {
title: "{{t('Delete record')}}", title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}", content: "{{t('Are you sure you want to delete it?')}}",
}, },
useProps: useBulkDestroyTemplateProps,
}, },
}, },
}, },
@ -86,11 +86,11 @@ export const uiSchemaTemplatesSchema: ISchema = {
[uid()]: { [uid()]: {
type: 'array', type: 'array',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': { 'x-component-props': {
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableBlockProps }}',
}, },
properties: { properties: {
actions: { actions: {
@ -146,9 +146,7 @@ export const uiSchemaTemplatesSchema: ISchema = {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
@ -171,10 +169,10 @@ export const uiSchemaTemplatesSchema: ISchema = {
title: '{{t("Submit")}}', title: '{{t("Submit")}}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': useUpdateSchemaTemplateActionProps,
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: useUpdateSchemaTemplateActionProps,
}, },
type: 'void', type: 'void',
}, },
@ -192,13 +190,13 @@ export const uiSchemaTemplatesSchema: ISchema = {
title: '{{ t("Delete") }}', title: '{{ t("Delete") }}',
'x-action': 'destroy', 'x-action': 'destroy',
'x-component': 'Action.Link', 'x-component': 'Action.Link',
'x-use-component-props': useDestroyTemplateProps,
'x-component-props': { 'x-component-props': {
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
confirm: { confirm: {
title: "{{t('Delete record')}}", title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}", content: "{{t('Are you sure you want to delete it?')}}",
}, },
useProps: useDestroyTemplateProps,
}, },
}, },
}, },

View File

@ -97,9 +97,9 @@ export const roleCollectionsSchema: ISchema = {
}, },
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },

View File

@ -122,9 +122,7 @@ export const scopesSchema: ISchema = {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': useFormBlockProps,
useProps: useFormBlockProps,
},
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
@ -137,15 +135,17 @@ export const scopesSchema: ISchema = {
name: 'filter', name: 'filter',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ctx = useContext(RoleResourceCollectionContext);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useFilterOptions(ctx.name);
return {
options,
};
},
'x-component-props': { 'x-component-props': {
dynamicComponent: VariableInput, dynamicComponent: VariableInput,
useProps() {
const ctx = useContext(RoleResourceCollectionContext);
const options = useFilterOptions(ctx.name);
return {
options,
};
},
}, },
}, },
actions: { actions: {
@ -162,10 +162,10 @@ export const scopesSchema: ISchema = {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCreateActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useCreateActionProps }}',
}, },
}, },
}, },
@ -183,12 +183,12 @@ export const scopesSchema: ISchema = {
value: { value: {
type: 'array', type: 'array',
'x-component': 'TableV2.Selector', 'x-component': 'TableV2.Selector',
'x-use-component-props': 'useTableSelectorProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableSelectorProps }}',
}, },
properties: { properties: {
column1: { column1: {
@ -250,9 +250,7 @@ export const scopesSchema: ISchema = {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
@ -265,15 +263,17 @@ export const scopesSchema: ISchema = {
name: 'filter', name: 'filter',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ctx = useContext(RoleResourceCollectionContext);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useFilterOptions(ctx.name);
return {
options,
};
},
'x-component-props': { 'x-component-props': {
dynamicComponent: VariableInput, dynamicComponent: VariableInput,
useProps() {
const ctx = useContext(RoleResourceCollectionContext);
const options = useFilterOptions(ctx.name);
return {
options,
};
},
}, },
}, },
actions: { actions: {
@ -290,10 +290,10 @@ export const scopesSchema: ISchema = {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useUpdateActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useUpdateActionProps }}',
}, },
}, },
}, },
@ -311,13 +311,13 @@ export const scopesSchema: ISchema = {
'x-action': 'destroy', 'x-action': 'destroy',
'x-decorator': 'ACLActionProvider', 'x-decorator': 'ACLActionProvider',
'x-component': 'Action.Link', 'x-component': 'Action.Link',
'x-use-component-props': 'useDestroyActionProps',
'x-component-props': { 'x-component-props': {
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
confirm: { confirm: {
title: "{{t('Delete record')}}", title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}", content: "{{t('Are you sure you want to delete it?')}}",
}, },
useProps: '{{ useDestroyActionProps }}',
}, },
}, },
}, },
@ -341,10 +341,10 @@ export const scopesSchema: ISchema = {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'usePickActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ usePickActionProps }}',
}, },
}, },
}, },

View File

@ -6,13 +6,13 @@ export const BulkEditSubmitActionInitializer = (props) => {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCustomizeBulkEditActionProps',
// 'x-designer': 'Action.Designer', // 'x-designer': 'Action.Designer',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:updateSubmit', 'x-settings': 'actionSettings:updateSubmit',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useCustomizeBulkEditActionProps }}',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;

View File

@ -36,9 +36,7 @@ export function createBulkEditBlockUISchema(options: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useCreateFormBlockProps',
useProps: '{{ useCreateFormBlockProps }}',
},
properties: { properties: {
grid: { grid: {
type: 'void', type: 'void',

View File

@ -7,6 +7,7 @@ export const BulkUpdateActionInitializer = () => {
type: 'void', type: 'void',
title: '{{ t("Bulk update") }}', title: '{{ t("Bulk update") }}',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCustomizeBulkUpdateActionProps',
'x-align': 'right', 'x-align': 'right',
'x-acl-action': 'update', 'x-acl-action': 'update',
'x-decorator': 'ACLActionProvider', 'x-decorator': 'ACLActionProvider',
@ -27,7 +28,6 @@ export const BulkUpdateActionInitializer = () => {
}, },
'x-component-props': { 'x-component-props': {
icon: 'EditOutlined', icon: 'EditOutlined',
useProps: '{{ useCustomizeBulkUpdateActionProps }}',
}, },
}; };
return <BlockInitializer {...itemConfig} schema={schema} item={itemConfig} />; return <BlockInitializer {...itemConfig} schema={schema} item={itemConfig} />;

View File

@ -84,7 +84,7 @@ function DuplicationMode() {
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const { name } = useCollection_deprecated(); const { name } = useCollection_deprecated();
const { collectionList, getEnableFieldTree, getOnLoadData, getOnCheck } = useCollectionState(name); const { collectionList, getEnableFieldTree, getOnLoadData, getOnCheck } = useCollectionState(name);
const duplicateValues = cloneDeep(fieldSchema['x-component-props'].duplicateFields || []); const duplicateValues = cloneDeep(fieldSchema['x-component-props']?.duplicateFields || []);
const record = useRecord(); const record = useRecord();
const syncCallBack = useCallback((treeData, selectFields, form) => { const syncCallBack = useCallback((treeData, selectFields, form) => {
form.query('duplicateFields').take((f) => { form.query('duplicateFields').take((f) => {

View File

@ -7,9 +7,9 @@ export const PrintActionInitializer = (props) => {
title: '{{ t("Print") }}', title: '{{ t("Print") }}',
'x-action': 'print', 'x-action': 'print',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useDetailPrintActionProps',
'x-component-props': { 'x-component-props': {
icon: 'PrinterOutlined', icon: 'PrinterOutlined',
useProps: '{{ useDetailPrintActionProps }}',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;

View File

@ -166,9 +166,9 @@ export const configurationSchema: ISchema = {
[uid()]: { [uid()]: {
type: 'array', type: 'array',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
useProps: '{{ useTableBlockProps }}',
}, },
properties: { properties: {
column1: { column1: {

View File

@ -66,10 +66,8 @@ export const AuditLogsViewActionInitializer = () => {
bv710pbf9w6: { bv710pbf9w6: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-use-component-props': 'useFormBlockProps',
'x-read-pretty': true, 'x-read-pretty': true,
'x-component-props': {
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
grid: { grid: {
type: 'void', type: 'void',
@ -259,9 +257,9 @@ export const AuditLogsViewActionInitializer = () => {
changes: { changes: {
type: 'array', type: 'array',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableFieldProps',
'x-component-props': { 'x-component-props': {
rowSelection: false, rowSelection: false,
useProps: '{{ useTableFieldProps }}',
}, },
properties: { properties: {
'5uvv96u9ict': { '5uvv96u9ict': {

View File

@ -37,12 +37,12 @@ export function createAuditLogsBlockSchema(): ISchema {
type: 'array', type: 'array',
'x-initializer': 'auditLogsTable:configureColumns', 'x-initializer': 'auditLogsTable:configureColumns',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableBlockProps }}',
}, },
properties: { properties: {
actions: { actions: {

View File

@ -145,9 +145,9 @@ export const AuditLogs: any = () => {
'x-action': 'filter', 'x-action': 'filter',
// 'x-designer': 'Filter.Action.Designer', // 'x-designer': 'Filter.Action.Designer',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },
@ -156,12 +156,12 @@ export const AuditLogs: any = () => {
y84dlntcaup: { y84dlntcaup: {
type: 'array', type: 'array',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableBlockProps }}',
}, },
properties: { properties: {
actions: { actions: {
@ -232,10 +232,8 @@ export const AuditLogs: any = () => {
mevpuonrda0: { mevpuonrda0: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-use-component-props': 'useFormBlockProps',
'x-read-pretty': true, 'x-read-pretty': true,
'x-component-props': {
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
grid: { grid: {
type: 'void', type: 'void',

View File

@ -39,9 +39,7 @@ const schema: ISchema = {
type: 'array', type: 'array',
name: 'calendar1', name: 'calendar1',
'x-component': 'CalendarV2', 'x-component': 'CalendarV2',
'x-component-props': { 'x-use-component-props': 'useCalendarBlockProps',
useProps: '{{ useCalendarBlockProps }}',
},
properties: { properties: {
toolBar: { toolBar: {
type: 'void', type: 'void',

View File

@ -132,6 +132,7 @@ export const CalendarFormActionInitializers = new SchemaInitializer({
schema: { schema: {
title: generateNTemplate('Update record'), title: generateNTemplate('Update record'),
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCustomizeUpdateActionProps',
// 'x-designer': 'Action.Designer', // 'x-designer': 'Action.Designer',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:updateRecord', 'x-settings': 'actionSettings:updateRecord',
@ -146,9 +147,6 @@ export const CalendarFormActionInitializers = new SchemaInitializer({
}, },
triggerWorkflows: [], triggerWorkflows: [],
}, },
'x-component-props': {
useProps: '{{ useCustomizeUpdateActionProps }}',
},
}, },
useVisible() { useVisible() {
const collection = useCollection_deprecated(); const collection = useCollection_deprecated();

View File

@ -231,7 +231,7 @@ export const ChartBlockEngineDesignerInitializer = (props) => {
field.title = values.chart.title; field.title = values.chart.title;
fieldSchema['title'] = values.chart.title; fieldSchema['title'] = values.chart.title;
field.componentProps.chartBlockEngineMetaData = values; field.componentProps.chartBlockEngineMetaData = values;
fieldSchema['x-component-props'].chartBlockEngineMetaData = values; _.set(fieldSchema, 'x-component-props.chartBlockEngineMetaData', values);
dn.emit('patch', { dn.emit('patch', {
schema: { schema: {
'x-uid': fieldSchema['x-uid'], 'x-uid': fieldSchema['x-uid'],

View File

@ -1,6 +1,7 @@
import { Collection } from '@nocobase/database'; import { Collection } from '@nocobase/database';
import { Migration } from '@nocobase/server'; import { Migration } from '@nocobase/server';
import { FieldModel } from '../models'; import { FieldModel } from '../models';
import _ from 'lodash';
export default class extends Migration { export default class extends Migration {
appVersion = '<0.10.0-alpha.3'; appVersion = '<0.10.0-alpha.3';
@ -24,7 +25,7 @@ export default class extends Migration {
if (uiSchema?.['x-component-props']?.step !== '0') { if (uiSchema?.['x-component-props']?.step !== '0') {
continue; continue;
} }
uiSchema['x-component-props']['step'] = '1'; _.set(uiSchema, 'x-component-props.step', '1');
fieldRecord.set('uiSchema', uiSchema); fieldRecord.set('uiSchema', uiSchema);
await fieldRecord.save({ await fieldRecord.save({
transaction, transaction,

View File

@ -1,39 +1,49 @@
import React from 'react'; import React from 'react';
import { Switch, Tooltip, message } from 'antd'; import { Switch, Tooltip, message } from 'antd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useCollectionManager_deprecated, useRecord, useAPIClient } from '@nocobase/client'; import {
useCollectionManager_deprecated,
useRecord,
useAPIClient,
withDynamicSchemaProps,
useProps,
} from '@nocobase/client';
import { useRemoteCollectionContext } from '../CollectionFields'; import { useRemoteCollectionContext } from '../CollectionFields';
export const TitleField = (props) => { export const TitleField = withDynamicSchemaProps(
const { useProps } = props; (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { isTitleField } = useCollectionManager_deprecated(); const { isTitleField } = useCollectionManager_deprecated();
const [loadingRecord, setLoadingRecord] = React.useState(null); const [loadingRecord, setLoadingRecord] = React.useState(null);
const { setTitleField, filterByTk, dataSourceKey } = useProps();
const record = useRecord(); // 新版 UISchema1.0 之后)中已经废弃了 useProps这里之所以继续保留是为了兼容旧版的 UISchema
const api = useAPIClient(); const { setTitleField, filterByTk, dataSourceKey } = useProps(props);
const { refreshRM, titleField } = useRemoteCollectionContext(); const record = useRecord();
const handleChange = async (checked) => { const api = useAPIClient();
setLoadingRecord(record); const { refreshRM, titleField } = useRemoteCollectionContext();
await api.request({ const handleChange = async (checked) => {
url: `dataSources/${dataSourceKey}/collections:update?filterByTk=${filterByTk}`, setLoadingRecord(record);
method: 'post', await api.request({
data: { titleField: checked ? record.name : 'id' }, url: `dataSources/${dataSourceKey}/collections:update?filterByTk=${filterByTk}`,
}); method: 'post',
message.success(t('Saved successfully')); data: { titleField: checked ? record.name : 'id' },
refreshRM(); });
setTitleField(checked ? record.name : 'id'); message.success(t('Saved successfully'));
setLoadingRecord(null); refreshRM();
}; setTitleField(checked ? record.name : 'id');
return isTitleField(record) ? ( setLoadingRecord(null);
<Tooltip title={t('Default title for each record')} placement="right" overlayInnerStyle={{ textAlign: 'center' }}> };
<Switch return isTitleField(record) ? (
aria-label={`switch-title-field-${record?.name}`} <Tooltip title={t('Default title for each record')} placement="right" overlayInnerStyle={{ textAlign: 'center' }}>
size="small" <Switch
loading={record?.name === loadingRecord?.name} aria-label={`switch-title-field-${record?.name}`}
checked={record?.name === (titleField || 'id')} size="small"
onChange={handleChange} loading={record?.name === loadingRecord?.name}
/> checked={record?.name === (titleField || 'id')}
</Tooltip> onChange={handleChange}
) : null; />
}; </Tooltip>
) : null;
},
{ displayName: 'TitleField' },
);

View File

@ -194,10 +194,8 @@ export const fieldsTableSchema: ISchema = {
properties: { properties: {
titleField: { titleField: {
'x-component': 'TitleField', 'x-component': 'TitleField',
'x-use-component-props': 'useTitleFieldProps',
'x-read-pretty': false, 'x-read-pretty': false,
'x-component-props': {
useProps: '{{useTitleFieldProps}}',
},
}, },
}, },
}, },

View File

@ -136,9 +136,9 @@ export const collectionTableSchema: ISchema = {
}, },
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'cm.useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ cm.useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },
@ -146,9 +146,9 @@ export const collectionTableSchema: ISchema = {
type: 'void', type: 'void',
title: '{{ t("Refresh") }}', title: '{{ t("Refresh") }}',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useRefreshActionProps',
'x-component-props': { 'x-component-props': {
icon: 'ReloadOutlined', icon: 'ReloadOutlined',
useProps: '{{ useRefreshActionProps }}',
}, },
}, },
delete: { delete: {

View File

@ -137,9 +137,9 @@ export const collectionTableSchema: ISchema = {
}, },
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'cm.useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ cm.useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },

View File

@ -112,9 +112,9 @@ export const roleCollectionsSchema: ISchema = {
}, },
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'cm.useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ cm.useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },

View File

@ -125,9 +125,7 @@ export const getScopesSchema = (dataSourceKey) => {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': useFormBlockProps,
useProps: useFormBlockProps,
},
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
@ -140,15 +138,17 @@ export const getScopesSchema = (dataSourceKey) => {
name: 'filter', name: 'filter',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ctx = useContext(RoleResourceCollectionContext);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useFilterFieldOptions(ctx.fields);
return {
options,
};
},
'x-component-props': { 'x-component-props': {
dynamicComponent: VariableInput, dynamicComponent: VariableInput,
useProps() {
const ctx = useContext(RoleResourceCollectionContext);
const options = useFilterFieldOptions(ctx.fields);
return {
options,
};
},
}, },
}, },
actions: { actions: {
@ -165,10 +165,10 @@ export const getScopesSchema = (dataSourceKey) => {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useCreateActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useCreateActionProps }}',
}, },
}, },
}, },
@ -186,12 +186,12 @@ export const getScopesSchema = (dataSourceKey) => {
value: { value: {
type: 'array', type: 'array',
'x-component': 'TableV2.Selector', 'x-component': 'TableV2.Selector',
'x-use-component-props': 'useTableSelectorProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
rowSelection: { rowSelection: {
type: 'checkbox', type: 'checkbox',
}, },
useProps: '{{ useTableSelectorProps }}',
}, },
properties: { properties: {
column1: { column1: {
@ -253,9 +253,7 @@ export const getScopesSchema = (dataSourceKey) => {
form: { form: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
@ -268,15 +266,17 @@ export const getScopesSchema = (dataSourceKey) => {
name: 'filter', name: 'filter',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ctx = useContext(RoleResourceCollectionContext);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useFilterFieldOptions(ctx.fields);
return {
options,
};
},
'x-component-props': { 'x-component-props': {
dynamicComponent: VariableInput, dynamicComponent: VariableInput,
useProps() {
const ctx = useContext(RoleResourceCollectionContext);
const options = useFilterFieldOptions(ctx.fields);
return {
options,
};
},
}, },
}, },
actions: { actions: {
@ -293,10 +293,10 @@ export const getScopesSchema = (dataSourceKey) => {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useUpdateActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ useUpdateActionProps }}',
}, },
}, },
}, },
@ -314,13 +314,13 @@ export const getScopesSchema = (dataSourceKey) => {
'x-action': 'destroy', 'x-action': 'destroy',
'x-decorator': 'ACLActionProvider', 'x-decorator': 'ACLActionProvider',
'x-component': 'Action.Link', 'x-component': 'Action.Link',
'x-use-component-props': 'useDestroyActionProps',
'x-component-props': { 'x-component-props': {
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
confirm: { confirm: {
title: "{{t('Delete record')}}", title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}", content: "{{t('Are you sure you want to delete it?')}}",
}, },
useProps: '{{ useDestroyActionProps }}',
}, },
}, },
}, },
@ -344,10 +344,10 @@ export const getScopesSchema = (dataSourceKey) => {
title: '{{ t("Submit") }}', title: '{{ t("Submit") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'usePickActionProps',
'x-component-props': { 'x-component-props': {
type: 'primary', type: 'primary',
htmlType: 'submit', htmlType: 'submit',
useProps: '{{ usePickActionProps }}',
}, },
}, },
}, },

View File

@ -102,9 +102,9 @@ export const databaseConnectionSchema: ISchema = {
type: 'void', type: 'void',
title: '{{ t("Refresh") }}', title: '{{ t("Refresh") }}',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useRefreshActionProps',
'x-component-props': { 'x-component-props': {
icon: 'ReloadOutlined', icon: 'ReloadOutlined',
useProps: '{{ useRefreshActionProps }}',
}, },
}, },
delete: { delete: {

View File

@ -88,11 +88,11 @@ const ChartFilterActionInitializer = (props) => {
title: '{{ t("Filter") }}', title: '{{ t("Filter") }}',
'x-action': 'submit', 'x-action': 'submit',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useChartFilterActionProps',
'x-designer': 'ChartFilterActionDesigner', 'x-designer': 'ChartFilterActionDesigner',
'x-component-props': { 'x-component-props': {
htmlType: 'submit', htmlType: 'submit',
type: 'primary', type: 'primary',
useProps: '{{ useChartFilterActionProps }}',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;
@ -103,10 +103,8 @@ const ChartFilterResetInitializer = (props) => {
title: '{{ t("Reset") }}', title: '{{ t("Reset") }}',
'x-action': 'reset', 'x-action': 'reset',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useChartFilterResetProps',
'x-designer': 'ChartFilterActionDesigner', 'x-designer': 'ChartFilterActionDesigner',
'x-component-props': {
useProps: '{{ useChartFilterResetProps }}',
},
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializer {...props} schema={schema} />;
}; };
@ -116,9 +114,9 @@ const ChartFilterCollapseInitializer = (props) => {
title: `{{ t("Collapse") }}`, title: `{{ t("Collapse") }}`,
'x-action': 'collapse', 'x-action': 'collapse',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useChartFilterCollapseProps',
'x-component-props': { 'x-component-props': {
type: 'link', type: 'link',
useProps: '{{ useChartFilterCollapseProps }}',
}, },
'x-designer': 'ChartFilterCollapseDesigner', 'x-designer': 'ChartFilterCollapseDesigner',
}; };

View File

@ -20,6 +20,7 @@ import lodash from 'lodash';
import { getFormulaComponent, getValuesByPath } from '../utils'; import { getFormulaComponent, getValuesByPath } from '../utils';
import deepmerge from 'deepmerge'; import deepmerge from 'deepmerge';
import { findSchema, getFilterFieldPrefix, parseFilterFieldName } from '../filter/utils'; import { findSchema, getFilterFieldPrefix, parseFilterFieldName } from '../filter/utils';
import _ from 'lodash';
export const useCustomFieldInterface = () => { export const useCustomFieldInterface = () => {
const { getInterface } = useCollectionManager_deprecated(); const { getInterface } = useCollectionManager_deprecated();
@ -135,7 +136,7 @@ export const useChartFilter = () => {
}; };
} }
if (['oho', 'o2m'].includes(field.interface)) { if (['oho', 'o2m'].includes(field.interface)) {
schema['x-component-props'].useOriginalFilter = true; _.set(schema, 'x-component-props.useOriginalFilter', true);
} }
const resultItem: SchemaInitializerItemType = { const resultItem: SchemaInitializerItemType = {
key: `${name}.${field.name}`, key: `${name}.${field.name}`,

View File

@ -61,9 +61,9 @@ export const ExportActionInitializer = () => {
'x-settings': 'actionSettings:export', 'x-settings': 'actionSettings:export',
'x-decorator': 'ACLActionProvider', 'x-decorator': 'ACLActionProvider',
'x-component': 'Action', 'x-component': 'Action',
'x-use-component-props': 'useExportAction',
'x-component-props': { 'x-component-props': {
icon: 'clouddownloadoutlined', icon: 'clouddownloadoutlined',
useProps: '{{ useExportAction }}',
}, },
}; };
return ( return (

View File

@ -26,10 +26,10 @@ export const UploadActionInitializer = (props) => {
type: 'void', type: 'void',
title: '{{ t("Upload files") }}', title: '{{ t("Upload files") }}',
'x-component': 'Upload.DraggerV2', 'x-component': 'Upload.DraggerV2',
'x-use-component-props': 'useUploadFiles',
'x-component-props': { 'x-component-props': {
height: '50vh', height: '50vh',
// action: `${collection.name}:create`, // action: `${collection.name}:create`,
useProps: '{{useUploadFiles}}',
multiple: true, multiple: true,
listType: 'picture', listType: 'picture',
}, },

View File

@ -31,6 +31,7 @@ export default class extends Migration {
if (!field) { if (!field) {
continue; continue;
} }
schema['x-component-props'] = schema['x-component-props'] || {};
schema['x-component-props'].action = schema['x-component-props'].action.replace( schema['x-component-props'].action = schema['x-component-props'].action.replace(
'attachementField', 'attachementField',
'attachmentField', 'attachmentField',

View File

@ -7,8 +7,8 @@ const schema = {
tasks: { tasks: {
type: 'void', type: 'void',
'x-component': 'Gantt', 'x-component': 'Gantt',
'x-use-component-props': 'useGanttBlockProps',
'x-component-props': { 'x-component-props': {
useProps: '{{ useGanttBlockProps }}',
tasks: [ tasks: [
{ {
start: new Date(2020, 0, 1), start: new Date(2020, 0, 1),

View File

@ -44,9 +44,7 @@ export const createSnapshotBlockSchema = (options) => {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-read-pretty': true, 'x-read-pretty': true,
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
grid: template || { grid: template || {
type: 'void', type: 'void',

View File

@ -2,6 +2,7 @@ import { Schema } from '@formily/json-schema';
import { Migration } from '@nocobase/server'; import { Migration } from '@nocobase/server';
import { uid } from '@nocobase/utils'; import { uid } from '@nocobase/utils';
import UiSchemaRepository from '../repository'; import UiSchemaRepository from '../repository';
import _ from 'lodash';
export default class extends Migration { export default class extends Migration {
appVersion = '<0.9.3-alpha.1'; appVersion = '<0.9.3-alpha.1';
@ -23,7 +24,8 @@ export default class extends Migration {
const schema = item.schema; const schema = item.schema;
schema['type'] = 'object'; schema['type'] = 'object';
schema['x-component'] = 'CollectionField'; schema['x-component'] = 'CollectionField';
schema['x-component-props']['mode'] = 'Nester'; _.set(schema, 'x-component-props.mode', 'Nester');
item.set('schema', schema); item.set('schema', schema);
await item.save({ transaction }); await item.save({ transaction });
const s = await r.getProperties(item['x-uid'], { transaction }); const s = await r.getProperties(item['x-uid'], { transaction });

View File

@ -152,9 +152,9 @@ export const usersSchema: ISchema = {
title: '{{ t("Filter") }}', title: '{{ t("Filter") }}',
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },
@ -493,9 +493,9 @@ export const getRoleUsersSchema = (): ISchema => ({
title: '{{ t("Filter") }}', title: '{{ t("Filter") }}',
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },
@ -556,9 +556,9 @@ export const getRoleUsersSchema = (): ISchema => ({
}, },
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },

View File

@ -13,9 +13,7 @@ const submitToWorkflowActionInitializer: SchemaInitializerItemType = {
schema: { schema: {
title: '{{t("Submit to workflow", { ns: "workflow" })}}', title: '{{t("Submit to workflow", { ns: "workflow" })}}',
'x-component': 'Action', 'x-component': 'Action',
'x-component-props': { 'x-use-component-props': 'useTriggerWorkflowsActionProps',
useProps: '{{ useTriggerWorkflowsActionProps }}',
},
'x-designer': 'Action.Designer', 'x-designer': 'Action.Designer',
'x-action-settings': { 'x-action-settings': {
// assignedValues: {}, // assignedValues: {},

View File

@ -341,19 +341,21 @@ export default class extends Instruction {
title: '{{t("Filter")}}', title: '{{t("Filter")}}',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { values } = useForm();
const [dataSourceName, collectionName] = parseCollectionName(values?.collection);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useCollectionFilterOptions(collectionName, dataSourceName);
return {
options,
className: css`
position: relative;
width: 100%;
`,
};
},
'x-component-props': { 'x-component-props': {
useProps() {
const { values } = useForm();
const [dataSourceName, collectionName] = parseCollectionName(values?.collection);
const options = useCollectionFilterOptions(collectionName, dataSourceName);
return {
options,
className: css`
position: relative;
width: 100%;
`,
};
},
dynamicComponent: 'FilterDynamicComponent', dynamicComponent: 'FilterDynamicComponent',
}, },
'x-reactions': [ 'x-reactions': [

View File

@ -245,9 +245,9 @@ export const WorkflowTodo: React.FC & { Drawer: React.FC; Decorator: React.FC }
'x-action': 'filter', 'x-action': 'filter',
'x-designer': 'Filter.Action.Designer', 'x-designer': 'Filter.Action.Designer',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },
@ -259,9 +259,9 @@ export const WorkflowTodo: React.FC & { Drawer: React.FC; Decorator: React.FC }
// 'x-designer': 'Action.Designer', // 'x-designer': 'Action.Designer',
'x-toolbar': 'ActionSchemaToolbar', 'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:refresh', 'x-settings': 'actionSettings:refresh',
'x-use-component-props': 'useRefreshActionProps',
'x-component-props': { 'x-component-props': {
icon: 'ReloadOutlined', icon: 'ReloadOutlined',
useProps: '{{ useRefreshActionProps }}',
}, },
'x-align': 'right', 'x-align': 'right',
}, },
@ -270,9 +270,9 @@ export const WorkflowTodo: React.FC & { Drawer: React.FC; Decorator: React.FC }
table: { table: {
type: 'array', type: 'array',
'x-component': 'TableV2', 'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
useProps: '{{ useTableBlockProps }}',
}, },
properties: { properties: {
actions: { actions: {

View File

@ -95,10 +95,7 @@ function CustomFormBlockInitializer() {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
// disabled / read-pretty / initialValues
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
grid: { grid: {
type: 'void', type: 'void',

View File

@ -39,13 +39,14 @@ function UpdateFormDesigner() {
title: `{{t("Filter")}}`, title: `{{t("Filter")}}`,
// 'x-decorator': 'FormItem', // 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useCollectionFilterOptions(fieldSchema?.['x-decorator-props']?.collection);
return {
options,
};
},
'x-component-props': { 'x-component-props': {
useProps() {
const options = useCollectionFilterOptions(fieldSchema?.['x-decorator-props']?.collection);
return {
options,
};
},
dynamicComponent: 'FilterDynamicComponent', dynamicComponent: 'FilterDynamicComponent',
}, },
}} }}

View File

@ -48,9 +48,7 @@ function InnerCollectionBlockInitializer({ collection, dataPath, ...props }) {
grid: { grid: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useDetailsBlockProps',
useProps: '{{useDetailsBlockProps}}',
},
'x-read-pretty': true, 'x-read-pretty': true,
properties: { properties: {
grid: template || { grid: template || {

View File

@ -407,10 +407,7 @@ export function NodeDefaultView(props) {
</div> </div>
), ),
'x-decorator': 'FormV2', 'x-decorator': 'FormV2',
'x-decorator-props': { 'x-use-decorator-props': 'useFormProviderProps',
// form,
useProps: '{{ useFormProviderProps }}',
},
'x-component': 'Action.Drawer', 'x-component': 'Action.Drawer',
properties: { properties: {
...(instruction.description ...(instruction.description

View File

@ -30,19 +30,21 @@ export const filter = {
title: '{{t("Filter")}}', title: '{{t("Filter")}}',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Filter', 'x-component': 'Filter',
'x-use-component-props': () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { values } = useForm();
const [dataSourceName, collectionName] = parseCollectionName(values?.collection);
// eslint-disable-next-line react-hooks/rules-of-hooks
const options = useCollectionFilterOptions(collectionName, dataSourceName);
return {
options,
className: css`
position: relative;
width: 100%;
`,
};
},
'x-component-props': { 'x-component-props': {
useProps() {
const { values } = useForm();
const [dataSourceName, collectionName] = parseCollectionName(values?.collection);
const options = useCollectionFilterOptions(collectionName, dataSourceName);
return {
options,
className: css`
position: relative;
width: 100%;
`,
};
},
dynamicComponent: 'FilterDynamicComponent', dynamicComponent: 'FilterDynamicComponent',
}, },
}; };

View File

@ -178,9 +178,9 @@ export const workflowSchema: ISchema = {
}, },
'x-action': 'filter', 'x-action': 'filter',
'x-component': 'Filter.Action', 'x-component': 'Filter.Action',
'x-use-component-props': 'cm.useFilterActionProps',
'x-component-props': { 'x-component-props': {
icon: 'FilterOutlined', icon: 'FilterOutlined',
useProps: '{{ cm.useFilterActionProps }}',
}, },
'x-align': 'left', 'x-align': 'left',
}, },

View File

@ -123,9 +123,7 @@ export default class extends Trigger {
condition: { condition: {
...filter, ...filter,
title: `{{t("Only triggers when match conditions", { ns: "${NAMESPACE}" })}}`, title: `{{t("Only triggers when match conditions", { ns: "${NAMESPACE}" })}}`,
'x-component-props': { 'x-component-props': {},
useProps: filter['x-component-props'].useProps,
},
'x-reactions': [ 'x-reactions': [
{ {
dependencies: ['collection'], dependencies: ['collection'],

View File

@ -266,10 +266,7 @@ export const TriggerConfig = () => {
title: titleText, title: titleText,
'x-component': 'Action.Drawer', 'x-component': 'Action.Drawer',
'x-decorator': 'FormV2', 'x-decorator': 'FormV2',
'x-decorator-props': { 'x-use-decorator-props': 'useFormProviderProps',
// form,
useProps: '{{ useFormProviderProps }}',
},
properties: { properties: {
...(trigger.description ...(trigger.description
? { ? {

View File

@ -108,9 +108,7 @@ function migrateConfig({ schema = {}, actions = [] }: { schema: any; actions: nu
[formId]: { [formId]: {
type: 'void', type: 'void',
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useFormBlockProps',
useProps: '{{ useFormBlockProps }}',
},
properties: { properties: {
grid: Object.assign(formBlock.properties.grid, { grid: Object.assign(formBlock.properties.grid, {
'x-initializer': 'workflowManual:customForm:configureFields', 'x-initializer': 'workflowManual:customForm:configureFields',

View File

@ -56,9 +56,7 @@ function migrateSchema(schema = {}): object {
type: 'void', type: 'void',
name: id, name: id,
'x-component': 'FormV2', 'x-component': 'FormV2',
'x-component-props': { 'x-use-component-props': 'useDetailsBlockProps',
useProps: '{{useDetailsBlockProps}}',
},
properties: { properties: {
grid: { grid: {
type: 'void', type: 'void',