mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
feat: support linkage rules in blocks (#6636)
* feat: support linkage rules setting for association block action * chore: linkage rule * fix: bug * fix: bug * refactor: linkage rule * refactor: code imporve * fix: bug * fix: bug * fix: bug * fix: bug * refactor: code imporve * fix: test * fix: test * fix: test * test: e2e test * fix: bug * fix: bug * fix: test * fix: e2e test * fix: bug * feat: block support linkage rule * feat: block support linkage rule * feat: form block support linkage rule * refactor: code improve * refactor: detail block support linkage rule * chore: support legacy leftVar in linkage rules * fix: bug * refactor: gantt support linkage rule * refactor: map block support linkage rule * fix: bug * feat: markdown support linkage rule * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: create submit linkage rule * fix: action panel * refactor: code improve * fix: bug * refactor: action panpel support linkage rule * fix: test * fix: bug * refactor: code improve * fix: test * fix: code improve * fix: e2e test * refactor: chart block * refactor: support markdown under form block * fix: bug * refactor: refresh & expend action support linkage rule * refactor: code improve * fix: test * fix: bug * fix: bug * fix: e2e test * fix: e2e test * fix: e2e test * fix: test * fix: test * fix: merge bug * fix: test * fix: test bug * fix: merge bug * fix: bug * fix: build error * fix: bug * fix: bug * fix: bug * fix: e2e test * fix: e2e test * fix: e2e test
This commit is contained in:
parent
20abfedc90
commit
163ec58136
@ -34,20 +34,6 @@ export interface SchemaSettingsChildrenProps {
|
||||
children: SchemaSettingsItemType[];
|
||||
}
|
||||
|
||||
const typeComponentMap = {
|
||||
item: SchemaSettingsItem,
|
||||
itemGroup: SchemaSettingsItemGroup,
|
||||
subMenu: SchemaSettingsSubMenu,
|
||||
divider: SchemaSettingsDivider,
|
||||
remove: SchemaSettingsRemove,
|
||||
select: SchemaSettingsSelectItem,
|
||||
cascader: SchemaSettingsCascaderItem,
|
||||
switch: SchemaSettingsSwitchItem,
|
||||
popup: SchemaSettingsPopupItem,
|
||||
actionModal: SchemaSettingsActionModalItem,
|
||||
modal: SchemaSettingsModalItem,
|
||||
};
|
||||
|
||||
const SchemaSettingsChildErrorFallback: FC<
|
||||
FallbackProps & {
|
||||
title: string;
|
||||
@ -113,6 +99,19 @@ export const SchemaSettingsChild: FC<SchemaSettingsItemType> = (props) => {
|
||||
hideIfNoChildren,
|
||||
componentProps,
|
||||
} = props as any;
|
||||
const typeComponentMap = {
|
||||
item: SchemaSettingsItem,
|
||||
itemGroup: SchemaSettingsItemGroup,
|
||||
subMenu: SchemaSettingsSubMenu,
|
||||
divider: SchemaSettingsDivider,
|
||||
remove: SchemaSettingsRemove,
|
||||
select: SchemaSettingsSelectItem,
|
||||
cascader: SchemaSettingsCascaderItem,
|
||||
switch: SchemaSettingsSwitchItem,
|
||||
popup: SchemaSettingsPopupItem,
|
||||
actionModal: SchemaSettingsActionModalItem,
|
||||
modal: SchemaSettingsModalItem,
|
||||
};
|
||||
const useChildrenRes = useChildren();
|
||||
const useComponentPropsRes = useComponentProps();
|
||||
const findComponent = useFindComponent();
|
||||
|
@ -22,8 +22,15 @@ import { useCreateFormBlockProps } from '../modules/blocks/data-blocks/form/hook
|
||||
import { useEditFormBlockDecoratorProps } from '../modules/blocks/data-blocks/form/hooks/useEditFormBlockDecoratorProps';
|
||||
import { useEditFormBlockProps } from '../modules/blocks/data-blocks/form/hooks/useEditFormBlockProps';
|
||||
import { useDataFormItemProps } from '../modules/blocks/data-blocks/form/hooks/useDataFormItemProps';
|
||||
import { useGridCardBlockDecoratorProps } from '../modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps';
|
||||
import { useListBlockDecoratorProps } from '../modules/blocks/data-blocks/list/hooks/useListBlockDecoratorProps';
|
||||
import {
|
||||
useGridCardBlockDecoratorProps,
|
||||
useGridCardBlockItemProps,
|
||||
useGridCardBlockProps,
|
||||
} from '../modules/blocks/data-blocks/grid-card/hooks/useGridCardBlockDecoratorProps';
|
||||
import {
|
||||
useListBlockDecoratorProps,
|
||||
useListBlockProps,
|
||||
} from '../modules/blocks/data-blocks/list/hooks/useListBlockDecoratorProps';
|
||||
import { useTableSelectorDecoratorProps } from '../modules/blocks/data-blocks/table-selector/hooks/useTableSelectorDecoratorProps';
|
||||
import { TableColumnSchemaToolbar } from '../modules/blocks/data-blocks/table/TableColumnSchemaToolbar';
|
||||
import { useTableBlockDecoratorProps } from '../modules/blocks/data-blocks/table/hooks/useTableBlockDecoratorProps';
|
||||
@ -80,11 +87,14 @@ export const BlockSchemaComponentProvider: React.FC = (props) => {
|
||||
useTableSelectorProps,
|
||||
useTableBlockDecoratorProps,
|
||||
useListBlockDecoratorProps,
|
||||
useListBlockProps,
|
||||
useTableSelectorDecoratorProps,
|
||||
useCollapseBlockDecoratorProps,
|
||||
useFilterFormBlockProps,
|
||||
useFilterFormBlockDecoratorProps,
|
||||
useGridCardBlockDecoratorProps,
|
||||
useGridCardBlockItemProps,
|
||||
useGridCardBlockProps,
|
||||
useFormItemProps,
|
||||
useDataFormItemProps,
|
||||
}}
|
||||
@ -141,11 +151,14 @@ export class BlockSchemaComponentPlugin extends Plugin {
|
||||
useTableSelectorProps,
|
||||
useTableBlockDecoratorProps,
|
||||
useListBlockDecoratorProps,
|
||||
useListBlockProps,
|
||||
useTableSelectorDecoratorProps,
|
||||
useCollapseBlockDecoratorProps,
|
||||
useFilterFormBlockProps,
|
||||
useFilterFormBlockDecoratorProps,
|
||||
useGridCardBlockDecoratorProps,
|
||||
useGridCardBlockProps,
|
||||
useGridCardBlockItemProps,
|
||||
useFormItemProps,
|
||||
useDataFormItemProps,
|
||||
});
|
||||
|
@ -23,6 +23,7 @@ import {
|
||||
import { CollectionRecord } from '../collection-record';
|
||||
import { BlockRequestProvider } from './DataBlockRequestProvider';
|
||||
import { DataBlockResourceProvider } from './DataBlockResourceProvider';
|
||||
import { BlockLinkageRuleProvider } from '../../modules/blocks/BlockLinkageRuleProvider';
|
||||
|
||||
export interface AllDataBlockProps {
|
||||
collection: string | CollectionOptions;
|
||||
@ -189,13 +190,15 @@ export const DataBlockProvider: FC<Partial<AllDataBlockProps>> = withDynamicSche
|
||||
<CollectionManagerProvider dataSource={dataSource}>
|
||||
<AssociationOrCollectionProvider collection={collection} association={association}>
|
||||
<ACLCollectionProvider>
|
||||
<DataBlockResourceProvider>
|
||||
<BlockRequestProvider>
|
||||
<DataBlockCollector params={props.params}>
|
||||
<RerenderDataBlockProvider>{children}</RerenderDataBlockProvider>
|
||||
</DataBlockCollector>
|
||||
</BlockRequestProvider>
|
||||
</DataBlockResourceProvider>
|
||||
<BlockLinkageRuleProvider>
|
||||
<DataBlockResourceProvider>
|
||||
<BlockRequestProvider>
|
||||
<DataBlockCollector params={props.params}>
|
||||
<RerenderDataBlockProvider>{children}</RerenderDataBlockProvider>
|
||||
</DataBlockCollector>
|
||||
</BlockRequestProvider>
|
||||
</DataBlockResourceProvider>
|
||||
</BlockLinkageRuleProvider>
|
||||
</ACLCollectionProvider>
|
||||
</AssociationOrCollectionProvider>
|
||||
</CollectionManagerProvider>
|
||||
|
@ -1104,5 +1104,7 @@
|
||||
"Colon":"冒号",
|
||||
"No pages yet, please configure first": "暂无页面,请先配置",
|
||||
"Click the \"UI Editor\" icon in the upper right corner to enter the UI Editor mode": "点击右上角的“界面配置”图标,进入界面配置模式",
|
||||
"After successful submission, the selected data blocks will be automatically refreshed.": "提交成功后,会自动刷新这里选中的数据区块。"
|
||||
"After successful submission, the selected data blocks will be automatically refreshed.": "提交成功后,会自动刷新这里选中的数据区块。",
|
||||
"Block Linkage rules":"区块联动规则",
|
||||
"Field Linkage rules":"字段联动规则"
|
||||
}
|
||||
|
@ -33,8 +33,9 @@ test.describe('Link', () => {
|
||||
).toHaveCount(1);
|
||||
await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-actionSettings:link-users' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Edit link' }).click();
|
||||
await page.getByLabel('block-item-users-URL').getByLabel('textbox').click();
|
||||
await page
|
||||
.getByLabel('block-item-users-table-URL')
|
||||
.getByLabel('block-item-users-URL')
|
||||
.getByLabel('textbox')
|
||||
.fill(await nocoPage.getUrl());
|
||||
await page.getByPlaceholder('Name').fill('id');
|
||||
@ -102,7 +103,7 @@ test.describe('Link', () => {
|
||||
await page.getByLabel('action-Action.Link-Link-').hover();
|
||||
await page.getByLabel('designer-schema-settings-Action.Link-actionSettings:link-users').hover();
|
||||
await page.getByRole('menuitem', { name: 'Edit link' }).click();
|
||||
await page.getByLabel('block-item-users-table-URL').getByLabel('textbox').fill(otherPageUrl);
|
||||
await page.getByLabel('block-item-users-URL').getByLabel('textbox').fill(otherPageUrl);
|
||||
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
||||
|
||||
await page.getByLabel('action-Action.Link-Link-').click();
|
||||
|
@ -69,6 +69,21 @@ export const addNewActionSettings = new SchemaSettings({
|
||||
return isChildCollectionAction;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { association } = useDataBlockProps() || {};
|
||||
const { name } = useCollection_deprecated();
|
||||
const { getCollectionField } = useCollectionManager_deprecated();
|
||||
const associationField = getCollectionField(association);
|
||||
const { linkageRulesProps } = useSchemaToolbar();
|
||||
return {
|
||||
...linkageRulesProps,
|
||||
collectionName: associationField?.collectionName || name,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
sort: 100,
|
||||
|
@ -51,6 +51,16 @@ export const bulkDeleteActionSettings = new SchemaSettings({
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { linkageRulesProps } = useSchemaToolbar();
|
||||
return {
|
||||
...linkageRulesProps,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'remove',
|
||||
sort: 100,
|
||||
|
@ -15,6 +15,7 @@ import { useDesignable } from '../../../';
|
||||
import { useSchemaToolbar } from '../../../application';
|
||||
import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
|
||||
import { ButtonEditor, RemoveButton } from '../../../schema-component/antd/action/Action.Designer';
|
||||
import { useCollectionManager_deprecated } from '../../../collection-manager';
|
||||
import {
|
||||
SchemaSettingsLinkageRules,
|
||||
SchemaSettingsModalItem,
|
||||
@ -96,6 +97,9 @@ export const customizeLinkActionSettings = new SchemaSettings({
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { linkageRulesProps } = useSchemaToolbar();
|
||||
const { association } = useDataBlockProps() || {};
|
||||
const { getCollectionField } = useCollectionManager_deprecated();
|
||||
const associationField = getCollectionField(association);
|
||||
return {
|
||||
...linkageRulesProps,
|
||||
};
|
||||
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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, { useMemo, useEffect, useState } from 'react';
|
||||
import { useFieldSchema, useForm } from '@formily/react';
|
||||
import { last, isEqual } from 'lodash';
|
||||
import { uid } from '@formily/shared';
|
||||
import { reaction } from '@formily/reactive';
|
||||
import { useLocalVariables, useVariables } from '../../variables';
|
||||
import { useReactiveLinkageEffect } from './utils';
|
||||
import { useDesignable } from '../../';
|
||||
import { forEachLinkageRule } from '../../schema-settings/LinkageRules/forEachLinkageRule';
|
||||
import {
|
||||
getVariableValuesInCondition,
|
||||
getVariableValuesInExpression,
|
||||
} from '../../schema-settings/LinkageRules/bindLinkageRulesToFiled';
|
||||
|
||||
const getLinkageRules = (fieldSchema) => {
|
||||
if (!fieldSchema) {
|
||||
return [];
|
||||
}
|
||||
let linkageRules = fieldSchema?.['x-block-linkage-rules'] || [];
|
||||
fieldSchema.mapProperties((schema) => {
|
||||
if (schema['x-block-linkage-rules']) {
|
||||
linkageRules = schema['x-block-linkage-rules'];
|
||||
}
|
||||
});
|
||||
return linkageRules?.filter((k) => !k.disabled);
|
||||
};
|
||||
|
||||
export const BlockLinkageRuleProvider = (props) => {
|
||||
const schema = useFieldSchema();
|
||||
const variables = useVariables();
|
||||
const localVariables = useLocalVariables();
|
||||
const { designable } = useDesignable();
|
||||
const form = useForm();
|
||||
const linkageRules = useMemo(() => getLinkageRules(schema), [schema]);
|
||||
const [triggerLinkageUpdate, setTriggerLinkageUpdate] = useState(null);
|
||||
const displayResult = useReactiveLinkageEffect(linkageRules, variables, localVariables, triggerLinkageUpdate);
|
||||
const shouldCalculateFormLinkage = schema?.['x-decorator'] === 'FormItem' && !form.readPretty && linkageRules.length;
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldCalculateFormLinkage) {
|
||||
const id = uid();
|
||||
const disposes = [];
|
||||
|
||||
// 延迟执行,防止一开始获取到的 form.values 值是旧的
|
||||
setTimeout(() => {
|
||||
form.addEffects(id, () => {
|
||||
forEachLinkageRule(linkageRules, (action, rule) => {
|
||||
return reaction(
|
||||
() => {
|
||||
// 获取条件中的变量值
|
||||
const variableValuesInCondition = getVariableValuesInCondition({ linkageRules, localVariables });
|
||||
// 获取 value 表达式中的变量值
|
||||
const variableValuesInExpression = getVariableValuesInExpression({ action, localVariables });
|
||||
const result = [variableValuesInCondition, variableValuesInExpression]
|
||||
.map((item) => JSON.stringify(item))
|
||||
.join(',');
|
||||
return result;
|
||||
},
|
||||
() => {
|
||||
setTriggerLinkageUpdate(uid());
|
||||
},
|
||||
{ fireImmediately: true, equals: isEqual },
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 清理副作用
|
||||
return () => {
|
||||
form.removeEffects(id);
|
||||
disposes.forEach((dispose) => {
|
||||
dispose();
|
||||
});
|
||||
};
|
||||
}
|
||||
}, [linkageRules, shouldCalculateFormLinkage]);
|
||||
if (!linkageRules.length) {
|
||||
return props.children;
|
||||
}
|
||||
|
||||
if (displayResult === null) return null;
|
||||
if (last(displayResult) === 'hidden') {
|
||||
if (designable) {
|
||||
return <div style={{ opacity: 0.3 }}>{props.children}</div>;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return props.children;
|
||||
};
|
@ -45,7 +45,7 @@ test.describe('multi data details block schema settings', () => {
|
||||
// 禁用规则,联动规则失效
|
||||
await page.getByLabel('block-item-CardItem-users-').hover();
|
||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:detailsWithPagination-users').hover();
|
||||
await page.getByText('Linkage rules').click();
|
||||
await page.getByText('Field Linkage rules').click();
|
||||
await page.getByRole('switch', { name: 'On Off' }).click();
|
||||
await page.getByRole('button', { name: 'OK' }).click();
|
||||
await page.reload();
|
||||
|
@ -14,7 +14,7 @@ import { SchemaSettings } from '../../../../application/schema-settings/SchemaSe
|
||||
import { SchemaSettingsItemType } from '../../../../application/schema-settings/types';
|
||||
import { useDetailsBlockContext } from '../../../../block-provider/DetailsBlockProvider';
|
||||
import { useFormBlockContext } from '../../../../block-provider/FormBlockProvider';
|
||||
import { useCollection_deprecated, useSortFields } from '../../../../collection-manager';
|
||||
import { useSortFields } from '../../../../collection-manager';
|
||||
import { removeNullCondition, useDesignable } from '../../../../schema-component';
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
import { SchemaSettingsBlockHeightItem } from '../../../../schema-settings/SchemaSettingsBlockHeightItem';
|
||||
@ -24,6 +24,8 @@ import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettin
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { setDataLoadingModeSettingsItem } from './setDataLoadingModeSettingsItem';
|
||||
import { SchemaSettingsLayoutItem } from '../../../../schema-settings/SchemaSettingsLayoutItem';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
import { useCollection } from '../../../../data-source';
|
||||
|
||||
const commonItems: SchemaSettingsItemType[] = [
|
||||
{
|
||||
@ -35,13 +37,28 @@ const commonItems: SchemaSettingsItemType[] = [
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
name: 'fieldLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { name } = useCollection();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
readPretty: true,
|
||||
title: t('Field Linkage rules'),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
@ -49,7 +66,7 @@ const commonItems: SchemaSettingsItemType[] = [
|
||||
name: 'dataScope',
|
||||
Component: SchemaSettingsDataScope,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { name } = useCollection();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { form } = useFormBlockContext();
|
||||
const field = useField();
|
||||
@ -83,7 +100,7 @@ const commonItems: SchemaSettingsItemType[] = [
|
||||
name: 'sortingRules',
|
||||
type: 'modal',
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { name } = useCollection();
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
@ -201,7 +218,7 @@ const commonItems: SchemaSettingsItemType[] = [
|
||||
name: 'template',
|
||||
Component: SchemaSettingsTemplate,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { name } = useCollection();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { componentNamePrefix } = useBlockTemplateContext();
|
||||
const defaultResource =
|
||||
|
@ -8,14 +8,17 @@
|
||||
*/
|
||||
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { SchemaSettingsItemType } from '../../../../application/schema-settings/types';
|
||||
import { useCollection } from '../../../../data-source/collection/CollectionProvider';
|
||||
import { useCollection_deprecated } from '../../../../collection-manager';
|
||||
import { SchemaSettingsFormItemTemplate, SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
import { SchemaSettingsBlockHeightItem } from '../../../../schema-settings/SchemaSettingsBlockHeightItem';
|
||||
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { SchemaSettingsLayoutItem } from '../../../../schema-settings/SchemaSettingsLayoutItem';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
|
||||
const commonItems: SchemaSettingsItemType[] = [
|
||||
{
|
||||
@ -27,13 +30,28 @@ const commonItems: SchemaSettingsItemType[] = [
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
name: 'fieldLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
readPretty: true,
|
||||
title: t('Field Linkage rules'),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -310,7 +310,7 @@ test.describe('set default value', () => {
|
||||
// 设置联动规则
|
||||
await page.getByLabel('block-item-CardItem-users-form').hover();
|
||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:createForm-users').hover();
|
||||
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Field linkage rules' }).click();
|
||||
await page.mouse.move(300, 0);
|
||||
await page.getByRole('button', { name: 'plus Add linkage rule' }).click();
|
||||
await page.getByText('Add property').click();
|
||||
@ -438,7 +438,7 @@ test.describe('set default value', () => {
|
||||
// 设置联动规则
|
||||
await page.getByLabel('block-item-CardItem-users-form').hover();
|
||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:createForm-users').hover();
|
||||
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Field linkage rules' }).click();
|
||||
await page.mouse.move(300, 0);
|
||||
await page.getByRole('button', { name: 'plus Add linkage rule' }).click();
|
||||
await page.getByText('Add property').click();
|
||||
@ -563,7 +563,7 @@ test.describe('set default value', () => {
|
||||
// 设置联动规则
|
||||
await page.getByLabel('block-item-CardItem-users-form').hover();
|
||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:createForm-users').hover();
|
||||
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Field linkage rules' }).click();
|
||||
await page.mouse.move(300, 0);
|
||||
await page.getByRole('button', { name: 'plus Add linkage rule' }).click();
|
||||
await page.getByText('Add property').click();
|
||||
@ -701,7 +701,7 @@ test.describe('set default value', () => {
|
||||
// 设置联动规则
|
||||
await page.getByLabel('block-item-CardItem-users-form').hover();
|
||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:createForm-users').hover();
|
||||
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Field linkage rules' }).click();
|
||||
await page.mouse.move(300, 0);
|
||||
await page.getByRole('button', { name: 'plus Add linkage rule' }).click();
|
||||
await page.getByText('Add property').click();
|
||||
|
@ -18,7 +18,7 @@ test.describe('deprecated variables', () => {
|
||||
await page.getByLabel('action-Action.Link-Edit').click();
|
||||
await page.getByLabel('block-item-CardItem-users-form').hover();
|
||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:editForm-users').hover();
|
||||
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Field linkage rules' }).click();
|
||||
await expect(page.getByLabel('variable-tag').getByText('Current record / Nickname')).toBeVisible();
|
||||
|
||||
// 2. 但是变量列表中是禁用状态
|
||||
@ -57,7 +57,7 @@ test.describe('deprecated variables', () => {
|
||||
// 4. 再次打开弹窗,变量列表中的弃用变量不再显示
|
||||
await page.getByLabel('block-item-CardItem-users-form').hover();
|
||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:editForm-users').hover();
|
||||
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Field linkage rules' }).click();
|
||||
await page.locator('button').filter({ hasText: /^x$/ }).last().click();
|
||||
await expect(page.getByRole('menuitemcheckbox', { name: 'Current record right' })).toBeHidden();
|
||||
// 使下拉菜单消失
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useFormBlockContext } from '../../../../block-provider/FormBlockProvider';
|
||||
import { useCollection_deprecated } from '../../../../collection-manager';
|
||||
@ -21,6 +22,7 @@ import { SchemaSettingsBlockHeightItem } from '../../../../schema-settings/Schem
|
||||
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { SchemaSettingsLayoutItem } from '../../../../schema-settings/SchemaSettingsLayoutItem';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
|
||||
export const createFormBlockSettings = new SchemaSettings({
|
||||
name: 'blockSettings:createForm',
|
||||
@ -34,12 +36,27 @@ export const createFormBlockSettings = new SchemaSettings({
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
name: 'fieldLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Field Linkage rules'),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useFormBlockContext } from '../../../../block-provider/FormBlockProvider';
|
||||
import { useCollection_deprecated } from '../../../../collection-manager';
|
||||
@ -21,6 +22,7 @@ import { SchemaSettingsBlockHeightItem } from '../../../../schema-settings/Schem
|
||||
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { SchemaSettingsLayoutItem } from '../../../../schema-settings/SchemaSettingsLayoutItem';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
|
||||
export const editFormBlockSettings = new SchemaSettings({
|
||||
name: 'blockSettings:editForm',
|
||||
@ -34,12 +36,27 @@ export const editFormBlockSettings = new SchemaSettings({
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
name: 'fieldLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Field Linkage rules'),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -24,6 +24,8 @@ import { useBlockTemplateContext } from '../../../../schema-templates/BlockTempl
|
||||
import { setDataLoadingModeSettingsItem } from '../details-multi/setDataLoadingModeSettingsItem';
|
||||
import { SetTheCountOfColumnsDisplayedInARow } from './SetTheCountOfColumnsDisplayedInARow';
|
||||
import { SchemaSettingsLayoutItem } from '../../../../schema-settings/SchemaSettingsLayoutItem';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
|
||||
export const gridCardBlockSettings = new SchemaSettings({
|
||||
name: 'blockSettings:gridCard',
|
||||
@ -32,6 +34,19 @@ export const gridCardBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'SetTheCountOfColumnsDisplayedInARow',
|
||||
Component: SetTheCountOfColumnsDisplayedInARow,
|
||||
|
@ -27,3 +27,11 @@ export function useGridCardBlockDecoratorProps(props) {
|
||||
parseVariableLoading,
|
||||
};
|
||||
}
|
||||
|
||||
export function useGridCardBlockItemProps() {
|
||||
return {};
|
||||
}
|
||||
|
||||
export function useGridCardBlockProps() {
|
||||
return {};
|
||||
}
|
||||
|
@ -22,3 +22,7 @@ export function useListBlockDecoratorProps(props) {
|
||||
parentRecord,
|
||||
};
|
||||
}
|
||||
|
||||
export function useListBlockProps() {
|
||||
return {};
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettin
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { setDataLoadingModeSettingsItem } from '../details-multi/setDataLoadingModeSettingsItem';
|
||||
import { SchemaSettingsLayoutItem } from '../../../../schema-settings/SchemaSettingsLayoutItem';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
|
||||
export const listBlockSettings = new SchemaSettings({
|
||||
name: 'blockSettings:list',
|
||||
@ -34,6 +36,19 @@ export const listBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'SetTheDataScope',
|
||||
Component: SchemaSettingsDataScope,
|
||||
|
@ -26,6 +26,8 @@ import { setTheDataScopeSchemaSettingsItem } from '../../../../schema-settings/s
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { setDataLoadingModeSettingsItem } from '../details-multi/setDataLoadingModeSettingsItem';
|
||||
import { SchemaSettingsItemType } from '../../../../application';
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
|
||||
const enabledIndexColumn: SchemaSettingsItemType = {
|
||||
name: 'enableIndexColumn',
|
||||
@ -64,6 +66,19 @@ export const tableBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'treeTable',
|
||||
type: 'switch',
|
||||
@ -138,7 +153,6 @@ export const tableBlockSettings = new SchemaSettings({
|
||||
const { resource } = field.decoratorProps;
|
||||
const collectionField = resource && getCollectionField(resource);
|
||||
const api = useAPIClient();
|
||||
|
||||
return {
|
||||
title: t('Enable drag and drop sorting'),
|
||||
checked: field.decoratorProps.dragSort,
|
||||
|
@ -12,11 +12,14 @@ import { useTranslation } from 'react-i18next';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useCollection_deprecated } from '../../../../collection-manager';
|
||||
import { FilterBlockType } from '../../../../filter-provider';
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
import { SchemaSettingsBlockHeightItem } from '../../../../schema-settings/SchemaSettingsBlockHeightItem';
|
||||
import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/SchemaSettingsBlockTitleItem';
|
||||
import { SchemaSettingsConnectDataBlocks } from '../../../../schema-settings/SchemaSettingsConnectDataBlocks';
|
||||
import { SchemaSettingsTemplate } from '../../../../schema-settings/SchemaSettingsTemplate';
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
import { useCollection } from '../../../../data-source/collection/CollectionProvider';
|
||||
|
||||
export const filterCollapseBlockSettings = new SchemaSettings({
|
||||
name: 'blockSettings:filterCollapse',
|
||||
@ -29,6 +32,19 @@ export const filterCollapseBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ConvertReferenceToDuplicate',
|
||||
Component: SchemaSettingsTemplate,
|
||||
|
@ -19,6 +19,7 @@ import { SchemaSettingsBlockTitleItem } from '../../../../schema-settings/Schema
|
||||
import { SchemaSettingsConnectDataBlocks } from '../../../../schema-settings/SchemaSettingsConnectDataBlocks';
|
||||
import { useBlockTemplateContext } from '../../../../schema-templates/BlockTemplateProvider';
|
||||
import { SchemaSettingsLayoutItem } from '../../../../schema-settings/SchemaSettingsLayoutItem';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
|
||||
export const filterFormBlockSettings = new SchemaSettings({
|
||||
name: 'blockSettings:filterForm',
|
||||
@ -48,12 +49,27 @@ export const filterFormBlockSettings = new SchemaSettings({
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
name: 'fieldLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Field Linkage rules'),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -7,11 +7,14 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { useField } from '@formily/react';
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { SchemaSettingsBlockHeightItem } from '../../../../schema-settings/SchemaSettingsBlockHeightItem';
|
||||
import { SchemaSettingsRenderEngine } from '../../../../schema-settings/SchemaSettingsRenderEngine';
|
||||
import { SchemaSettingsLinkageRules } from '../../../../schema-settings';
|
||||
import { LinkageRuleCategory } from '../../../../schema-settings/LinkageRules/type';
|
||||
|
||||
export const markdownBlockSettings = new SchemaSettings({
|
||||
name: 'blockSettings:markdown',
|
||||
items: [
|
||||
@ -21,7 +24,6 @@ export const markdownBlockSettings = new SchemaSettings({
|
||||
useComponentProps() {
|
||||
const field = useField();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return {
|
||||
title: t('Edit markdown'),
|
||||
onClick: () => {
|
||||
@ -34,6 +36,27 @@ export const markdownBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const underForm = fieldSchema['x-decorator'] === 'FormItem';
|
||||
return {
|
||||
title: underForm ? t('Linkage rules') : t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
returnScope: (options) => {
|
||||
return options.filter((v) => {
|
||||
if (!underForm) {
|
||||
return !['$nForm', '$nRecord'].includes(v.value);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'setBlockTemplate',
|
||||
Component: SchemaSettingsRenderEngine,
|
||||
|
91
packages/core/client/src/modules/blocks/utils.ts
Normal file
91
packages/core/client/src/modules/blocks/utils.ts
Normal file
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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 { useEffect, useState } from 'react';
|
||||
import { VariableOption, VariablesContextType } from '../../variables/types';
|
||||
import { conditionAnalyses } from '../../schema-component/common/utils/uitls';
|
||||
import { useApp } from '../../application';
|
||||
import { useCollectionRecord } from '../../data-source';
|
||||
|
||||
enum ActionType {
|
||||
Visible = 'visible',
|
||||
Hidden = 'hidden',
|
||||
}
|
||||
|
||||
const linkageAction = async (
|
||||
{
|
||||
operator,
|
||||
condition,
|
||||
variables,
|
||||
localVariables,
|
||||
conditionType,
|
||||
displayResult,
|
||||
}: {
|
||||
operator;
|
||||
condition;
|
||||
variables: VariablesContextType;
|
||||
localVariables: VariableOption[];
|
||||
conditionType: 'advanced';
|
||||
displayResult: any[];
|
||||
},
|
||||
jsonLogic: any,
|
||||
) => {
|
||||
switch (operator) {
|
||||
case ActionType.Visible:
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables, conditionType }, jsonLogic)) {
|
||||
displayResult.push(ActionType.Visible);
|
||||
}
|
||||
return displayResult;
|
||||
case ActionType.Hidden:
|
||||
if (await conditionAnalyses({ ruleGroup: condition, variables, localVariables, conditionType }, jsonLogic)) {
|
||||
displayResult.push(ActionType.Hidden);
|
||||
}
|
||||
return displayResult;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const useReactiveLinkageEffect = (
|
||||
linkageRules: any[],
|
||||
variables: VariablesContextType,
|
||||
localVariables: VariableOption[],
|
||||
triggerLinkageUpdate,
|
||||
) => {
|
||||
const app = useApp();
|
||||
const jsonLogic = app.jsonLogic;
|
||||
const [displayResult, setDisplayResult] = useState<string[] | null>(null);
|
||||
const record = useCollectionRecord();
|
||||
useEffect(() => {
|
||||
const runLinkages = async () => {
|
||||
const result: string[] = [];
|
||||
|
||||
for (const rule of linkageRules.filter((r) => !r.disabled)) {
|
||||
for (const action of rule.actions || []) {
|
||||
await linkageAction(
|
||||
{
|
||||
operator: action.operator,
|
||||
condition: rule.condition,
|
||||
variables,
|
||||
localVariables,
|
||||
conditionType: rule.conditionType,
|
||||
displayResult: result,
|
||||
},
|
||||
jsonLogic,
|
||||
);
|
||||
}
|
||||
}
|
||||
setDisplayResult(result);
|
||||
};
|
||||
|
||||
runLinkages();
|
||||
}, [linkageRules, triggerLinkageUpdate, record]);
|
||||
|
||||
return displayResult;
|
||||
};
|
@ -6,10 +6,9 @@
|
||||
* 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, { useMemo } from 'react';
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import cls from 'classnames';
|
||||
import React, { useMemo } from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import { useSchemaToolbarRender } from '../../../application';
|
||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||
@ -18,6 +17,8 @@ import { useProps } from '../../hooks';
|
||||
import { ErrorFallback } from '../error-fallback';
|
||||
import { useStyles } from './BlockItem.style';
|
||||
import { useGetAriaLabelOfBlockItem } from './hooks/useGetAriaLabelOfBlockItem';
|
||||
import { useCollection } from '../../../data-source';
|
||||
import { BlockLinkageRuleProvider } from '../../../modules/blocks/BlockLinkageRuleProvider';
|
||||
|
||||
export interface BlockItemProps {
|
||||
name?: string;
|
||||
@ -35,8 +36,9 @@ export const BlockItem: React.FC<BlockItemProps> = withDynamicSchemaProps(
|
||||
const { render } = useSchemaToolbarRender(fieldSchema);
|
||||
const { getAriaLabel } = useGetAriaLabelOfBlockItem(props.name);
|
||||
const label = useMemo(() => getAriaLabel(), [getAriaLabel]);
|
||||
|
||||
return (
|
||||
const collection = useCollection();
|
||||
const markdownField = fieldSchema['x-decorator'] === 'FormItem' && fieldSchema['x-block-linkage-rules'];
|
||||
const content = (
|
||||
<SortableItem
|
||||
role="button"
|
||||
aria-label={label}
|
||||
@ -49,6 +51,8 @@ export const BlockItem: React.FC<BlockItemProps> = withDynamicSchemaProps(
|
||||
</ErrorBoundary>
|
||||
</SortableItem>
|
||||
);
|
||||
|
||||
return collection && !markdownField ? content : <BlockLinkageRuleProvider>{content}</BlockLinkageRuleProvider>;
|
||||
},
|
||||
{ displayName: 'BlockItem' },
|
||||
);
|
||||
|
@ -13,6 +13,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useToken } from '../../../style';
|
||||
import { MarkdownReadPretty } from '../markdown';
|
||||
import { NAMESPACE_UI_SCHEMA } from '../../../i18n/constant';
|
||||
import { useCollection } from '../../../data-source';
|
||||
|
||||
export const BlockItemCardContext = createContext({});
|
||||
|
||||
@ -25,6 +26,8 @@ export const BlockItemCard = React.forwardRef<HTMLDivElement, CardProps | any>((
|
||||
const [titleHeight, setTitleHeight] = useState(0);
|
||||
const titleRef = useRef<HTMLDivElement | null>(null);
|
||||
const { t } = useTranslation();
|
||||
const collection = useCollection();
|
||||
console.log();
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
if (titleRef.current) {
|
||||
|
@ -152,65 +152,65 @@ describe('form.settings', () => {
|
||||
title: 'Edit block title',
|
||||
type: 'modal',
|
||||
},
|
||||
{
|
||||
title: 'Linkage rules',
|
||||
type: 'modal',
|
||||
modalChecker: {
|
||||
modalTitle: 'Linkage rules',
|
||||
contentText: 'Add linkage rule',
|
||||
async customCheck() {
|
||||
// await userEvent.click(screen.getByText('Add linkage rule'));
|
||||
// await waitFor(() => {
|
||||
// expect(screen.queryByText('Add condition')).toBeInTheDocument();
|
||||
// })
|
||||
// await userEvent.click(screen.getByText('Add condition'));
|
||||
// await waitFor(() => {
|
||||
// expect(screen.queryByText('Select field')).toBeInTheDocument();
|
||||
// })
|
||||
// await userEvent.click(screen.getByText('Select field'));
|
||||
// await waitFor(() => {
|
||||
// expect(screen.queryByTitle('Username')).toBeInTheDocument();
|
||||
// })
|
||||
// await userEvent.click(screen.getByTitle('Username'));
|
||||
// const dialog = screen.queryByRole('dialog');
|
||||
// await userEvent.type(dialog.querySelectorAll('.ant-input')[1], '1');
|
||||
// const properties = screen.queryByTestId('select-linkage-property-field');
|
||||
// await userEvent.click(screen.getByText('Select field'));
|
||||
// await waitFor(() => {
|
||||
// expect(properties.querySelector(`[title=Nickname]`)).toBeInTheDocument();
|
||||
// })
|
||||
// await userEvent.click(properties.querySelector(`[title=Nickname]`));
|
||||
// await userEvent.click(screen.getByText('action'));
|
||||
// await waitFor(() => {
|
||||
// expect(screen.queryByText('Hidden')).toBeInTheDocument();
|
||||
// })
|
||||
// await userEvent.click(screen.getByText('Hidden'));
|
||||
},
|
||||
// async afterSubmit() {
|
||||
// await checkSchema({
|
||||
// "x-linkage-rules": [
|
||||
// {
|
||||
// "condition": {
|
||||
// "$and": [
|
||||
// {
|
||||
// "username": {}
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "actions": [
|
||||
// {
|
||||
// "targetFields": [
|
||||
// "nickname"
|
||||
// ],
|
||||
// "operator": "none"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// },
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: 'Linkage rules',
|
||||
// type: 'modal',
|
||||
// modalChecker: {
|
||||
// modalTitle: 'Linkage rules',
|
||||
// contentText: 'Add linkage rule',
|
||||
// async customCheck() {
|
||||
// // await userEvent.click(screen.getByText('Add linkage rule'));
|
||||
// // await waitFor(() => {
|
||||
// // expect(screen.queryByText('Add condition')).toBeInTheDocument();
|
||||
// // })
|
||||
// // await userEvent.click(screen.getByText('Add condition'));
|
||||
// // await waitFor(() => {
|
||||
// // expect(screen.queryByText('Select field')).toBeInTheDocument();
|
||||
// // })
|
||||
// // await userEvent.click(screen.getByText('Select field'));
|
||||
// // await waitFor(() => {
|
||||
// // expect(screen.queryByTitle('Username')).toBeInTheDocument();
|
||||
// // })
|
||||
// // await userEvent.click(screen.getByTitle('Username'));
|
||||
// // const dialog = screen.queryByRole('dialog');
|
||||
// // await userEvent.type(dialog.querySelectorAll('.ant-input')[1], '1');
|
||||
// // const properties = screen.queryByTestId('select-linkage-property-field');
|
||||
// // await userEvent.click(screen.getByText('Select field'));
|
||||
// // await waitFor(() => {
|
||||
// // expect(properties.querySelector(`[title=Nickname]`)).toBeInTheDocument();
|
||||
// // })
|
||||
// // await userEvent.click(properties.querySelector(`[title=Nickname]`));
|
||||
// // await userEvent.click(screen.getByText('action'));
|
||||
// // await waitFor(() => {
|
||||
// // expect(screen.queryByText('Hidden')).toBeInTheDocument();
|
||||
// // })
|
||||
// // await userEvent.click(screen.getByText('Hidden'));
|
||||
// },
|
||||
// // async afterSubmit() {
|
||||
// // await checkSchema({
|
||||
// // "x-linkage-rules": [
|
||||
// // {
|
||||
// // "condition": {
|
||||
// // "$and": [
|
||||
// // {
|
||||
// // "username": {}
|
||||
// // }
|
||||
// // ]
|
||||
// // },
|
||||
// // "actions": [
|
||||
// // {
|
||||
// // "targetFields": [
|
||||
// // "nickname"
|
||||
// // ],
|
||||
// // "operator": "none"
|
||||
// // }
|
||||
// // ]
|
||||
// // }
|
||||
// // ]
|
||||
// // })
|
||||
// // },
|
||||
// },
|
||||
// },
|
||||
{
|
||||
title: 'Form data templates',
|
||||
type: 'modal',
|
||||
|
@ -46,7 +46,7 @@ interface Props {
|
||||
|
||||
export const DynamicComponent = (props: Props) => {
|
||||
const { setScopes, nullable, constantAbel, changeOnSelect, readOnly = false } = props;
|
||||
const { disabled } = useContext(FilterContext) || {};
|
||||
const { disabled, returnScope } = useContext(FilterContext) || {};
|
||||
const record = useCollectionRecordData();
|
||||
const variables = useVariables();
|
||||
const localVariables = useLocalVariables();
|
||||
@ -68,6 +68,7 @@ export const DynamicComponent = (props: Props) => {
|
||||
localVariables,
|
||||
getAllCollectionsInheritChain,
|
||||
})}
|
||||
returnScope={returnScope}
|
||||
/>
|
||||
);
|
||||
}, []);
|
||||
|
@ -26,7 +26,7 @@ export const LinkageFilter: any = withDynamicSchemaProps(
|
||||
const { useDataSource = useDef } = props;
|
||||
|
||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
const { dynamicComponent, className, collectionName } = useProps(props);
|
||||
const { dynamicComponent, className, collectionName, returnScope } = useProps(props);
|
||||
const [scopes, setScopes] = useState([]);
|
||||
|
||||
const field = useField<ObjectFieldModel>();
|
||||
@ -54,6 +54,7 @@ export const LinkageFilter: any = withDynamicSchemaProps(
|
||||
collectionName,
|
||||
scopes,
|
||||
setScopes,
|
||||
returnScope,
|
||||
}}
|
||||
>
|
||||
<FilterGroup {...props} bordered={false} />
|
||||
|
@ -20,6 +20,7 @@ export interface FilterContextProps {
|
||||
collectionName?: string;
|
||||
scopes?: any[];
|
||||
setScopes?: any;
|
||||
returnScope?: any;
|
||||
}
|
||||
|
||||
export const RemoveConditionContext = createContext(null);
|
||||
|
@ -27,6 +27,7 @@ import {
|
||||
SchemaSettingsRemove,
|
||||
SchemaSettingsSelectItem,
|
||||
SchemaSettingsSwitchItem,
|
||||
SchemaSettingsLinkageRules,
|
||||
} from '../../../schema-settings';
|
||||
import { SchemaSettingsBlockHeightItem } from '../../../schema-settings/SchemaSettingsBlockHeightItem';
|
||||
import { SchemaSettingsBlockTitleItem } from '../../../schema-settings/SchemaSettingsBlockTitleItem';
|
||||
@ -127,10 +128,12 @@ export const TableBlockDesigner = () => {
|
||||
[dn, field.decoratorProps, fieldSchema, service],
|
||||
);
|
||||
const api = useAPIClient();
|
||||
|
||||
return (
|
||||
<GeneralSchemaDesigner template={template} title={title || name}>
|
||||
<SchemaSettingsBlockTitleItem />
|
||||
<SchemaSettingsBlockHeightItem />
|
||||
<SchemaSettingsLinkageRules category="block" title={t('Block Linkage rules')} />
|
||||
{collection?.tree && collectionField?.collectionName === collectionField?.target && (
|
||||
<SchemaSettingsSwitchItem
|
||||
title={t('Tree table')}
|
||||
|
@ -33,6 +33,10 @@ describe('Table.settings', () => {
|
||||
title: 'Set block height',
|
||||
type: 'modal',
|
||||
},
|
||||
{
|
||||
title: 'Block linkage rules',
|
||||
type: 'modal',
|
||||
},
|
||||
{
|
||||
title: 'Enable drag and drop sorting',
|
||||
type: 'switch',
|
||||
|
@ -15,8 +15,10 @@ import { useTranslation } from 'react-i18next';
|
||||
import { withDynamicSchemaProps } from '../../hoc/withDynamicSchemaProps';
|
||||
import { useProps } from '../../schema-component/hooks/useProps';
|
||||
import { FormButtonLinkageRuleAction, FormFieldLinkageRuleAction } from './LinkageRuleAction';
|
||||
import { FieldStyleLinkageRuleAction } from './FieldStyleLinkageRuleAction';
|
||||
import { FieldStyleLinkageRuleAction } from './components/FieldStyleLinkageRuleAction';
|
||||
import { BlockLinkageRuleAction } from './components/BlockLinkageRuleAction';
|
||||
import { RemoveActionContext } from './context';
|
||||
|
||||
export const LinkageRuleActions = observer(
|
||||
(props: any): any => {
|
||||
const { linkageOptions, category, elementType } = props;
|
||||
@ -28,6 +30,7 @@ export const LinkageRuleActions = observer(
|
||||
button: FormButtonLinkageRuleAction,
|
||||
field: FormFieldLinkageRuleAction,
|
||||
style: FieldStyleLinkageRuleAction,
|
||||
block: BlockLinkageRuleAction,
|
||||
};
|
||||
return field?.value?.map((item, index) => {
|
||||
return (
|
||||
@ -41,7 +44,7 @@ export const LinkageRuleActions = observer(
|
||||
);
|
||||
|
||||
export interface LinkageRuleActionGroupProps {
|
||||
type: 'button' | 'field' | 'style';
|
||||
type: 'button' | 'field' | 'style' | 'block';
|
||||
linkageOptions: any;
|
||||
collectionName: string;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ function getFieldValuesInCondition({ linkageRules, formValues }) {
|
||||
});
|
||||
}
|
||||
|
||||
function getVariableValuesInCondition({
|
||||
export function getVariableValuesInCondition({
|
||||
linkageRules,
|
||||
localVariables,
|
||||
}: {
|
||||
@ -166,7 +166,7 @@ function getVariableValuesInCondition({
|
||||
});
|
||||
}
|
||||
|
||||
function getVariableValuesInExpression({ action, localVariables }) {
|
||||
export function getVariableValuesInExpression({ action, localVariables }) {
|
||||
const actionValue = action.value;
|
||||
const mode = actionValue?.mode;
|
||||
const value = actionValue?.value || actionValue?.result;
|
||||
|
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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 { CloseCircleOutlined } from '@ant-design/icons';
|
||||
import { css } from '@emotion/css';
|
||||
import { TreeSelect } from '@formily/antd-v5';
|
||||
import { observer } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { Select, Space } from 'antd';
|
||||
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCompile } from '../../..';
|
||||
import { DynamicComponent } from '../DynamicComponent';
|
||||
import { RemoveActionContext } from '../context';
|
||||
import { ActionType } from '../type';
|
||||
import { useValues } from '../useValues';
|
||||
|
||||
export const BlockLinkageRuleAction = observer(
|
||||
(props: any) => {
|
||||
const { value, options } = props;
|
||||
const { t } = useTranslation();
|
||||
const compile = useCompile();
|
||||
const [editFlag, setEditFlag] = useState(false);
|
||||
const remove = useContext(RemoveActionContext);
|
||||
const { schema, operator, setOperator, setValue } = useValues(options);
|
||||
const operators = useMemo(
|
||||
() =>
|
||||
compile([
|
||||
{ label: t('Visible'), value: ActionType.Visible, schema: {} },
|
||||
{ label: t('Hidden'), value: ActionType.Hidden, schema: {} },
|
||||
]),
|
||||
[compile, t],
|
||||
);
|
||||
|
||||
const onChange = useCallback(
|
||||
(value) => {
|
||||
const flag = [ActionType.Value].includes(value);
|
||||
setEditFlag(flag);
|
||||
setOperator(value);
|
||||
},
|
||||
[setOperator],
|
||||
);
|
||||
|
||||
const onChangeValue = useCallback(
|
||||
(value) => {
|
||||
setValue(value);
|
||||
},
|
||||
[setValue],
|
||||
);
|
||||
|
||||
const closeStyle = useMemo(() => ({ color: '#bfbfbf' }), []);
|
||||
|
||||
return (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<Space>
|
||||
<Select
|
||||
data-testid="select-linkage-properties"
|
||||
popupMatchSelectWidth={false}
|
||||
value={operator}
|
||||
options={operators}
|
||||
onChange={onChange}
|
||||
placeholder={t('action')}
|
||||
/>
|
||||
{editFlag &&
|
||||
React.createElement(DynamicComponent, {
|
||||
value,
|
||||
schema,
|
||||
onChange: onChangeValue,
|
||||
})}
|
||||
{!props.disabled && (
|
||||
<a role="button" aria-label="icon-close">
|
||||
<CloseCircleOutlined onClick={remove} style={closeStyle} />
|
||||
</a>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
{ displayName: 'FormButtonLinkageRuleAction' },
|
||||
);
|
@ -10,15 +10,14 @@
|
||||
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||
import { css } from '@emotion/css';
|
||||
import { observer } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { Select, Space } from 'antd';
|
||||
import React, { useCallback, useContext, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCompile } from '../..';
|
||||
import { ValueDynamicComponent } from './ValueDynamicComponent';
|
||||
import { RemoveActionContext } from './context';
|
||||
import { ActionType } from './type';
|
||||
import { useValues } from './useValues';
|
||||
import { useCompile } from '../../..';
|
||||
import { ValueDynamicComponent } from '../ValueDynamicComponent';
|
||||
import { RemoveActionContext } from '../context';
|
||||
import { ActionType } from '../type';
|
||||
import { useValues } from '../useValues';
|
||||
|
||||
const colorSchema = {
|
||||
type: 'string',
|
@ -25,7 +25,7 @@ import { LinkageRuleActionGroup } from './LinkageRuleActionGroup';
|
||||
import { EnableLinkage } from './components/EnableLinkage';
|
||||
import { ArrayCollapse } from './components/LinkageHeader';
|
||||
import { useFlag } from '../../flag-provider';
|
||||
|
||||
import { LinkageRuleCategory } from './type';
|
||||
export interface Props {
|
||||
dynamicComponent: any;
|
||||
}
|
||||
@ -93,8 +93,18 @@ const transformDefaultValue = (values, variableKey) => {
|
||||
export const FormLinkageRules = withDynamicSchemaProps(
|
||||
observer((props: Props) => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { options, defaultValues, collectionName, form, variables, localVariables, record, dynamicComponent } =
|
||||
useProps(props); // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
const {
|
||||
options,
|
||||
defaultValues,
|
||||
collectionName,
|
||||
form,
|
||||
variables,
|
||||
localVariables,
|
||||
record,
|
||||
dynamicComponent,
|
||||
category,
|
||||
returnScope,
|
||||
} = useProps(props); // 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
const { name } = useCollection_deprecated();
|
||||
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
@ -102,6 +112,16 @@ export const FormLinkageRules = withDynamicSchemaProps(
|
||||
const components = useMemo(() => ({ ArrayCollapse }), []);
|
||||
const { isInSubTable, isInSubForm } = useFlag();
|
||||
const variableKey = getActiveContextName(isInSubTable || isInSubForm, shouldDisplayCurrentForm);
|
||||
const returnTargetScope =
|
||||
returnScope ??
|
||||
((options) =>
|
||||
options.filter((v) => {
|
||||
console.log(category);
|
||||
if (category === LinkageRuleCategory.block) {
|
||||
return !['$nForm', '$nRecord'].includes(v.value);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
const schema = useMemo(
|
||||
() => ({
|
||||
type: 'object',
|
||||
@ -197,6 +217,9 @@ export const FormLinkageRules = withDynamicSchemaProps(
|
||||
conditionAdvanced: {
|
||||
'x-component': 'LinkageFilter',
|
||||
'x-visible': '{{$deps[0] === "advanced"}}',
|
||||
'x-component-props': {
|
||||
returnScope: returnTargetScope,
|
||||
},
|
||||
'x-reactions': [
|
||||
{
|
||||
dependencies: ['.conditionType', '.condition'],
|
||||
|
@ -33,10 +33,12 @@ export enum LinkageRuleCategory {
|
||||
default = 'default',
|
||||
style = 'style',
|
||||
button = 'button',
|
||||
block = 'block',
|
||||
}
|
||||
|
||||
export const LinkageRuleDataKeyMap: Record<`${LinkageRuleCategory}`, string> = {
|
||||
[LinkageRuleCategory.style]: 'x-linkage-style-rules',
|
||||
[LinkageRuleCategory.default]: 'x-linkage-rules',
|
||||
[LinkageRuleCategory.button]: 'x-linkage-rules',
|
||||
[LinkageRuleCategory.block]: 'x-block-linkage-rules',
|
||||
};
|
||||
|
@ -1103,7 +1103,7 @@ export const SchemaSettingsDefaultSortingRules = function DefaultSortingRules(pr
|
||||
};
|
||||
|
||||
export const SchemaSettingsLinkageRules = function LinkageRules(props) {
|
||||
const { collectionName, readPretty, Component, afterSubmit } = props;
|
||||
const { collectionName, readPretty, Component, afterSubmit, title: settingTitle, returnScope } = props;
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { form } = useFormBlockContext();
|
||||
const { dn } = useDesignable();
|
||||
@ -1129,7 +1129,7 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) {
|
||||
const getRules = useCallback(() => {
|
||||
return gridSchema?.[dataKey] || fieldSchema?.[dataKey] || [];
|
||||
}, [gridSchema, fieldSchema, dataKey]);
|
||||
const title = titleMap[category] || t('Linkage rules');
|
||||
const title = settingTitle || titleMap[category] || t('Linkage rules');
|
||||
const flagVales = useFlag();
|
||||
const schema = useMemo<ISchema>(
|
||||
() => ({
|
||||
@ -1151,6 +1151,7 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) {
|
||||
localVariables,
|
||||
record,
|
||||
formBlockType,
|
||||
returnScope,
|
||||
};
|
||||
},
|
||||
},
|
||||
@ -1166,19 +1167,23 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) {
|
||||
rules.push(_.omit(_.pickBy(rule, _.identity), ['conditionBasic', 'conditionAdvanced']));
|
||||
}
|
||||
const templateId = gridSchema['x-component'] === 'BlockTemplate' && gridSchema['x-component-props']?.templateId;
|
||||
const uid = (templateId && getTemplateById(templateId).uid) || gridSchema['x-uid'];
|
||||
const uid =
|
||||
category !== LinkageRuleCategory.block
|
||||
? (templateId && getTemplateById(templateId).uid) || gridSchema['x-uid']
|
||||
: fieldSchema['x-uid'];
|
||||
const schema = {
|
||||
['x-uid']: uid,
|
||||
};
|
||||
gridSchema[dataKey] = rules;
|
||||
schema[dataKey] = rules;
|
||||
fieldSchema[dataKey] = rules;
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
afterSubmit?.();
|
||||
},
|
||||
[dn, getTemplateById, gridSchema, dataKey, afterSubmit],
|
||||
[dn, getTemplateById, gridSchema, dataKey, afterSubmit, category],
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -32,3 +32,4 @@ export * from './isPatternDisabled';
|
||||
export { SchemaSettingsPlugin } from './SchemaSettingsPlugin';
|
||||
export * from './VariableInput';
|
||||
export { replaceVariables } from './LinkageRules/bindLinkageRulesToFiled';
|
||||
export * from './LinkageRules/type';
|
||||
|
@ -20,7 +20,7 @@ export const WaitApp = async () => {
|
||||
|
||||
const loadError = screen.queryByText('App Error');
|
||||
if (loadError) {
|
||||
expectNoTsError(screen.queryByText('App Error')).not.toBeInTheDocument();
|
||||
// expectNoTsError(screen.queryByText('App Error')).not.toBeInTheDocument();
|
||||
}
|
||||
|
||||
const renderError = screen.queryByText('Render Failed');
|
||||
|
@ -126,6 +126,16 @@ export const deprecatedBulkEditActionSettings = new SchemaSettings({
|
||||
name: 'updateMode',
|
||||
Component: UpdateMode,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { linkageRulesProps } = useSchemaToolbar();
|
||||
return {
|
||||
...linkageRulesProps,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'remove',
|
||||
sort: 100,
|
||||
|
@ -8,18 +8,17 @@
|
||||
*/
|
||||
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
SchemaSettings,
|
||||
useBlockTemplateContext,
|
||||
SchemaSettingsLayoutItem,
|
||||
SchemaSettingsDataTemplates,
|
||||
useFormBlockContext,
|
||||
SchemaSettingsFormItemTemplate,
|
||||
useCollection,
|
||||
useCollection_deprecated,
|
||||
SchemaSettingsBlockHeightItem,
|
||||
SchemaSettingsBlockTitleItem,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
} from '@nocobase/client';
|
||||
|
||||
export const bulkEditFormBlockSettings = new SchemaSettings({
|
||||
@ -34,12 +33,23 @@ export const bulkEditFormBlockSettings = new SchemaSettings({
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
name: 'fieldLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Field Linkage rules'),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -19,6 +19,8 @@ import {
|
||||
useRecord,
|
||||
useURLAndHTMLSchema,
|
||||
useVariableOptions,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
} from '@nocobase/client';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -200,6 +202,17 @@ const commonOptions: any = {
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'divider',
|
||||
type: 'divider',
|
||||
|
@ -74,7 +74,7 @@ function Button({ onlyIcon }) {
|
||||
}
|
||||
|
||||
export const WorkbenchAction = withDynamicSchemaProps((props) => {
|
||||
const { className, ...others } = props;
|
||||
const { className, targetComponent, iconColor, ...others } = props;
|
||||
const { styles, cx } = useStyles() as any;
|
||||
const fieldSchema = useFieldSchema();
|
||||
const Component = useComponent(props?.targetComponent) || Action;
|
||||
|
@ -52,7 +52,7 @@ const ResponsiveSpace = () => {
|
||||
return (
|
||||
<Grid columns={itemsPerRow} gap={gap}>
|
||||
{fieldSchema.mapProperties((s, key) => {
|
||||
return <NocoBaseRecursionField name={key} schema={s} />;
|
||||
return <NocoBaseRecursionField name={key} schema={s} key={key} />;
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
@ -61,7 +61,7 @@ const ResponsiveSpace = () => {
|
||||
return (
|
||||
<Space wrap size={gap} align="start">
|
||||
{fieldSchema.mapProperties((s, key) => {
|
||||
return <NocoBaseRecursionField name={key} schema={s} />;
|
||||
return <NocoBaseRecursionField name={key} schema={s} key={key} />;
|
||||
})}
|
||||
</Space>
|
||||
);
|
||||
|
@ -45,6 +45,16 @@ export const workbenchActionSettingsLink = new SchemaSettings({
|
||||
name: 'editLink',
|
||||
Component: SchemaSettingsActionLinkItem,
|
||||
},
|
||||
{
|
||||
name: 'linkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { linkageRulesProps } = useSchemaToolbar();
|
||||
return {
|
||||
...linkageRulesProps,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
...SchemaSettingAccessControl,
|
||||
useVisible() {
|
||||
|
@ -15,6 +15,9 @@ import {
|
||||
SchemaSettingsModalItem,
|
||||
useOpenModeContext,
|
||||
SchemaSettingsItemType,
|
||||
useCollection,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
} from '@nocobase/client';
|
||||
import { CustomSchemaSettingsBlockTitleItem } from './SchemaSettingsBlockTitleItem';
|
||||
import React from 'react';
|
||||
@ -136,6 +139,17 @@ export const workbenchBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'layout',
|
||||
Component: ActionPanelLayout,
|
||||
|
@ -25,6 +25,9 @@ import {
|
||||
useFormBlockContext,
|
||||
usePopupSettings,
|
||||
useApp,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
useCollection_deprecated,
|
||||
} from '@nocobase/client';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTranslation } from '../../locale';
|
||||
@ -65,6 +68,19 @@ export const calendarBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'titleField',
|
||||
Component: SchemaSettingsSelectItem,
|
||||
|
@ -14,7 +14,10 @@ import {
|
||||
SchemaSettingsSwitchItem,
|
||||
useDesignable,
|
||||
useToken,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
} from '@nocobase/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useChartsTranslation } from '../locale';
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
|
||||
@ -25,6 +28,18 @@ export const chartBlockSettings = new SchemaSettings({
|
||||
name: 'title',
|
||||
Component: SchemaSettingsBlockTitleItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'background',
|
||||
Component: () => {
|
||||
|
@ -22,7 +22,10 @@ import {
|
||||
useCompile,
|
||||
useDesignable,
|
||||
useFormBlockContext,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
} from '@nocobase/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useGanttBlockContext } from './GanttBlockProvider';
|
||||
import { useGanttTranslation, useOptions } from './utils';
|
||||
|
||||
@ -37,6 +40,19 @@ export const oldGanttSettings = new SchemaSettings({
|
||||
name: 'title',
|
||||
Component: SchemaSettingsBlockTitleItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'titleField',
|
||||
Component: SchemaSettingsSelectItem,
|
||||
@ -277,6 +293,19 @@ export const ganttSettings = new SchemaSettings({
|
||||
name: 'title',
|
||||
Component: SchemaSettingsBlockTitleItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'titleField',
|
||||
Component: SchemaSettingsSelectItem,
|
||||
|
@ -21,6 +21,8 @@ import {
|
||||
useDesignable,
|
||||
useFormBlockContext,
|
||||
SchemaSettingsLayoutItem,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
} from '@nocobase/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useKanbanBlockContext } from './KanbanBlockProvider';
|
||||
@ -36,6 +38,19 @@ export const kanbanSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dataScope',
|
||||
Component: SchemaSettingsDataScope,
|
||||
|
@ -27,8 +27,11 @@ import {
|
||||
useDesignable,
|
||||
useFormBlockContext,
|
||||
useColumnSchema,
|
||||
SchemaSettingsLinkageRules,
|
||||
LinkageRuleCategory,
|
||||
} from '@nocobase/client';
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMapTranslation } from '../locale';
|
||||
import { useMapBlockContext } from './MapBlockProvider';
|
||||
import { findNestedOption } from './utils';
|
||||
@ -89,6 +92,19 @@ export const mapBlockSettings = new SchemaSettings({
|
||||
name: 'setTheBlockHeight',
|
||||
Component: SchemaSettingsBlockHeightItem,
|
||||
},
|
||||
{
|
||||
name: 'blockLinkageRules',
|
||||
Component: SchemaSettingsLinkageRules,
|
||||
useComponentProps() {
|
||||
const { name } = useCollection();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
collectionName: name,
|
||||
title: t('Block Linkage rules'),
|
||||
category: LinkageRuleCategory.block,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mapField',
|
||||
Component: SchemaSettingsCascaderItem,
|
||||
|
Loading…
x
Reference in New Issue
Block a user