fix(filter-form): fix operator not valid in block templates (#4390)

* fix(filter-form): fix operator not valid in block templates

* test: add e2e test

* test: clear data templates

* chore: fix e2e tests

* chore: stash

* chore: change import path to fix unit tests

* chore: change import path to fix unit tests

* chore: fix build
This commit is contained in:
Zeke Zhang 2024-05-20 16:50:34 +08:00 committed by GitHub
parent a5ede09a2a
commit ef8e4aed48
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
84 changed files with 857 additions and 752 deletions

View File

@ -9,8 +9,8 @@
import { render } from '@nocobase/test/client';
import React from 'react';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { SchemaComponent, SchemaComponentProvider } from '../../../schema-component';
import { withDynamicSchemaProps } from '../../hoc';
const HelloComponent = withDynamicSchemaProps((props: any) => (
<pre data-testid="component">{JSON.stringify(props)}</pre>

View File

@ -7,9 +7,9 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React from 'react';
import { Application, SchemaSettings, useSchemaSettingsRender } from '@nocobase/client';
import { render, screen, waitFor } from '@nocobase/test/client';
import React from 'react';
describe('useSchemaSettingsRender', () => {
async function createApp(DemoComponent: any) {

View File

@ -8,15 +8,16 @@
*/
export * from './Application';
export * from './hooks';
export * from './Plugin';
export * from './RouterManager';
export * from './utils';
export * from './components';
export * from './schema-initializer';
export * from './schema-settings';
export * from './schema-toolbar';
export * from './PluginSettingsManager';
export * from './hoc';
export * from './RouterManager';
export * from './components';
export { ApplicationContext } from './context';
export * from './globalType';
export * from './hooks';
export * from './schema-initializer';
export * from './schema-settings';
export * from './schema-settings/context/SchemaSettingItemContext';
export * from './schema-settings/hooks/useSchemaSettingsRender';
export * from './schema-toolbar';
export * from './utils';

View File

@ -9,6 +9,7 @@
import React, { FC, memo, useEffect, useMemo, useRef } from 'react';
import { useFieldComponentName } from '../../../common/useFieldComponentName';
import { useFindComponent } from '../../../schema-component';
import {
SchemaSettingsActionModalItem,
@ -24,9 +25,8 @@ import {
SchemaSettingsSwitchItem,
useSchemaSettings,
} from '../../../schema-settings/SchemaSettings';
import { SchemaSettingItemContext } from '../context';
import { SchemaSettingItemContext } from '../context/SchemaSettingItemContext';
import { SchemaSettingsItemType } from '../types';
import { useFieldComponentName } from '../../../common/useFieldComponentName';
export interface SchemaSettingsChildrenProps {
children: SchemaSettingsItemType[];

View File

@ -1,10 +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.
*/
export * from './SchemaSettingItemContext';

View File

@ -1,10 +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.
*/
export * from './useSchemaSettingsRender';

View File

@ -9,7 +9,6 @@
export * from './SchemaSettings';
export * from './SchemaSettingsManager';
export * from './hooks';
export * from './components';
export * from './context';
export * from './context/SchemaSettingItemContext';
export * from './types';

View File

@ -31,6 +31,7 @@ import { CollapseItemSchemaToolbar } from '../modules/blocks/filter-blocks/colla
import { useCollapseBlockDecoratorProps } from '../modules/blocks/filter-blocks/collapse/hooks/useCollapseBlockDecoratorProps';
import { useFilterFormBlockDecoratorProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockDecoratorProps';
import { useFilterFormBlockProps } from '../modules/blocks/filter-blocks/form/hooks/useFilterFormBlockProps';
import { useFormItemProps } from '../modules/blocks/filter-blocks/form/hooks/useFormItemProps';
import { SchemaComponentOptions } from '../schema-component';
import { RecordLink, useParamsFromRecord, useSourceIdFromParentRecord, useSourceIdFromRecord } from './BlockProvider';
import { DetailsBlockProvider, useDetailsBlockProps } from './DetailsBlockProvider';
@ -83,6 +84,7 @@ export const BlockSchemaComponentProvider: React.FC = (props) => {
useFilterFormBlockProps,
useFilterFormBlockDecoratorProps,
useGridCardBlockDecoratorProps,
useFormItemProps,
}}
>
{props.children}
@ -142,6 +144,7 @@ export class BlockSchemaComponentPlugin extends Plugin {
useFilterFormBlockProps,
useFilterFormBlockDecoratorProps,
useGridCardBlockDecoratorProps,
useFormItemProps,
});
}
}

View File

@ -0,0 +1,71 @@
/**
* 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 React, { FC, createContext, useCallback, useRef } from 'react';
const NOOP = () => {};
const CollectOperatorsContext = createContext<{
/** 手机单个字段的操作符 */
collectOperator: (name: string | number, operator: string) => void;
/** 获取所有字段的操作符 */
getOperators: () => Record<string, string>;
/** 获取单个字段的操作符 */
getOperator: (name: string | number) => string;
/** 移除单个字段的操作符 */
removeOperator: (name: string | number) => void;
}>(null);
export const CollectOperators: FC<{ defaultOperators: Record<string, string> }> = (props) => {
const operators = useRef(props.defaultOperators || {});
const collectOperator = useCallback((name: string, operator: string) => {
operators.current[name] = operator;
}, []);
const getOperators = useCallback(() => {
return { ...operators.current };
}, []);
const getOperator = useCallback((name: string) => {
return operators.current[name];
}, []);
const removeOperator = useCallback((name: string) => {
delete operators.current[name];
}, []);
return (
<CollectOperatorsContext.Provider
value={{
collectOperator,
getOperators,
getOperator,
removeOperator,
}}
>
{props.children}
</CollectOperatorsContext.Provider>
);
};
export const useOperators = () => {
const {
getOperator = NOOP,
getOperators = NOOP,
collectOperator = NOOP,
removeOperator = NOOP,
} = React.useContext(CollectOperatorsContext) || {};
return {
getOperator,
getOperators: getOperators as () => Record<string, string> | undefined,
collectOperator,
removeOperator,
};
};

View File

@ -11,10 +11,10 @@ import { createForm } from '@formily/core';
import { useField, useFieldSchema } from '@formily/react';
import { Spin } from 'antd';
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps';
import { useCollectionManager_deprecated } from '../collection-manager';
import { useCollectionRecordData } from '../data-source';
import { useCollectionParentRecord } from '../data-source/collection-record/CollectionRecordProvider';
import { withDynamicSchemaProps } from '../hoc/withDynamicSchemaProps';
import { useDetailsWithPaginationBlockParams } from '../modules/blocks/data-blocks/details-multi/hooks/useDetailsWithPaginationBlockParams';
import { RecordProvider } from '../record-provider';
import { useDesignable } from '../schema-component';

View File

@ -7,18 +7,26 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { useFieldSchema } from '@formily/react';
import React from 'react';
import { withDynamicSchemaProps } from '../hoc/withDynamicSchemaProps';
import { DatePickerProvider } from '../schema-component';
import { DefaultValueProvider } from '../schema-settings';
import { CollectOperators } from './CollectOperators';
import { FormBlockProvider } from './FormBlockProvider';
import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps';
export const FilterFormBlockProvider = withDynamicSchemaProps((props) => {
const filedSchema = useFieldSchema();
// 'x-filter-operators' 已被弃用,这里是为了兼容旧的配置
const deprecatedOperators = filedSchema['x-filter-operators'] || {};
return (
<DatePickerProvider value={{ utc: false }}>
<DefaultValueProvider isAllowToSetDefaultValue={() => false}>
<FormBlockProvider name="filter-form" {...props}></FormBlockProvider>
</DefaultValueProvider>
</DatePickerProvider>
<CollectOperators defaultOperators={deprecatedOperators}>
<DatePickerProvider value={{ utc: false }}>
<DefaultValueProvider isAllowToSetDefaultValue={() => false}>
<FormBlockProvider name="filter-form" {...props}></FormBlockProvider>
</DefaultValueProvider>
</DatePickerProvider>
</CollectOperators>
);
});

View File

@ -11,13 +11,13 @@ import { createForm } from '@formily/core';
import { Schema, useField } from '@formily/react';
import { Spin } from 'antd';
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps';
import {
CollectionRecord,
useCollectionManager,
useCollectionParentRecordData,
useCollectionRecord,
} from '../data-source';
import { withDynamicSchemaProps } from '../hoc/withDynamicSchemaProps';
import { useTreeParentRecord } from '../modules/blocks/data-blocks/table/TreeRecordProvider';
import { RecordProvider } from '../record-provider';
import { useActionContext } from '../schema-component';

View File

@ -10,8 +10,8 @@
import { createForm } from '@formily/core';
import { FormContext, useField, useFieldSchema } from '@formily/react';
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps';
import { useCollectionManager_deprecated } from '../collection-manager';
import { withDynamicSchemaProps } from '../hoc/withDynamicSchemaProps';
import { useTableBlockParams } from '../modules/blocks/data-blocks/table';
import { FixedBlockWrapper, SchemaComponentOptions } from '../schema-component';
import { BlockProvider, useBlockRequestContext } from './BlockProvider';

View File

@ -12,11 +12,11 @@ import { Schema, useField, useFieldSchema } from '@formily/react';
import _ from 'lodash';
import uniq from 'lodash/uniq';
import React, { createContext, useContext, useEffect, useState } from 'react';
import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps';
import { useCollectionManager_deprecated } from '../collection-manager';
import { useCollectionParentRecordData } from '../data-source/collection-record/CollectionRecordProvider';
import { isInFilterFormBlock } from '../filter-provider';
import { mergeFilter } from '../filter-provider/utils';
import { withDynamicSchemaProps } from '../hoc/withDynamicSchemaProps';
import { RecordProvider, useRecord } from '../record-provider';
import { SchemaComponentOptions } from '../schema-component';
import { BlockProvider, useBlockRequestContext } from './BlockProvider';

View File

@ -0,0 +1,52 @@
/**
* 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 { render } from '@nocobase/test/client';
import React from 'react';
import { CollectOperators, useOperators } from '../CollectOperators';
describe('CollectOperators', () => {
it('should collect and get operators correctly', () => {
const defaultOperators = {
field1: 'operator1',
field2: 'operator2',
};
const TestComponent = () => {
const { collectOperator, getOperators, getOperator } = useOperators();
collectOperator('field3', 'operator3');
const operators = getOperators();
const operator = getOperator('field1') as string;
return (
<div>
<span data-testid="operators">{JSON.stringify(operators)}</span>
<span data-testid="operator">{operator}</span>
</div>
);
};
const { getByTestId } = render(
<CollectOperators defaultOperators={defaultOperators}>
<TestComponent />
</CollectOperators>,
);
const operatorsElement = getByTestId('operators');
const operatorElement = getByTestId('operator');
expect(JSON.parse(operatorsElement.textContent)).toEqual({
...defaultOperators,
field3: 'operator3',
});
expect(operatorElement.textContent).toBe('operator1');
});
});

View File

@ -40,6 +40,7 @@ import { useLocalVariables, useVariables } from '../../variables';
import { isVariable } from '../../variables/utils/isVariable';
import { transformVariableValue } from '../../variables/utils/transformVariableValue';
import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../BlockProvider';
import { useOperators } from '../CollectOperators';
import { useDetailsBlockContext } from '../DetailsBlockProvider';
import { TableFieldResource } from '../TableFieldProvider';
@ -413,6 +414,7 @@ export const useFilterBlockActionProps = () => {
const { getDataBlocks } = useFilterBlock();
const { name } = useCollection_deprecated();
const { getCollectionJoinField } = useCollectionManager_deprecated();
const { getOperators } = useOperators();
actionField.data = actionField.data || {};
@ -433,7 +435,7 @@ export const useFilterBlockActionProps = () => {
const storedFilter = block.service.params?.[1]?.filters || {};
storedFilter[uid] = removeNullCondition(
transformToFilter(form.values, fieldSchema, getCollectionJoinField, name),
transformToFilter(form.values, getOperators(), getCollectionJoinField, name),
);
const mergedFilter = mergeFilter([

View File

@ -13,10 +13,10 @@ import { merge } from '@formily/shared';
import { concat } from 'lodash';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useFormBlockContext } from '../../block-provider/FormBlockProvider';
import { useDynamicComponentProps } from '../../hoc/withDynamicSchemaProps';
import { useCompile, useComponent } from '../../schema-component';
import { useIsAllowToSetDefaultValue } from '../../schema-settings/hooks/useIsAllowToSetDefaultValue';
import { CollectionFieldProvider, useCollectionField } from './CollectionFieldProvider';
import { useDynamicComponentProps } from '../../application/hoc';
type Props = {
component: any;

View File

@ -11,7 +11,7 @@ import React, { FC, ReactNode, createContext, useContext, useMemo } from 'react'
import { ACLCollectionProvider } from '../../acl/ACLProvider';
import { UseRequestOptions, UseRequestService } from '../../api-client';
import { withDynamicSchemaProps } from '../../application/hoc';
import { withDynamicSchemaProps } from '../../hoc/withDynamicSchemaProps';
import { Designable, useDesignable } from '../../schema-component';
import {
AssociationProvider,

View File

@ -1,67 +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 { transformToFilter } from '../utils';
// TODO: 前端测试报错解决之后,把该文件重命名为 transformToFilter.test.ts
describe('transformToFilter', () => {
it('should transform to filter', () => {
const values = {
name: 'name',
email: 'email',
user: {
name: 'name',
},
list: [{ name: 'name1' }, { name: 'name2' }, { name: 'name3' }],
};
const fieldSchema = {
'x-filter-operators': {
name: '$eq',
email: '$eq',
},
};
const getField = (name: string) => {
if (name === 'user' || name === 'list') {
return {
targetKey: 'name',
};
}
return {
targetKey: undefined,
};
};
expect(transformToFilter(values, fieldSchema as any, getField)).toEqual({
$and: [
{
name: {
$eq: 'name',
},
},
{
email: {
$eq: 'email',
},
},
{
'user.name': {
$eq: 'name',
},
},
{
'list.name': {
$eq: ['name1', 'name2', 'name3'],
},
},
],
});
});
});

View File

@ -1,63 +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 { render } from '@testing-library/react';
import React from 'react';
import { FilterBlockProvider, useFilterBlock } from '../FilterProvider';
describe('useFilter', () => {
test('should get a empty array', () => {
let getDataBlocks = null;
const Comp = () => {
({ getDataBlocks } = useFilterBlock());
return null;
};
const App = () => {
return (
<FilterBlockProvider>
<Comp />
</FilterBlockProvider>
);
};
render(<App />);
expect(getDataBlocks()).toEqual([]);
});
test('should not repeat', () => {
let getDataBlocks = null,
recordDataBlocks = null;
const Comp = () => {
({ getDataBlocks, recordDataBlocks } = useFilterBlock());
return null;
};
const App = () => {
return (
<FilterBlockProvider>
<Comp />
</FilterBlockProvider>
);
};
render(<App />);
recordDataBlocks({
name: 'test',
collection: {},
doFilter: () => {},
});
expect(getDataBlocks().length).toBe(1);
// avoid repeat
recordDataBlocks({
name: 'test',
collection: {},
doFilter: () => {},
});
expect(getDataBlocks().length).toBe(1);
});
});

View File

@ -13,14 +13,13 @@ import _ from 'lodash';
import { useCallback, useEffect, useState } from 'react';
import { FilterTarget, findFilterTargets } from '../block-provider/hooks';
import {
Collection_deprecated,
CollectionFieldOptions_deprecated,
Collection_deprecated,
FieldOptions,
useCollection_deprecated,
useCollectionManager_deprecated,
useCollection_deprecated,
} from '../collection-manager';
import { removeNullCondition } from '../schema-component';
import { findFilterOperators } from '../schema-component/antd/form-item/SchemaSettingOptions';
import { DataBlock, useFilterBlock } from './FilterProvider';
export enum FilterBlockType {
@ -99,12 +98,10 @@ export const useSupportedBlocks = (filterBlockType: FilterBlockType) => {
export const transformToFilter = (
values: Record<string, any>,
fieldSchema: Schema,
operators: Record<string, string>,
getCollectionJoinField: (name: string) => CollectionFieldOptions_deprecated,
collectionName: string,
) => {
const { operators } = findFilterOperators(fieldSchema);
values = flatten(values, {
breakOn({ value, path }) {
// 下面操作符的值是一个数组,需要特殊处理

View File

@ -8,9 +8,9 @@
*/
import { useExpressionScope } from '@formily/react';
import React, { ComponentType, useMemo } from 'react';
import { useDesignable } from '../../schema-component';
import _ from 'lodash';
import React, { ComponentType, useMemo } from 'react';
import { useDesignable } from '../schema-component';
const useDefaultDynamicComponentProps = () => undefined;

View File

@ -60,13 +60,13 @@ export * from './testUtils';
export * from './user';
export * from './variables';
export { withDynamicSchemaProps } from './application/hoc/withDynamicSchemaProps';
export { withDynamicSchemaProps } from './hoc/withDynamicSchemaProps';
export * from './modules/blocks/BlockSchemaToolbar';
export * from './modules/blocks/data-blocks/form';
export * from './modules/blocks/data-blocks/table';
export * from './modules/blocks/data-blocks/table-selector';
export * from './modules/blocks/useParentRecordCommon';
export * from './modules/blocks/index';
export * from './modules/blocks/useParentRecordCommon';
export { DeclareVariable } from './modules/variable/DeclareVariable';

View File

@ -16,12 +16,10 @@ import { useFormBlockContext } from '../../../../block-provider';
import { useDetailsBlockContext } from '../../../../block-provider/DetailsBlockProvider';
import { useCollection_deprecated, useSortFields } from '../../../../collection-manager';
import { removeNullCondition, useDesignable } from '../../../../schema-component';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsTemplate,
SchemaSettingsLinkageRules,
} from '../../../../schema-settings';
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettingsTemplate';
import { setDataLoadingModeSettingsItem } from './setDataLoadingModeSettingsItem';
const commonItems: SchemaSettingsItemType[] = [

View File

@ -9,13 +9,10 @@
import { useFieldSchema } from '@formily/react';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { useCollection_deprecated } from '../../../../collection-manager';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsFormItemTemplate,
SchemaSettingsLinkageRules,
} from '../../../../schema-settings';
import { SchemaSettingsItemType } from '../../../../application/schema-settings/types';
import { useCollection_deprecated } from '../../../../collection-manager';
import { SchemaSettingsFormItemTemplate, SchemaSettingsLinkageRules } from '../../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
const commonItems: SchemaSettingsItemType[] = [
{

View File

@ -7,20 +7,19 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import {
screen,
checkSettings,
renderSingleSettings,
waitFor,
userEvent,
renderReadPrettySingleSettings,
renderSettings,
renderReadPrettySettings,
checkFieldTitle,
} from '@nocobase/test/client';
import { FilterFormBlockProvider, FormBlockProvider, FormItem, fieldSettingsFormItem } from '@nocobase/client';
import { useFieldSchema } from '@formily/react';
import { observer } from '@formily/reactive-react';
import { FilterFormBlockProvider, FormBlockProvider, FormItem, fieldSettingsFormItem } from '@nocobase/client';
import {
checkFieldTitle,
checkSettings,
renderReadPrettySettings,
renderSettings,
renderSingleSettings,
screen,
userEvent,
waitFor,
} from '@nocobase/test/client';
import React from 'react';
describe('FieldSettingsFormItem', () => {

View File

@ -12,11 +12,11 @@ import { SchemaSettings } from '../../../../application/schema-settings/SchemaSe
import { useFormBlockContext } from '../../../../block-provider';
import { useCollection_deprecated } from '../../../../collection-manager';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsDataTemplates,
SchemaSettingsFormItemTemplate,
SchemaSettingsLinkageRules,
} from '../../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
export const createFormBlockSettings = new SchemaSettings({
name: 'blockSettings:createForm',

View File

@ -12,11 +12,11 @@ import { SchemaSettings } from '../../../../application/schema-settings/SchemaSe
import { useFormBlockContext } from '../../../../block-provider';
import { useCollection_deprecated } from '../../../../collection-manager';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsDataTemplates,
SchemaSettingsFormItemTemplate,
SchemaSettingsLinkageRules,
} from '../../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
export const editFormBlockSettings = new SchemaSettings({
name: 'blockSettings:editForm',

View File

@ -17,8 +17,8 @@ import { useFormBlockContext } from '../../../../block-provider';
import { useCollection_deprecated, useSortFields } from '../../../../collection-manager';
import { removeNullCondition, useDesignable } from '../../../../schema-component';
import { pageSizeOptions } from '../../../../schema-component/antd/grid-card/options';
import { SchemaSettingsTemplate } from '../../../../schema-settings';
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettingsTemplate';
import { setDataLoadingModeSettingsItem } from '../details-multi/setDataLoadingModeSettingsItem';
import { SetTheCountOfColumnsDisplayedInARow } from './SetTheCountOfColumnsDisplayedInARow';

View File

@ -15,8 +15,9 @@ import { SchemaSettings } from '../../../../application/schema-settings/SchemaSe
import { useFormBlockContext } from '../../../../block-provider';
import { useCollection_deprecated, useSortFields } from '../../../../collection-manager';
import { removeNullCondition, useDesignable } from '../../../../schema-component';
import { SchemaSettingsBlockTitleItem, SchemaSettingsTemplate } from '../../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettingsTemplate';
import { setDataLoadingModeSettingsItem } from '../details-multi/setDataLoadingModeSettingsItem';
export const listBlockSettings = new SchemaSettings({

View File

@ -7,29 +7,27 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ArrayItems } from '@formily/antd-v5';
import { ISchema } from '@formily/json-schema';
import { useField, useFieldSchema } from '@formily/react';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useAPIClient } from '../../../../api-client';
import { useTableBlockContext, useFormBlockContext } from '../../../../block-provider';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { useFormBlockContext, useTableBlockContext } from '../../../../block-provider';
import {
useCollectionManager_deprecated,
useCollection_deprecated,
useSortFields,
} from '../../../../collection-manager';
import { FilterBlockType } from '../../../../filter-provider/utils';
import { useDesignable, removeNullCondition } from '../../../../schema-component';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsSortField,
SchemaSettingsConnectDataBlocks,
SchemaSettingsTemplate,
} from '../../../../schema-settings/SchemaSettings';
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { ArrayItems } from '@formily/antd-v5';
import { removeNullCondition, useDesignable } from '../../../../schema-component';
import { FixedBlockDesignerItem } from '../../../../schema-component/antd/page/FixedBlockDesignerItem';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsConnectDataBlocks } from '../../../../schema-settings/SchemaSettingsConnectDataBlocks';
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsSortField } from '../../../../schema-settings/SchemaSettingsSortField';
import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettingsTemplate';
import { setDataLoadingModeSettingsItem } from '../details-multi/setDataLoadingModeSettingsItem';
export const tableBlockSettings = new SchemaSettings({

View File

@ -12,11 +12,9 @@ import { useTranslation } from 'react-i18next';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { useCollection_deprecated } from '../../../../collection-manager';
import { FilterBlockType } from '../../../../filter-provider';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsConnectDataBlocks,
SchemaSettingsTemplate,
} from '../../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsConnectDataBlocks } from '../../../../schema-settings/SchemaSettingsConnectDataBlocks';
import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettingsTemplate';
export const filterCollapseBlockSettings = new SchemaSettings({
name: 'blockSettings:filterCollapse',

View File

@ -36,7 +36,12 @@ test.describe('filter block schema settings', () => {
});
test.describe('connect data blocks', () => {
test('connecting two blocks of the same collection', async ({ page, mockPage, mockRecords }) => {
test('connecting two blocks of the same collection', async ({
page,
mockPage,
mockRecords,
clearBlockTemplates,
}) => {
const nocoPage = await mockPage(oneFormAndOneTableWithSameCollection).waitForInit();
const records = await mockRecords('general', 3);
await nocoPage.goto();
@ -81,6 +86,81 @@ test.describe('filter block schema settings', () => {
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[0].singleLineText }),
).toBeVisible();
// 更改操作符为 “is not”
await page.getByLabel('block-item-CollectionField-').hover();
await page.getByLabel('designer-schema-settings-CollectionField-FormItem.FilterFormDesigner-general-').hover();
await page.getByRole('menuitem', { name: 'Operator contains' }).click();
await page.getByRole('option', { name: 'is not', exact: true }).click();
// 输入值,点击筛选按钮
await page
.getByLabel('block-item-CollectionField-general-filter-form-general.singleLineText-singleLineText')
.getByRole('textbox')
.click();
await page
.getByLabel('block-item-CollectionField-general-filter-form-general.singleLineText-singleLineText')
.getByRole('textbox')
.fill(records[0].singleLineText);
// 点击筛选按钮
await page.getByLabel('action-Action-Filter records-submit-general-filter-form').click();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[1].singleLineText }),
).toBeVisible();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[2].singleLineText }),
).toBeVisible();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[0].singleLineText }),
).toBeHidden();
// 点击重置按钮
await page.getByLabel('action-Action-Reset records-general-filter-form').click();
// 将筛选表单区块保存为模板
await page.getByLabel('block-item-CardItem-general-filter-form').hover();
await page.getByLabel('designer-schema-settings-CardItem-FormV2.FilterDesigner-general').hover();
await page.getByRole('menuitem', { name: 'Save as block template' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 输入值,点击筛选按钮
await page
.getByLabel('block-item-CollectionField-general-filter-form-general.singleLineText-singleLineText')
.getByRole('textbox')
.click();
await page
.getByLabel('block-item-CollectionField-general-filter-form-general.singleLineText-singleLineText')
.getByRole('textbox')
.fill(records[0].singleLineText);
// 点击筛选按钮
await page.getByLabel('action-Action-Filter records-submit-general-filter-form').click();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[1].singleLineText }),
).toBeVisible();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[2].singleLineText }),
).toBeVisible();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[0].singleLineText }),
).toBeHidden();
// 点击重置按钮
await page.getByLabel('action-Action-Reset records-general-filter-form').click();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[1].singleLineText }),
).toBeVisible();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[2].singleLineText }),
).toBeVisible();
await expect(
page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[0].singleLineText }),
).toBeVisible();
await clearBlockTemplates();
});
});
});

