fix: popup record (#1116)

Reviewed-on: daoyoucloud/tachybase#1116
This commit is contained in:
sealday 2024-06-05 11:34:40 +08:00
parent 171d56aaff
commit 72231f8bf1
13 changed files with 211 additions and 75 deletions

View File

@ -270,7 +270,7 @@
"Sub-table": "Sub-table",
"Sub-details": "Sub-details",
"Sub-form(Popover)": "Sub-form(Popover)",
"Sub-form(Drawer)": "Sub-form(Drawer)",
"Subtable: Drawer": "Subtable: Drawer",
"System info": "System info",
"Created at": "Created at",
"Last updated at": "Last updated at",
@ -627,6 +627,7 @@
"Current user": "Current user",
"Current role": "Current role",
"Current record": "Current record",
"Current popup record": "Current popup record",
"Associated records": "Associated records",
"Parent record": "Parent record",
"Current time": "Current time",

View File

@ -334,7 +334,7 @@
"Subtable": "子表格",
"Sub-form": "子表单",
"Sub-form(Popover)": "子表单(弹窗)",
"Sub-form(Drawer)": "子表单(抽屉)",
"Subtable: Drawer": "子表格:抽屉",
"Sub-details": "子详情",
"Record picker": "数据选择器",
"Toggles the subfield mode": "切换子字段模式",
@ -599,6 +599,7 @@
"Single select and radio fields can be used as the grouping field": "数据表的单选字段可以作为分组字段",
"Tab name": "标签名称",
"Current record blocks": "当前数据区块",
"Current popup record": "当前弹窗记录",
"Popup message": "弹窗提示消息",
"Delete role": "删除角色",
"Role display name": "角色名称",

View File

@ -0,0 +1,29 @@
import React, { createContext } from 'react';
import { Collection } from '../../data-source';
interface DeclareVariableProps {
/* 变量名称 */
name: string;
/** 变量值 */
value: any;
/** 显示给用户的名字 */
title?: string;
/** 变量对应的数据表信息 */
collection?: Collection;
children?: React.ReactNode;
}
export const DeclareVariableContext = createContext<DeclareVariableProps>(null);
/**
*
*/
export const DeclareVariable = (props: DeclareVariableProps) => {
const { name, value, title, collection } = props;
return (
<DeclareVariableContext.Provider value={{ name, value, title, collection }}>
{props.children}
</DeclareVariableContext.Provider>
);
};

View File

@ -0,0 +1,16 @@
import { useContext } from 'react';
import { DeclareVariableContext } from './DeclareVariable';
/**
*
* @param variableName
* @returns
*/
export const useVariable = (variableName: string) => {
const { name, value, title, collection } = useContext(DeclareVariableContext) || {};
if (name === variableName) {
return { value, title, collection };
}
return {};
};

View File

@ -1,9 +1,13 @@
import React, { Fragment, useRef, useState } from 'react';
import { observer, RecursionField, toArr, useField, useFieldSchema } from '@tachybase/schema';
import { useTranslation } from 'react-i18next';
import { useDesignable } from '../../';
import { BlockAssociationContext, WithoutTableFieldResource } from '../../../block-provider';
import { CollectionProvider_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
import { Collection } from '../../../data-source';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { RecordProvider, useRecord } from '../../../record-provider';
import { FormProvider } from '../../core';
import { useCompile } from '../../hooks';
@ -29,6 +33,8 @@ export function isObject(value) {
}
export const ReadPrettyInternalViewer = observer(
(props: any) => {
const { t } = useTranslation();
const fieldSchema = useFieldSchema();
const recordCtx = useRecord();
const { getCollection } = useCollectionManager_deprecated();
@ -97,18 +103,25 @@ export const ReadPrettyInternalViewer = observer(
);
});
const renderWithoutTableFieldResourceProvider = () => (
<WithoutTableFieldResource.Provider value={true}>
<FormProvider>
<RecursionField
schema={fieldSchema}
onlyRenderProperties
basePath={field.address}
filterProperties={(s) => {
return s['x-component'] === 'AssociationField.Viewer';
}}
/>
</FormProvider>
</WithoutTableFieldResource.Provider>
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={record}
collection={targetCollection as Collection}
>
<WithoutTableFieldResource.Provider value={true}>
<FormProvider>
<RecursionField
schema={fieldSchema}
onlyRenderProperties
basePath={field.address}
filterProperties={(s) => {
return s['x-component'] === 'AssociationField.Viewer';
}}
/>
</FormProvider>
</WithoutTableFieldResource.Provider>
</DeclareVariable>
);
const renderRecordProvider = () => {

View File

@ -35,6 +35,7 @@ import {
} from '../../../';
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
import { isNewRecord, markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { SubFormProvider } from '../association-field/hooks';
import { ColumnFieldProvider } from './components/ColumnFieldProvider';
import { useStyles } from './Table.styles';
@ -46,7 +47,7 @@ const useArrayField = (props) => {
};
const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => {
const { token } = useToken();
const { t } = useTranslation();
const { styles } = useStyles();
const field = useArrayField(props);
const schema = useFieldSchema();
@ -81,21 +82,28 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
render: (v, record) => {
const index = field.value?.indexOf(record);
return (
<SubFormProvider value={{ value: record, collection }}>
<RecordIndexProvider index={record.__index || index}>
<RecordProvider isNew={isNewRecord(record)} record={record} parent={parentRecordData}>
<ColumnFieldProvider schema={s} basePath={field.address.concat(record.__index || index)}>
<span role="button" className={styles.toolbar}>
<RecursionField
basePath={field.address.concat(record.__index || index)}
schema={s}
onlyRenderProperties
/>
</span>
</ColumnFieldProvider>
</RecordProvider>
</RecordIndexProvider>
</SubFormProvider>
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={record}
collection={collection}
>
<SubFormProvider value={{ value: record, collection }}>
<RecordIndexProvider index={record.__index || index}>
<RecordProvider isNew={isNewRecord(record)} record={record} parent={parentRecordData}>
<ColumnFieldProvider schema={s} basePath={field.address.concat(record.__index || index)}>
<span role="button" className={styles.toolbar}>
<RecursionField
basePath={field.address.concat(record.__index || index)}
schema={s}
onlyRenderProperties
/>
</span>
</ColumnFieldProvider>
</RecordProvider>
</RecordIndexProvider>
</SubFormProvider>
</DeclareVariable>
);
},
} as TableColumnProps<any>;

View File

@ -1,6 +1,8 @@
import { useField, useFieldSchema, useForm } from '@tachybase/schema';
import { useMemo } from 'react';
import { useField, useFieldSchema, useForm } from '@tachybase/schema';
import { useTranslation } from 'react-i18next';
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../collection-manager';
export const useFieldModeOptions = (props?) => {
@ -55,7 +57,7 @@ export const useFieldModeOptions = (props?) => {
{ label: t('Cascade Select'), value: 'CascadeSelect' },
!isTableField && { label: t('Sub-form'), value: 'Nester' },
{ label: t('Sub-form(Popover)'), value: 'PopoverNester' },
{ label: t('Sub-form(Drawer)'), value: 'DrawerSubTable' },
{ label: t('Subtable: Drawer'), value: 'DrawerSubTable' },
{ label: t('Cascader'), value: 'Cascader' },
];
}
@ -73,7 +75,7 @@ export const useFieldModeOptions = (props?) => {
{ label: t('Record picker'), value: 'Picker' },
!isTableField && { label: t('Sub-form'), value: 'Nester' },
{ label: t('Sub-form(Popover)'), value: 'PopoverNester' },
{ label: t('Sub-form(Drawer)'), value: 'DrawerSubTable' },
{ label: t('Subtable: Drawer'), value: 'DrawerSubTable' },
!isTableField && { label: t('Sub-table'), value: 'SubTable' },
];
case 'm2m':
@ -90,7 +92,7 @@ export const useFieldModeOptions = (props?) => {
!isTableField && { label: t('Sub-table'), value: 'SubTable' },
!isTableField && { label: t('Sub-form'), value: 'Nester' },
{ label: t('Sub-form(Popover)'), value: 'PopoverNester' },
{ label: t('Sub-form(Drawer)'), value: 'DrawerSubTable' },
{ label: t('Subtable: Drawer'), value: 'DrawerSubTable' },
];
case 'm2o':
case 'linkTo':
@ -105,7 +107,7 @@ export const useFieldModeOptions = (props?) => {
{ label: t('Record picker'), value: 'Picker' },
!isTableField && { label: t('Sub-form'), value: 'Nester' },
{ label: t('Sub-form(Popover)'), value: 'PopoverNester' },
{ label: t('Sub-form(Drawer)'), value: 'DrawerSubTable' },
{ label: t('Subtable: Drawer'), value: 'DrawerSubTable' },
{ label: t('Cascader'), value: 'Cascader' },
];
@ -121,7 +123,7 @@ export const useFieldModeOptions = (props?) => {
{ label: t('Record picker'), value: 'Picker' },
!isTableField && { label: t('Sub-form'), value: 'Nester' },
{ label: t('Sub-form(Popover)'), value: 'PopoverNester' },
{ label: t('Sub-form(Drawer)'), value: 'DrawerSubTable' },
{ label: t('Subtable: Drawer'), value: 'DrawerSubTable' },
];
}
}, [t, collectionField?.interface, label]);

View File

@ -6,7 +6,6 @@ import React, {
useContext,
useEffect,
useMemo,
// @ts-ignore
useTransition as useReactTransition,
useState,
} from 'react';
@ -107,6 +106,8 @@ import {
} from '../filter-provider/utils';
import { FlagProvider } from '../flag-provider';
import { useCollectMenuItem, useCollectMenuItems, useMenuItem } from '../hooks/useMenuItem';
import { DeclareVariable } from '../modules/variable/DeclareVariable';
import { useVariable } from '../modules/variable/useVariable';
import { SubFormProvider, useSubFormValue } from '../schema-component/antd/association-field/hooks';
import { getTargetKey } from '../schema-component/antd/association-filter/utilts';
import { useSchemaTemplateManager } from '../schema-templates';
@ -1024,6 +1025,8 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
// 解决变量`当前对象`值在弹窗中丢失的问题
const { formValue: subFormValue, collection: subFormCollection } = useSubFormValue();
// 解决变量`$nPopupRecord`值在弹窗中丢失的问题
const popupRecordVariable = useVariable('$nPopupRecord');
if (hidden) {
return null;
@ -1039,40 +1042,47 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
{ title: schema.title || title, width },
() => {
return (
<ApplicationContext.Provider value={app}>
<CollectionRecordProvider record={record}>
<FormBlockContext.Provider value={formCtx}>
<SubFormProvider value={{ value: subFormValue, collection: subFormCollection }}>
<FormActiveFieldsProvider
name="form"
getActiveFieldsName={upLevelActiveFields?.getActiveFieldsName}
>
<Router location={location} navigator={null}>
<BlockRequestContext_deprecated.Provider value={ctx}>
<DataSourceApplicationProvider dataSourceManager={dm} dataSource={dataSourceKey}>
<AssociationOrCollectionProvider
allowNull
collection={collection.name}
association={association}
>
<SchemaComponentOptions scope={options.scope} components={options.components}>
<FormLayout layout={'vertical'} className={styles.modal}>
<APIClientProvider apiClient={apiClient}>
<ConfigProvider locale={locale}>
<SchemaComponent components={components} scope={scope} schema={schema} />
</ConfigProvider>
</APIClientProvider>
</FormLayout>
</SchemaComponentOptions>
</AssociationOrCollectionProvider>
</DataSourceApplicationProvider>
</BlockRequestContext_deprecated.Provider>
</Router>
</FormActiveFieldsProvider>
</SubFormProvider>
</FormBlockContext.Provider>
</CollectionRecordProvider>
</ApplicationContext.Provider>
<DeclareVariable
name="$nPopupRecord"
title={popupRecordVariable.title}
value={popupRecordVariable.value}
collection={popupRecordVariable.collection}
>
<ApplicationContext.Provider value={app}>
<CollectionRecordProvider record={record}>
<FormBlockContext.Provider value={formCtx}>
<SubFormProvider value={{ value: subFormValue, collection: subFormCollection }}>
<FormActiveFieldsProvider
name="form"
getActiveFieldsName={upLevelActiveFields?.getActiveFieldsName}
>
<Router location={location} navigator={null}>
<BlockRequestContext_deprecated.Provider value={ctx}>
<DataSourceApplicationProvider dataSourceManager={dm} dataSource={dataSourceKey}>
<AssociationOrCollectionProvider
allowNull
collection={collection.name}
association={association}
>
<SchemaComponentOptions scope={options.scope} components={options.components}>
<FormLayout layout={'vertical'} className={styles.modal}>
<APIClientProvider apiClient={apiClient}>
<ConfigProvider locale={locale}>
<SchemaComponent components={components} scope={scope} schema={schema} />
</ConfigProvider>
</APIClientProvider>
</FormLayout>
</SchemaComponentOptions>
</AssociationOrCollectionProvider>
</DataSourceApplicationProvider>
</BlockRequestContext_deprecated.Provider>
</Router>
</FormActiveFieldsProvider>
</SubFormProvider>
</FormBlockContext.Provider>
</CollectionRecordProvider>
</ApplicationContext.Provider>
</DeclareVariable>
);
},
theme,

View File

@ -1,8 +1,10 @@
import { Schema } from '@tachybase/schema';
import { useTranslation } from 'react-i18next';
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
import { useParentCollection } from '../../../data-source/collection/AssociationProvider';
import { useCollectionRecord } from '../../../data-source/collection-record/CollectionRecordProvider';
import { useParentCollection } from '../../../data-source/collection/AssociationProvider';
import { useFlag } from '../../../flag-provider/hooks/useFlag';
import { useBaseVariable } from './useBaseVariable';

View File

@ -0,0 +1,33 @@
import { useVariable } from '../../../modules/variable/useVariable';
import { useBaseVariable } from './useBaseVariable';
/**
* `Current popup record`
* @param props
* @returns
*/
export const usePopupVariable = (props: any = {}) => {
const { value, title, collection } = useVariable('$nPopupRecord');
const settings = useBaseVariable({
collectionField: props.collectionField,
uiSchema: props.schema,
name: '$nPopupRecord',
title,
collectionName: collection?.name,
noDisabled: props.noDisabled,
targetFieldSchema: props.targetFieldSchema,
dataSource: collection?.dataSource,
});
return {
/** 变量配置 */
settings,
/** 变量值 */
popupRecordCtx: value,
/** 用于判断是否需要显示配置项 */
shouldDisplayPopupRecord: !!value,
/** 当前记录对应的 collection name */
collectionName: collection?.name,
dataSource: collection?.dataSource,
};
};

View File

@ -1,12 +1,13 @@
import { Form } from '@tachybase/schema';
import { ISchema, Schema } from '@tachybase/schema';
import { useMemo } from 'react';
import { CollectionFieldOptions_deprecated, useCollection_deprecated } from '../../../collection-manager';
import { Form, ISchema, Schema } from '@tachybase/schema';
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
import { useBlockCollection } from './useBlockCollection';
import { useDatetimeVariable } from './useDateVariable';
import { useCurrentFormVariable } from './useFormVariable';
import { useCurrentObjectVariable } from './useIterationVariable';
import { useCurrentParentRecordVariable } from './useParentRecordVariable';
import { usePopupVariable } from './usePopupVariable';
import { useCurrentRecordVariable } from './useRecordVariable';
import { useCurrentRoleVariable } from './useRoleVariable';
import { useCurrentUserVariable } from './useUserVariable';
@ -81,6 +82,12 @@ export const useVariableOptions = ({
noDisabled,
targetFieldSchema,
});
const { settings: popupRecordSettings, shouldDisplayPopupRecord } = usePopupVariable({
schema: uiSchema,
collectionField,
noDisabled,
targetFieldSchema,
});
const { currentParentRecordSettings, shouldDisplayCurrentParentRecord } = useCurrentParentRecordVariable({
schema: uiSchema,
collectionName: blockParentCollectionName,
@ -98,6 +105,7 @@ export const useVariableOptions = ({
shouldDisplayCurrentObject && currentObjectSettings,
shouldDisplayCurrentRecord && currentRecordSettings,
shouldDisplayCurrentParentRecord && currentParentRecordSettings,
shouldDisplayPopupRecord && popupRecordSettings,
].filter(Boolean);
}, [
currentUserSettings,
@ -111,5 +119,7 @@ export const useVariableOptions = ({
currentRecordSettings,
shouldDisplayCurrentParentRecord,
currentParentRecordSettings,
shouldDisplayPopupRecord,
popupRecordSettings,
]);
};

View File

@ -7,6 +7,7 @@ import { useDatetimeVariable } from '../../schema-settings/VariableInput/hooks/u
import { useCurrentFormVariable } from '../../schema-settings/VariableInput/hooks/useFormVariable';
import { useCurrentObjectVariable } from '../../schema-settings/VariableInput/hooks/useIterationVariable';
import { useCurrentParentRecordVariable } from '../../schema-settings/VariableInput/hooks/useParentRecordVariable';
import { usePopupVariable } from '../../schema-settings/VariableInput/hooks/usePopupVariable';
import { useCurrentRecordVariable } from '../../schema-settings/VariableInput/hooks/useRecordVariable';
import { VariableOption } from '../types';
@ -18,6 +19,7 @@ interface Props {
const useLocalVariables = (props?: Props) => {
const { currentObjectCtx, shouldDisplayCurrentObject } = useCurrentObjectVariable();
const { currentRecordCtx, collectionName: collectionNameOfRecord } = useCurrentRecordVariable();
const { popupRecordCtx, collectionName: collectionNameOfPopupRecord } = usePopupVariable();
const { currentParentRecordCtx, collectionName: collectionNameOfParentRecord } = useCurrentParentRecordVariable();
const { datetimeCtx } = useDatetimeVariable();
const { currentFormCtx } = useCurrentFormVariable({ form: props?.currentForm });
@ -68,6 +70,11 @@ const useLocalVariables = (props?: Props) => {
ctx: currentParentRecordCtx,
collectionName: collectionNameOfParentRecord,
},
{
name: '$nPopupRecord',
ctx: popupRecordCtx,
collectionName: collectionNameOfPopupRecord,
},
{
name: '$nForm',
ctx: currentFormCtx,
@ -99,6 +106,8 @@ const useLocalVariables = (props?: Props) => {
currentFormCtx,
currentParentRecordCtx,
collectionNameOfParentRecord,
popupRecordCtx,
collectionNameOfPopupRecord,
datetimeCtx,
shouldDisplayCurrentObject,
currentObjectCtx,

View File

@ -78,4 +78,6 @@ export interface VariableOption {
};
/** 变量所对应的数据表的名称 */
collectionName?: string;
/** 数据表所对应的数据源 */
dataSource?: string;
}