fix(variable): missing variables and invalid translations (#4054)

* fix(variable):  missing variables and invalid translations

* refactor: better

* fix: should display current record variable

* fix: template

* chore: add deps

* chore: add e2e for table view

* fix: current record variable

* chore: avoid error

* fix: bugs

* chore: fix failed e2e

* chore: fix e2e

* fix: colection name
This commit is contained in:
Zeke Zhang 2024-04-16 22:50:52 +08:00 committed by GitHub
parent 8b88b29b5e
commit 3d857d2e69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 368 additions and 190 deletions

View File

@ -2,6 +2,7 @@ import { ArrayItems } from '@formily/antd-v5';
import { ISchema, useField, useFieldSchema } from '@formily/react'; import { ISchema, useField, useFieldSchema } from '@formily/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { SchemaSettingsItemType } from '../../../../application/schema-settings/types';
import { useFormBlockContext } from '../../../../block-provider'; import { useFormBlockContext } from '../../../../block-provider';
import { useDetailsBlockContext } from '../../../../block-provider/DetailsBlockProvider'; import { useDetailsBlockContext } from '../../../../block-provider/DetailsBlockProvider';
import { useCollection_deprecated, useSortFields } from '../../../../collection-manager'; import { useCollection_deprecated, useSortFields } from '../../../../collection-manager';
@ -9,7 +10,6 @@ import { removeNullCondition, useDesignable } from '../../../../schema-component
import { SchemaSettingsBlockTitleItem, SchemaSettingsTemplate } from '../../../../schema-settings'; import { SchemaSettingsBlockTitleItem, SchemaSettingsTemplate } from '../../../../schema-settings';
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope'; import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
import { setDataLoadingModeSettingsItem } from './setDataLoadingModeSettingsItem'; import { setDataLoadingModeSettingsItem } from './setDataLoadingModeSettingsItem';
import { SchemaSettingsItemType } from '../../../../application/schema-settings/types';
const commonItems: SchemaSettingsItemType[] = [ const commonItems: SchemaSettingsItemType[] = [
{ {
@ -29,6 +29,7 @@ const commonItems: SchemaSettingsItemType[] = [
collectionName: name, collectionName: name,
defaultFilter: fieldSchema?.['x-decorator-props']?.params?.filter || {}, defaultFilter: fieldSchema?.['x-decorator-props']?.params?.filter || {},
form, form,
noRecord: true,
onSubmit: ({ filter }) => { onSubmit: ({ filter }) => {
filter = removeNullCondition(filter); filter = removeNullCondition(filter);
const params = field.decoratorProps.params || {}; const params = field.decoratorProps.params || {};

View File

@ -51,19 +51,23 @@ export const FormBlockInitializer = ({
}, },
[createBlockSchema, createFormBlock], [createBlockSchema, createFormBlock],
); );
const doTemplateWrap = useCallback(
(templateSchema, options) => {
if (customizeTemplateWrap) {
return customizeTemplateWrap(templateSchema, options);
}
return templateWrap(templateSchema, options);
},
[customizeTemplateWrap, templateWrap],
);
return ( return (
<DataBlockInitializer <DataBlockInitializer
{...itemConfig} {...itemConfig}
icon={<FormOutlined />} icon={<FormOutlined />}
componentType={componentType} componentType={componentType}
templateWrap={(templateSchema, options) => { templateWrap={doTemplateWrap}
if (customizeTemplateWrap) {
return customizeTemplateWrap(templateSchema, options);
}
return templateWrap(templateSchema, options);
}}
onCreateBlockSchema={onCreateFormBlockSchema} onCreateBlockSchema={onCreateFormBlockSchema}
filter={filterCollections} filter={filterCollections}
onlyCurrentDataSource={onlyCurrentDataSource} onlyCurrentDataSource={onlyCurrentDataSource}
@ -80,28 +84,34 @@ export const useCreateFormBlock = () => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { isCusomeizeCreate: isCustomizeCreate } = itemConfig; const { isCusomeizeCreate: isCustomizeCreate } = itemConfig;
const createFormBlock = ({ item }) => { const createFormBlock = useCallback(
insert( ({ item }) => {
createCreateFormBlockUISchema({ insert(
collectionName: item.collectionName || item.name, createCreateFormBlockUISchema({
dataSource: item.dataSource, collectionName: item.collectionName || item.name,
isCusomeizeCreate: isCustomizeCreate, dataSource: item.dataSource,
}), isCusomeizeCreate: isCustomizeCreate,
); }),
}; );
},
[insert, isCustomizeCreate],
);
const templateWrap = (templateSchema, { item }) => { const templateWrap = useCallback(
const schema = createCreateFormBlockUISchema({ (templateSchema, { item }) => {
isCusomeizeCreate: isCustomizeCreate, const schema = createCreateFormBlockUISchema({
dataSource: item.dataSource, isCusomeizeCreate: isCustomizeCreate,
templateSchema: templateSchema, dataSource: item.dataSource,
collectionName: item.name, templateSchema: templateSchema,
}); collectionName: item.name,
if (item.template && item.mode === 'reference') { });
schema['x-template-key'] = item.template.key; if (item.template && item.mode === 'reference') {
} schema['x-template-key'] = item.template.key;
return schema; }
}; return schema;
},
[isCustomizeCreate],
);
return { return {
createFormBlock, createFormBlock,

View File

@ -9,74 +9,6 @@ import {
SchemaSettingsLinkageRules, SchemaSettingsLinkageRules,
} from '../../../../schema-settings'; } from '../../../../schema-settings';
// TODO: 0.20 版之后可以删除
export const creationFormBlockSettings = new SchemaSettings({
name: 'blockSettings:creationForm',
items: [
{
name: 'title',
Component: SchemaSettingsBlockTitleItem,
},
{
name: 'linkageRules',
Component: SchemaSettingsLinkageRules,
useComponentProps() {
const { name } = useCollection_deprecated();
return {
collectionName: name,
};
},
},
{
name: 'dataTemplates',
Component: SchemaSettingsDataTemplates,
useVisible() {
const { action } = useFormBlockContext();
return !action;
},
useComponentProps() {
const { name } = useCollection_deprecated();
return {
collectionName: name,
};
},
},
{
name: 'divider',
type: 'divider',
},
{
name: 'formItemTemplate',
Component: SchemaSettingsFormItemTemplate,
useComponentProps() {
const { name } = useCollection_deprecated();
const fieldSchema = useFieldSchema();
const defaultResource =
fieldSchema?.['x-decorator-props']?.resource || fieldSchema?.['x-decorator-props']?.association;
return {
componentName: 'FormItem',
collectionName: name,
resourceName: defaultResource,
};
},
},
{
name: 'divider2',
type: 'divider',
},
{
name: 'remove',
type: 'remove',
componentProps: {
removeParentsIfNoChildren: true,
breakRemoveOn: {
'x-component': 'Grid',
},
},
},
],
});
export const createFormBlockSettings = new SchemaSettings({ export const createFormBlockSettings = new SchemaSettings({
name: 'blockSettings:createForm', name: 'blockSettings:createForm',
items: [ items: [

View File

@ -0,0 +1,19 @@
import { expect, test } from '@nocobase/test/e2e';
import { tableViewLinkageRulesVariables } from './templates';
test.describe('variables', () => {
test('linkage rules of table view action', async ({ page, mockPage }) => {
await mockPage(tableViewLinkageRulesVariables).goto();
// 1. 打开联动规则设置弹窗,并显示变量列表
await page.getByLabel('action-Action.Link-View-view-').hover();
await page.getByLabel('designer-schema-settings-Action.Link-actionSettings:view-users').hover();
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
await page.getByLabel('variable-button').click();
// 2. 断言应该显示的变量
['Constant', 'Current user', 'Current role', 'Date variables', 'Current record'].forEach(async (name) => {
await expect(page.getByRole('menuitemcheckbox', { name })).toBeVisible();
});
});
});

View File

@ -0,0 +1,229 @@
export const tableViewLinkageRulesVariables = {
pageSchema: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Page',
properties: {
g1wycipht9k: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'page:addBlock',
properties: {
'7i8pwd4xhj5': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '0.21.0-alpha.8',
properties: {
pblvpmq357i: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '0.21.0-alpha.8',
properties: {
dwwc54m8ky1: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'TableBlockProvider',
'x-acl-action': 'users:list',
'x-use-decorator-props': 'useTableBlockDecoratorProps',
'x-decorator-props': {
collection: 'users',
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': '0.21.0-alpha.8',
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': '0.21.0-alpha.8',
'x-uid': 'dwfejl3y35l',
'x-async': false,
'x-index': 1,
},
b0gp5kve5cy: {
_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': '0.21.0-alpha.8',
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': '0.21.0-alpha.8',
properties: {
tf980vw8dg7: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'DndContext',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
'x-app-version': '0.21.0-alpha.8',
properties: {
dmpqsodnxr6: {
'x-uid': 'vivhb5goy37',
_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-linkage-rules': [
{
condition: {
$and: [{}],
},
actions: [],
},
],
properties: {
drawer: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{ t("View record") }}',
'x-component': 'Action.Container',
'x-component-props': {
className: 'nb-action-popup',
},
properties: {
tabs: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'popup:addTab',
properties: {
tab1: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Details")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'popup:common:addBlock',
'x-uid': '8mxgjwcq1lu',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '9fbdmfbk67y',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'dn6hvykic0s',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'czk4w54afwy',
'x-async': false,
'x-index': 1,
},
},
'x-async': false,
'x-index': 1,
},
},
'x-uid': '3hbqk34vlxs',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'fptg47gw3v0',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'r6rocjxtxwr',
'x-async': false,
'x-index': 2,
},
},
'x-uid': 'gy0al0nl08m',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '2vkcx6nt5y0',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '2zeeh485ev6',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'ckrzeha5h5t',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'qnwmpeqykgx',
'x-async': true,
'x-index': 1,
},
};

View File

@ -9,10 +9,16 @@ import { StablePopover, useActionContext } from '../..';
import { useDesignable } from '../../'; import { useDesignable } from '../../';
import { useACLActionParamsContext } from '../../../acl'; import { useACLActionParamsContext } from '../../../acl';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useCollectionParentRecordData, useDataBlockRequest } from '../../../data-source'; import {
useCollection,
useCollectionParentRecordData,
useCollectionRecordData,
useDataBlockRequest,
} from '../../../data-source';
import { Icon } from '../../../icon'; import { Icon } from '../../../icon';
import { TreeRecordProvider } from '../../../modules/blocks/data-blocks/table/TreeRecordProvider'; import { TreeRecordProvider } from '../../../modules/blocks/data-blocks/table/TreeRecordProvider';
import { RecordProvider, useRecord } from '../../../record-provider'; import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { RecordProvider } from '../../../record-provider';
import { useLocalVariables, useVariables } from '../../../variables'; import { useLocalVariables, useVariables } from '../../../variables';
import { SortableItem } from '../../common'; import { SortableItem } from '../../common';
import { useCompile, useComponent, useDesigner } from '../../hooks'; import { useCompile, useComponent, useDesigner } from '../../hooks';
@ -63,8 +69,9 @@ export const Action: ComposedAction = withDynamicSchemaProps(
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const compile = useCompile(); const compile = useCompile();
const form = useForm(); const form = useForm();
const record = useRecord(); const recordData = useCollectionRecordData();
const parentRecordData = useCollectionParentRecordData(); const parentRecordData = useCollectionParentRecordData();
const collection = useCollection();
const designerProps = fieldSchema['x-designer-props']; const designerProps = fieldSchema['x-designer-props'];
const openMode = fieldSchema?.['x-component-props']?.['openMode']; const openMode = fieldSchema?.['x-component-props']?.['openMode'];
const openSize = fieldSchema?.['x-component-props']?.['openSize']; const openSize = fieldSchema?.['x-component-props']?.['openSize'];
@ -76,7 +83,7 @@ export const Action: ComposedAction = withDynamicSchemaProps(
const tarComponent = useComponent(component) || component; const tarComponent = useComponent(component) || component;
const { modal } = App.useApp(); const { modal } = App.useApp();
const variables = useVariables(); const variables = useVariables();
const localVariables = useLocalVariables({ currentForm: { values: record } as any }); const localVariables = useLocalVariables({ currentForm: { values: recordData } as any });
const { getAriaLabel } = useGetAriaLabelOfAction(title); const { getAriaLabel } = useGetAriaLabelOfAction(title);
const service = useDataBlockRequest(); const service = useDataBlockRequest();
@ -196,7 +203,14 @@ export const Action: ComposedAction = withDynamicSchemaProps(
> >
{popover && <RecursionField basePath={field.address} onlyRenderProperties schema={fieldSchema} />} {popover && <RecursionField basePath={field.address} onlyRenderProperties schema={fieldSchema} />}
{!popover && renderButton()} {!popover && renderButton()}
{!popover && props.children} <DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={recordData}
collection={collection}
>
{!popover && props.children}
</DeclareVariable>
{element} {element}
</ActionContextProvider> </ActionContextProvider>
); );
@ -206,7 +220,7 @@ export const Action: ComposedAction = withDynamicSchemaProps(
return wrapSSR( return wrapSSR(
// fix https://nocobase.height.app/T-3966 // fix https://nocobase.height.app/T-3966
<RecordProvider record={null} parent={parentRecordData}> <RecordProvider record={null} parent={parentRecordData}>
<TreeRecordProvider parent={record}>{result}</TreeRecordProvider> <TreeRecordProvider parent={recordData}>{result}</TreeRecordProvider>
</RecordProvider>, </RecordProvider>,
); );
} }

View File

@ -3,11 +3,8 @@ import { ObjectField } from '@formily/core';
import { useField } from '@formily/react'; import { useField } from '@formily/react';
import { Card } from 'antd'; import { Card } from 'antd';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider'; import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
import { useCollection } from '../../../data-source/collection/CollectionProvider';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { RecordProvider } from '../../../record-provider'; import { RecordProvider } from '../../../record-provider';
const itemCss = css` const itemCss = css`
@ -32,22 +29,13 @@ const gridCardCss = css`
export const GridCardItem = withDynamicSchemaProps( export const GridCardItem = withDynamicSchemaProps(
(props) => { (props) => {
const { t } = useTranslation();
const collection = useCollection();
const field = useField<ObjectField>(); const field = useField<ObjectField>();
const parentRecordData = useCollectionParentRecordData(); const parentRecordData = useCollectionParentRecordData();
return ( return (
<Card role="button" aria-label="grid-card-item" className={gridCardCss}> <Card role="button" aria-label="grid-card-item" className={gridCardCss}>
<div className={itemCss}> <div className={itemCss}>
<RecordProvider record={field.value} parent={parentRecordData}> <RecordProvider record={field.value} parent={parentRecordData}>
<DeclareVariable {props.children}
name="$nPopupRecord"
title={t('Current popup record')}
value={field.value}
collection={collection}
>
{props.children}
</DeclareVariable>
</RecordProvider> </RecordProvider>
</div> </div>
</Card> </Card>

View File

@ -5,16 +5,11 @@ import classnames from 'classnames';
import React from 'react'; import React from 'react';
import { useDesignable } from '../../hooks'; import { useDesignable } from '../../hooks';
import { useTranslation } from 'react-i18next';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider'; import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
import { useCollection } from '../../../data-source/collection/CollectionProvider';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { RecordProvider } from '../../../record-provider'; import { RecordProvider } from '../../../record-provider';
export const ListItem = withDynamicSchemaProps((props) => { export const ListItem = withDynamicSchemaProps((props) => {
const { t } = useTranslation();
const collection = useCollection();
const field = useField<ObjectField>(); const field = useField<ObjectField>();
const { designable } = useDesignable(); const { designable } = useDesignable();
const parentRecordData = useCollectionParentRecordData(); const parentRecordData = useCollectionParentRecordData();
@ -31,14 +26,7 @@ export const ListItem = withDynamicSchemaProps((props) => {
])} ])}
> >
<RecordProvider record={field.value} parent={parentRecordData}> <RecordProvider record={field.value} parent={parentRecordData}>
<DeclareVariable {props.children}
name="$nPopupRecord"
title={t('Current popup record')}
value={field.value}
collection={collection}
>
{props.children}
</DeclareVariable>
</RecordProvider> </RecordProvider>
</div> </div>
); );

View File

@ -28,7 +28,6 @@ import {
import { useACLFieldWhitelist } from '../../../acl/ACLProvider'; import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { isNewRecord } from '../../../data-source/collection-record/isNewRecord'; import { isNewRecord } from '../../../data-source/collection-record/isNewRecord';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { useToken } from '../__builtins__'; import { useToken } from '../__builtins__';
import { SubFormProvider } from '../association-field/hooks'; import { SubFormProvider } from '../association-field/hooks';
import { ColumnFieldProvider } from './components/ColumnFieldProvider'; import { ColumnFieldProvider } from './components/ColumnFieldProvider';
@ -57,7 +56,6 @@ export const useColumnsDeepMemoized = (columns: any[]) => {
}; };
const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => { const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => {
const { t } = useTranslation();
const { token } = useToken(); const { token } = useToken();
const field = useArrayField(props); const field = useArrayField(props);
const schema = useFieldSchema(); const schema = useFieldSchema();
@ -108,24 +106,17 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
const index = field.value?.indexOf(record); const index = field.value?.indexOf(record);
const basePath = field.address.concat(record.__index || index); const basePath = field.address.concat(record.__index || index);
return ( return (
<DeclareVariable <SubFormProvider value={{ value: record, collection }}>
name="$nPopupRecord" <RecordIndexProvider index={record.__index || index}>
title={t('Current popup record')} <RecordProvider isNew={isNewRecord(record)} record={record} parent={parentRecordData}>
value={record} <ColumnFieldProvider schema={s} basePath={basePath}>
collection={collection} <span role="button" className={schemaToolbarBigger}>
> <RecursionField basePath={basePath} schema={s} onlyRenderProperties />
<SubFormProvider value={{ value: record, collection }}> </span>
<RecordIndexProvider index={record.__index || index}> </ColumnFieldProvider>
<RecordProvider isNew={isNewRecord(record)} record={record} parent={parentRecordData}> </RecordProvider>
<ColumnFieldProvider schema={s} basePath={basePath}> </RecordIndexProvider>
<span role="button" className={schemaToolbarBigger}> </SubFormProvider>
<RecursionField basePath={basePath} schema={s} onlyRenderProperties />
</span>
</ColumnFieldProvider>
</RecordProvider>
</RecordIndexProvider>
</SubFormProvider>
</DeclareVariable>
); );
}, },
} as TableColumnProps<any>; } as TableColumnProps<any>;
@ -133,15 +124,7 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
// 这里不能把 columnsSchema 作为依赖,因为其每次都会变化,这里使用 hasChangedColumns 作为依赖 // 这里不能把 columnsSchema 作为依赖,因为其每次都会变化,这里使用 hasChangedColumns 作为依赖
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}), }),
[ [columnsSchema, field.value, field.address, collection, parentRecordData, schemaToolbarBigger],
hasChangedColumns,
schema,
field,
parentRecordData,
schemaInWhitelist,
token.paddingContentVerticalLG,
token.marginSM,
],
); );
const tableColumns = useMemo(() => { const tableColumns = useMemo(() => {

View File

@ -280,14 +280,11 @@ export interface DataBlockInitializerProps {
/** 如果只有一项数据表时,不显示 children 列表 */ /** 如果只有一项数据表时,不显示 children 列表 */
hideChildrenIfSingleCollection?: boolean; hideChildrenIfSingleCollection?: boolean;
items?: ReturnType<typeof useCollectionDataSourceItems>[]; items?: ReturnType<typeof useCollectionDataSourceItems>[];
/**
* Others
*/
fromOthersInPopup?: boolean;
/** /**
* Other records * Other records
*/ */
hideOtherRecordsInPopup?: boolean; hideOtherRecordsInPopup?: boolean;
onClick?: (args: any) => void;
} }
export const DataBlockInitializer = (props: DataBlockInitializerProps) => { export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
@ -305,14 +302,20 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
hideChildrenIfSingleCollection, hideChildrenIfSingleCollection,
filterDataSource, filterDataSource,
items: itemsFromProps, items: itemsFromProps,
fromOthersInPopup,
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
onClick: propsOnClick,
} = props; } = props;
const { insert, setVisible } = useSchemaInitializer(); const { insert, setVisible } = useSchemaInitializer();
const compile = useCompile(); const compile = useCompile();
const { getTemplateSchemaByMode } = useSchemaTemplateManager(); const { getTemplateSchemaByMode } = useSchemaTemplateManager();
const onClick = useCallback( const onClick = useCallback(
async ({ item }) => { async (options) => {
const { item, fromOthersInPopup } = options;
if (propsOnClick) {
return propsOnClick(options);
}
if (item.template) { if (item.template) {
const s = await getTemplateSchemaByMode(item); const s = await getTemplateSchemaByMode(item);
templateWrap ? insert(templateWrap(s, { item, fromOthersInPopup })) : insert(s); templateWrap ? insert(templateWrap(s, { item, fromOthersInPopup })) : insert(s);
@ -323,7 +326,7 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
} }
setVisible(false); setVisible(false);
}, },
[fromOthersInPopup, getTemplateSchemaByMode, insert, onCreateBlockSchema, setVisible, templateWrap], [getTemplateSchemaByMode, insert, onCreateBlockSchema, propsOnClick, setVisible, templateWrap],
); );
const items = const items =
itemsFromProps || itemsFromProps ||
@ -336,6 +339,7 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
showAssociationFields, showAssociationFields,
dataBlockInitializerProps: props, dataBlockInitializerProps: props,
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
onClick,
}); });
const getMenuItems = useGetSchemaInitializerMenuItems(onClick); const getMenuItems = useGetSchemaInitializerMenuItems(onClick);
const childItems = useMemo(() => { const childItems = useMemo(() => {

View File

@ -79,10 +79,9 @@ export function useCreateAssociationFormBlock() {
const templateWrap = useCallback( const templateWrap = useCallback(
(templateSchema, { item }) => { (templateSchema, { item }) => {
const field = item.associationField; if (item.template.componentName === 'FormItem' && item.associationField) {
const collection = getCollection(field.target); const field = item.associationField;
const collection = getCollection(field.target);
if (item.template.componentName === 'FormItem') {
const blockSchema = createCreateFormBlockUISchema({ const blockSchema = createCreateFormBlockUISchema({
dataSource: collection.dataSource, dataSource: collection.dataSource,
association: `${field.collectionName}.${field.name}`, association: `${field.collectionName}.${field.name}`,

View File

@ -13,13 +13,13 @@ import {
useDataSourceKey, useDataSourceKey,
useFormBlockContext, useFormBlockContext,
} from '../'; } from '../';
import { useFormActiveFields } from '../block-provider/hooks/useFormActiveFields';
import { FieldOptions, useCollectionManager_deprecated, useCollection_deprecated } from '../collection-manager'; import { FieldOptions, useCollectionManager_deprecated, useCollection_deprecated } from '../collection-manager';
import { Collection, CollectionFieldOptions } from '../data-source/collection/Collection'; import { Collection, CollectionFieldOptions } from '../data-source/collection/Collection';
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider'; import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
import { isAssocField } from '../filter-provider/utils'; import { isAssocField } from '../filter-provider/utils';
import { useActionContext, useCompile, useDesignable } from '../schema-component'; import { useActionContext, useCompile, useDesignable } from '../schema-component';
import { useSchemaTemplateManager } from '../schema-templates'; import { useSchemaTemplateManager } from '../schema-templates';
import { useFormActiveFields } from '../block-provider/hooks/useFormActiveFields';
export const itemsMerge = (items1) => { export const itemsMerge = (items1) => {
return items1; return items1;
}; };
@ -842,6 +842,7 @@ export const useCollectionDataSourceItems = ({
filterDataSource, filterDataSource,
dataBlockInitializerProps, dataBlockInitializerProps,
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
onClick,
}: { }: {
componentName; componentName;
filter?: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean; filter?: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
@ -853,6 +854,7 @@ export const useCollectionDataSourceItems = ({
* Other records * Other records
*/ */
hideOtherRecordsInPopup?: boolean; hideOtherRecordsInPopup?: boolean;
onClick?: (options: any) => void;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const dm = useDataSourceManager(); const dm = useDataSourceManager();
@ -956,11 +958,13 @@ export const useCollectionDataSourceItems = ({
onlyCurrentDataSource: false, onlyCurrentDataSource: false,
hideChildrenIfSingleCollection: false, hideChildrenIfSingleCollection: false,
onCreateBlockSchema: dataBlockInitializerProps.onCreateBlockSchema, onCreateBlockSchema: dataBlockInitializerProps.onCreateBlockSchema,
fromOthersInPopup: true,
componentType: componentTypeMap[componentName] || componentName, componentType: componentTypeMap[componentName] || componentName,
filter({ collection: c, associationField }) { filter({ collection: c, associationField }) {
return true; return true;
}, },
onClick(options) {
onClick({ ...options, fromOthersInPopup: true });
},
}, },
}; };
@ -1008,6 +1012,7 @@ export const useCollectionDataSourceItems = ({
dataBlockInitializerProps, dataBlockInitializerProps,
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
noAssociationMenu, noAssociationMenu,
onClick,
t, t,
]); ]);
} }
@ -1608,7 +1613,6 @@ function useAssociationFields({
}; };
}); });
}, [ }, [
cm,
collection.fields, collection.fields,
compile, compile,
componentName, componentName,

View File

@ -65,7 +65,6 @@ import {
useGlobalTheme, useGlobalTheme,
useLinkageCollectionFilterOptions, useLinkageCollectionFilterOptions,
useRecord, useRecord,
useSchemaSettingsItem,
useSortFields, useSortFields,
} from '..'; } from '..';
import { import {
@ -947,6 +946,8 @@ export interface SchemaSettingsModalItemProps {
asyncGetInitialValues?: () => Promise<any>; asyncGetInitialValues?: () => Promise<any>;
eventKey?: string; eventKey?: string;
hide?: boolean; hide?: boolean;
/** 上下文中不需要当前记录 */
noRecord?: boolean;
} }
export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props) => { export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props) => {
const { const {
@ -959,6 +960,7 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
asyncGetInitialValues, asyncGetInitialValues,
initialValues, initialValues,
width = 'fit-content', width = 'fit-content',
noRecord = false,
...others ...others
} = props; } = props;
const options = useContext(SchemaOptionsContext); const options = useContext(SchemaOptionsContext);
@ -1000,7 +1002,7 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
value={popupRecordVariable.value} value={popupRecordVariable.value}
collection={popupRecordVariable.collection} collection={popupRecordVariable.collection}
> >
<CollectionRecordProvider record={record}> <CollectionRecordProvider record={noRecord ? null : record}>
<FormBlockContext.Provider value={formCtx}> <FormBlockContext.Provider value={formCtx}>
<SubFormProvider value={{ value: subFormValue, collection: subFormCollection }}> <SubFormProvider value={{ value: subFormValue, collection: subFormCollection }}>
<FormActiveFieldsProvider <FormActiveFieldsProvider

View File

@ -7,10 +7,10 @@ import { useCollectionFilterOptionsV2 } from '../collection-manager/action-hooks
import { FlagProvider, useFlag } from '../flag-provider'; import { FlagProvider, useFlag } from '../flag-provider';
import { DynamicComponentProps } from '../schema-component/antd/filter/DynamicComponent'; import { DynamicComponentProps } from '../schema-component/antd/filter/DynamicComponent';
import { useLocalVariables, useVariables } from '../variables'; import { useLocalVariables, useVariables } from '../variables';
import { SchemaSettingsModalItem } from './SchemaSettings';
import { VariableInput, getShouldChange } from './VariableInput/VariableInput'; import { VariableInput, getShouldChange } from './VariableInput/VariableInput';
import { BaseVariableProvider, IsDisabledParams } from './VariableInput/hooks/useBaseVariable'; import { BaseVariableProvider, IsDisabledParams } from './VariableInput/hooks/useBaseVariable';
import { DataScopeProps } from './types'; import { DataScopeProps } from './types';
import { SchemaSettingsModalItem } from './SchemaSettings';
export const SchemaSettingsDataScope: FC<DataScopeProps> = function DataScopeConfigure(props) { export const SchemaSettingsDataScope: FC<DataScopeProps> = function DataScopeConfigure(props) {
const { t } = useTranslation(); const { t } = useTranslation();
@ -76,6 +76,7 @@ export const SchemaSettingsDataScope: FC<DataScopeProps> = function DataScopeCon
initialValues={{ filter: props.defaultFilter }} initialValues={{ filter: props.defaultFilter }}
schema={getSchema as () => ISchema} schema={getSchema as () => ISchema}
onSubmit={props.onSubmit} onSubmit={props.onSubmit}
noRecord={props.noRecord}
/> />
); );
}; };

View File

@ -23,10 +23,7 @@ import {
detailsBlockSettings, detailsBlockSettings,
singleDataDetailsBlockSettings, singleDataDetailsBlockSettings,
} from '../modules/blocks/data-blocks/details-single/detailsBlockSettings'; } from '../modules/blocks/data-blocks/details-single/detailsBlockSettings';
import { import { createFormBlockSettings } from '../modules/blocks/data-blocks/form/createFormBlockSettings';
createFormBlockSettings,
creationFormBlockSettings,
} from '../modules/blocks/data-blocks/form/createFormBlockSettings';
import { editFormBlockSettings } from '../modules/blocks/data-blocks/form/editFormBlockSettings'; import { editFormBlockSettings } from '../modules/blocks/data-blocks/form/editFormBlockSettings';
import { fieldSettingsFormItem } from '../modules/blocks/data-blocks/form/fieldSettingsFormItem'; import { fieldSettingsFormItem } from '../modules/blocks/data-blocks/form/fieldSettingsFormItem';
import { gridCardBlockSettings } from '../modules/blocks/data-blocks/grid-card/gridCardBlockSettings'; import { gridCardBlockSettings } from '../modules/blocks/data-blocks/grid-card/gridCardBlockSettings';
@ -43,6 +40,7 @@ import { cascadeSelectComponentFieldSettings } from '../modules/fields/component
import { datePickerComponentFieldSettings } from '../modules/fields/component/DatePicker/datePickerComponentFieldSettings'; import { datePickerComponentFieldSettings } from '../modules/fields/component/DatePicker/datePickerComponentFieldSettings';
import { fileManagerComponentFieldSettings } from '../modules/fields/component/FileManager/fileManagerComponentFieldSettings'; import { fileManagerComponentFieldSettings } from '../modules/fields/component/FileManager/fileManagerComponentFieldSettings';
import { uploadAttachmentComponentFieldSettings } from '../modules/fields/component/FileManager/uploadAttachmentComponentFieldSettings'; import { uploadAttachmentComponentFieldSettings } from '../modules/fields/component/FileManager/uploadAttachmentComponentFieldSettings';
import { inputNumberComponentFieldSettings } from '../modules/fields/component/InputNumber/inputNumberComponentFieldSettings';
import { subformComponentFieldSettings } from '../modules/fields/component/Nester/subformComponentFieldSettings'; import { subformComponentFieldSettings } from '../modules/fields/component/Nester/subformComponentFieldSettings';
import { recordPickerComponentFieldSettings } from '../modules/fields/component/Picker/recordPickerComponentFieldSettings'; import { recordPickerComponentFieldSettings } from '../modules/fields/component/Picker/recordPickerComponentFieldSettings';
import { subformPopoverComponentFieldSettings } from '../modules/fields/component/PopoverNester/subformPopoverComponentFieldSettings'; import { subformPopoverComponentFieldSettings } from '../modules/fields/component/PopoverNester/subformPopoverComponentFieldSettings';
@ -50,13 +48,11 @@ import { selectComponentFieldSettings } from '../modules/fields/component/Select
import { subTablePopoverComponentFieldSettings } from '../modules/fields/component/SubTable/subTablePopoverComponentFieldSettings'; import { subTablePopoverComponentFieldSettings } from '../modules/fields/component/SubTable/subTablePopoverComponentFieldSettings';
import { tagComponentFieldSettings } from '../modules/fields/component/Tag/tagComponentFieldSettings'; import { tagComponentFieldSettings } from '../modules/fields/component/Tag/tagComponentFieldSettings';
import { unixTimestampComponentFieldSettings } from '../modules/fields/component/UnixTimestamp/unixTimestampComponentFieldSettings'; import { unixTimestampComponentFieldSettings } from '../modules/fields/component/UnixTimestamp/unixTimestampComponentFieldSettings';
import { inputNumberComponentFieldSettings } from '../modules/fields/component/InputNumber/inputNumberComponentFieldSettings';
export class SchemaSettingsPlugin extends Plugin { export class SchemaSettingsPlugin extends Plugin {
async load() { async load() {
// block settings // block settings
this.schemaSettingsManager.add(tableBlockSettings); this.schemaSettingsManager.add(tableBlockSettings);
this.schemaSettingsManager.add(creationFormBlockSettings);
this.schemaSettingsManager.add(createFormBlockSettings); this.schemaSettingsManager.add(createFormBlockSettings);
this.schemaSettingsManager.add(editFormBlockSettings); this.schemaSettingsManager.add(editFormBlockSettings);
this.schemaSettingsManager.add(filterFormBlockSettings); this.schemaSettingsManager.add(filterFormBlockSettings);

View File

@ -1,9 +1,10 @@
import { Schema } from '@formily/json-schema'; import { Schema } from '@formily/json-schema';
import _ from 'lodash'; import _ from 'lodash';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
import { useBaseVariable } from './useBaseVariable';
import { useFormBlockContext } from '../../../block-provider/FormBlockProvider'; import { useFormBlockContext } from '../../../block-provider/FormBlockProvider';
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
import { useCollection, useCollectionRecordData } from '../../../data-source';
import { useBaseVariable } from './useBaseVariable';
interface Props { interface Props {
collectionField?: CollectionFieldOptions_deprecated; collectionField?: CollectionFieldOptions_deprecated;
@ -45,13 +46,16 @@ export const useRecordVariable = (props: Props) => {
*/ */
export const useCurrentRecordVariable = (props: Props = {}) => { export const useCurrentRecordVariable = (props: Props = {}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const collection = useCollection();
const recordData = useCollectionRecordData();
const { formRecord, collectionName } = useFormBlockContext(); const { formRecord, collectionName } = useFormBlockContext();
const realCollectionName = formRecord?.data ? collectionName : collection?.name;
const currentRecordSettings = useBaseVariable({ const currentRecordSettings = useBaseVariable({
collectionField: props.collectionField, collectionField: props.collectionField,
uiSchema: props.schema, uiSchema: props.schema,
name: '$nRecord', name: '$nRecord',
title: t('Current record'), title: t('Current record'),
collectionName: collectionName, collectionName: realCollectionName,
noDisabled: props.noDisabled, noDisabled: props.noDisabled,
targetFieldSchema: props.targetFieldSchema, targetFieldSchema: props.targetFieldSchema,
}); });
@ -60,10 +64,10 @@ export const useCurrentRecordVariable = (props: Props = {}) => {
/** 变量配置 */ /** 变量配置 */
currentRecordSettings, currentRecordSettings,
/** 变量值 */ /** 变量值 */
currentRecordCtx: formRecord?.data, currentRecordCtx: formRecord?.data || recordData,
/** 用于判断是否需要显示配置项 */ /** 用于判断是否需要显示配置项 */
shouldDisplayCurrentRecord: !formRecord?.isNew && !_.isEmpty(formRecord?.data), shouldDisplayCurrentRecord: !_.isEmpty(_.omit(recordData, ['__collectionName', '__parent'])) || !!formRecord?.data,
/** 当前记录对应的 collection name */ /** 当前记录对应的 collection name */
collectionName, collectionName: realCollectionName,
}; };
}; };

View File

@ -29,4 +29,6 @@ export interface DataScopeProps {
* *
*/ */
form: Form; form: Form;
/** 上下文中不需要当前记录 */
noRecord?: boolean;
} }

View File

@ -12,5 +12,7 @@ export function generateNTemplate(key: string) {
} }
export function useTranslation() { export function useTranslation() {
return useT(NAMESPACE); return useT([NAMESPACE, 'client'], {
nsMode: 'fallback',
});
} }

View File

@ -15,7 +15,7 @@ export function generateNTemplate(key: string) {
} }
export function useKanbanTranslation() { export function useKanbanTranslation() {
return useTranslation(NAMESPACE, { return useTranslation([NAMESPACE, 'client'], {
nsMode: 'fallback', nsMode: 'fallback',
}); });
} }

View File

@ -15,7 +15,7 @@ export function generateNTemplate(key: string) {
} }
export function useMapTranslation() { export function useMapTranslation() {
return useTranslation(NAMESPACE, { return useTranslation([NAMESPACE, 'client'], {
nsMode: 'fallback', nsMode: 'fallback',
}); });
} }