View File

@ -55,7 +55,6 @@ describe('createFilterFormBlockSchema', () => {
"collection": "myCollection",
"dataSource": "myDataSource",
},
"x-filter-operators": {},
"x-filter-targets": [],
"x-settings": "blockSettings:filterForm",
"x-toolbar": "BlockSchemaToolbar",
@ -104,7 +103,6 @@ describe('createFilterFormBlockSchema', () => {
"collection": "myCollection",
"dataSource": "myDataSource",
},
"x-filter-operators": {},
"x-filter-targets": [],
"x-settings": "blockSettings:filterForm",
"x-toolbar": "BlockSchemaToolbar",

View File

@ -34,8 +34,6 @@ export const createFilterFormBlockSchema = (options: {
'x-component': 'CardItem',
// 保存当前筛选区块所能过滤的数据区块
'x-filter-targets': [],
// 用于存储用户设置的每个字段的运算符,目前仅筛选表单区块支持自定义
'x-filter-operators': {},
properties: {
[uid()]: {
type: 'void',

View File

@ -12,12 +12,9 @@ import { useTranslation } from 'react-i18next';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { useCollection_deprecated } from '../../../../collection-manager';
import { FilterBlockType } from '../../../../filter-provider';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsConnectDataBlocks,
SchemaSettingsFormItemTemplate,
SchemaSettingsLinkageRules,
} from '../../../../schema-settings';
import { SchemaSettingsFormItemTemplate, SchemaSettingsLinkageRules } from '../../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsConnectDataBlocks } from '../../../../schema-settings/SchemaSettingsConnectDataBlocks';
export const filterFormBlockSettings = new SchemaSettings({
name: 'blockSettings:filterForm',

View File

@ -0,0 +1,30 @@
/**
* 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 { useFieldSchema } from '@formily/react';
import { useEffect } from 'react';
import { useOperators } from '../../../../../block-provider/CollectOperators';
/**
*
*/
export const useCollectOperator = () => {
const fieldSchema = useFieldSchema();
const { collectOperator, removeOperator } = useOperators();
useEffect(() => {
return () => {
removeOperator(fieldSchema.name);
};
}, [fieldSchema.name, removeOperator]);
if (fieldSchema['x-filter-operator']) {
collectOperator(fieldSchema.name, fieldSchema['x-filter-operator']);
}
};

View File

@ -7,4 +7,8 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
export * from './withDynamicSchemaProps';
import { useCollectOperator } from './useCollectOperator';
export const useFormItemProps = () => {
useCollectOperator();
};

View File

@ -8,11 +8,11 @@
*/
import { observer } from '@formily/react';
import React from 'react';
import classnames from 'classnames';
import React from 'react';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import Action from './Action';
import { ComposedAction } from './types';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export const ActionLink: ComposedAction = withDynamicSchemaProps(
observer((props: any) => {

View File

@ -17,13 +17,13 @@ import { useTranslation } from 'react-i18next';
import { StablePopover, useActionContext } from '../..';
import { useDesignable } from '../../';
import { useACLActionParamsContext } from '../../../acl';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import {
useCollection,
useCollectionParentRecordData,
useCollectionRecordData,
useDataBlockRequest,
} from '../../../data-source';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { Icon } from '../../../icon';
import { TreeRecordProvider } from '../../../modules/blocks/data-blocks/table/TreeRecordProvider';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';

View File

@ -12,10 +12,10 @@ import { RecursionField, observer, useFieldSchema } from '@formily/react';
import { Space, SpaceProps } from 'antd';
import React, { CSSProperties, useContext } from 'react';
import { createPortal } from 'react-dom';
import { useSchemaInitializerRender } from '../../../application';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { DndContext } from '../../common';
import { useDesignable, useProps } from '../../hooks';
import { useSchemaInitializerRender } from '../../../application';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export interface ActionBarProps {
layout?: 'one-column' | 'two-columns';

View File

@ -12,14 +12,10 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { useCollection_deprecated } from '../../../collection-manager';
import { FilterBlockType } from '../../../filter-provider/utils';
import {
GeneralSchemaDesigner,
SchemaSettingsBlockTitleItem,
SchemaSettingsConnectDataBlocks,
SchemaSettingsDivider,
SchemaSettingsRemove,
SchemaSettingsTemplate,
} from '../../../schema-settings';
import { GeneralSchemaDesigner, SchemaSettingsDivider, SchemaSettingsRemove } from '../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsConnectDataBlocks } from '../../../schema-settings/SchemaSettingsConnectDataBlocks';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
import { useSchemaTemplate } from '../../../schema-templates';
export const AssociationFilterBlockDesigner = () => {

View File

@ -12,6 +12,7 @@ import { useFieldSchema } from '@formily/react';
import { Col, Collapse, Input, Row, Tree } from 'antd';
import cls from 'classnames';
import React, { ChangeEvent, MouseEvent, useMemo, useState } from 'react';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { SortableItem } from '../../common';
import { useCompile, useDesigner, useProps } from '../../hooks';
import { useToken } from '../__builtins__';
@ -19,7 +20,6 @@ import { EllipsisWithTooltip } from '../input';
import { getLabelFormatValue, useLabelUiSchema } from '../record-picker';
import { AssociationFilter } from './AssociationFilter';
import useStyles from './AssociationFilter.Item.style';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
const { Panel } = Collapse;

View File

@ -9,8 +9,8 @@
import { connect, mapProps, mapReadPretty } from '@formily/react';
import { AutoComplete as AntdAutoComplete } from 'antd';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { ReadPretty } from '../input';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export const AutoComplete = withDynamicSchemaProps(
connect(

View File

@ -10,7 +10,7 @@
import { useFieldSchema } from '@formily/react';
import cls from 'classnames';
import React, { useMemo } from 'react';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { CustomCreateStylesUtils, createStyles } from '../../../style';
import { SortableItem } from '../../common';
import { useDesigner, useProps } from '../../hooks';

View File

@ -11,14 +11,14 @@ import { LoadingOutlined } from '@ant-design/icons';
import { ArrayField } from '@formily/core';
import { connect, mapProps, mapReadPretty, useField } from '@formily/react';
import { toArr } from '@formily/shared';
import { Cascader as AntdCascader, Space, CascaderProps as AntdCascaderProps } from 'antd';
import { Cascader as AntdCascader, CascaderProps as AntdCascaderProps, Space } from 'antd';
import { BaseOptionType } from 'antd/es/select';
import { isBoolean, omit } from 'lodash';
import React from 'react';
import { UseRequestResult, useRequest } from '../../../api-client';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { ReadPretty } from './ReadPretty';
import { defaultFieldNames } from './defaultFieldNames';
import { BaseOptionType } from 'antd/es/select';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
const useDefDataSource = (options, props: any) => {
const field = useField<ArrayField>();

View File

@ -7,12 +7,12 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React from 'react';
import { FormV2 } from '../form-v2';
import _ from 'lodash';
import { Empty } from 'antd';
import _ from 'lodash';
import React from 'react';
import { useDataBlockRequest } from '../../../data-source';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { FormV2 } from '../form-v2';
import { FormProps } from '../form-v2/Form';
export type DetailsProps = FormProps;

View File

@ -11,13 +11,13 @@ import { ObjectField as ObjectFieldModel } from '@formily/core';
import { observer, useField, useFieldSchema } from '@formily/react';
import React, { useEffect } from 'react';
import { UseRequestOptions, useRequest } from '../../../api-client';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { useProps } from '../../hooks/useProps';
import { FilterActionDesigner } from './Filter.Action.Designer';
import { FilterAction } from './FilterAction';
import { FilterGroup } from './FilterGroup';
import { SaveDefaultValue } from './SaveDefaultValue';
import { FilterContext, FilterContextProps } from './context';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
const useDef = (options: UseRequestOptions) => {
const field = useField<ObjectFieldModel>();

View File

@ -14,12 +14,12 @@ import { flatten, unflatten } from '@nocobase/utils/client';
import { Button, Space } from 'antd';
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { FormProvider, SchemaComponent } from '../../core';
import { useDesignable } from '../../hooks';
import { useProps } from '../../hooks/useProps';
import { Action, ActionProps } from '../action';
import { StablePopover } from '../popover';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export const FilterActionContext = createContext<any>(null);
FilterActionContext.displayName = 'FilterActionContext';

View File

@ -11,12 +11,13 @@ import { css, cx } from '@emotion/css';
import { IFormItemProps, FormItem as Item } from '@formily/antd-v5';
import { Field } from '@formily/core';
import { observer, useField, useFieldSchema } from '@formily/react';
import React, { FC, useEffect, useMemo } from 'react';
import React, { useEffect, useMemo } from 'react';
import { ACLCollectionFieldProvider } from '../../../acl/ACLProvider';
import { useApp } from '../../../application';
import { useFormActiveFields } from '../../../block-provider/hooks/useFormActiveFields';
import { Collection_deprecated } from '../../../collection-manager';
import { CollectionFieldProvider } from '../../../data-source/collection-field/CollectionFieldProvider';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { GeneralSchemaDesigner } from '../../../schema-settings';
import { useVariables } from '../../../variables';
import useContextVariable from '../../../variables/hooks/useContextVariable';
@ -41,8 +42,8 @@ const formItemLabelCss = css`
}
`;
export const FormItem: any = observer(
(props: IFormItemProps) => {
export const FormItem: any = withDynamicSchemaProps(
observer((props: IFormItemProps) => {
useEnsureOperatorsValid();
const field = useField<Field>();
const schema = useFieldSchema();
@ -89,7 +90,7 @@ export const FormItem: any = observer(
</BlockItem>
</CollectionFieldProvider>
);
},
}),
{ displayName: 'FormItem' },
);

View File

@ -9,40 +9,18 @@
import { ArrayCollapse, FormLayout } from '@formily/antd-v5';
import { Field } from '@formily/core';
import { ISchema, Schema, useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import { ISchema, useField, useFieldSchema } from '@formily/react';
import _ from 'lodash';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useFormBlockContext } from '../../../block-provider';
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
import { useOperators } from '../../../block-provider/CollectOperators';
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../../collection-manager';
import { SchemaSettingsModalItem, SchemaSettingsSelectItem, SchemaSettingsSwitchItem } from '../../../schema-settings';
import { isPatternDisabled } from '../../../schema-settings/isPatternDisabled';
import { useCompile, useDesignable, useFieldModeOptions } from '../../hooks';
import { useOperatorList } from '../filter/useOperators';
import { isFileCollection } from './FormItem';
export const findFilterOperators = (schema: Schema) => {
while (schema) {
if (schema['x-filter-operators']) {
return {
operators: schema['x-filter-operators'],
uid: schema['x-uid'],
};
}
schema = schema.parent;
}
return {};
};
const divWrap = (schema: ISchema) => {
return {
type: 'void',
'x-component': 'div',
properties: {
[schema.name || uid()]: schema,
},
};
};
export const EditTitle = () => {
const { getCollectionJoinField } = useCollectionManager_deprecated();
@ -496,10 +474,11 @@ export const EditPattern = () => {
export const useEnsureOperatorsValid = () => {
const fieldSchema = useFieldSchema();
const operatorList = useOperatorList();
const { operators: storedOperators } = findFilterOperators(fieldSchema);
const { getOperators, collectOperator } = useOperators();
const storedOperators = getOperators();
if (storedOperators && operatorList.length && !storedOperators[fieldSchema.name]) {
storedOperators[fieldSchema.name] = operatorList[0].value;
collectOperator(fieldSchema.name, operatorList[0].value);
}
};
@ -510,61 +489,51 @@ export const EditOperator = () => {
const { t } = useTranslation();
const { dn } = useDesignable();
const operatorList = useOperatorList();
const { operators: storedOperators = {}, uid } = findFilterOperators(fieldSchema);
const { getOperator, collectOperator } = useOperators();
if (operatorList.length && !storedOperators[fieldSchema.name]) {
storedOperators[fieldSchema.name] = operatorList[0].value;
if (operatorList.length && !getOperator(fieldSchema.name)) {
collectOperator(fieldSchema.name, operatorList[0].value);
}
return operatorList.length ? (
<SchemaSettingsSelectItem
key="operator"
title={t('Operator')}
value={storedOperators[fieldSchema.name]}
value={getOperator(fieldSchema.name as string)}
options={compile(operatorList)}
onChange={(v) => {
storedOperators[fieldSchema.name] = v;
collectOperator(fieldSchema.name as string, v);
_.set(fieldSchema, 'x-filter-operator', v);
const operator = operatorList.find((item) => item.value === v);
const schema: ISchema = {
['x-uid']: uid,
['x-filter-operators']: storedOperators,
};
let componentProps = {};
// 根据操作符的配置,设置组件的属性
if (operator?.schema?.['x-component']) {
_.set(fieldSchema, 'x-component-props.component', operator.schema['x-component']);
_.set(field, 'componentProps.component', operator.schema['x-component']);
_.set(fieldSchema, 'x-component-props.component', operator.schema?.['x-component']);
_.set(field, 'componentProps.component', operator.schema?.['x-component']);
field.reset();
componentProps = {
component: operator.schema['x-component'],
...operator.schema['x-component-props'],
...operator.schema?.['x-component-props'],
};
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
['x-component-props']: componentProps,
},
});
} else if (fieldSchema['x-component-props']?.component) {
_.set(fieldSchema, 'x-component-props.component', null);
_.set(field, 'componentProps.component', null);
field.reset();
componentProps = {
component: null,
...operator.schema['x-component-props'],
...operator.schema?.['x-component-props'],
};
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
['x-component-props']: componentProps,
},
});
}
field.componentProps = componentProps;
dn.emit('patch', {
schema,
schema: {
['x-uid']: fieldSchema['x-uid'],
['x-component-props']: componentProps,
['x-filter-operator']: v,
},
});
dn.refresh();
}}

View File

@ -15,17 +15,17 @@ import { useFormBlockContext } from '../../../block-provider';
import { useDetailsBlockContext } from '../../../block-provider/DetailsBlockProvider';
import { useCollection_deprecated } from '../../../collection-manager';
import { useSortFields } from '../../../collection-manager/action-hooks';
import { setDataLoadingModeSettingsItem } from '../../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
import {
SchemaSettingsBlockTitleItem,
SchemaSettingsDataTemplates,
SchemaSettingsFormItemTemplate,
SchemaSettingsLinkageRules,
SchemaSettingsTemplate,
} from '../../../schema-settings/SchemaSettings';
import { SchemaSettingsBlockTitleItem } from '../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsDataScope } from '../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
import { useDesignable } from '../../hooks';
import { removeNullCondition } from '../filter';
import { setDataLoadingModeSettingsItem } from '../../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
/**
* @deprecated

View File

@ -18,8 +18,8 @@ import { ConfigProvider, Spin } from 'antd';
import React, { useEffect, useMemo } from 'react';
import { useActionContext } from '..';
import { useAttach, useComponent } from '../..';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useTemplateBlockContext } from '../../../block-provider/TemplateBlockProvider';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { ActionType } from '../../../schema-settings/LinkageRules/type';
import { useToken } from '../../../style';
import { useLocalVariables, useVariables } from '../../../variables';

View File

@ -9,7 +9,7 @@
import { SchemaSettings } from '../../../application/schema-settings';
import { useCollection_deprecated } from '../../../collection-manager';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettings';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
/**
* @deprecated

View File

@ -16,12 +16,8 @@ import React, { createContext, useContext, useEffect, useMemo } from 'react';
import { useAttach, useComponent } from '../..';
import { useRequest } from '../../../api-client';
import { useCollection_deprecated } from '../../../collection-manager';
import {
GeneralSchemaDesigner,
SchemaSettingsDivider,
SchemaSettingsRemove,
SchemaSettingsTemplate,
} from '../../../schema-settings';
import { GeneralSchemaDesigner, SchemaSettingsDivider, SchemaSettingsRemove } from '../../../schema-settings';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
import { useSchemaTemplate } from '../../../schema-templates';
type Opts = Options<any, any> & { uid?: string };

View File

@ -12,9 +12,9 @@ import { createForm } from '@formily/core';
import { FormContext, useField, useFieldSchema } from '@formily/react';
import React, { createContext, useContext, useEffect, useMemo } from 'react';
import { BlockProvider, useBlockRequestContext } from '../../../block-provider/BlockProvider';
import useStyles from './GridCard.Decorator.style';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { useGridCardBlockParams } from '../../../modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockParams';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import useStyles from './GridCard.Decorator.style';
export const GridCardBlockContext = createContext<any>({});
GridCardBlockContext.displayName = 'GridCardBlockContext';

View File

@ -24,9 +24,9 @@ import {
SchemaSettingsModalItem,
SchemaSettingsRemove,
SchemaSettingsSelectItem,
SchemaSettingsTemplate,
} from '../../../schema-settings';
import { SchemaSettingsDataScope } from '../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
import { useSchemaTemplate } from '../../../schema-templates';
import { SchemaComponentOptions } from '../../core';
import { useDesignable } from '../../hooks';

View File

@ -12,8 +12,8 @@ import { ObjectField } from '@formily/core';
import { useField } from '@formily/react';
import { Card } from 'antd';
import React from 'react';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { RecordProvider } from '../../../record-provider';
const itemCss = css`

View File

@ -12,6 +12,7 @@ import { ArrayField } from '@formily/core';
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
import { List as AntdList, Col, PaginationProps } from 'antd';
import React, { useCallback, useState } from 'react';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { SortableItem } from '../../common';
import { SchemaComponentOptions } from '../../core';
import { useDesigner, useProps } from '../../hooks';
@ -20,7 +21,6 @@ import { GridCardDesigner } from './GridCard.Designer';
import { GridCardItem } from './GridCard.Item';
import { useGridCardActionBarProps } from './hooks';
import { defaultColumnCount, pageSizeOptions } from './options';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
const rowGutter = {
md: 12,

View File

@ -14,8 +14,8 @@ import { FormContext, useField } from '@formily/react';
import _ from 'lodash';
import React, { createContext, useContext, useEffect, useMemo } from 'react';
import { BlockProvider, useBlockRequestContext } from '../../../block-provider/BlockProvider';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useParsedFilter } from '../../../block-provider/hooks/useParsedFilter';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
export const ListBlockContext = createContext<any>({});
ListBlockContext.displayName = 'ListBlockContext';

View File

@ -14,21 +14,21 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { useFormBlockContext } from '../../../block-provider';
import { useCollection_deprecated, useSortFields } from '../../../collection-manager';
import { SetDataLoadingMode } from '../../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
import { useRecord } from '../../../record-provider';
import {
GeneralSchemaDesigner,
SchemaSettingsBlockTitleItem,
SchemaSettingsDivider,
SchemaSettingsModalItem,
SchemaSettingsRemove,
SchemaSettingsSelectItem,
SchemaSettingsTemplate,
} from '../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsDataScope } from '../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
import { useSchemaTemplate } from '../../../schema-templates';
import { useDesignable } from '../../hooks';
import { removeNullCondition } from '../filter';
import { SchemaSettingsDataScope } from '../../../schema-settings/SchemaSettingsDataScope';
import { SetDataLoadingMode } from '../../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
/**
* @deprecated - 使 SchemaSettings

View File

@ -14,8 +14,8 @@ import classnames from 'classnames';
import React from 'react';
import { useDesignable } from '../../hooks';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { RecordProvider } from '../../../record-provider';
export const ListItem = withDynamicSchemaProps((props) => {

View File

@ -12,6 +12,7 @@ import { ArrayField } from '@formily/core';
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
import { List as AntdList, PaginationProps } from 'antd';
import React, { useCallback, useState } from 'react';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { SortableItem } from '../../common';
import { SchemaComponentOptions } from '../../core';
import { useDesigner } from '../../hooks';
@ -20,7 +21,6 @@ import { ListDesigner } from './List.Designer';
import { ListItem } from './List.Item';
import useStyles from './List.style';
import { useListActionBarProps } from './hooks';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
const InternalList = (props) => {
const { service } = useListBlockContext();

View File

@ -10,7 +10,6 @@
import { css } from '@emotion/css';
import { useField, useFieldSchema } from '@formily/react';
import React, { useContext, useEffect, useRef, useState } from 'react';
import { useRecord } from '../../../record-provider';
const FixedBlockContext = React.createContext<{
setFixedBlock: (value: string | false) => void;

View File

@ -12,7 +12,7 @@ import { useFieldSchema } from '@formily/react';
import { Space } from 'antd';
import React from 'react';
import { DragHandler, useDesignable } from '../..';
import { useSchemaSettingsRender } from '../../../application/schema-settings/hooks';
import { useSchemaSettingsRender } from '../../../application/schema-settings/hooks/useSchemaSettingsRender';
import { SchemaToolbarProvider } from '../../../application/schema-toolbar/context';
import { useGetAriaLabelOfDesigner } from '../../../schema-settings/hooks/useGetAriaLabelOfDesigner';

View File

@ -10,8 +10,8 @@
import { observer } from '@formily/react';
import { Pagination as AntdPagination, PaginationProps as AntdPaginationProps } from 'antd';
import React, { KeyboardEventHandler } from 'react';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { useProps } from '../../hooks/useProps';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
export interface PaginationProps extends AntdPaginationProps {
hidden?: boolean;

View File

@ -35,8 +35,8 @@ import {
useTableSelectorContext,
} from '../../../';
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { isNewRecord } from '../../../data-source/collection-record/isNewRecord';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { useToken } from '../__builtins__';
import { SubFormProvider } from '../association-field/hooks';
import { ColumnFieldProvider } from './components/ColumnFieldProvider';

View File

@ -8,34 +8,33 @@
*/
import { ArrayItems } from '@formily/antd-v5';
import { ISchema, useField, useFieldSchema } from '@formily/react';
import { Field } from '@formily/core';
import { ISchema, useField, useFieldSchema } from '@formily/react';
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useCompile } from '../../';
import { useAPIClient } from '../../../api-client';
import { useFormBlockContext, useTableBlockContext } from '../../../block-provider';
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../../collection-manager';
import { useSortFields } from '../../../collection-manager/action-hooks';
import { FilterBlockType, mergeFilter } from '../../../filter-provider/utils';
import { useRecord } from '../../../record-provider';
import { SetDataLoadingMode } from '../../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
import {
GeneralSchemaDesigner,
SchemaSettingsBlockTitleItem,
SchemaSettingsConnectDataBlocks,
SchemaSettingsDivider,
SchemaSettingsModalItem,
SchemaSettingsRemove,
SchemaSettingsSelectItem,
SchemaSettingsSwitchItem,
SchemaSettingsTemplate,
} from '../../../schema-settings';
import { SchemaSettingsBlockTitleItem } from '../../../schema-settings/SchemaSettingsBlockTitleItem';
import { SchemaSettingsConnectDataBlocks } from '../../../schema-settings/SchemaSettingsConnectDataBlocks';
import { SchemaSettingsDataScope } from '../../../schema-settings/SchemaSettingsDataScope';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
import { useSchemaTemplate } from '../../../schema-templates';
import { useDesignable } from '../../hooks';
import { removeNullCondition } from '../filter';
import { useCompile } from '../../';
import { SchemaSettingsDataScope } from '../../../schema-settings/SchemaSettingsDataScope';
import { FixedBlockDesignerItem } from '../page/FixedBlockDesignerItem';
import { SetDataLoadingMode } from '../../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
export const EditSortField = () => {
const { fields } = useCollection_deprecated();

View File

@ -14,13 +14,13 @@ import {
useTableBlockDecoratorProps,
} from '@nocobase/client';
import {
CheckSettingsOptions,
checkSchema,
checkSettings,
renderSettings,
checkSchema,
screen,
userEvent,
waitFor,
CheckSettingsOptions,
} from '@nocobase/test/client';
import { withSchema } from '@nocobase/test/web';

View File

@ -20,8 +20,8 @@ import {
SchemaSettingsRemove,
SchemaSettingsSelectItem,
SchemaSettingsSwitchItem,
SchemaSettingsTemplate,
} from '../../../schema-settings';
import { SchemaSettingsTemplate } from '../../../schema-settings/SchemaSettingsTemplate';
import { useSchemaTemplate } from '../../../schema-templates';
import { useDesignable } from '../../hooks';

View File

@ -16,7 +16,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import LightBox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { useProps } from '../../hooks/useProps';
import { ReadPretty } from './ReadPretty';
import { isImage, isPdf, toArr, toFileList, toItem, toValue, useUploadProps } from './shared';

View File

@ -382,6 +382,7 @@ export const useFilterFormItemInitializerFields = (options?: any) => {
'x-settings': 'fieldSettings:FilterFormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useFormItemProps',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': {},
};
@ -395,6 +396,7 @@ export const useFilterFormItemInitializerFields = (options?: any) => {
'x-settings': 'fieldSettings:FilterFormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useFormItemProps',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': field.uiSchema?.['x-component-props'],
};

View File

@ -16,6 +16,7 @@ import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useCollectionManager_deprecated } from '../../collection-manager';
import { mergeFilter } from '../../filter-provider/utils';
import { withDynamicSchemaProps } from '../../hoc/withDynamicSchemaProps';
import { SchemaComponent, SchemaComponentContext, removeNullCondition, useProps } from '../../schema-component';
import { ITemplate } from '../../schema-component/antd/form-v2/Templates';
import { VariableInput } from '../VariableInput';
@ -24,7 +25,6 @@ import { ArrayCollapse } from './components/DataTemplateTitle';
import { getSelectedIdFilter } from './components/Designer';
import { useCollectionState } from './hooks/useCollectionState';
import { useSyncFromForm } from './utils';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
const Tree = connect(
AntdTree,

View File

@ -11,8 +11,8 @@ import { observer, useForm } from '@formily/react';
import { action } from '@formily/reactive';
import React from 'react';
import { useCollectionManager_deprecated } from '../../collection-manager';
import { withDynamicSchemaProps } from '../../hoc/withDynamicSchemaProps';
import { SchemaComponent, useCompile, useProps } from '../../schema-component';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
export const EnableChildCollections = withDynamicSchemaProps(
observer((props: any) => {

View File

@ -14,13 +14,8 @@ import { Space } from 'antd';
import classNames from 'classnames';
import React, { FC, useEffect, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import {
SchemaInitializer,
SchemaSettings,
SchemaToolbarProvider,
useSchemaInitializerRender,
useSchemaSettingsRender,
} from '../application';
import { SchemaInitializer, SchemaSettings, SchemaToolbarProvider, useSchemaInitializerRender } from '../application';
import { useSchemaSettingsRender } from '../application/schema-settings/hooks/useSchemaSettingsRender';
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
import { useDataSource } from '../data-source/data-source/DataSourceProvider';
import { DragHandler, useCompile, useDesignable, useGridContext, useGridRowContext } from '../schema-component';

View File

@ -12,10 +12,10 @@ import { ArrayField, ObjectField, observer, useField } from '@formily/react';
import { Space } from 'antd';
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { withDynamicSchemaProps } from '../../hoc/withDynamicSchemaProps';
import { useProps } from '../../schema-component/hooks/useProps';
import { FormButtonLinkageRuleAction, FormFieldLinkageRuleAction } from './LinkageRuleAction';
import { RemoveActionContext } from './context';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
import { useProps } from '../../schema-component/hooks/useProps';
export const LinkageRuleActions = observer(
(props: any): any => {
const { type, linkageOptions } = props;

View File

@ -10,10 +10,10 @@
import { css } from '@emotion/css';
import { observer, useFieldSchema } from '@formily/react';
import React, { useMemo } from 'react';
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
import { FormBlockContext } from '../../block-provider';
import { useCollectionManager_deprecated } from '../../collection-manager';
import { useCollectionParentRecordData } from '../../data-source/collection-record/CollectionRecordProvider';
import { withDynamicSchemaProps } from '../../hoc/withDynamicSchemaProps';
import { RecordProvider } from '../../record-provider';
import { SchemaComponent, useProps } from '../../schema-component';
import { DynamicComponentProps } from '../../schema-component/antd/filter/DynamicComponent';

View File

@ -12,7 +12,6 @@ import { ArrayCollapse, ArrayItems, FormItem, FormLayout, Input } from '@formily
import { Field, GeneralField, createForm } from '@formily/core';
import { ISchema, Schema, SchemaOptionsContext, useField, useFieldSchema, useForm } from '@formily/react';
import { uid } from '@formily/shared';
import { error } from '@nocobase/utils/client';
import type { DropdownProps } from 'antd';
import {
Alert,
@ -22,7 +21,6 @@ import {
CascaderProps,
ConfigProvider,
Dropdown,
Empty,
MenuItemProps,
MenuProps,
Modal,
@ -46,65 +44,47 @@ import React, {
import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next';
import { Router } from 'react-router-dom';
import { APIClientProvider } from '../api-client/APIClientProvider';
import { useAPIClient } from '../api-client/hooks/useAPIClient';
import { FormBlockContext, findFormBlock, useFormBlockContext, useFormBlockType } from '../block-provider';
import {
APIClientProvider,
ActionContextProvider,
AssociationOrCollectionProvider,
CollectionFieldOptions_deprecated,
CollectionRecordProvider,
DataSourceApplicationProvider,
Designable,
FormDialog,
FormProvider,
RemoteSchemaComponent,
SchemaComponent,
SchemaComponentContext,
SchemaComponentOptions,
createDesignable,
findFormBlock,
useAPIClient,
useCollectionManager_deprecated,
useCollectionRecord,
useCollection_deprecated,
useCompile,
useDataBlockProps,
useDesignable,
useGlobalTheme,
useLinkageCollectionFilterOptions,
useRecord,
useSortFields,
} from '..';
import { FormBlockContext, useFormBlockContext, useFormBlockType, useTableBlockContext } from '../block-provider';
import {
FormActiveFieldsProvider,
findFilterTargets,
updateFilterTargets,
useFormActiveFields,
} from '../block-provider/hooks';
import {
useBlockRequestContext,
BlockContext,
BlockRequestContext_deprecated,
useBlockContext,
BlockContext,
useBlockRequestContext,
} from '../block-provider/BlockProvider';
import { FormActiveFieldsProvider, useFormActiveFields } from '../block-provider/hooks';
import { useLinkageCollectionFilterOptions, useSortFields } from '../collection-manager/action-hooks';
import { useCollectionManager_deprecated } from '../collection-manager/hooks/useCollectionManager_deprecated';
import { useCollection_deprecated } from '../collection-manager/hooks/useCollection_deprecated';
import { CollectionFieldOptions_deprecated } from '../collection-manager/types';
import { SelectWithTitle, SelectWithTitleProps } from '../common/SelectWithTitle';
import { useNiceDropdownMaxHeight } from '../common/useNiceDropdownHeight';
import {
CollectionRecordProvider,
useCollectionRecord,
} from '../data-source/collection-record/CollectionRecordProvider';
import { DataSourceApplicationProvider } from '../data-source/components/DataSourceApplicationProvider';
import { AssociationOrCollectionProvider, useDataBlockProps } from '../data-source/data-block/DataBlockProvider';
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
import { useDataSourceKey } from '../data-source/data-source/DataSourceProvider';
import {
FilterBlockType,
getSupportFieldsByAssociation,
getSupportFieldsByForeignKey,
isSameCollection,
useSupportedBlocks,
} from '../filter-provider/utils';
import { useFilterBlock } from '../filter-provider/FilterProvider';
import { FlagProvider } from '../flag-provider';
import { useGlobalTheme } from '../global-theme';
import { useCollectMenuItem, useCollectMenuItems, useMenuItem } from '../hooks/useMenuItem';
import { DeclareVariable } from '../modules/variable/DeclareVariable';
import { useVariable } from '../modules/variable/useVariable';
import { useRecord } from '../record-provider';
import { ActionContextProvider } from '../schema-component/antd/action/context';
import { SubFormProvider, useSubFormValue } from '../schema-component/antd/association-field/hooks';
import { getTargetKey } from '../schema-component/antd/association-filter/utilts';
import { FormDialog } from '../schema-component/antd/form-dialog';
import { SchemaComponentContext } from '../schema-component/context';
import { FormProvider } from '../schema-component/core/FormProvider';
import { RemoteSchemaComponent } from '../schema-component/core/RemoteSchemaComponent';
import { SchemaComponent } from '../schema-component/core/SchemaComponent';
import { SchemaComponentOptions } from '../schema-component/core/SchemaComponentOptions';
import { useCompile } from '../schema-component/hooks/useCompile';
import { Designable, createDesignable, useDesignable } from '../schema-component/hooks/useDesignable';
import { useSchemaTemplateManager } from '../schema-templates';
import { useBlockTemplateContext } from '../schema-templates/BlockTemplate';
import { useLocalVariables, useVariables } from '../variables';
@ -207,103 +187,6 @@ export const SchemaSettingsDropdown: React.FC<SchemaSettingsProps> = (props) =>
);
};
export const SchemaSettingsTemplate = function Template(props) {
const { componentName, collectionName, resourceName, needRender } = props;
const { t } = useTranslation();
const { getCollection } = useCollectionManager_deprecated();
const { dn, setVisible, template, fieldSchema } = useSchemaSettings();
const compile = useCompile();
const api = useAPIClient();
const { dn: tdn } = useBlockTemplateContext();
const { saveAsTemplate, copyTemplateSchema } = useSchemaTemplateManager();
const { theme } = useGlobalTheme();
if (!collectionName && !needRender) {
return null;
}
if (template) {
return (
<SchemaSettingsItem
title="Convert reference to duplicate"
onClick={async () => {
const schema = await copyTemplateSchema(template);
const removed = tdn.removeWithoutEmit();
tdn.insertAfterEnd(schema, {
async onSuccess() {
await api.request({
url: `/uiSchemas:remove/${removed['x-uid']}`,
});
},
});
}}
>
{t('Convert reference to duplicate')}
</SchemaSettingsItem>
);
}
return (
<SchemaSettingsItem
title="Save as template"
onClick={async () => {
setVisible(false);
const collection = collectionName && getCollection(collectionName);
const values = await FormDialog(
t('Save as template'),
() => {
return (
<FormLayout layout={'vertical'}>
<SchemaComponent
components={{ Input, FormItem }}
schema={{
type: 'object',
properties: {
name: {
title: t('Template name'),
required: true,
default: collection
? `${compile(collection?.title || collection?.name)}_${t(componentName)}`
: t(componentName),
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
}}
/>
</FormLayout>
);
},
theme,
).open({});
const sdn = createDesignable({
t,
api,
refresh: dn.refresh.bind(dn),
current: fieldSchema.parent,
});
sdn.loadAPIClientEvents();
const { key } = await saveAsTemplate({
collectionName,
resourceName,
componentName,
dataSourceKey: collection.dataSource,
name: values.name,
uid: fieldSchema['x-uid'],
});
sdn.removeWithoutEmit(fieldSchema);
sdn.insertBeforeEnd({
type: 'void',
'x-component': 'BlockTemplate',
'x-component-props': {
templateId: key,
},
});
}}
>
{t('Save as template')}
</SchemaSettingsItem>
);
};
const findGridSchema = (fieldSchema) => {
return fieldSchema.reduceProperties((buf, s) => {
if (s['x-component'] === 'FormV2' || s['x-component'] === 'Details') {
@ -609,144 +492,6 @@ export const SchemaSettingsRemove: FC<SchemaSettingsRemoveProps> = (props) => {
);
};
interface SchemaSettingsConnectDataBlocksProps {
type: FilterBlockType;
emptyDescription?: string;
}
export const SchemaSettingsConnectDataBlocks: FC<SchemaSettingsConnectDataBlocksProps> = (props) => {
const { type, emptyDescription } = props;
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
const { t } = useTranslation();
const collection = useCollection_deprecated();
const { inProvider } = useFilterBlock();
const dataBlocks = useSupportedBlocks(type);
// eslint-disable-next-line prefer-const
let { targets = [], uid } = findFilterTargets(fieldSchema);
const compile = useCompile();
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
if (!inProvider) {
return null;
}
const Content = dataBlocks.map((block) => {
const title = `${compile(block.collection.title)} #${block.uid.slice(0, 4)}`;
const onHover = () => {
const dom = block.dom;
const designer = dom.querySelector('.general-schema-designer') as HTMLElement;
if (designer) {
designer.style.display = 'block';
}
dom.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.2)';
dom.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
};
const onLeave = () => {
const dom = block.dom;
const designer = dom.querySelector('.general-schema-designer') as HTMLElement;
if (designer) {
designer.style.display = null;
}
dom.style.boxShadow = 'none';
};
if (isSameCollection(block.collection, collection)) {
return (
<SchemaSettingsSwitchItem
key={block.uid}
title={title}
checked={targets.some((target) => target.uid === block.uid)}
onChange={(checked) => {
if (checked) {
targets.push({ uid: block.uid });
} else {
targets = targets.filter((target) => target.uid !== block.uid);
block.clearFilter(uid);
}
updateFilterTargets(fieldSchema, targets);
dn.emit('patch', {
schema: {
['x-uid']: uid,
'x-filter-targets': targets,
},
}).catch(error);
dn.refresh();
}}
onMouseEnter={onHover}
onMouseLeave={onLeave}
/>
);
}
const target = targets.find((target) => target.uid === block.uid);
// 与筛选区块的数据表具有关系的表
return (
<SchemaSettingsSelectItem
key={block.uid}
title={title}
value={target?.field || ''}
options={[
...getSupportFieldsByAssociation(getAllCollectionsInheritChain(collection.name), block).map((field) => {
return {
label: compile(field.uiSchema.title) || field.name,
value: `${field.name}.${getTargetKey(field)}`,
};
}),
...getSupportFieldsByForeignKey(collection, block).map((field) => {
return {
label: `${compile(field.uiSchema.title) || field.name} [${t('Foreign key')}]`,
value: field.name,
};
}),
{
label: t('Unconnected'),
value: '',
},
]}
onChange={(value) => {
if (value === '') {
targets = targets.filter((target) => target.uid !== block.uid);
block.clearFilter(uid);
} else {
targets = targets.filter((target) => target.uid !== block.uid);
targets.push({ uid: block.uid, field: value });
}
updateFilterTargets(fieldSchema, targets);
dn.emit('patch', {
schema: {
['x-uid']: uid,
'x-filter-targets': targets,
},
});
dn.refresh();
}}
onMouseEnter={onHover}
onMouseLeave={onLeave}
/>
);
});
return (
<SchemaSettingsSubMenu title={t('Connect data blocks')}>
{Content.length ? (
Content
) : (
<SchemaSettingsItem title="empty">
<Empty
style={{ width: 160, padding: '0 1em' }}
description={emptyDescription}
image={Empty.PRESENTED_IMAGE_SIMPLE}
/>
</SchemaSettingsItem>
)}
</SchemaSettingsSubMenu>
);
};
export interface SchemaSettingsSelectItemProps
extends Omit<SchemaSettingsItemProps, 'onChange' | 'onClick'>,
Omit<SelectWithTitleProps, 'title' | 'defaultValue'> {
@ -1087,47 +832,6 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
);
};
export const SchemaSettingsBlockTitleItem = function BlockTitleItem() {
const field = useField();
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
const { t } = useTranslation();
return (
<SchemaSettingsModalItem
title={t('Edit block title')}
schema={
{
type: 'object',
title: t('Edit block title'),
properties: {
title: {
title: t('Block title'),
type: 'string',
default: fieldSchema?.['x-component-props']?.['title'],
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
} as ISchema
}
onSubmit={({ title }) => {
const componentProps = fieldSchema['x-component-props'] || {};
componentProps.title = title;
fieldSchema['x-component-props'] = componentProps;
field.componentProps.title = title;
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-component-props': fieldSchema['x-component-props'],
},
});
dn.refresh();
}}
/>
);
};
export const SchemaSettingsDefaultSortingRules = function DefaultSortingRules(props) {
const { path = 'x-component-props.params.sort' } = props;
const { t } = useTranslation();
@ -1500,48 +1204,6 @@ export const findParentFieldSchema = (fieldSchema: Schema) => {
}
};
export const SchemaSettingsSortField = () => {
const { fields } = useCollection_deprecated();
const field = useField<Field>();
const fieldSchema = useFieldSchema();
const { t } = useTranslation();
const { dn } = useDesignable();
const compile = useCompile();
const { service, association } = useTableBlockContext();
const { getCollectionJoinField } = useCollectionManager_deprecated();
const collectionField = getCollectionJoinField(association);
const options = fields
.filter((field) => !field?.target && field.interface === 'sort')
.map((field) => {
return {
value: field?.name,
label: compile(field?.uiSchema?.title) || field?.name,
disabled: field?.scopeKey && collectionField?.foreignKey !== field.scopeKey,
};
});
return (
<SchemaSettingsSelectItem
key="sort-field"
title={t('Drag and drop sorting field')}
options={options}
value={field.decoratorProps.dragSortBy}
onChange={(dragSortBy) => {
fieldSchema['x-decorator-props'].dragSortBy = dragSortBy;
service.run({ ...service.params?.[0], sort: dragSortBy });
field.decoratorProps.dragSortBy = dragSortBy;
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-decorator-props': fieldSchema['x-decorator-props'],
},
});
dn.refresh();
}}
/>
);
};
// 是否是系统字段
export const isSystemField = (collectionField: CollectionFieldOptions_deprecated, getInterface) => {
const i = getInterface?.(collectionField?.interface);

View File

@ -0,0 +1,55 @@
/**
* 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 { ISchema, useField, useFieldSchema } from '@formily/react';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useDesignable } from '../schema-component/hooks/useDesignable';
import { SchemaSettingsModalItem } from './SchemaSettings';
export function SchemaSettingsBlockTitleItem() {
const field = useField();
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
const { t } = useTranslation();
return (
<SchemaSettingsModalItem
title={t('Edit block title')}
schema={
{
type: 'object',
title: t('Edit block title'),
properties: {
title: {
title: t('Block title'),
type: 'string',
default: fieldSchema?.['x-component-props']?.['title'],
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
} as ISchema
}
onSubmit={({ title }) => {
const componentProps = fieldSchema['x-component-props'] || {};
componentProps.title = title;
fieldSchema['x-component-props'] = componentProps;
field.componentProps.title = title;
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-component-props': fieldSchema['x-component-props'],
},
});
dn.refresh();
}}
/>
);
}

View File

@ -0,0 +1,166 @@
/**
* 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 { useFieldSchema } from '@formily/react';
import { error } from '@nocobase/utils/client';
import { Empty } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { findFilterTargets, updateFilterTargets } from '../block-provider/hooks';
import { useCollectionManager_deprecated } from '../collection-manager/hooks/useCollectionManager_deprecated';
import { useCollection_deprecated } from '../collection-manager/hooks/useCollection_deprecated';
import { useFilterBlock } from '../filter-provider/FilterProvider';
import {
getSupportFieldsByAssociation,
getSupportFieldsByForeignKey,
isSameCollection,
useSupportedBlocks,
} from '../filter-provider/utils';
import { getTargetKey } from '../schema-component/antd/association-filter/utilts';
import { useCompile } from '../schema-component/hooks/useCompile';
import { useDesignable } from '../schema-component/hooks/useDesignable';
import {
SchemaSettingsItem,
SchemaSettingsSelectItem,
SchemaSettingsSubMenu,
SchemaSettingsSwitchItem,
} from './SchemaSettings';
export function SchemaSettingsConnectDataBlocks(props) {
const { type, emptyDescription } = props;
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
const { t } = useTranslation();
const collection = useCollection_deprecated();
const { inProvider } = useFilterBlock();
const dataBlocks = useSupportedBlocks(type);
// eslint-disable-next-line prefer-const
let { targets = [], uid } = findFilterTargets(fieldSchema);
const compile = useCompile();
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
if (!inProvider) {
return null;
}
const Content = dataBlocks.map((block) => {
const title = `${compile(block.collection.title)} #${block.uid.slice(0, 4)}`;
const onHover = () => {
const dom = block.dom;
const designer = dom.querySelector('.general-schema-designer') as HTMLElement;
if (designer) {
designer.style.display = 'block';
}
dom.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.2)';
dom.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
};
const onLeave = () => {
const dom = block.dom;
const designer = dom.querySelector('.general-schema-designer') as HTMLElement;
if (designer) {
designer.style.display = null;
}
dom.style.boxShadow = 'none';
};
if (isSameCollection(block.collection, collection)) {
return (
<SchemaSettingsSwitchItem
key={block.uid}
title={title}
checked={targets.some((target) => target.uid === block.uid)}
onChange={(checked) => {
if (checked) {
targets.push({ uid: block.uid });
} else {
targets = targets.filter((target) => target.uid !== block.uid);
block.clearFilter(uid);
}
updateFilterTargets(fieldSchema, targets);
dn.emit('patch', {
schema: {
['x-uid']: uid,
'x-filter-targets': targets,
},
}).catch(error);
dn.refresh();
}}
onMouseEnter={onHover}
onMouseLeave={onLeave}
/>
);
}
const target = targets.find((target) => target.uid === block.uid);
// 与筛选区块的数据表具有关系的表
return (
<SchemaSettingsSelectItem
key={block.uid}
title={title}
value={target?.field || ''}
options={[
...getSupportFieldsByAssociation(getAllCollectionsInheritChain(collection.name), block).map((field) => {
return {
label: compile(field.uiSchema.title) || field.name,
value: `${field.name}.${getTargetKey(field)}`,
};
}),
...getSupportFieldsByForeignKey(collection, block).map((field) => {
return {
label: `${compile(field.uiSchema.title) || field.name} [${t('Foreign key')}]`,
value: field.name,
};
}),
{
label: t('Unconnected'),
value: '',
},
]}
onChange={(value) => {
if (value === '') {
targets = targets.filter((target) => target.uid !== block.uid);
block.clearFilter(uid);
} else {
targets = targets.filter((target) => target.uid !== block.uid);
targets.push({ uid: block.uid, field: value });
}
updateFilterTargets(fieldSchema, targets);
dn.emit('patch', {
schema: {
['x-uid']: uid,
'x-filter-targets': targets,
},
});
dn.refresh();
}}
onMouseEnter={onHover}
onMouseLeave={onLeave}
/>
);
});
return (
<SchemaSettingsSubMenu title={t('Connect data blocks')}>
{Content.length ? (
Content
) : (
<SchemaSettingsItem title="empty">
<Empty
style={{ width: 160, padding: '0 1em' }}
description={emptyDescription}
image={Empty.PRESENTED_IMAGE_SIMPLE}
/>
</SchemaSettingsItem>
)}
</SchemaSettingsSubMenu>
);
}

View File

@ -0,0 +1,61 @@
/**
* 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 React from 'react';
import { useTranslation } from 'react-i18next';
import { useTableBlockContext } from '../block-provider';
import { useCollectionManager_deprecated } from '../collection-manager/hooks/useCollectionManager_deprecated';
import { useCollection_deprecated } from '../collection-manager/hooks/useCollection_deprecated';
import { useCompile } from '../schema-component/hooks/useCompile';
import { useDesignable } from '../schema-component/hooks/useDesignable';
import { SchemaSettingsSelectItem } from './SchemaSettings';
export function SchemaSettingsSortField() {
const { fields } = useCollection_deprecated();
const field = useField<Field>();
const fieldSchema = useFieldSchema();
const { t } = useTranslation();
const { dn } = useDesignable();
const compile = useCompile();
const { service, association } = useTableBlockContext();
const { getCollectionJoinField } = useCollectionManager_deprecated();
const collectionField = getCollectionJoinField(association);
const options = fields
.filter((field) => !field?.target && field.interface === 'sort')
.map((field) => {
return {
value: field?.name,
label: compile(field?.uiSchema?.title) || field?.name,
disabled: field?.scopeKey && collectionField?.foreignKey !== field.scopeKey,
};
});
return (
<SchemaSettingsSelectItem
key="sort-field"
title={t('Drag and drop sorting field')}
options={options}
value={field.decoratorProps.dragSortBy}
onChange={(dragSortBy) => {
fieldSchema['x-decorator-props'].dragSortBy = dragSortBy;
service.run({ ...service.params?.[0], sort: dragSortBy });
field.decoratorProps.dragSortBy = dragSortBy;
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-decorator-props': fieldSchema['x-decorator-props'],
},
});
dn.refresh();
}}
/>
);
}

View File

@ -0,0 +1,121 @@
/**
* 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 { FormLayout } from '@formily/antd-v5';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useAPIClient } from '../api-client/hooks/useAPIClient';
import { useCollectionManager_deprecated } from '../collection-manager/hooks/useCollectionManager_deprecated';
import { useGlobalTheme } from '../global-theme';
import { FormDialog } from '../schema-component/antd/form-dialog';
import { FormItem } from '../schema-component/antd/form-item/FormItem';
import { Input } from '../schema-component/antd/input/Input';
import { SchemaComponent } from '../schema-component/core/SchemaComponent';
import { useCompile } from '../schema-component/hooks/useCompile';
import { createDesignable } from '../schema-component/hooks/useDesignable';
import { useSchemaTemplateManager } from '../schema-templates';
import { useBlockTemplateContext } from '../schema-templates/BlockTemplate';
import { SchemaSettingsItem, useSchemaSettings } from './SchemaSettings';
export function SchemaSettingsTemplate(props) {
const { componentName, collectionName, resourceName, needRender } = props;
const { t } = useTranslation();
const { getCollection } = useCollectionManager_deprecated();
const { dn, setVisible, template, fieldSchema } = useSchemaSettings();
const compile = useCompile();
const api = useAPIClient();
const { dn: tdn } = useBlockTemplateContext();
const { saveAsTemplate, copyTemplateSchema } = useSchemaTemplateManager();
const { theme } = useGlobalTheme();
if (!collectionName && !needRender) {
return null;
}
if (template) {
return (
<SchemaSettingsItem
title="Convert reference to duplicate"
onClick={async () => {
const schema = await copyTemplateSchema(template);
const removed = tdn.removeWithoutEmit();
tdn.insertAfterEnd(schema, {
async onSuccess() {
await api.request({
url: `/uiSchemas:remove/${removed['x-uid']}`,
});
},
});
}}
>
{t('Convert reference to duplicate')}
</SchemaSettingsItem>
);
}
return (
<SchemaSettingsItem
title="Save as template"
onClick={async () => {
setVisible(false);
const collection = collectionName && getCollection(collectionName);
const values = await FormDialog(
t('Save as template'),
() => {
return (
<FormLayout layout={'vertical'}>
<SchemaComponent
components={{ Input, FormItem }}
schema={{
type: 'object',
properties: {
name: {
title: t('Template name'),
required: true,
default: collection
? `${compile(collection?.title || collection?.name)}_${t(componentName)}`
: t(componentName),
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
}}
/>
</FormLayout>
);
},
theme,
).open({});
const sdn = createDesignable({
t,
api,
refresh: dn.refresh.bind(dn),
current: fieldSchema.parent,
});
sdn.loadAPIClientEvents();
const { key } = await saveAsTemplate({
collectionName,
resourceName,
componentName,
dataSourceKey: collection.dataSource,
name: values.name,
uid: fieldSchema['x-uid'],
});
sdn.removeWithoutEmit(fieldSchema);
sdn.insertBeforeEnd({
type: 'void',
'x-component': 'BlockTemplate',
'x-component-props': {
templateId: key,
},
});
}}
>
{t('Save as template')}
</SchemaSettingsItem>
);
}

View File

@ -11,15 +11,18 @@ export * from './DataTemplates/hooks/useCollectionState';
export * from './DataTemplates/utils';
export * from './GeneralSchemaDesigner';
export * from './SchemaSettings';
export * from './SchemaSettingsBlockTitleItem';
export * from './SchemaSettingsConnectDataBlocks';
export * from './SchemaSettingsDataScope';
export * from './SchemaSettingsDateFormat';
export * from './SchemaSettingsDefaultValue';
export * from './SchemaSettingsNumberFormat';
export * from './SchemaSettingsSortingRule';
export * from './SchemaSettingsTemplate';
export * from './hooks/useGetAriaLabelOfDesigner';
export * from './hooks/useIsAllowToSetDefaultValue';
export * from './isPatternDisabled';
export * from './SchemaSettingsDataScope';
export * from './SchemaSettingsDefaultValue';
export * from './SchemaSettingsDateFormat';
export * from './SchemaSettingsSortingRule';
export * from './SchemaSettingsNumberFormat';
export { default as useParseDataScopeFilter } from './hooks/useParseDataScopeFilter';
export * from './isPatternDisabled';
export { SchemaSettingsPlugin } from './SchemaSettingsPlugin';
export * from './VariableInput';

View File

@ -11,6 +11,7 @@ import { ISchema, useField, useFieldSchema } from '@formily/react';
import {
FilterBlockType,
FixedBlockDesignerItem,
SchemaSettings,
SchemaSettingsBlockTitleItem,
SchemaSettingsCascaderItem,
SchemaSettingsConnectDataBlocks,
@ -19,13 +20,11 @@ import {
SchemaSettingsModalItem,
SchemaSettingsSelectItem,
SchemaSettingsTemplate,
setDataLoadingModeSettingsItem,
useCollection,
useCollectionManager_deprecated,
useDesignable,
useFormBlockContext,
SchemaSettings,
useCollectionManager_deprecated,
setDataLoadingModeSettingsItem,
useDataLoadingMode,
} from '@nocobase/client';
import lodash from 'lodash';
import { useMapTranslation } from '../locale';