mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 08:26:21 +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[];
|
||||
loadRemotePlugins?: boolean;
|
||||
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)
|
||||
- `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)
|
||||
- `addFieldInterfaceComponentOption`: Add field interface component options. For more details, refer to: [CollectionFieldInterfaceManager](/core/data-source/collection-field-interface-manager#addfieldinterfacecomponentoption)
|
||||
|
||||
## 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.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
|
||||
|
||||
### 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
|
||||
|
||||
#### addFieldInterfaceGroups()
|
||||
|
@ -34,10 +34,6 @@ class CollectionFieldInterface {
|
||||
validateSchema(fieldSchema: ISchema): Record<string, ISchema>
|
||||
usePathOptions(field: CollectionFieldOptions): any
|
||||
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[];
|
||||
loadRemotePlugins?: boolean;
|
||||
dataSourceManager?: DataSourceManagerOptions;
|
||||
addFieldInterfaceComponentOption(fieldName: string, componentOption: CollectionFieldInterfaceComponentOption): void;
|
||||
}
|
||||
```
|
||||
|
||||
- 详细信息
|
||||
- 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)
|
||||
- providers:上下文
|
||||
- components:全局组件
|
||||
- scopes:全局 scopes
|
||||
- router:配置路由,具体请参考:[RouterManager](/core/application/router-manager)
|
||||
- pluginSettings: [PluginSettingsManager](/core/application/plugin-settings-manager)
|
||||
- schemaSettings:Schema 设置工具,具体参考:[SchemaSettingsManager](/core/ui-schema/schema-initializer-manager)
|
||||
- schemaInitializers:Schema 添加工具,具体参考:[SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
|
||||
- loadRemotePlugins:用于控制是否加载远程插件,默认为 `false`,即不加载远程插件(方便单测和 DEMO 环境)。
|
||||
- dataSourceManager:数据源管理器,具体参考:[DataSourceManager](/core/data-source/data-source-manager)
|
||||
- `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)
|
||||
- `providers`:上下文
|
||||
- `components`:全局组件
|
||||
- `scopes`:全局 scopes
|
||||
- `router`:配置路由,具体请参考:[RouterManager](/core/application/router-manager)
|
||||
- `pluginSettings`: [PluginSettingsManager](/core/application/plugin-settings-manager)
|
||||
- `schemaSettings`:Schema 设置工具,具体参考:[SchemaSettingsManager](/core/ui-schema/schema-initializer-manager)
|
||||
- `schemaInitializers`:Schema 添加工具,具体参考:[SchemaInitializerManager](/core/ui-schema/schema-initializer-manager)
|
||||
- `loadRemotePlugins`:用于控制是否加载远程插件,默认为 `false`,即不加载远程插件(方便单测和 DEMO 环境)。
|
||||
- `dataSourceManager`:数据源管理器,具体参考:[DataSourceManager](/core/data-source/data-source-manager)
|
||||
- `addFieldInterfaceComponentOption`: 添加 Field interface 组件选项。具体参考: [CollectionFieldInterfaceManager](/core/data-source/collection-field-interface-manager#addfieldinterfacecomponentoption)
|
||||
- 示例
|
||||
|
||||
```tsx
|
||||
@ -343,6 +345,24 @@ app.getCollectionManager() // 获取默认数据源的 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
|
||||
|
||||
### 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
|
||||
|
||||
#### addFieldInterfaceGroups()
|
||||
|
@ -34,10 +34,6 @@ class CollectionFieldInterface {
|
||||
validateSchema(fieldSchema: ISchema): Record<string, ISchema>
|
||||
usePathOptions(field: CollectionFieldOptions): any
|
||||
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 { DataBlockProvider } from '../data-source/data-block/DataBlockProvider';
|
||||
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 { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
|
||||
@ -355,4 +356,11 @@ export class Application {
|
||||
root.render(<App />);
|
||||
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 { Plugin } from '../Plugin';
|
||||
import { useApp } from '../hooks';
|
||||
import { CollectionFieldInterface } from '../../data-source';
|
||||
|
||||
describe('Application', () => {
|
||||
beforeAll(() => {
|
||||
@ -439,4 +440,43 @@ describe('Application', () => {
|
||||
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 { SchemaSettingsItemType } from '../types';
|
||||
import { getNewSchema, useHookDefault } from './util';
|
||||
import { getNewSchema, useHookDefault, useSchemaByType } from './util';
|
||||
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
||||
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
||||
import { useColumnSchema } from '../../../schema-component';
|
||||
|
||||
export interface CreateModalSchemaSettingsItemProps {
|
||||
name: string;
|
||||
@ -27,6 +28,10 @@ export interface CreateModalSchemaSettingsItemProps {
|
||||
useVisible?: () => boolean;
|
||||
width?: number | string;
|
||||
useSubmit?: () => (values: any) => void;
|
||||
/**
|
||||
* @default 'common'
|
||||
*/
|
||||
type?: 'common' | 'field';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,26 +52,36 @@ export function createModalSettingsItem(options: CreateModalSchemaSettingsItemPr
|
||||
defaultValue: propsDefaultValue,
|
||||
useDefaultValue = useHookDefault,
|
||||
width,
|
||||
type = 'common',
|
||||
} = options;
|
||||
return {
|
||||
name,
|
||||
type: 'actionModal',
|
||||
useVisible,
|
||||
useComponentProps() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { deepMerge } = useDesignable();
|
||||
const fieldSchema = useSchemaByType(type);
|
||||
const { dn } = useDesignable();
|
||||
const defaultValue = useDefaultValue(propsDefaultValue);
|
||||
const values = parentSchemaKey ? _.get(fieldSchema, parentSchemaKey) : undefined;
|
||||
const compile = useCompile();
|
||||
const { t } = useTranslation();
|
||||
const onSubmit = useSubmit();
|
||||
const { fieldSchema: tableColumnSchema } = useColumnSchema() || {};
|
||||
|
||||
return {
|
||||
title: typeof title === 'function' ? title(t) : compile(title),
|
||||
width,
|
||||
schema: schema({ ...defaultValue, ...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);
|
||||
},
|
||||
};
|
||||
|
@ -8,14 +8,15 @@
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
import { TFunction, useTranslation } from 'react-i18next';
|
||||
|
||||
import { SchemaSettingsItemType } from '../types';
|
||||
import { getNewSchema, useHookDefault } from './util';
|
||||
import { getNewSchema, useHookDefault, useSchemaByType } from './util';
|
||||
import { SelectProps } from '../../../schema-component/antd/select';
|
||||
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
||||
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
||||
import { useColumnSchema } from '../../../schema-component';
|
||||
|
||||
interface CreateSelectSchemaSettingsItemProps {
|
||||
name: string;
|
||||
@ -26,6 +27,10 @@ interface CreateSelectSchemaSettingsItemProps {
|
||||
defaultValue?: string | number;
|
||||
useDefaultValue?: () => string | number;
|
||||
useVisible?: () => boolean;
|
||||
/**
|
||||
* @default 'common'
|
||||
*/
|
||||
type?: 'common' | 'field';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,6 +49,7 @@ export const createSelectSchemaSettingsItem = (
|
||||
useOptions = useHookDefault,
|
||||
schemaKey,
|
||||
useVisible,
|
||||
type = 'common',
|
||||
defaultValue: propsDefaultValue,
|
||||
useDefaultValue = useHookDefault,
|
||||
} = options;
|
||||
@ -52,8 +58,9 @@ export const createSelectSchemaSettingsItem = (
|
||||
type: 'select',
|
||||
useVisible,
|
||||
useComponentProps() {
|
||||
const filedSchema = useFieldSchema();
|
||||
const { deepMerge } = useDesignable();
|
||||
const fieldSchema = useSchemaByType(type);
|
||||
const { fieldSchema: tableColumnSchema } = useColumnSchema() || {};
|
||||
const { dn } = useDesignable();
|
||||
const options = useOptions(propsOptions);
|
||||
const defaultValue = useDefaultValue(propsDefaultValue);
|
||||
const compile = useCompile();
|
||||
@ -62,9 +69,17 @@ export const createSelectSchemaSettingsItem = (
|
||||
return {
|
||||
title: typeof title === 'function' ? title(t) : compile(title),
|
||||
options,
|
||||
value: _.get(filedSchema, schemaKey, defaultValue),
|
||||
value: _.get(fieldSchema, schemaKey, defaultValue),
|
||||
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 { SchemaSettingsItemType } from '../types';
|
||||
import { getNewSchema, useHookDefault } from './util';
|
||||
import { getNewSchema, useHookDefault, useSchemaByType } from './util';
|
||||
import { useCompile } from '../../../schema-component/hooks/useCompile';
|
||||
import { useDesignable } from '../../../schema-component/hooks/useDesignable';
|
||||
import { useColumnSchema } from '../../../schema-component';
|
||||
|
||||
export interface CreateSwitchSchemaSettingsItemProps {
|
||||
name: string;
|
||||
@ -23,6 +24,10 @@ export interface CreateSwitchSchemaSettingsItemProps {
|
||||
defaultValue?: boolean;
|
||||
useDefaultValue?: () => boolean;
|
||||
useVisible?: () => boolean;
|
||||
/**
|
||||
* @default 'common'
|
||||
*/
|
||||
type?: 'common' | 'field';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,6 +42,7 @@ export function createSwitchSettingsItem(options: CreateSwitchSchemaSettingsItem
|
||||
useVisible,
|
||||
schemaKey,
|
||||
title,
|
||||
type = 'common',
|
||||
defaultValue: propsDefaultValue,
|
||||
useDefaultValue = useHookDefault,
|
||||
} = options;
|
||||
@ -45,17 +51,26 @@ export function createSwitchSettingsItem(options: CreateSwitchSchemaSettingsItem
|
||||
useVisible,
|
||||
type: 'switch',
|
||||
useComponentProps() {
|
||||
const filedSchema = useFieldSchema();
|
||||
const { deepMerge } = useDesignable();
|
||||
const fieldSchema = useSchemaByType(type);
|
||||
const { dn } = useDesignable();
|
||||
const defaultValue = useDefaultValue(propsDefaultValue);
|
||||
const compile = useCompile();
|
||||
const { t } = useTranslation();
|
||||
const { fieldSchema: tableColumnSchema } = useColumnSchema() || {};
|
||||
|
||||
return {
|
||||
title: typeof title === 'function' ? title(t) : compile(title),
|
||||
checked: !!_.get(filedSchema, schemaKey, defaultValue),
|
||||
checked: !!_.get(fieldSchema, schemaKey, defaultValue),
|
||||
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 { useFieldSchema } from '@formily/react';
|
||||
import _ from 'lodash';
|
||||
import { useColumnSchema } from '../../../schema-component';
|
||||
|
||||
type IGetNewSchema = {
|
||||
fieldSchema: ISchema;
|
||||
// x-component-props.title
|
||||
schemaKey?: string;
|
||||
// x-component-props
|
||||
parentSchemaKey?: string;
|
||||
value: any;
|
||||
valueKeys?: string[];
|
||||
};
|
||||
|
||||
export function getNewSchema(options: IGetNewSchema) {
|
||||
const { fieldSchema, schemaKey, value, parentSchemaKey, valueKeys } = options;
|
||||
const { fieldSchema, schemaKey, parentSchemaKey, value, valueKeys } = options as any;
|
||||
if (schemaKey) {
|
||||
_.set(fieldSchema, schemaKey, value);
|
||||
} else if (parentSchemaKey) {
|
||||
if (value == undefined) return fieldSchema;
|
||||
|
||||
if (value != undefined && typeof value === 'object') {
|
||||
if (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);
|
||||
console.error('value must be object');
|
||||
}
|
||||
}
|
||||
|
||||
return fieldSchema;
|
||||
}
|
||||
|
||||
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',
|
||||
},
|
||||
};
|
||||
componentOptions = [
|
||||
{
|
||||
label: 'URL',
|
||||
value: 'Input.URL',
|
||||
},
|
||||
{
|
||||
label: 'Preview',
|
||||
value: 'Input.Preview',
|
||||
},
|
||||
];
|
||||
availableTypes = ['string', 'text'];
|
||||
schemaInitialize(schema: ISchema, { block }) {}
|
||||
properties = {
|
||||
|
@ -132,4 +132,191 @@ describe('CollectionFieldInterfaceManager', () => {
|
||||
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,
|
||||
) => CollectionFieldInterface;
|
||||
|
||||
export interface CollectionFieldInterfaceComponentOption {
|
||||
label: string;
|
||||
value: string;
|
||||
useVisible?: () => boolean;
|
||||
useProps?: () => any;
|
||||
}
|
||||
|
||||
export abstract class CollectionFieldInterface {
|
||||
constructor(public collectionFieldInterfaceManager: CollectionFieldInterfaceManager) {}
|
||||
name: string;
|
||||
@ -32,6 +39,7 @@ export abstract class CollectionFieldInterface {
|
||||
supportDataSourceType?: string[];
|
||||
notSupportDataSourceType?: string[];
|
||||
hasDefaultValue?: boolean;
|
||||
componentOptions?: CollectionFieldInterfaceComponentOption[];
|
||||
isAssociation?: boolean;
|
||||
operators?: any[];
|
||||
/**
|
||||
@ -54,4 +62,24 @@ export abstract class CollectionFieldInterface {
|
||||
usePathOptions?(field: CollectionFieldOptions): any;
|
||||
schemaInitialize?(schema: ISchema, data: any): void;
|
||||
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 { CollectionFieldInterface, CollectionFieldInterfaceFactory } from './CollectionFieldInterface';
|
||||
import type {
|
||||
CollectionFieldInterface,
|
||||
CollectionFieldInterfaceComponentOption,
|
||||
CollectionFieldInterfaceFactory,
|
||||
} from './CollectionFieldInterface';
|
||||
|
||||
interface ActionType {
|
||||
type: 'addComponentOption';
|
||||
data: any;
|
||||
}
|
||||
|
||||
export class CollectionFieldInterfaceManager {
|
||||
protected collectionFieldInterfaceInstances: Record<string, CollectionFieldInterface> = {};
|
||||
protected collectionFieldGroups: Record<string, { label: string; order?: number }> = {};
|
||||
protected actionList: Record<string, ActionType[]> = {};
|
||||
|
||||
constructor(
|
||||
fieldInterfaceClasses: CollectionFieldInterfaceFactory[],
|
||||
@ -27,11 +37,30 @@ export class CollectionFieldInterfaceManager {
|
||||
const newCollectionFieldInterfaces = fieldInterfaceClasses.reduce((acc, Interface) => {
|
||||
const instance = new Interface(this);
|
||||
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;
|
||||
}, {});
|
||||
|
||||
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) {
|
||||
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 './utils';
|
||||
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 { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
||||
import { useIsAllowToSetDefaultValue } from '../../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
||||
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
import { useIsFieldReadPretty } from '../../../../schema-component/antd/form-item/FormItem.Settings';
|
||||
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 { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
||||
import { isPatternDisabled } from '../../../../schema-settings/isPatternDisabled';
|
||||
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
|
||||
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 { SchemaSettingsDefaultSortingRules } from '../../../../schema-settings';
|
||||
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
|
||||
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||
|
||||
export const filterCollapseItemFieldSettings = new SchemaSettings({
|
||||
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 { EditOperator, useDesignable, useValidateSchema } from '../../../../schema-component';
|
||||
import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue';
|
||||
import { fieldComponentSettingsItem } from '../../../../data-source/commonsSettingsItem';
|
||||
|
||||
export const filterFormItemFieldSettings = new SchemaSettings({
|
||||
name: 'fieldSettings:FilterFormItem',
|
||||
@ -329,6 +330,7 @@ export const filterFormItemFieldSettings = new SchemaSettings({
|
||||
name: 'operator',
|
||||
Component: EditOperator,
|
||||
},
|
||||
fieldComponentSettingsItem,
|
||||
];
|
||||
},
|
||||
},
|
||||
|
@ -12,9 +12,11 @@ import { useField, useFieldSchema } from '@formily/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
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',
|
||||
type: 'select',
|
||||
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({
|
||||
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 { uploadAttachmentComponentFieldSettings } from '../modules/fields/component/FileManager/uploadAttachmentComponentFieldSettings';
|
||||
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 { subformComponentFieldSettings } from '../modules/fields/component/Nester/subformComponentFieldSettings';
|
||||
import { recordPickerComponentFieldSettings } from '../modules/fields/component/Picker/recordPickerComponentFieldSettings';
|
||||
@ -120,7 +120,7 @@ export class SchemaSettingsPlugin extends Plugin {
|
||||
this.schemaSettingsManager.add(tagComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(cascadeSelectComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(inputPreviewComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(inputURLComponentFieldSettings);
|
||||
// this.schemaSettingsManager.add(inputURLComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(uploadAttachmentComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(previewComponentFieldSettings);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
useFormBlockContext,
|
||||
useIsFormReadPretty,
|
||||
useValidateSchema,
|
||||
fieldComponentSettingsItem,
|
||||
EditValidationRules,
|
||||
} from '@nocobase/client';
|
||||
import _ from 'lodash';
|
||||
@ -201,6 +202,7 @@ export const bulkEditFormItemSettings = new SchemaSettings({
|
||||
return form && !isFormReadPretty && validateSchema;
|
||||
},
|
||||
},
|
||||
fieldComponentSettingsItem,
|
||||
];
|
||||
},
|
||||
},
|
||||
|
@ -233,6 +233,7 @@ test.describe('PageHeader', () => {
|
||||
await page.getByRole('menuitem', { name: 'Edit button' }).click();
|
||||
await page.getByRole('textbox').fill('Test_changed');
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await expect(page.getByLabel('Edit button')).not.toBeVisible();
|
||||
await expect(navigationBarPositionElement).toContainText('Test_changed');
|
||||
|
||||
// 编辑 URL
|
||||
|
Loading…
Reference in New Issue
Block a user