diff --git a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx index 207dbd3f15..704c7156f7 100644 --- a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx +++ b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx @@ -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'; @@ -85,6 +86,7 @@ export const BlockSchemaComponentProvider: React.FC = (props) => { useFilterFormBlockDecoratorProps, useGridCardBlockDecoratorProps, useFormItemProps, + useDataFormItemProps, }} > {props.children} @@ -145,6 +147,7 @@ export class BlockSchemaComponentPlugin extends Plugin { useFilterFormBlockDecoratorProps, useGridCardBlockDecoratorProps, useFormItemProps, + useDataFormItemProps, }); } } diff --git a/packages/core/client/src/locale/en_US.json b/packages/core/client/src/locale/en_US.json index a972f9fb4c..1807bdd95f 100644 --- a/packages/core/client/src/locale/en_US.json +++ b/packages/core/client/src/locale/en_US.json @@ -426,6 +426,7 @@ "Option value": "Option value", "Option label": "Option label", "Color": "Color", + "Background Color": "Background Color", "Add option": "Add option", "Related collection": "Related collection", "Allow linking to multiple records": "Allow linking to multiple records", @@ -552,6 +553,7 @@ "Add condition group": "Add condition group", "exists": "exists", "not exists": "not exists", + "Style": "Style", "=": "=", "≠": "≠", ">": ">", diff --git a/packages/core/client/src/locale/zh-CN.json b/packages/core/client/src/locale/zh-CN.json index cbc0fd100f..efa153cc0a 100644 --- a/packages/core/client/src/locale/zh-CN.json +++ b/packages/core/client/src/locale/zh-CN.json @@ -447,6 +447,7 @@ "Option value": "选项值", "Option label": "选项标签", "Color": "颜色", + "Background Color": "背景颜色", "Add option": "添加选项", "Related collection": "关系表", "Allow linking to multiple records": "允许关联多条记录", diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-view/schemaSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-view/schemaSettings.test.ts new file mode 100644 index 0000000000..6fdd933a25 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-view/schemaSettings.test.ts @@ -0,0 +1,63 @@ +/** + * 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, commonFormViewPage, test } from '@nocobase/test/e2e'; + +test.describe('field schema settings', () => { + test('linkage style color', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(commonFormViewPage).waitForInit(); + await mockRecord('general', { singleLineText: 'asdfcedg' }); + await nocoPage.goto(); + await page.getByText('asdfcedg', { exact: true }).hover(); + await page.getByLabel('block-item-CollectionField-general-details-general.singleLineText-singleLineText').hover(); + + await page + .getByLabel('designer-schema-settings-CollectionField-fieldSettings:FormItem-general-general.singleLineText', { + exact: true, + }) + .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.getByTestId('select-linkage-properties').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 + .getByLabel('block-item-CollectionField-general-details-general.singleLineText-singleLineText') + .locator('div.ant-formily-item-control-content-component'); + await expect(cell).toHaveCSS('color', 'rgb(163, 79, 204)'); + }); + test('linkage style background color', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(commonFormViewPage).waitForInit(); + await mockRecord('general', { singleLineText: 'asdfcedg' }); + await nocoPage.goto(); + await page.getByText('asdfcedg', { exact: true }).hover(); + await page.getByLabel('block-item-CollectionField-general-details-general.singleLineText-singleLineText').hover(); + + await page + .getByLabel('designer-schema-settings-CollectionField-fieldSettings:FormItem-general-general.singleLineText', { + exact: true, + }) + .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.getByTestId('select-linkage-properties').click(); + await page.getByText('Background 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 + .getByLabel('block-item-CollectionField-general-details-general.singleLineText-singleLineText') + .locator('div.ant-formily-item-control-content-component'); + await expect(cell).toHaveCSS('background-color', 'rgb(163, 79, 204)'); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/fieldSettingsFormItem.test.tsx b/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/fieldSettingsFormItem.test.tsx index 69663c8b61..d6b1e2fa09 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/fieldSettingsFormItem.test.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__tests__/fieldSettingsFormItem.test.tsx @@ -242,6 +242,10 @@ describe('FieldSettingsFormItem', () => { title: 'Pattern', type: 'select', }, + { + title: 'Style', + type: 'modal', + }, { title: 'Set validation rules', type: 'modal', @@ -284,6 +288,10 @@ describe('FieldSettingsFormItem', () => { title: 'Pattern', type: 'select', }, + { + title: 'Style', + type: 'modal', + }, { title: 'Field component', type: 'select', diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/fieldSettingsFormItem.tsx b/packages/core/client/src/modules/blocks/data-blocks/form/fieldSettingsFormItem.tsx index 4548fb02df..231f236ffb 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/fieldSettingsFormItem.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/form/fieldSettingsFormItem.tsx @@ -6,7 +6,7 @@ * 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 from 'react'; import { ArrayCollapse, FormLayout } from '@formily/antd-v5'; import { Field } from '@formily/core'; import { ISchema, useField, useFieldSchema } from '@formily/react'; @@ -16,6 +16,7 @@ import { useApp, useSchemaToolbar } from '../../../../application'; import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; import { useFormBlockContext } from '../../../../block-provider/FormBlockProvider'; import { useCollectionManager_deprecated, useCollection_deprecated } from '../../../../collection-manager'; +import { useCollection } from '../../../../data-source'; import { useFieldComponentName } from '../../../../common/useFieldComponentName'; import { useDesignable, useValidateSchema } from '../../../../schema-component'; import { useIsFormReadPretty } from '../../../../schema-component/antd/form-item/FormItem.Settings'; @@ -24,7 +25,8 @@ import { isPatternDisabled } from '../../../../schema-settings'; import { ActionType } from '../../../../schema-settings/LinkageRules/type'; import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue'; import { useIsAllowToSetDefaultValue } from '../../../../schema-settings/hooks/useIsAllowToSetDefaultValue'; - +import { SchemaSettingsLinkageRules } from '../../../../schema-settings'; +import { useIsFieldReadPretty } from '../../../../schema-component/antd/form-item/FormItem.Settings'; export const fieldSettingsFormItem = new SchemaSettings({ name: 'fieldSettings:FormItem', items: [ @@ -442,6 +444,25 @@ export const fieldSettingsFormItem = new SchemaSettings({ return form && !isFormReadPretty && validateSchema; }, }, + { + name: 'style', + Component: (props) => { + const localProps = { ...props, category: 'style' }; + return ; + }, + useVisible() { + const isFieldReadPretty = useIsFieldReadPretty(); + return isFieldReadPretty; + }, + useComponentProps() { + const { name } = useCollection(); + const { linkageRulesProps } = useSchemaToolbar(); + return { + ...linkageRulesProps, + collectionName: name, + }; + }, + }, ]; }, }, diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useDataFormItemProps.ts b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useDataFormItemProps.ts new file mode 100644 index 0000000000..b9e50ff5f0 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/hooks/useDataFormItemProps.ts @@ -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 { wrapperStyle: style }; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/linkageStyleSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/linkageStyleSettings.test.ts new file mode 100644 index 0000000000..350073ebbf --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/linkageStyleSettings.test.ts @@ -0,0 +1,60 @@ +/** + * 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, oneTableBlockWithIntegerAndIDColumn, test } from '@nocobase/test/e2e'; + +test.describe('view', () => { + test('linkage style color', 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.getByTestId('select-linkage-properties').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 = page.getByRole('button', { name: '423' }); + const color = await cell.evaluate((el) => getComputedStyle(el).color); + expect(color).toContain('163, 79, 204'); + }); + + test('linkage style background color', 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.getByTestId('select-linkage-properties').click(); + await page.getByText('Background 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 = page.getByRole('button', { name: '423' }); + const bgColor = await cell.evaluate((el) => getComputedStyle(el.parentElement).backgroundColor); + expect(bgColor).toContain('163, 79, 204'); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/tableColumnSettings.tsx b/packages/core/client/src/modules/blocks/data-blocks/table/tableColumnSettings.tsx index b7c8a1c1df..96a1f3f3b6 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/tableColumnSettings.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/table/tableColumnSettings.tsx @@ -7,10 +7,11 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ +import React from 'react'; import { ISchema } from '@formily/json-schema'; import { useField, useFieldSchema } from '@formily/react'; import { useTranslation } from 'react-i18next'; -import { useApp } from '../../../../application'; +import { useApp, useSchemaToolbar } from '../../../../application'; import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; import { useCollectionManager_deprecated } from '../../../../collection-manager'; import { useFieldComponentName } from '../../../../common/useFieldComponentName'; @@ -20,6 +21,7 @@ import { useAssociationFieldContext } from '../../../../schema-component/antd/as import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator'; import { SchemaSettingsDefaultValue } from '../../../../schema-settings/SchemaSettingsDefaultValue'; import { isPatternDisabled } from '../../../../schema-settings/isPatternDisabled'; +import { SchemaSettingsLinkageRules } from '../../../../schema-settings'; export const tableColumnSettings = new SchemaSettings({ name: 'fieldSettings:TableColumn', @@ -44,7 +46,6 @@ export const tableColumnSettings = new SchemaSettings({ const { t } = useTranslation(); const columnSchema = useFieldSchema(); const { dn } = useDesignable(); - return { title: t('Custom column title'), schema: { @@ -79,6 +80,30 @@ export const tableColumnSettings = new SchemaSettings({ }; }, }, + { + name: 'style', + Component: (props) => { + const localProps = { ...props, category: 'style' }; + return ; + }, + useVisible() { + const { fieldSchema } = useColumnSchema(); + const field: any = useField(); + const path = field.path?.splice(field.path?.length - 1, 1); + if (fieldSchema) { + const isReadPretty = field.form.query(`${path.concat(`*.` + fieldSchema.name)}`).get('readPretty'); + return isReadPretty; + } else return false; + }, + useComponentProps() { + const { name } = useCollection(); + const { linkageRulesProps } = useSchemaToolbar(); + return { + ...linkageRulesProps, + collectionName: name, + }; + }, + }, { name: 'columnWidth', type: 'modal', diff --git a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx index 3eb65f08e1..ff4dfca2e0 100644 --- a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx +++ b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx @@ -10,7 +10,7 @@ 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 { observer, useField, useFieldSchema, useForm } from '@formily/react'; import React, { useEffect, useMemo } from 'react'; import { ACLCollectionFieldProvider } from '../../../acl/ACLProvider'; import { useApp } from '../../../application'; @@ -19,14 +19,14 @@ 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'; 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 { useVariables, useContextVariable } from '../../../variables'; +import { useDataFormItemProps } from '../../../modules/blocks/data-blocks/form/hooks/useDataFormItemProps'; Item.displayName = 'FormilyFormItem'; @@ -47,14 +47,14 @@ export const FormItem: any = withDynamicSchemaProps( useEnsureOperatorsValid(); const field = useField(); const schema = useFieldSchema(); - const contextVariable = useContextVariable(); - const variables = useVariables(); const { addActiveFieldName } = useFormActiveFields() || {}; - + const form = useForm(); + const { wrapperStyle } = useDataFormItemProps(); + const variables = useVariables(); + const contextVariable = useContextVariable(); useEffect(() => { variables?.registerVariable(contextVariable); - }, [contextVariable]); - + }, [contextVariable, variables]); // 需要放在注冊完变量之后 useParseDefaultValue(); useLazyLoadDisplayAssociationFieldsOfForm(); @@ -87,7 +87,7 @@ export const FormItem: any = withDynamicSchemaProps( - + diff --git a/packages/core/client/src/schema-component/antd/table-v2/Table.Column.Designer.tsx b/packages/core/client/src/schema-component/antd/table-v2/Table.Column.Designer.tsx index 4df8366b33..b14e546899 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/Table.Column.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/Table.Column.Designer.tsx @@ -30,6 +30,9 @@ import { isPatternDisabled } from '../../../schema-settings/isPatternDisabled'; import { useCompile, useDesignable, useFieldModeOptions } from '../../hooks'; import { useAssociationFieldContext } from '../association-field/hooks'; import { removeNullCondition } from '../filter'; +import { SchemaSettingsLinkageRules } from '../../../schema-settings'; +import { useCollection } from '../../../data-source'; +import { useSchemaToolbar } from '../../../application'; export const useLabelFields = (collectionName?: any) => { // 需要在组件顶层调用 @@ -98,6 +101,12 @@ export const TableColumnDesigner = (props) => { readOnlyMode = 'read-pretty'; } const isSelectFieldMode = isAssociationField && fieldMode === 'Select'; + + const StyleSetting = () => { + const { name } = useCollection(); + const { linkageRulesProps } = useSchemaToolbar(); + return ; + }; return ( { dn.refresh(); }} /> + {interfaceCfg && interfaceCfg.sortable === true && !currentMode && ( { @@ -145,6 +145,9 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => ); }, + onCell: (record) => { + return { record, schema: s }; + }, } as TableColumnProps; // 这里不能把 columnsSchema 作为依赖,因为其每次都会变化,这里使用 hasChangedColumns 作为依赖 @@ -529,16 +532,17 @@ export const Table: any = withDynamicSchemaProps( const BodyCellComponent = useCallback( (props) => { const isIndex = props.className?.includes('selection-column'); - + 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 { valueMap: style } = useSatisfiedActionValues({ formValues: record, category: 'style', schema }); return ( - + {inView || isIndex ? props.children : } ); diff --git a/packages/core/client/src/schema-items/GeneralSettings.tsx b/packages/core/client/src/schema-items/GeneralSettings.tsx index d34b5f2ee0..1fe2c2e424 100644 --- a/packages/core/client/src/schema-items/GeneralSettings.tsx +++ b/packages/core/client/src/schema-items/GeneralSettings.tsx @@ -6,7 +6,7 @@ * 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 from 'react'; import { Field } from '@formily/core'; import { ISchema, useField, useFieldSchema } from '@formily/react'; import { useTranslation } from 'react-i18next'; @@ -14,6 +14,9 @@ import { useDesignable } from '../schema-component'; import { SchemaSettingOptions } from '../application'; import { useSchemaToolbar } from '../application/schema-toolbar'; import { useCollection_deprecated, useCollectionManager_deprecated } from '../collection-manager'; +import { SchemaSettingsLinkageRules } from '../schema-settings'; +import { useIsFieldReadPretty } from '../schema-component'; +import { useCollection } from '../data-source'; export const generalSettingsItems: SchemaSettingOptions['items'] = [ { @@ -216,4 +219,23 @@ export const generalSettingsItems: SchemaSettingOptions['items'] = [ return !field.readPretty && fieldSchema['x-component'] !== 'FormField' && required; }, }, + { + name: 'style', + Component: (props) => { + const localProps = { ...props, category: 'style' }; + return ; + }, + useVisible() { + const isFieldReadPretty = useIsFieldReadPretty(); + return isFieldReadPretty; + }, + useComponentProps() { + const { name } = useCollection(); + const { linkageRulesProps } = useSchemaToolbar(); + return { + ...linkageRulesProps, + collectionName: name, + }; + }, + }, ]; diff --git a/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx b/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx index 7cb7cd959f..47cb97f7a2 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx +++ b/packages/core/client/src/schema-settings/LinkageRules/LinkageRuleAction.tsx @@ -184,3 +184,67 @@ export const FormButtonLinkageRuleAction = observer( }, { displayName: 'FormButtonLinkageRuleAction' }, ); + +export const FormStyleLinkageRuleAction = observer( + (props: any) => { + const { value, options, collectionName } = props; + const { t } = useTranslation(); + const compile = useCompile(); + const remove = useContext(RemoveActionContext); + const { operator, setOperator, value: fieldValue, setValue } = useValues(options); + const operators = useMemo( + () => + compile([ + { label: t('Color'), value: ActionType.Color, schema: {} }, + { label: t('Background Color'), value: ActionType.BackgroundColor, schema: {} }, + ]), + [compile, t], + ); + const schema = { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'ColorPicker', + 'x-component-props': { + defaultValue: '', + }, + }; + + const onChange = useCallback( + (value) => { + setOperator(value); + }, + [setOperator], + ); + + const closeStyle = useMemo(() => ({ color: '#bfbfbf' }), []); + return ( +
+ + { }); }} > - - - + {options.map((option) => ( + + ))} {modeMap[mode]} diff --git a/packages/core/client/src/schema-settings/LinkageRules/compute-rules.ts b/packages/core/client/src/schema-settings/LinkageRules/compute-rules.ts new file mode 100644 index 0000000000..a7e109b687 --- /dev/null +++ b/packages/core/client/src/schema-settings/LinkageRules/compute-rules.ts @@ -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 { ActionType } from './type'; +import { InputModeType } from './ValueDynamicComponent'; +import { conditionAnalyses } from '../../schema-component/common/utils/uitls'; +const getActionValue = (operator, value) => { + const getValueByMode = (value) => { + const mode = value?.mode as InputModeType; + if (mode === 'constant') { + return value.value; + } else return null; + }; + switch (true) { + case [ActionType.Color, ActionType.BackgroundColor].includes(operator): + return getValueByMode(value); + default: + return null; + break; + } +}; + +const getSatisfiedActions = async ({ rules, variables, localVariables }) => { + const satisfiedRules = ( + await Promise.all( + rules + .filter((k) => !k.disabled) + .map(async (rule) => { + if (await conditionAnalyses({ ruleGroup: rule.condition, variables, localVariables })) { + return rule; + } else return null; + }), + ) + ).filter(Boolean); + return satisfiedRules.map((rule) => rule.actions).flat(); +}; + +const getSatisfiedValues = async ({ rules, variables, localVariables }) => { + return (await getSatisfiedActions({ rules, variables, localVariables })).map((action) => ({ + ...action, + value: getActionValue(action.operator, action.value), + })); +}; + +export const getSatisfiedValueMap = async ({ rules, variables, localVariables }) => { + const values = await getSatisfiedValues({ rules, variables, localVariables }); + const valueMap = values.reduce((a, v) => ({ ...a, [v.operator]: v.value }), {}); + return valueMap; +}; diff --git a/packages/core/client/src/schema-settings/LinkageRules/type.ts b/packages/core/client/src/schema-settings/LinkageRules/type.ts index 279f640130..dcf7b58b38 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/type.ts +++ b/packages/core/client/src/schema-settings/LinkageRules/type.ts @@ -19,4 +19,16 @@ export enum ActionType { Disabled = 'disabled', Value = 'value', Active = 'enabled', + Color = 'color', + BackgroundColor = 'backgroundColor', } + +export enum LinkageRuleCategory { + default = 'default', + style = 'style', +} + +export const LinkageRuleDataKeyMap: Record<`${LinkageRuleCategory}`, string> = { + [LinkageRuleCategory.style]: 'x-linkage-style-rules', + [LinkageRuleCategory.default]: 'x-linkage-rules', +}; diff --git a/packages/core/client/src/schema-settings/LinkageRules/useActionValues.ts b/packages/core/client/src/schema-settings/LinkageRules/useActionValues.ts new file mode 100644 index 0000000000..ec1dc3a1af --- /dev/null +++ b/packages/core/client/src/schema-settings/LinkageRules/useActionValues.ts @@ -0,0 +1,48 @@ +/** + * 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 { isEmpty } from 'lodash'; +export function useSatisfiedActionValues({ + formValues, + category = 'default', + rules, + schema, +}: { + category: `${LinkageRuleCategory}`; + formValues: Record; + rules?: any; + schema?: any; +}) { + const [valueMap, setValueMap] = useState({}); + const fieldSchema = useFieldSchema(); + const variables = useVariables(); + const localVariables = useLocalVariables({ currentForm: { values: formValues } as any }); + const localSchema = schema ?? fieldSchema; + const linkageRules = rules ?? localSchema[LinkageRuleDataKeyMap[category]]; + + 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 }; +} diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index 1758e5591a..9a3790a4f9 100644 --- a/packages/core/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/core/client/src/schema-settings/SchemaSettings.tsx @@ -101,6 +101,7 @@ import { EnableChildCollections } from './EnableChildCollections'; import { ChildDynamicComponent } from './EnableChildCollections/DynamicComponent'; import { FormLinkageRules } from './LinkageRules'; import { useLinkageCollectionFieldOptions } from './LinkageRules/action-hooks'; +import { LinkageRuleDataKeyMap, LinkageRuleCategory } from './LinkageRules/type'; export interface SchemaSettingsProps { title?: any; @@ -983,23 +984,35 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) { const localVariables = useLocalVariables(); const record = useRecord(); const { type: formBlockType } = useFormBlockType(); - const type = props?.type || fieldSchema?.['x-action'] ? 'button' : 'field'; + const category = props?.category ?? LinkageRuleCategory.default; + const elementType = ['Action', 'Action.Link'].includes(fieldSchema['x-component']) ? 'button' : 'field'; + const gridSchema = findGridSchema(fieldSchema) || fieldSchema; const options = useLinkageCollectionFilterOptions(collectionName); const linkageOptions = useLinkageCollectionFieldOptions(collectionName, readPretty); + const titleMap = { + [LinkageRuleCategory.default]: t('Linkage rules'), + [LinkageRuleCategory.style]: t('Style'), + }; + const dataKey = LinkageRuleDataKeyMap[category]; + const getRules = useCallback(() => { + return gridSchema?.[dataKey] || fieldSchema?.[dataKey] || []; + }, [gridSchema, fieldSchema, dataKey]); + const title = titleMap[category]; const schema = useMemo( () => ({ type: 'object', - title: t('Linkage rules'), + title, properties: { fieldReaction: { 'x-component': FormLinkageRules, 'x-use-component-props': () => { return { options, - defaultValues: gridSchema?.['x-linkage-rules'] || fieldSchema?.['x-linkage-rules'], - type, + defaultValues: getRules(), linkageOptions, + category, + elementType, collectionName, form, variables, @@ -1011,7 +1024,7 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) { }, }, }), - [collectionName, fieldSchema, form, gridSchema, localVariables, record, t, type, variables], + [collectionName, fieldSchema, form, gridSchema, localVariables, record, t, variables, getRules], ); const components = useMemo(() => ({ ArrayCollapse, FormLayout }), []); const onSubmit = useCallback( @@ -1025,25 +1038,18 @@ export const SchemaSettingsLinkageRules = function LinkageRules(props) { const schema = { ['x-uid']: uid, }; - - gridSchema['x-linkage-rules'] = rules; - schema['x-linkage-rules'] = rules; + gridSchema[dataKey] = rules; + schema[dataKey] = rules; dn.emit('patch', { schema, }); dn.refresh(); }, - [dn, getTemplateById, gridSchema], + [dn, getTemplateById, gridSchema, dataKey], ); return ( - + ); }; diff --git a/packages/core/test/src/e2e/index.ts b/packages/core/test/src/e2e/index.ts index fccee56d02..af3bd9a04f 100644 --- a/packages/core/test/src/e2e/index.ts +++ b/packages/core/test/src/e2e/index.ts @@ -10,3 +10,4 @@ export * from './e2eUtils'; export * from './templatesOfCollection'; export * from './templatesOfPage'; +export * from './templates'; diff --git a/packages/core/test/src/e2e/templates/form-view/commonView.ts b/packages/core/test/src/e2e/templates/form-view/commonView.ts new file mode 100644 index 0000000000..851644e9ec --- /dev/null +++ b/packages/core/test/src/e2e/templates/form-view/commonView.ts @@ -0,0 +1,551 @@ +/** + * 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. + */ + +/** + * 一个通用表单详情 + * 显示 email, number, integer, singleLineText, longText + * password, percent, phone + */ +import { generalWithBasic } from '../../templatesOfCollection'; +export const commonFormViewPage = { + collections: generalWithBasic, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + 'x-index': 1, + properties: { + nyayqbdi6fw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + udrskvvihwz: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + sic837d78ru: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + j3tcb77zrjs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action': 'general:view', + 'x-decorator': 'DetailsBlockProvider', + 'x-use-decorator-props': 'useDetailsWithPaginationDecoratorProps', + 'x-decorator-props': { + dataSource: 'main', + collection: 'general', + readPretty: true, + action: 'list', + params: { + pageSize: 1, + }, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:detailsWithPagination', + 'x-component': 'CardItem', + 'x-app-version': '1.0.0-alpha.17', + properties: { + hgde2qiovq4: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Details', + 'x-read-pretty': true, + 'x-use-component-props': 'useDetailsWithPaginationProps', + 'x-app-version': '1.0.0-alpha.17', + properties: { + xaaixt3ikr2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'details:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + 'x-app-version': '1.0.0-alpha.17', + properties: { + zc467d4k8pe: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit") }}', + 'x-action': 'update', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:edit', + 'x-component': 'Action', + 'x-component-props': { + openMode: 'drawer', + icon: 'EditOutlined', + type: 'primary', + }, + 'x-decorator': 'ACLActionProvider', + 'x-app-version': '1.0.0-alpha.17', + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + 'x-app-version': '1.0.0-alpha.17', + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'popup:addTab', + 'x-app-version': '1.0.0-alpha.17', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'popup:common:addBlock', + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': 'tbxcoz6blxo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'x4gthikn85e', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'dlcr60v0lae', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'goi3ac29a92', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xhu94zjv18h', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'dotl8t82ufw', + 'x-async': false, + 'x-index': 1, + }, + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'details:configureFields', + 'x-app-version': '1.0.0-alpha.17', + properties: { + qbd9sojqba9: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + '6fi8dxh1515': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + email: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.email', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': '1ht8ymnfc18', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2y8bzf9fa92', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'mszcq97x37n', + 'x-async': false, + 'x-index': 1, + }, + '5qwtnq93h4m': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + woxnz7b32ms: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + number: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.number', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': 'lg2wluayh2c', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'awljxm8hh55', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'g8raovgeqjc', + 'x-async': false, + 'x-index': 2, + }, + v7ht9slmzwn: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + ijjcbuis4tv: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + integer: { + 'x-uid': 'dhdtfo7nrxn', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.integer', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-linkage-style-rules': [], + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9rd5u4d3lhj', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ii6w1eqf21k', + 'x-async': false, + 'x-index': 3, + }, + fekkqosx4q6: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + nmpljskg642: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + singleLineText: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.singleLineText', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': '88cqngc9wzf', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '44pljtolwui', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zq7dfy9uvrj', + 'x-async': false, + 'x-index': 4, + }, + p318qpfu85n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + '1fayljjx90o': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + longText: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.longText', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': 'y6rf9v4iz8o', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1vhh859rxwx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '19lk0gejxo3', + 'x-async': false, + 'x-index': 5, + }, + '6t21tyr1aun': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + '3h1hp3t902r': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + password: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.password', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': '2zgn6ew5mwy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i3twoaoewde', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'uvsong5fn8l', + 'x-async': false, + 'x-index': 6, + }, + inytkbn0nae: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + h8e5m0gy2ei: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + percent: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.percent', + 'x-component-props': { + style: { + width: '100%', + }, + }, + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': '2maem18o31o', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jtbdipyy5sc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'as7c9lme7mm', + 'x-async': false, + 'x-index': 7, + }, + '81q1yw3hkkn': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + properties: { + ykobkj6pe8n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + properties: { + phone: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': 'useDataFormItemProps', + 'x-collection-field': 'general.phone', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': 'e66n6ewz0hi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ai34z8y2eb4', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'eltj0z2txug', + 'x-async': false, + 'x-index': 8, + }, + }, + 'x-uid': '7crv1u0i3co', + 'x-async': false, + 'x-index': 2, + }, + pagination: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Pagination', + 'x-use-component-props': 'useDetailsPaginationProps', + 'x-app-version': '1.0.0-alpha.17', + 'x-uid': 'jfs3ntlghyo', + 'x-async': false, + 'x-index': 3, + }, + }, + 'x-uid': 'buvsjjof9pw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9ruom7jpm1h', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3pl1k9mqhy8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0eax0yvji6y', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'cs71v511x7o', + 'x-async': false, + }, + }, + 'x-uid': 'welnfb52obj', + 'x-async': true, + }, +}; diff --git a/packages/core/test/src/e2e/templates/form-view/index.ts b/packages/core/test/src/e2e/templates/form-view/index.ts new file mode 100644 index 0000000000..7a161c3845 --- /dev/null +++ b/packages/core/test/src/e2e/templates/form-view/index.ts @@ -0,0 +1,10 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +export * from './commonView'; diff --git a/packages/core/test/src/e2e/templates/index.ts b/packages/core/test/src/e2e/templates/index.ts new file mode 100644 index 0000000000..c14b2bc143 --- /dev/null +++ b/packages/core/test/src/e2e/templates/index.ts @@ -0,0 +1,10 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +export * from './form-view'; diff --git a/packages/core/test/src/e2e/templatesOfPage.ts b/packages/core/test/src/e2e/templatesOfPage.ts index a91070da5f..7d1cbe6e87 100644 --- a/packages/core/test/src/e2e/templatesOfPage.ts +++ b/packages/core/test/src/e2e/templatesOfPage.ts @@ -5839,6 +5839,569 @@ export const oneTableBlockWithAddNewAndViewAndEditAndBasicFields: PageConfig = { }, }; +/** + * 1. 一个 Table 区块 + * 2. 显示ID和一个整数列 + * 3. 查看详情: email integer number phone + */ +export const oneTableBlockWithIntegerAndIDColumn: PageConfig = { + collections: generalWithBasic, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + 'x-index': 1, + properties: { + nyayqbdi6fw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + a7zqokjj6gt: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + '3lbci797d7d': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + wvjxlk9dpcp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-use-decorator-props': 'useTableBlockDecoratorProps', + 'x-decorator-props': { + collection: 'general', + dataSource: 'main', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:table', + 'x-component': 'CardItem', + 'x-filter-targets': [], + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'table:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'uafyrboeeeh', + 'x-async': false, + }, + xpv8gfkv0w4: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'table:configureColumns', + 'x-component': 'TableV2', + 'x-use-component-props': 'useTableBlockProps', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + }, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 2, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'table:configureItemActions', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + c3br6p1m4ay: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + ycbfg04aq1u: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View") }}', + 'x-action': 'view', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:view', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + 'x-index': 1, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + 'x-index': 1, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'popup:addTab', + 'x-index': 1, + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'popup:common:addBlock', + 'x-index': 1, + properties: { + fecjkwzjrlc: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + u5047nn630n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + g6nol2a8f0v: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action': 'general:get', + 'x-decorator': 'DetailsBlockProvider', + 'x-use-decorator-props': 'useDetailsDecoratorProps', + 'x-decorator-props': { + dataSource: 'main', + collection: 'general', + readPretty: true, + action: 'get', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:details', + 'x-component': 'CardItem', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + qe6uvivhlcs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Details', + 'x-read-pretty': true, + 'x-use-component-props': 'useDetailsProps', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + '1ul3ug1mjn1': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'details:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'tx7ej82dtav', + 'x-async': false, + }, + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'details:configureFields', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 2, + properties: { + i4gnqtwjsmo: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + kpg3nd9z03j: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + email: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': + 'useDataFormItemProps', + 'x-collection-field': + 'general.email', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'igz2roi2lgf', + 'x-async': false, + }, + }, + 'x-uid': 'twtz1r704we', + 'x-async': false, + }, + }, + 'x-uid': '4yltx4dtlwa', + 'x-async': false, + }, + '0j7ky7h63km': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 2, + properties: { + '1yq1bw53408': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + integer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': + 'useDataFormItemProps', + 'x-collection-field': + 'general.integer', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'kz1wgswubq6', + 'x-async': false, + }, + }, + 'x-uid': 'hxdhhdrttal', + 'x-async': false, + }, + }, + 'x-uid': 'h3df5v19yer', + 'x-async': false, + }, + tqgzzposgug: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 3, + properties: { + j88upzin86t: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + number: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': + 'useDataFormItemProps', + 'x-collection-field': + 'general.number', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'lb582vapwrl', + 'x-async': false, + }, + }, + 'x-uid': 'b9hxznmlw4y', + 'x-async': false, + }, + }, + 'x-uid': 'ccemewjagrc', + 'x-async': false, + }, + zsifuulhfj8: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 4, + properties: { + '94mix5vzskc': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + properties: { + phone: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-use-decorator-props': + 'useDataFormItemProps', + 'x-collection-field': + 'general.phone', + 'x-component-props': {}, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'b9sth7gi9co', + 'x-async': false, + }, + }, + 'x-uid': '24nb1vhc3c8', + 'x-async': false, + }, + }, + 'x-uid': 'q3fdeysf8i0', + 'x-async': false, + }, + }, + 'x-uid': 'w2d78a9y0s2', + 'x-async': false, + }, + }, + 'x-uid': 'cjtl8872i5s', + 'x-async': false, + }, + }, + 'x-uid': 'x79v0wahp73', + 'x-async': false, + }, + }, + 'x-uid': 'z5k8x76thiv', + 'x-async': false, + }, + }, + 'x-uid': 'dz7694elunl', + 'x-async': false, + }, + }, + 'x-uid': 'dpyxl72qav7', + 'x-async': false, + }, + }, + 'x-uid': 'ejoaawmib5s', + 'x-async': false, + }, + }, + 'x-uid': 'vqu7oj3nsba', + 'x-async': false, + }, + }, + 'x-uid': '80o560bno10', + 'x-async': false, + }, + }, + 'x-uid': 'as0562wfiri', + 'x-async': false, + }, + }, + 'x-uid': 'ipotr34hb0r', + 'x-async': false, + }, + }, + 'x-uid': 'hy58uesiqfe', + 'x-async': false, + }, + '2tygi2ob18k': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-toolbar': 'TableColumnSchemaToolbar', + 'x-settings': 'fieldSettings:TableColumn', + 'x-component': 'TableV2.Column', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 2, + properties: { + id: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'general.id', + 'x-component': 'CollectionField', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'uxtounspwze', + 'x-async': false, + }, + }, + 'x-uid': 'yvfmjf6tzk7', + 'x-async': false, + }, + t8rlom0c3ju: { + 'x-uid': 'jt87by9dks1', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-toolbar': 'TableColumnSchemaToolbar', + 'x-settings': 'fieldSettings:TableColumn', + 'x-component': 'TableV2.Column', + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 3, + 'x-linkage-style-rules': [], + properties: { + integer: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'general.integer', + 'x-component': 'CollectionField', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-app-version': '1.0.0-alpha.17', + 'x-index': 1, + 'x-uid': 'd3fvg9v46yu', + 'x-async': false, + }, + }, + 'x-async': false, + }, + }, + 'x-uid': 'nwqvi9i433x', + 'x-async': false, + }, + }, + 'x-uid': 'qf53grjobl2', + 'x-async': false, + }, + }, + 'x-uid': 'c95omaoid1m', + 'x-async': false, + }, + }, + 'x-uid': 'h70lk7jikxa', + 'x-async': false, + }, + }, + 'x-uid': 'iylotyrenoo', + 'x-async': false, + }, + }, + 'x-uid': '7z81p33jsb1', + 'x-async': true, + }, +}; /** * 1. 一个 Table 区块 * 2. 点击 Add new 有一个 Form 区块,里面有一个 sub-table 字段