Skip to content

Commit

Permalink
feat: add some e2e test for linkage style in table, extract linkage
Browse files Browse the repository at this point in the history
  style logic to hooks
  • Loading branch information
sheldon66 committed Jun 2, 2024
1 parent 9cdb97b commit 234f115
Show file tree
Hide file tree
Showing 13 changed files with 446 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { useCreateFormBlockDecoratorProps } from '../modules/blocks/data-blocks/
import { useCreateFormBlockProps } from '../modules/blocks/data-blocks/form/hooks/useCreateFormBlockProps';
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 { useTableSelectorDecoratorProps } from '../modules/blocks/data-blocks/table-selector/hooks/useTableSelectorDecoratorProps';
Expand Down Expand Up @@ -85,6 +86,7 @@ export const BlockSchemaComponentProvider: React.FC = (props) => {
useFilterFormBlockDecoratorProps,
useGridCardBlockDecoratorProps,
useFormItemProps,
useDataFormItemProps,
}}
>
{props.children}
Expand Down Expand Up @@ -145,6 +147,7 @@ export class BlockSchemaComponentPlugin extends Plugin {
useFilterFormBlockDecoratorProps,
useGridCardBlockDecoratorProps,
useFormItemProps,
useDataFormItemProps,
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ export const fieldSettingsFormItem = new SchemaSettings({
{
name: 'style',
Component: (props) => {
const propsWithType = { ...props, type: 'style' };
return <SchemaSettingsLinkageRules {...propsWithType} />;
const localProps = { ...props, category: 'style' };
return <SchemaSettingsLinkageRules {...localProps} />;
},
useVisible() {
const field: any = useField();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* 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 { useForm } from '@formily/react';
import { useSatisfiedActionValues } from '../../../../../schema-settings/LinkageRules/useActionValues';
export function useDataFormItemProps() {
const form = useForm();
const { valueMap: style } = useSatisfiedActionValues({ category: 'style', formValues: form?.values });
return { style };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* 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 { expect, test, oneTableBlockWithIntegerAndIDColumn } from '@nocobase/test/e2e';

test.describe('view', () => {
test('linkage style', async ({ page, mockPage, mockRecord }) => {
const nocoPage = await mockPage(oneTableBlockWithIntegerAndIDColumn).waitForInit();
await mockRecord('general', { integer: '423' });
await nocoPage.goto();
await page.getByText('integer', { exact: true }).hover();

await page
.getByRole('button', {
name: 'designer-schema-settings-TableV2.Column-fieldSettings:TableColumn-general',
})
.click();
await page.getByRole('menuitem', { name: 'Style' }).click();
await page.getByRole('button', { name: 'plus Add linkage rule' }).click();
await page.getByText('Add property').click();
await page.locator('#rc_select_2').click();
await page.getByText('Color', { exact: true }).click();
await page.getByLabel('color-picker-normal').click();
await page.locator('input[type="text"]').fill('A34FCC');
await page.getByRole('button', { name: 'OK' }).click();
const cell = await page.getByRole('button', { name: '423' });
const color = await cell.evaluate((el) => getComputedStyle(el).color);
await expect(color).toBe('rgb(163, 79, 204)');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ export const tableColumnSettings = new SchemaSettings({
{
name: 'style',
Component: (props) => {
const propsWithType = { ...props, type: 'style' };
return <SchemaSettingsLinkageRules {...propsWithType} />;
const localProps = { ...props, category: 'style' };
return <SchemaSettingsLinkageRules {...localProps} />;
},
useVisible() {
const { uiSchema, fieldSchema } = useColumnSchema();
Expand All @@ -94,7 +94,7 @@ export const tableColumnSettings = new SchemaSettings({
return isReadPretty;
},
useComponentProps() {
const { name } = useCollection_deprecated();
const { name } = useCollection();
const { linkageRulesProps } = useSchemaToolbar();
return {
...linkageRulesProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,22 @@ import { css, cx } from '@emotion/css';
import { IFormItemProps, FormItem as Item } from '@formily/antd-v5';
import { Field } from '@formily/core';
import { observer, useField, useFieldSchema, useForm } from '@formily/react';
import React, { useEffect, useMemo, useState } 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, useLocalVariables } from '../../../variables';
import useContextVariable from '../../../variables/hooks/useContextVariable';
import { BlockItem } from '../block-item';
import { HTMLEncode } from '../input/shared';
import { FilterFormDesigner } from './FormItem.FilterFormDesigner';
import { useEnsureOperatorsValid } from './SchemaSettingOptions';
import useLazyLoadDisplayAssociationFieldsOfForm from './hooks/useLazyLoadDisplayAssociationFieldsOfForm';
import useParseDefaultValue from './hooks/useParseDefaultValue';
import { LinkageRuleDataKey } from '../../../schema-settings/LinkageRules/type';
import { getSatisfiedValueMap } from '../../../schema-settings/LinkageRules/compute-rules';
import { isEmpty } from 'lodash';
import { useDataFormItemProps } from '../../../modules/blocks/data-blocks/form/hooks/useDataFormItemProps';

Item.displayName = 'FormilyFormItem';

const formItemWrapCss = css`
Expand All @@ -49,29 +46,9 @@ export const FormItem: any = withDynamicSchemaProps(
useEnsureOperatorsValid();
const field = useField<Field>();
const schema = useFieldSchema();
const contextVariable = useContextVariable();
const variables = useVariables();
const { addActiveFieldName } = useFormActiveFields() || {};
const form = useForm();
const localVariables = useLocalVariables({ currentForm: { values: form?.values } as any });
const [style, setStyle] = useState({});
useEffect(() => {
variables?.registerVariable(contextVariable);
}, [contextVariable]);
const linkageStyleRules = schema[LinkageRuleDataKey.style];
useEffect(() => {
if (form && linkageStyleRules) {
getSatisfiedValueMap({ rules: linkageStyleRules, variables, localVariables })
.then((valueMap) => {
if (!isEmpty(valueMap)) {
setStyle(valueMap);
} else setStyle({});
})
.catch((err) => {
throw new Error(err.message);
});
}
}, [variables, localVariables, form, linkageStyleRules]);
const { style } = useDataFormItemProps();
// 需要放在注冊完变量之后
useParseDefaultValue();
useLazyLoadDisplayAssociationFieldsOfForm();
Expand Down
30 changes: 6 additions & 24 deletions packages/core/client/src/schema-component/antd/table-v2/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import { isPortalInBody } from '@nocobase/utils/client';
import { useCreation, useDeepCompareEffect, useMemoizedFn } from 'ahooks';
import { Table as AntdTable, Skeleton, TableColumnProps } from 'antd';
import { default as classNames, default as cls } from 'classnames';
import _, { omit, isEmpty } from 'lodash';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import _, { omit } from 'lodash';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useInView } from 'react-intersection-observer';
import { DndContext, useDesignable, useTableSize } from '../..';
Expand All @@ -34,16 +34,14 @@ import {
useTableBlockContext,
useTableSelectorContext,
} from '../../../';
import { useLocalVariables, useVariables } from '../../../';
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
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';
import { extractIndex, isCollectionFieldComponent, isColumnComponent } from './utils';
import { getSatisfiedValueMap } from '../../../schema-settings/LinkageRules/compute-rules';
import { LinkageRuleDataKey } from '../../../schema-settings/LinkageRules/type';
import { useSatisfiedActionValues } from '../../../schema-settings/LinkageRules/useActionValues';
const MemoizedAntdTable = React.memo(AntdTable);

const useArrayField = (props) => {
Expand Down Expand Up @@ -110,7 +108,6 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
}, [token.paddingContentVerticalLG, token.marginSM]);

const collection = useCollection();
const variables = useVariables();

const columns = useMemo(
() =>
Expand All @@ -121,7 +118,6 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
}
}, []);
const dataIndex = collectionFields?.length > 0 ? collectionFields[0].name : s.name;
const linkageStyleRules = s?.[LinkageRuleDataKey.style] || [];
return {
title: <RecursionField name={s.name} schema={s} onlyRenderSelf />,
dataIndex,
Expand Down Expand Up @@ -150,7 +146,7 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
);
},
onCell: (record) => {
return { record, linkageStyleRules, variables };
return { record, schema: s };
},
} as TableColumnProps<any>;

Expand Down Expand Up @@ -533,28 +529,14 @@ export const Table: any = withDynamicSchemaProps(
const BodyCellComponent = useCallback(
(props) => {
const isIndex = props.className?.includes('selection-column');
const { record, linkageStyleRules, variables } = props;
const { record, schema } = props;
const { ref, inView } = useInView({
threshold: 0,
triggerOnce: true,
initialInView: isIndex || !!process.env.__E2E__ || dataSource.length <= 10,
skip: isIndex || !!process.env.__E2E__,
});
const localVariables = useLocalVariables({ currentForm: { values: record } as any });
const [style, setStyle] = useState({});
useEffect(() => {
if (linkageStyleRules) {
getSatisfiedValueMap({ rules: linkageStyleRules, variables, localVariables })
.then((valueMap) => {
if (!isEmpty(valueMap)) {
setStyle(valueMap);
} else setStyle({});
})
.catch((err) => {
throw new Error(err);
});
}
}, [linkageStyleRules, variables, localVariables]);
const { valueMap: style } = useSatisfiedActionValues({ formValues: record, category: 'style', schema });

return (
<td {...props} ref={ref} className={classNames(props.className, cellClass)} style={style}>
Expand Down
1 change: 1 addition & 0 deletions packages/core/client/src/schema-initializer/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ export const useFormItemInitializerFields = (options?: any) => {
'x-settings': 'fieldSettings:FormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-use-decorator-props': 'useDataFormItemProps',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': isFileCollection
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import {
import { RemoveActionContext } from './context';
export const LinkageRuleActions = observer(
(props: any): any => {
const { type, linkageOptions } = props;
const { linkageOptions, category, elementType } = props;
const field = useField<ArrayFieldModel>();
const type = category === 'default' ? elementType : category;
const componentMap: {
[key in LinkageRuleActionGroupProps['type']]: any;
} = {
Expand Down Expand Up @@ -55,12 +56,11 @@ export const LinkageRuleActionGroup = withDynamicSchemaProps(
const logic = 'actions';

// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
const { type, linkageOptions, collectionName } = useProps(props);

const { category, elementType, linkageOptions, collectionName } = useProps(props);
const style = useMemo(() => ({ marginLeft: 10 }), []);
const components = useMemo(
() => [LinkageRuleActions, { type, linkageOptions, collectionName }],
[collectionName, linkageOptions, type],
() => [LinkageRuleActions, { category, elementType, linkageOptions, collectionName }],
[collectionName, linkageOptions, category, elementType],
);
const spaceStyle = useMemo(() => ({ marginTop: 8, marginBottom: 8 }), []);
const onClick = useCallback(() => {
Expand Down
11 changes: 8 additions & 3 deletions packages/core/client/src/schema-settings/LinkageRules/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ export enum ActionType {
BackgroundColor = 'backgroundColor',
}

export enum LinkageRuleDataKey {
style = 'x-linkage-rules-style',
default = 'x-linkage-rules',
export enum LinkageRuleCategory {
default = 'default',
style = 'style',
}

export const LinkageRuleDataKeyMap: Record<`${LinkageRuleCategory}`, string> = {
[LinkageRuleCategory.style]: 'x-linkage-style-rules',
[LinkageRuleCategory.default]: 'x-linkage-rules',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* 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 { useState, useEffect } from 'react';
import { useVariables, useLocalVariables } from '../../variables';
import { useFieldSchema } from '@formily/react';
import { LinkageRuleCategory, LinkageRuleDataKeyMap } from './type';
import { getSatisfiedValueMap } from './compute-rules';
import { useContextVariable } from '../../variables';
import { isEmpty } from 'lodash';
export function useSatisfiedActionValues({
formValues,
category = 'default',
rules,
schema,
}: {
category: `${LinkageRuleCategory}`;
formValues: Record<string, any>;
rules?: any;
schema?: any;
}) {
const [valueMap, setValueMap] = useState({});
const fieldSchema = useFieldSchema();
const variables = useVariables();
const localVariables = useLocalVariables({ currentForm: { values: formValues } as any });
const contextVariable = useContextVariable();
const localSchema = schema ?? fieldSchema;
const linkageRules = rules ?? localSchema[LinkageRuleDataKeyMap[category]];
useEffect(() => {
variables?.registerVariable(contextVariable);
}, [contextVariable, variables]);

useEffect(() => {
if (linkageRules && formValues) {
getSatisfiedValueMap({ rules: linkageRules, variables, localVariables })
.then((valueMap) => {
if (!isEmpty(valueMap)) {
setValueMap(valueMap);
} else setValueMap({});
})
.catch((err) => {
throw new Error(err.message);
});
}
}, [variables, localVariables, formValues, linkageRules]);
return { valueMap };
}
Loading

0 comments on commit 234f115

Please sign in to comment.