mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 08:55:33 +00:00
refactor: support dynamic field component (#4932)
* refactor: support dynamic field component * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: add addFieldInterfaceComponentOption() doc * fix: bug * fix: bug * fix: add unit test * fix: bug * fix: bug
This commit is contained in:
parent
7276a404e4
commit
a7c2f90260
@ -20,6 +20,7 @@ export interface ApplicationOptions {
|
|||||||
schemaInitializers?: SchemaInitializer[];
|
schemaInitializers?: SchemaInitializer[];
|
||||||
loadRemotePlugins?: boolean;
|
loadRemotePlugins?: boolean;
|
||||||
dataSourceManager?: DataSourceManagerOptions;
|
dataSourceManager?: DataSourceManagerOptions;
|
||||||
|
addFieldInterfaceComponentOption(fieldName: string, componentOption: CollectionFieldInterfaceComponentOption): void;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ export interface ApplicationOptions {
|
|||||||
- `schemaInitializers`: Schema addition tool. For more information, refer to: [SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
|
- `schemaInitializers`: Schema addition tool. For more information, refer to: [SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
|
||||||
- `loadRemotePlugins`: Used to control whether to load remote plugins. Default is `false`, meaning remote plugins are not loaded (convenient for unit testing and DEMO environments).
|
- `loadRemotePlugins`: Used to control whether to load remote plugins. Default is `false`, meaning remote plugins are not loaded (convenient for unit testing and DEMO environments).
|
||||||
- `dataSourceManager`: Data source manager. For more details, refer to: [DataSourceManager](/core/data-source/data-source-manager)
|
- `dataSourceManager`: Data source manager. For more details, refer to: [DataSourceManager](/core/data-source/data-source-manager)
|
||||||
|
- `addFieldInterfaceComponentOption`: Add field interface component options. For more details, refer to: [CollectionFieldInterfaceManager](/core/data-source/collection-field-interface-manager#addfieldinterfacecomponentoption)
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
@ -344,6 +346,23 @@ app.getCollectionManager() // Get the default data source collection manager
|
|||||||
app.getCollectionManager('test') // Get the specified data source collection manager
|
app.getCollectionManager('test') // Get the specified data source collection manager
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### app.addFieldInterfaceComponentOption()
|
||||||
|
|
||||||
|
Add field interface component option.
|
||||||
|
|
||||||
|
For a detailed introduction, please refer to: [CollectionFieldInterfaceManager](/core/data-source/collection-field-interface-manager#addfieldinterfacecomponentoption)
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
class MyPlugin extends Plugin {
|
||||||
|
async load() {
|
||||||
|
this.app.addFieldInterfaceComponentOption('url', {
|
||||||
|
label: 'Preview',
|
||||||
|
value: 'Input.Preview',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Hooks
|
## Hooks
|
||||||
|
|
||||||
### useApp()
|
### useApp()
|
||||||
|
@ -89,6 +89,41 @@ class MyPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### addFieldInterfaceComponentOption()
|
||||||
|
|
||||||
|
Add field interface component option.
|
||||||
|
|
||||||
|
![20240725113756](https://static-docs.nocobase.com/20240725113756.png)
|
||||||
|
|
||||||
|
- 类型
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
interface CollectionFieldInterfaceComponentOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
useVisible?: () => boolean;
|
||||||
|
useProps?: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionFieldInterfaceManager {
|
||||||
|
addFieldInterfaceComponentOption(interfaceName: string, componentOption: CollectionFieldInterfaceComponentOption): void
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 示例
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
class MyPlugin extends Plugin {
|
||||||
|
async load() {
|
||||||
|
this.app.dataSourceManager.collectionFieldInterfaceManager.addFieldInterfaceComponentOption('url', {
|
||||||
|
label: 'Preview',
|
||||||
|
value: 'Input.Preview',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### field interface group
|
### field interface group
|
||||||
|
|
||||||
#### addFieldInterfaceGroups()
|
#### addFieldInterfaceGroups()
|
||||||
|
@ -34,10 +34,6 @@ class CollectionFieldInterface {
|
|||||||
validateSchema(fieldSchema: ISchema): Record<string, ISchema>
|
validateSchema(fieldSchema: ISchema): Record<string, ISchema>
|
||||||
usePathOptions(field: CollectionFieldOptions): any
|
usePathOptions(field: CollectionFieldOptions): any
|
||||||
schemaInitialize(schema: ISchema, data: any): void
|
schemaInitialize(schema: ISchema, data: any): void
|
||||||
|
|
||||||
getOption<K extends keyof IField>(key: K): CollectionFieldInterfaceOptions[K]
|
|
||||||
getOptions(): CollectionFieldInterfaceOptions;
|
|
||||||
setOptions(options: CollectionFieldInterfaceOptions): void;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -20,21 +20,23 @@ export interface ApplicationOptions {
|
|||||||
schemaInitializers?: SchemaInitializer[];
|
schemaInitializers?: SchemaInitializer[];
|
||||||
loadRemotePlugins?: boolean;
|
loadRemotePlugins?: boolean;
|
||||||
dataSourceManager?: DataSourceManagerOptions;
|
dataSourceManager?: DataSourceManagerOptions;
|
||||||
|
addFieldInterfaceComponentOption(fieldName: string, componentOption: CollectionFieldInterfaceComponentOption): void;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- 详细信息
|
- 详细信息
|
||||||
- apiClient:API 请求实例,具体说明请参见:[https://docs.nocobase.com/api/sdk](https://docs.nocobase.com/api/sdk)
|
- `apiClient`:API 请求实例,具体说明请参见:[https://docs.nocobase.com/api/sdk](https://docs.nocobase.com/api/sdk)
|
||||||
- i18n:国际化,具体请参考:[https://www.i18next.com/overview/api#createinstance](https://www.i18next.com/overview/api#createinstance)
|
- `i18n`:国际化,具体请参考:[https://www.i18next.com/overview/api#createinstance](https://www.i18next.com/overview/api#createinstance)
|
||||||
- providers:上下文
|
- `providers`:上下文
|
||||||
- components:全局组件
|
- `components`:全局组件
|
||||||
- scopes:全局 scopes
|
- `scopes`:全局 scopes
|
||||||
- router:配置路由,具体请参考:[RouterManager](/core/application/router-manager)
|
- `router`:配置路由,具体请参考:[RouterManager](/core/application/router-manager)
|
||||||
- pluginSettings: [PluginSettingsManager](/core/application/plugin-settings-manager)
|
- `pluginSettings`: [PluginSettingsManager](/core/application/plugin-settings-manager)
|
||||||
- schemaSettings:Schema 设置工具,具体参考:[SchemaSettingsManager](/core/ui-schema/schema-initializer-manager)
|
- `schemaSettings`:Schema 设置工具,具体参考:[SchemaSettingsManager](/core/ui-schema/schema-initializer-manager)
|
||||||
- schemaInitializers:Schema 添加工具,具体参考:[SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
|
- `schemaInitializers`:Schema 添加工具,具体参考:[SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
|
||||||
- loadRemotePlugins:用于控制是否加载远程插件,默认为 `false`,即不加载远程插件(方便单测和 DEMO 环境)。
|
- `loadRemotePlugins`:用于控制是否加载远程插件,默认为 `false`,即不加载远程插件(方便单测和 DEMO 环境)。
|
||||||
- dataSourceManager:数据源管理器,具体参考:[DataSourceManager](/core/data-source/data-source-manager)
|
- `dataSourceManager`:数据源管理器,具体参考:[DataSourceManager](/core/data-source/data-source-manager)
|
||||||
|
- `addFieldInterfaceComponentOption`: 添加 Field interface 组件选项。具体参考: [CollectionFieldInterfaceManager](/core/data-source/collection-field-interface-manager#addfieldinterfacecomponentoption)
|
||||||
- 示例
|
- 示例
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
@ -343,6 +345,24 @@ app.getCollectionManager() // 获取默认数据源的 collection manager
|
|||||||
app.getCollectionManager('test') // 获取指定数据源的 collection manager
|
app.getCollectionManager('test') // 获取指定数据源的 collection manager
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### app.addFieldInterfaceComponentOption()
|
||||||
|
|
||||||
|
Add field interface component option.
|
||||||
|
|
||||||
|
添加 Field interface 组件选项。具体参考: [CollectionFieldInterfaceManager](/core/data-source/collection-field-interface-manager#addfieldinterfacecomponentoption)
|
||||||
|
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
class MyPlugin extends Plugin {
|
||||||
|
async load() {
|
||||||
|
this.app.addFieldInterfaceComponentOption('url', {
|
||||||
|
label: 'Preview',
|
||||||
|
value: 'Input.Preview',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Hooks
|
## Hooks
|
||||||
|
|
||||||
### useApp()
|
### useApp()
|
||||||
|
@ -89,6 +89,40 @@ class MyPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### addFieldInterfaceComponentOption()
|
||||||
|
|
||||||
|
添加 Field interface 组件选项。
|
||||||
|
|
||||||
|
![20240725113756](https://static-docs.nocobase.com/20240725113756.png)
|
||||||
|
|
||||||
|
- 类型
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
interface CollectionFieldInterfaceComponentOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
useVisible?: () => boolean;
|
||||||
|
useProps?: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionFieldInterfaceManager {
|
||||||
|
addFieldInterfaceComponentOption(interfaceName: string, componentOption: CollectionFieldInterfaceComponentOption): void
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 示例
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
class MyPlugin extends Plugin {
|
||||||
|
async load() {
|
||||||
|
this.app.dataSourceManager.collectionFieldInterfaceManager.addFieldInterfaceComponentOption('url', {
|
||||||
|
label: 'Preview',
|
||||||
|
value: 'Input.Preview',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### field interface group
|
### field interface group
|
||||||
|
|
||||||
#### addFieldInterfaceGroups()
|
#### addFieldInterfaceGroups()
|
||||||
|
@ -34,10 +34,6 @@ class CollectionFieldInterface {
|
|||||||
validateSchema(fieldSchema: ISchema): Record<string, ISchema>
|
validateSchema(fieldSchema: ISchema): Record<string, ISchema>
|
||||||
usePathOptions(field: CollectionFieldOptions): any
|
usePathOptions(field: CollectionFieldOptions): any
|
||||||
schemaInitialize(schema: ISchema, data: any): void
|
schemaInitialize(schema: ISchema, data: any): void
|
||||||
|
|
||||||
getOption<K extends keyof IField>(key: K): CollectionFieldInterfaceOptions[K]
|
|
||||||
getOptions(): CollectionFieldInterfaceOptions;
|
|
||||||
setOptions(options: CollectionFieldInterfaceOptions): void;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import { CollectionField } from '../data-source/collection-field/CollectionField
|
|||||||
import { DataSourceApplicationProvider } from '../data-source/components/DataSourceApplicationProvider';
|
import { DataSourceApplicationProvider } from '../data-source/components/DataSourceApplicationProvider';
|
||||||
import { DataBlockProvider } from '../data-source/data-block/DataBlockProvider';
|
import { DataBlockProvider } from '../data-source/data-block/DataBlockProvider';
|
||||||
import { DataSourceManager, type DataSourceManagerOptions } from '../data-source/data-source/DataSourceManager';
|
import { DataSourceManager, type DataSourceManagerOptions } from '../data-source/data-source/DataSourceManager';
|
||||||
|
import { CollectionFieldInterfaceComponentOption } from '../data-source/collection-field-interface/CollectionFieldInterface';
|
||||||
|
|
||||||
import { OpenModeProvider } from '../modules/popup/OpenModeProvider';
|
import { OpenModeProvider } from '../modules/popup/OpenModeProvider';
|
||||||
import { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
|
import { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
|
||||||
@ -355,4 +356,11 @@ export class Application {
|
|||||||
root.render(<App />);
|
root.render(<App />);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addFieldInterfaceComponentOption(fieldName: string, componentOption: CollectionFieldInterfaceComponentOption) {
|
||||||
|
return this.dataSourceManager.collectionFieldInterfaceManager.addFieldInterfaceComponentOption(
|
||||||
|
fieldName,
|
||||||
|
componentOption,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import { OpenModeProvider } from '../../modules/popup/OpenModeProvider';
|
|||||||
import { Application } from '../Application';
|
import { Application } from '../Application';
|
||||||
import { Plugin } from '../Plugin';
|
import { Plugin } from '../Plugin';
|
||||||
import { useApp } from '../hooks';
|
import { useApp } from '../hooks';
|
||||||
|
import { CollectionFieldInterface } from '../../data-source';
|
||||||
|
|
||||||
describe('Application', () => {
|
describe('Application', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@ -439,4 +440,43 @@ describe('Application', () => {
|
|||||||
console.error = originalConsoleWarn;
|
console.error = originalConsoleWarn;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('alias', () => {
|
||||||
|
test('addFieldInterfaceComponentOption', () => {
|
||||||
|
class TestInterface extends CollectionFieldInterface {
|
||||||
|
name = 'test';
|
||||||
|
default = {
|
||||||
|
type: 'string',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'TestComponent',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const app = new Application({
|
||||||
|
dataSourceManager: {
|
||||||
|
fieldInterfaces: [TestInterface],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
app.addFieldInterfaceComponentOption('test', {
|
||||||
|
label: 'A',
|
||||||
|
value: 'a',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(app.dataSourceManager.collectionFieldInterfaceManager.getFieldInterface('test').componentOptions)
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "TestComponent",
|
||||||
|
"useProps": [Function],
|
||||||
|
"value": "TestComponent",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "A",
|
||||||
|
"value": "a",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -12,9 +12,10 @@ import { ISchema, useFieldSchema } from '@formily/react';
|
|||||||
import { TFunction, useTranslation } from 'react-i18next';
|
import { TFunction, useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { SchemaSettingsItemType } from '../types';
|
import { SchemaSettingsItemType } from '../types';
|
||||||
import { getNewSchema, useHookDefault } from './util';
|
import { getNewSchema, useHookDefault, useSchemaByType } from './util';
|
||||||
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
||||||
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
||||||
|
import { useColumnSchema } from '../../../schema-component';
|
||||||
|
|
||||||
export interface CreateModalSchemaSettingsItemProps {
|
export interface CreateModalSchemaSettingsItemProps {
|
||||||
name: string;
|
name: string;
|
||||||
@ -27,6 +28,10 @@ export interface CreateModalSchemaSettingsItemProps {
|
|||||||
useVisible?: () => boolean;
|
useVisible?: () => boolean;
|
||||||
width?: number | string;
|
width?: number | string;
|
||||||
useSubmit?: () => (values: any) => void;
|
useSubmit?: () => (values: any) => void;
|
||||||
|
/**
|
||||||
|
* @default 'common'
|
||||||
|
*/
|
||||||
|
type?: 'common' | 'field';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,26 +52,36 @@ export function createModalSettingsItem(options: CreateModalSchemaSettingsItemPr
|
|||||||
defaultValue: propsDefaultValue,
|
defaultValue: propsDefaultValue,
|
||||||
useDefaultValue = useHookDefault,
|
useDefaultValue = useHookDefault,
|
||||||
width,
|
width,
|
||||||
|
type = 'common',
|
||||||
} = options;
|
} = options;
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
type: 'actionModal',
|
type: 'actionModal',
|
||||||
useVisible,
|
useVisible,
|
||||||
useComponentProps() {
|
useComponentProps() {
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useSchemaByType(type);
|
||||||
const { deepMerge } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const defaultValue = useDefaultValue(propsDefaultValue);
|
const defaultValue = useDefaultValue(propsDefaultValue);
|
||||||
const values = parentSchemaKey ? _.get(fieldSchema, parentSchemaKey) : undefined;
|
const values = parentSchemaKey ? _.get(fieldSchema, parentSchemaKey) : undefined;
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const onSubmit = useSubmit();
|
const onSubmit = useSubmit();
|
||||||
|
const { fieldSchema: tableColumnSchema } = useColumnSchema() || {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: typeof title === 'function' ? title(t) : compile(title),
|
title: typeof title === 'function' ? title(t) : compile(title),
|
||||||
width,
|
width,
|
||||||
schema: schema({ ...defaultValue, ...values }),
|
schema: schema({ ...defaultValue, ...values }),
|
||||||
onSubmit(values) {
|
onSubmit(values) {
|
||||||
deepMerge(getNewSchema({ fieldSchema, parentSchemaKey, value: values, valueKeys }));
|
const newSchema = getNewSchema({ fieldSchema, parentSchemaKey: parentSchemaKey, value: values, valueKeys });
|
||||||
|
if (tableColumnSchema) {
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: newSchema,
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
} else {
|
||||||
|
dn.deepMerge(newSchema);
|
||||||
|
}
|
||||||
return onSubmit?.(values);
|
return onSubmit?.(values);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -8,14 +8,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useFieldSchema } from '@formily/react';
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
import { TFunction, useTranslation } from 'react-i18next';
|
import { TFunction, useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { SchemaSettingsItemType } from '../types';
|
import { SchemaSettingsItemType } from '../types';
|
||||||
import { getNewSchema, useHookDefault } from './util';
|
import { getNewSchema, useHookDefault, useSchemaByType } from './util';
|
||||||
import { SelectProps } from '../../../schema-component/antd/select';
|
import { SelectProps } from '../../../schema-component/antd/select';
|
||||||
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
||||||
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
||||||
|
import { useColumnSchema } from '../../../schema-component';
|
||||||
|
|
||||||
interface CreateSelectSchemaSettingsItemProps {
|
interface CreateSelectSchemaSettingsItemProps {
|
||||||
name: string;
|
name: string;
|
||||||
@ -26,6 +27,10 @@ interface CreateSelectSchemaSettingsItemProps {
|
|||||||
defaultValue?: string | number;
|
defaultValue?: string | number;
|
||||||
useDefaultValue?: () => string | number;
|
useDefaultValue?: () => string | number;
|
||||||
useVisible?: () => boolean;
|
useVisible?: () => boolean;
|
||||||
|
/**
|
||||||
|
* @default 'common'
|
||||||
|
*/
|
||||||
|
type?: 'common' | 'field';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,6 +49,7 @@ export const createSelectSchemaSettingsItem = (
|
|||||||
useOptions = useHookDefault,
|
useOptions = useHookDefault,
|
||||||
schemaKey,
|
schemaKey,
|
||||||
useVisible,
|
useVisible,
|
||||||
|
type = 'common',
|
||||||
defaultValue: propsDefaultValue,
|
defaultValue: propsDefaultValue,
|
||||||
useDefaultValue = useHookDefault,
|
useDefaultValue = useHookDefault,
|
||||||
} = options;
|
} = options;
|
||||||
@ -52,8 +58,9 @@ export const createSelectSchemaSettingsItem = (
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
useVisible,
|
useVisible,
|
||||||
useComponentProps() {
|
useComponentProps() {
|
||||||
const filedSchema = useFieldSchema();
|
const fieldSchema = useSchemaByType(type);
|
||||||
const { deepMerge } = useDesignable();
|
const { fieldSchema: tableColumnSchema } = useColumnSchema() || {};
|
||||||
|
const { dn } = useDesignable();
|
||||||
const options = useOptions(propsOptions);
|
const options = useOptions(propsOptions);
|
||||||
const defaultValue = useDefaultValue(propsDefaultValue);
|
const defaultValue = useDefaultValue(propsDefaultValue);
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
@ -62,9 +69,17 @@ export const createSelectSchemaSettingsItem = (
|
|||||||
return {
|
return {
|
||||||
title: typeof title === 'function' ? title(t) : compile(title),
|
title: typeof title === 'function' ? title(t) : compile(title),
|
||||||
options,
|
options,
|
||||||
value: _.get(filedSchema, schemaKey, defaultValue),
|
value: _.get(fieldSchema, schemaKey, defaultValue),
|
||||||
onChange(v) {
|
onChange(v) {
|
||||||
deepMerge(getNewSchema({ fieldSchema: filedSchema, schemaKey, value: v }));
|
const newSchema = getNewSchema({ fieldSchema, schemaKey, value: v });
|
||||||
|
if (tableColumnSchema) {
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: newSchema,
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
} else {
|
||||||
|
dn.deepMerge(newSchema);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -12,9 +12,10 @@ import { useFieldSchema } from '@formily/react';
|
|||||||
import { TFunction, useTranslation } from 'react-i18next';
|
import { TFunction, useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { SchemaSettingsItemType } from '../types';
|
import { SchemaSettingsItemType } from '../types';
|
||||||
import { getNewSchema, useHookDefault } from './util';
|
import { getNewSchema, useHookDefault, useSchemaByType } from './util';
|
||||||
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
||||||
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
||||||
|
import { useColumnSchema } from '../../../schema-component';
|
||||||
|
|
||||||
export interface CreateSwitchSchemaSettingsItemProps {
|
export interface CreateSwitchSchemaSettingsItemProps {
|
||||||
name: string;
|
name: string;
|
||||||
@ -23,6 +24,10 @@ export interface CreateSwitchSchemaSettingsItemProps {
|
|||||||
defaultValue?: boolean;
|
defaultValue?: boolean;
|
||||||
useDefaultValue?: () => boolean;
|
useDefaultValue?: () => boolean;
|
||||||
useVisible?: () => boolean;
|
useVisible?: () => boolean;
|
||||||
|
/**
|
||||||
|
* @default 'common'
|
||||||
|
*/
|
||||||
|
type?: 'common' | 'field';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +42,7 @@ export function createSwitchSettingsItem(options: CreateSwitchSchemaSettingsItem
|
|||||||
useVisible,
|
useVisible,
|
||||||
schemaKey,
|
schemaKey,
|
||||||
title,
|
title,
|
||||||
|
type = 'common',
|
||||||
defaultValue: propsDefaultValue,
|
defaultValue: propsDefaultValue,
|
||||||
useDefaultValue = useHookDefault,
|
useDefaultValue = useHookDefault,
|
||||||
} = options;
|
} = options;
|
||||||
@ -45,17 +51,26 @@ export function createSwitchSettingsItem(options: CreateSwitchSchemaSettingsItem
|
|||||||
useVisible,
|
useVisible,
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
useComponentProps() {
|
useComponentProps() {
|
||||||
const filedSchema = useFieldSchema();
|
const fieldSchema = useSchemaByType(type);
|
||||||
const { deepMerge } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const defaultValue = useDefaultValue(propsDefaultValue);
|
const defaultValue = useDefaultValue(propsDefaultValue);
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { fieldSchema: tableColumnSchema } = useColumnSchema() || {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: typeof title === 'function' ? title(t) : compile(title),
|
title: typeof title === 'function' ? title(t) : compile(title),
|
||||||
checked: !!_.get(filedSchema, schemaKey, defaultValue),
|
checked: !!_.get(fieldSchema, schemaKey, defaultValue),
|
||||||
onChange(v) {
|
onChange(v) {
|
||||||
deepMerge(getNewSchema({ fieldSchema: filedSchema, schemaKey, value: v }));
|
const newSchema = getNewSchema({ fieldSchema, schemaKey, value: v });
|
||||||
|
if (tableColumnSchema) {
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: newSchema,
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
} else {
|
||||||
|
dn.deepMerge(newSchema);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -8,28 +8,44 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ISchema } from '@formily/json-schema';
|
import { ISchema } from '@formily/json-schema';
|
||||||
|
import { useFieldSchema } from '@formily/react';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { useColumnSchema } from '../../../schema-component';
|
||||||
|
|
||||||
type IGetNewSchema = {
|
type IGetNewSchema = {
|
||||||
fieldSchema: ISchema;
|
fieldSchema: ISchema;
|
||||||
|
// x-component-props.title
|
||||||
schemaKey?: string;
|
schemaKey?: string;
|
||||||
|
// x-component-props
|
||||||
parentSchemaKey?: string;
|
parentSchemaKey?: string;
|
||||||
value: any;
|
value: any;
|
||||||
valueKeys?: string[];
|
valueKeys?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getNewSchema(options: IGetNewSchema) {
|
export function getNewSchema(options: IGetNewSchema) {
|
||||||
const { fieldSchema, schemaKey, value, parentSchemaKey, valueKeys } = options;
|
const { fieldSchema, schemaKey, parentSchemaKey, value, valueKeys } = options as any;
|
||||||
|
if (schemaKey) {
|
||||||
if (value != undefined && typeof value === 'object') {
|
|
||||||
Object.keys(value).forEach((key) => {
|
|
||||||
if (valueKeys && !valueKeys.includes(key)) return;
|
|
||||||
_.set(fieldSchema, `${parentSchemaKey}.${key}`, value[key]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
_.set(fieldSchema, schemaKey, value);
|
_.set(fieldSchema, schemaKey, value);
|
||||||
|
} else if (parentSchemaKey) {
|
||||||
|
if (value == undefined) return fieldSchema;
|
||||||
|
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
Object.keys(value).forEach((key) => {
|
||||||
|
if (valueKeys && !valueKeys.includes(key)) return;
|
||||||
|
_.set(fieldSchema, `${parentSchemaKey}.${key}`, value[key]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('value must be object');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fieldSchema;
|
return fieldSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useHookDefault = (defaultValues?: any) => defaultValues;
|
export const useHookDefault = (defaultValues?: any) => defaultValues;
|
||||||
|
|
||||||
|
export const useSchemaByType = (type: 'common' | 'field' = 'common') => {
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
const { fieldSchema: tableColumnSchema } = useColumnSchema() || {};
|
||||||
|
return type === 'field' ? tableColumnSchema || schema : schema;
|
||||||
|
};
|
||||||
|
@ -24,6 +24,16 @@ export class UrlFieldInterface extends CollectionFieldInterface {
|
|||||||
'x-component': 'Input.URL',
|
'x-component': 'Input.URL',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
componentOptions = [
|
||||||
|
{
|
||||||
|
label: 'URL',
|
||||||
|
value: 'Input.URL',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Preview',
|
||||||
|
value: 'Input.Preview',
|
||||||
|
},
|
||||||
|
];
|
||||||
availableTypes = ['string', 'text'];
|
availableTypes = ['string', 'text'];
|
||||||
schemaInitialize(schema: ISchema, { block }) {}
|
schemaInitialize(schema: ISchema, { block }) {}
|
||||||
properties = {
|
properties = {
|
||||||
|
@ -132,4 +132,191 @@ describe('CollectionFieldInterfaceManager', () => {
|
|||||||
expect(collectionFieldInterfaceManager.getFieldInterfaceGroup('nonExistentGroup')).toBeUndefined();
|
expect(collectionFieldInterfaceManager.getFieldInterfaceGroup('nonExistentGroup')).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('addFieldInterfaceComponentOption', () => {
|
||||||
|
it('should add field interface component option', () => {
|
||||||
|
class A extends CollectionFieldInterface {
|
||||||
|
name = 'a';
|
||||||
|
default = {
|
||||||
|
type: 'string',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'A',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaces([A]);
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaceComponentOption('a', {
|
||||||
|
label: 'Test',
|
||||||
|
value: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
const fieldInterface = collectionFieldInterfaceManager.getFieldInterface('a');
|
||||||
|
expect(fieldInterface.componentOptions).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "A",
|
||||||
|
"useProps": [Function],
|
||||||
|
"value": "A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Test",
|
||||||
|
"value": "test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('async addFieldInterfaceComponentOptions', async () => {
|
||||||
|
class A extends CollectionFieldInterface {
|
||||||
|
name = 'a';
|
||||||
|
default = {
|
||||||
|
type: 'string',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'A',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaceComponentOption('a', {
|
||||||
|
label: 'Test',
|
||||||
|
value: 'test',
|
||||||
|
});
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaces([A]);
|
||||||
|
|
||||||
|
const fieldInterface = collectionFieldInterfaceManager.getFieldInterface('a');
|
||||||
|
expect(fieldInterface.componentOptions).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "A",
|
||||||
|
"useProps": [Function],
|
||||||
|
"value": "A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Test",
|
||||||
|
"value": "test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('not default properties', () => {
|
||||||
|
class A extends CollectionFieldInterface {
|
||||||
|
name = 'a';
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaces([A]);
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaceComponentOption('a', {
|
||||||
|
label: 'Test',
|
||||||
|
value: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
const fieldInterface = collectionFieldInterfaceManager.getFieldInterface('a');
|
||||||
|
expect(fieldInterface.componentOptions).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "Test",
|
||||||
|
"value": "test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('not uiSchema properties', () => {
|
||||||
|
class A extends CollectionFieldInterface {
|
||||||
|
name = 'a';
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaces([A]);
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaceComponentOption('a', {
|
||||||
|
label: 'Test',
|
||||||
|
value: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
const fieldInterface = collectionFieldInterfaceManager.getFieldInterface('a');
|
||||||
|
expect(fieldInterface.componentOptions).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "Test",
|
||||||
|
"value": "test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Label', () => {
|
||||||
|
class A extends CollectionFieldInterface {
|
||||||
|
name = 'a';
|
||||||
|
default = {
|
||||||
|
type: 'string',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'A.B',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaces([A]);
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaceComponentOption('a', {
|
||||||
|
label: 'Test',
|
||||||
|
value: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
const fieldInterface = collectionFieldInterfaceManager.getFieldInterface('a');
|
||||||
|
expect(fieldInterface.componentOptions).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "B",
|
||||||
|
"useProps": [Function],
|
||||||
|
"value": "A.B",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Test",
|
||||||
|
"value": "test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('have componentOptions', () => {
|
||||||
|
class A extends CollectionFieldInterface {
|
||||||
|
name = 'a';
|
||||||
|
default = {
|
||||||
|
type: 'string',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'A',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
componentOptions = [
|
||||||
|
{
|
||||||
|
label: 'A',
|
||||||
|
value: 'A',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaces([A]);
|
||||||
|
collectionFieldInterfaceManager.addFieldInterfaceComponentOption('a', {
|
||||||
|
label: 'Test',
|
||||||
|
value: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
const fieldInterface = collectionFieldInterfaceManager.getFieldInterface('a');
|
||||||
|
expect(fieldInterface.componentOptions).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "A",
|
||||||
|
"value": "A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Test",
|
||||||
|
"value": "test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -15,6 +15,13 @@ export type CollectionFieldInterfaceFactory = new (
|
|||||||
collectionFieldInterfaceManager: CollectionFieldInterfaceManager,
|
collectionFieldInterfaceManager: CollectionFieldInterfaceManager,
|
||||||
) => CollectionFieldInterface;
|
) => CollectionFieldInterface;
|
||||||
|
|
||||||
|
export interface CollectionFieldInterfaceComponentOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
useVisible?: () => boolean;
|
||||||
|
useProps?: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class CollectionFieldInterface {
|
export abstract class CollectionFieldInterface {
|
||||||
constructor(public collectionFieldInterfaceManager: CollectionFieldInterfaceManager) {}
|
constructor(public collectionFieldInterfaceManager: CollectionFieldInterfaceManager) {}
|
||||||
name: string;
|
name: string;
|
||||||
@ -32,6 +39,7 @@ export abstract class CollectionFieldInterface {
|
|||||||
supportDataSourceType?: string[];
|
supportDataSourceType?: string[];
|
||||||
notSupportDataSourceType?: string[];
|
notSupportDataSourceType?: string[];
|
||||||
hasDefaultValue?: boolean;
|
hasDefaultValue?: boolean;
|
||||||
|
componentOptions?: CollectionFieldInterfaceComponentOption[];
|
||||||
isAssociation?: boolean;
|
isAssociation?: boolean;
|
||||||
operators?: any[];
|
operators?: any[];
|
||||||
/**
|
/**
|
||||||
@ -54,4 +62,24 @@ export abstract class CollectionFieldInterface {
|
|||||||
usePathOptions?(field: CollectionFieldOptions): any;
|
usePathOptions?(field: CollectionFieldOptions): any;
|
||||||
schemaInitialize?(schema: ISchema, data: any): void;
|
schemaInitialize?(schema: ISchema, data: any): void;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
|
|
||||||
|
addComponentOption(componentOption: CollectionFieldInterfaceComponentOption) {
|
||||||
|
if (!this.componentOptions) {
|
||||||
|
this.componentOptions = [];
|
||||||
|
const xComponent = this.default?.uiSchema?.['x-component'];
|
||||||
|
const componentProps = this.default?.uiSchema?.['x-component-props'];
|
||||||
|
if (xComponent) {
|
||||||
|
this.componentOptions = [
|
||||||
|
{
|
||||||
|
label: xComponent.split('.').pop(),
|
||||||
|
value: xComponent,
|
||||||
|
useProps() {
|
||||||
|
return componentProps || {};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.componentOptions.push(componentOption);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { DataSourceManager } from '../data-source';
|
import type { DataSourceManager } from '../data-source';
|
||||||
import type { CollectionFieldInterface, CollectionFieldInterfaceFactory } from './CollectionFieldInterface';
|
import type {
|
||||||
|
CollectionFieldInterface,
|
||||||
|
CollectionFieldInterfaceComponentOption,
|
||||||
|
CollectionFieldInterfaceFactory,
|
||||||
|
} from './CollectionFieldInterface';
|
||||||
|
|
||||||
|
interface ActionType {
|
||||||
|
type: 'addComponentOption';
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
export class CollectionFieldInterfaceManager {
|
export class CollectionFieldInterfaceManager {
|
||||||
protected collectionFieldInterfaceInstances: Record<string, CollectionFieldInterface> = {};
|
protected collectionFieldInterfaceInstances: Record<string, CollectionFieldInterface> = {};
|
||||||
protected collectionFieldGroups: Record<string, { label: string; order?: number }> = {};
|
protected collectionFieldGroups: Record<string, { label: string; order?: number }> = {};
|
||||||
|
protected actionList: Record<string, ActionType[]> = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
fieldInterfaceClasses: CollectionFieldInterfaceFactory[],
|
fieldInterfaceClasses: CollectionFieldInterfaceFactory[],
|
||||||
@ -27,11 +37,30 @@ export class CollectionFieldInterfaceManager {
|
|||||||
const newCollectionFieldInterfaces = fieldInterfaceClasses.reduce((acc, Interface) => {
|
const newCollectionFieldInterfaces = fieldInterfaceClasses.reduce((acc, Interface) => {
|
||||||
const instance = new Interface(this);
|
const instance = new Interface(this);
|
||||||
acc[instance.name] = instance;
|
acc[instance.name] = instance;
|
||||||
|
if (Array.isArray(this.actionList[instance.name])) {
|
||||||
|
this.actionList[instance.name].forEach((item) => {
|
||||||
|
instance[item.type](item.data);
|
||||||
|
});
|
||||||
|
this.actionList[instance.name] = undefined;
|
||||||
|
}
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
Object.assign(this.collectionFieldInterfaceInstances, newCollectionFieldInterfaces);
|
Object.assign(this.collectionFieldInterfaceInstances, newCollectionFieldInterfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addFieldInterfaceComponentOption(interfaceName: string, componentOption: CollectionFieldInterfaceComponentOption) {
|
||||||
|
const fieldInterface = this.getFieldInterface(interfaceName);
|
||||||
|
if (!fieldInterface) {
|
||||||
|
if (!this.actionList[interfaceName]) {
|
||||||
|
this.actionList[interfaceName] = [];
|
||||||
|
}
|
||||||
|
this.actionList[interfaceName].push({ type: 'addComponentOption', data: componentOption });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fieldInterface.addComponentOption(componentOption);
|
||||||
|
}
|
||||||
|
|
||||||
getFieldInterface<T extends CollectionFieldInterface>(name: string) {
|
getFieldInterface<T extends CollectionFieldInterface>(name: string) {
|
||||||
return this.collectionFieldInterfaceInstances[name] as T;
|
return this.collectionFieldInterfaceInstances[name] as T;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Field } from '@formily/core';
|
||||||
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useDataSourceManager } from '../data-source/DataSourceManagerProvider';
|
||||||
|
import { useCollectionField } from '../collection-field/CollectionFieldProvider';
|
||||||
|
import { useColumnSchema, useCompile, useDesignable } from '../../schema-component';
|
||||||
|
import type { SchemaSettingsItemType } from '../../application';
|
||||||
|
|
||||||
|
export const fieldComponentSettingsItem: SchemaSettingsItemType = {
|
||||||
|
name: 'fieldComponent',
|
||||||
|
type: 'select',
|
||||||
|
useVisible() {
|
||||||
|
const collectionField = useCollectionField();
|
||||||
|
const dm = useDataSourceManager();
|
||||||
|
if (!collectionField) return false;
|
||||||
|
const collectionInterface = dm.collectionFieldInterfaceManager.getFieldInterface(collectionField?.interface);
|
||||||
|
return (
|
||||||
|
Array.isArray(collectionInterface?.componentOptions) &&
|
||||||
|
collectionInterface.componentOptions.length > 1 &&
|
||||||
|
collectionInterface.componentOptions.filter((item) => !item.useVisible || item.useVisible()).length > 1
|
||||||
|
);
|
||||||
|
},
|
||||||
|
useComponentProps() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const field = useField<Field>();
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
const collectionField = useCollectionField();
|
||||||
|
const dm = useDataSourceManager();
|
||||||
|
const collectionInterface = dm.collectionFieldInterfaceManager.getFieldInterface(collectionField?.interface);
|
||||||
|
const { fieldSchema: tableColumnSchema } = useColumnSchema();
|
||||||
|
const fieldSchema = tableColumnSchema || schema;
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const compile = useCompile();
|
||||||
|
|
||||||
|
const options =
|
||||||
|
collectionInterface?.componentOptions
|
||||||
|
?.filter((item) => !item.useVisible || item.useVisible())
|
||||||
|
?.map((item) => {
|
||||||
|
return {
|
||||||
|
label: compile(item.label),
|
||||||
|
value: item.value,
|
||||||
|
useProps: item.useProps,
|
||||||
|
};
|
||||||
|
}) || [];
|
||||||
|
return {
|
||||||
|
title: t('Field component'),
|
||||||
|
options,
|
||||||
|
value: fieldSchema['x-component-props']?.['component'] || options[0]?.value,
|
||||||
|
onChange(component) {
|
||||||
|
const componentOptions = options.find((item) => item.value === component);
|
||||||
|
const componentProps = {
|
||||||
|
component,
|
||||||
|
...(componentOptions?.useProps?.() || {}),
|
||||||
|
};
|
||||||
|
_.set(fieldSchema, 'x-component-props', componentProps);
|
||||||
|
field.componentProps = componentProps;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-component-props': componentProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './fieldComponent';
|
@ -17,3 +17,4 @@ export * from './data-source';
|
|||||||
export * from './collection-record';
|
export * from './collection-record';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
export * from './collection-fields-to-initializer-items';
|
export * from './collection-fields-to-initializer-items';
|
||||||
|
export * from './commonsSettingsItem';
|
||||||
|
@ -25,6 +25,8 @@ import { isPatternDisabled } from '../../../../schema-settings';
|
|||||||
import { ActionType } from '../../../../schema-settings/LinkageRules/type';
|
import { ActionType } from '../../../../schema-settings/LinkageRules/type';
|
||||||
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
||||||
import { useIsAllowToSetDefaultValue } from '../../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
import { useIsAllowToSetDefaultValue } from '../../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
||||||
|
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||||
|
|
||||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||||
import { useIsFieldReadPretty } from '../../../../schema-component/antd/form-item/FormItem.Settings';
|
import { useIsFieldReadPretty } from '../../../../schema-component/antd/form-item/FormItem.Settings';
|
||||||
export const fieldSettingsFormItem = new SchemaSettings({
|
export const fieldSettingsFormItem = new SchemaSettings({
|
||||||
@ -464,6 +466,7 @@ export const fieldSettingsFormItem = new SchemaSettings({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fieldComponentSettingsItem,
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,7 @@ import { useAssociationFieldContext } from '../../../../schema-component/antd/as
|
|||||||
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||||
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
||||||
import { isPatternDisabled } from '../../../../schema-settings/isPatternDisabled';
|
import { isPatternDisabled } from '../../../../schema-settings/isPatternDisabled';
|
||||||
|
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||||
|
|
||||||
export const tableColumnSettings = new SchemaSettings({
|
export const tableColumnSettings = new SchemaSettings({
|
||||||
@ -378,6 +379,7 @@ export const tableColumnSettings = new SchemaSettings({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fieldComponentSettingsItem,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@ import { useCollectionManager } from '../../../../data-source/collection/Collect
|
|||||||
import { useCompile, useDesignable } from '../../../../schema-component';
|
import { useCompile, useDesignable } from '../../../../schema-component';
|
||||||
import { SchemaSettingsDefaultSortingRules } from '../../../../schema-settings';
|
import { SchemaSettingsDefaultSortingRules } from '../../../../schema-settings';
|
||||||
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
|
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
|
||||||
|
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||||
|
|
||||||
export const filterCollapseItemFieldSettings = new SchemaSettings({
|
export const filterCollapseItemFieldSettings = new SchemaSettings({
|
||||||
name: 'fieldSettings:FilterCollapseItem',
|
name: 'fieldSettings:FilterCollapseItem',
|
||||||
@ -197,6 +198,7 @@ export const filterCollapseItemFieldSettings = new SchemaSettings({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fieldComponentSettingsItem,
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@ import { useCollectionManager_deprecated, useCollection_deprecated } from '../..
|
|||||||
import { useFieldComponentName } from '../../../../common/useFieldComponentName';
|
import { useFieldComponentName } from '../../../../common/useFieldComponentName';
|
||||||
import { EditOperator, useDesignable, useValidateSchema } from '../../../../schema-component';
|
import { EditOperator, useDesignable, useValidateSchema } from '../../../../schema-component';
|
||||||
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
||||||
|
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||||
|
|
||||||
export const filterFormItemFieldSettings = new SchemaSettings({
|
export const filterFormItemFieldSettings = new SchemaSettings({
|
||||||
name: 'fieldSettings:FilterFormItem',
|
name: 'fieldSettings:FilterFormItem',
|
||||||
@ -329,6 +330,7 @@ export const filterFormItemFieldSettings = new SchemaSettings({
|
|||||||
name: 'operator',
|
name: 'operator',
|
||||||
Component: EditOperator,
|
Component: EditOperator,
|
||||||
},
|
},
|
||||||
|
fieldComponentSettingsItem,
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -12,9 +12,11 @@ import { useField, useFieldSchema } from '@formily/react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||||
import { useColumnSchema, useDesignable } from '../../../../schema-component';
|
import { useColumnSchema, useDesignable } from '../../../../schema-component';
|
||||||
import { fieldComponent } from '../Input.URL/settings';
|
import { SchemaSettingsItemType } from '../../../../application/schema-settings';
|
||||||
|
// import { createSelectSchemaSettingsItem } from '../../../../application';
|
||||||
|
// import { fieldComponent } from '../Input.URL/settings';
|
||||||
|
|
||||||
const size = {
|
const size: SchemaSettingsItemType = {
|
||||||
name: 'size',
|
name: 'size',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
useComponentProps() {
|
useComponentProps() {
|
||||||
@ -50,7 +52,23 @@ const size = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// const size2 = createSelectSchemaSettingsItem({
|
||||||
|
// name: 'size2',
|
||||||
|
// title: 'Size2',
|
||||||
|
// type: 'field',
|
||||||
|
// schemaKey: 'x-component-props.size',
|
||||||
|
// options: [
|
||||||
|
// { value: 'small', label: 'Small' },
|
||||||
|
// { value: 'middle', label: 'Middle' },
|
||||||
|
// { value: 'large', label: 'Large' },
|
||||||
|
// { value: 'auto', label: 'Auto' },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
|
||||||
export const inputPreviewComponentFieldSettings = new SchemaSettings({
|
export const inputPreviewComponentFieldSettings = new SchemaSettings({
|
||||||
name: 'fieldSettings:component:Input.Preview',
|
name: 'fieldSettings:component:Input.Preview',
|
||||||
items: [fieldComponent, size],
|
items: [
|
||||||
|
size,
|
||||||
|
// size2
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
/**
|
|
||||||
* This file is part of the NocoBase (R) project.
|
|
||||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
||||||
* Authors: NocoBase Team.
|
|
||||||
*
|
|
||||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Field } from '@formily/core';
|
|
||||||
import { useField, useFieldSchema } from '@formily/react';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
|
||||||
import { useColumnSchema, useDesignable } from '../../../../schema-component';
|
|
||||||
|
|
||||||
export const fieldComponent: any = {
|
|
||||||
name: 'fieldComponent',
|
|
||||||
type: 'select',
|
|
||||||
useComponentProps() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const field = useField<Field>();
|
|
||||||
const schema = useFieldSchema();
|
|
||||||
const { fieldSchema: tableColumnSchema } = useColumnSchema();
|
|
||||||
const fieldSchema = tableColumnSchema || schema;
|
|
||||||
const { dn } = useDesignable();
|
|
||||||
return {
|
|
||||||
title: t('Field component'),
|
|
||||||
options: [
|
|
||||||
{ value: 'Input.URL', label: 'URL' },
|
|
||||||
{ value: 'Input.Preview', label: 'Preview' },
|
|
||||||
],
|
|
||||||
value: fieldSchema['x-component-props']?.['component'] || 'Input.URL',
|
|
||||||
onChange(component) {
|
|
||||||
_.set(fieldSchema, 'x-component-props.component', component);
|
|
||||||
field.componentProps.component = component;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
|
||||||
'x-component-props': fieldSchema['x-component-props'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const inputURLComponentFieldSettings = new SchemaSettings({
|
|
||||||
name: 'fieldSettings:component:Input.URL',
|
|
||||||
items: [fieldComponent],
|
|
||||||
});
|
|
@ -53,7 +53,7 @@ import { fileManagerComponentFieldSettings } from '../modules/fields/component/F
|
|||||||
import { previewComponentFieldSettings } from '../modules/fields/component/FileManager/previewComponentFieldSettings';
|
import { previewComponentFieldSettings } from '../modules/fields/component/FileManager/previewComponentFieldSettings';
|
||||||
import { uploadAttachmentComponentFieldSettings } from '../modules/fields/component/FileManager/uploadAttachmentComponentFieldSettings';
|
import { uploadAttachmentComponentFieldSettings } from '../modules/fields/component/FileManager/uploadAttachmentComponentFieldSettings';
|
||||||
import { inputPreviewComponentFieldSettings } from '../modules/fields/component/Input.Preview/settings';
|
import { inputPreviewComponentFieldSettings } from '../modules/fields/component/Input.Preview/settings';
|
||||||
import { inputURLComponentFieldSettings } from '../modules/fields/component/Input.URL/settings';
|
// import { inputURLComponentFieldSettings } from '../modules/fields/component/Input.URL/settings';
|
||||||
import { inputNumberComponentFieldSettings } from '../modules/fields/component/InputNumber/inputNumberComponentFieldSettings';
|
import { inputNumberComponentFieldSettings } from '../modules/fields/component/InputNumber/inputNumberComponentFieldSettings';
|
||||||
import { subformComponentFieldSettings } from '../modules/fields/component/Nester/subformComponentFieldSettings';
|
import { subformComponentFieldSettings } from '../modules/fields/component/Nester/subformComponentFieldSettings';
|
||||||
import { recordPickerComponentFieldSettings } from '../modules/fields/component/Picker/recordPickerComponentFieldSettings';
|
import { recordPickerComponentFieldSettings } from '../modules/fields/component/Picker/recordPickerComponentFieldSettings';
|
||||||
@ -120,7 +120,7 @@ export class SchemaSettingsPlugin extends Plugin {
|
|||||||
this.schemaSettingsManager.add(tagComponentFieldSettings);
|
this.schemaSettingsManager.add(tagComponentFieldSettings);
|
||||||
this.schemaSettingsManager.add(cascadeSelectComponentFieldSettings);
|
this.schemaSettingsManager.add(cascadeSelectComponentFieldSettings);
|
||||||
this.schemaSettingsManager.add(inputPreviewComponentFieldSettings);
|
this.schemaSettingsManager.add(inputPreviewComponentFieldSettings);
|
||||||
this.schemaSettingsManager.add(inputURLComponentFieldSettings);
|
// this.schemaSettingsManager.add(inputURLComponentFieldSettings);
|
||||||
this.schemaSettingsManager.add(uploadAttachmentComponentFieldSettings);
|
this.schemaSettingsManager.add(uploadAttachmentComponentFieldSettings);
|
||||||
this.schemaSettingsManager.add(previewComponentFieldSettings);
|
this.schemaSettingsManager.add(previewComponentFieldSettings);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
useFormBlockContext,
|
useFormBlockContext,
|
||||||
useIsFormReadPretty,
|
useIsFormReadPretty,
|
||||||
useValidateSchema,
|
useValidateSchema,
|
||||||
|
fieldComponentSettingsItem,
|
||||||
EditValidationRules,
|
EditValidationRules,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@ -201,6 +202,7 @@ export const bulkEditFormItemSettings = new SchemaSettings({
|
|||||||
return form && !isFormReadPretty && validateSchema;
|
return form && !isFormReadPretty && validateSchema;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fieldComponentSettingsItem,
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -233,6 +233,7 @@ test.describe('PageHeader', () => {
|
|||||||
await page.getByRole('menuitem', { name: 'Edit button' }).click();
|
await page.getByRole('menuitem', { name: 'Edit button' }).click();
|
||||||
await page.getByRole('textbox').fill('Test_changed');
|
await page.getByRole('textbox').fill('Test_changed');
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
await expect(page.getByLabel('Edit button')).not.toBeVisible();
|
||||||
await expect(navigationBarPositionElement).toContainText('Test_changed');
|
await expect(navigationBarPositionElement).toContainText('Test_changed');
|
||||||
|
|
||||||
// 编辑 URL
|
// 编辑 URL
|
||||||
|
Loading…
Reference in New Issue
Block a user