feat(variable): add current parent record (#2857)
* feat(variable): add currentParentRecord * chore: resolve table actions * chore: get collection name of parent * chore: table block and details block * chore: list block * chore: grid card block * chore: calendar * fix: bulk button * refactor: use useMemo * fix: fix form block
This commit is contained in:
parent
010c286f7c
commit
e05a30380a
@ -5,7 +5,7 @@ import { useRequest } from 'ahooks';
|
|||||||
import { Col, Row } from 'antd';
|
import { Col, Row } from 'antd';
|
||||||
import merge from 'deepmerge';
|
import merge from 'deepmerge';
|
||||||
import template from 'lodash/template';
|
import template from 'lodash/template';
|
||||||
import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
TableFieldResource,
|
TableFieldResource,
|
||||||
@ -285,7 +285,7 @@ export const RenderChildrenWithAssociationFilter: React.FC<any> = (props) => {
|
|||||||
export const BlockProvider = (props) => {
|
export const BlockProvider = (props) => {
|
||||||
const { collection, association } = props;
|
const { collection, association } = props;
|
||||||
const resource = useResource(props);
|
const resource = useResource(props);
|
||||||
const params = { ...props.params };
|
const params = useMemo(() => ({ ...props.params }), [props.params]);
|
||||||
const { appends, updateAssociationValues } = useAssociationNames();
|
const { appends, updateAssociationValues } = useAssociationNames();
|
||||||
if (!Object.keys(params).includes('appends')) {
|
if (!Object.keys(params).includes('appends')) {
|
||||||
params['appends'] = appends;
|
params['appends'] = appends;
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { ArrayField } from '@formily/core';
|
import { ArrayField } from '@formily/core';
|
||||||
import { useField } from '@formily/react';
|
import { useField } from '@formily/react';
|
||||||
|
import _ from 'lodash';
|
||||||
import React, { createContext, useContext, useEffect } from 'react';
|
import React, { createContext, useContext, useEffect } from 'react';
|
||||||
|
import { useRecord } from '../record-provider';
|
||||||
import { FixedBlockWrapper } from '../schema-component';
|
import { FixedBlockWrapper } from '../schema-component';
|
||||||
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
||||||
|
import { useParsedFilter } from './hooks';
|
||||||
|
|
||||||
export const CalendarBlockContext = createContext<any>({});
|
export const CalendarBlockContext = createContext<any>({});
|
||||||
|
|
||||||
@ -10,6 +13,18 @@ const InternalCalendarBlockProvider = (props) => {
|
|||||||
const { fieldNames, showLunar } = props;
|
const { fieldNames, showLunar } = props;
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { resource, service } = useBlockRequestContext();
|
const { resource, service } = useBlockRequestContext();
|
||||||
|
const record = useRecord();
|
||||||
|
|
||||||
|
const { filter } = useParsedFilter({
|
||||||
|
filterOption: service?.params?.[0]?.filter,
|
||||||
|
currentRecord: { __parent: record, __collectionName: props.collection },
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
if (!_.isEmpty(filter)) {
|
||||||
|
service?.run({ ...service?.params?.[0], filter });
|
||||||
|
}
|
||||||
|
}, [JSON.stringify(filter)]);
|
||||||
|
|
||||||
// if (service.loading) {
|
// if (service.loading) {
|
||||||
// return <Spin />;
|
// return <Spin />;
|
||||||
// }
|
// }
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { createForm } from '@formily/core';
|
import { createForm } from '@formily/core';
|
||||||
import { useField } from '@formily/react';
|
import { useField } from '@formily/react';
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
||||||
import { RecordProvider } from '../record-provider';
|
import { RecordProvider, useRecord } from '../record-provider';
|
||||||
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
||||||
|
import { useParsedFilter } from './hooks';
|
||||||
|
|
||||||
export const DetailsBlockContext = createContext<any>({});
|
export const DetailsBlockContext = createContext<any>({});
|
||||||
|
|
||||||
@ -18,21 +20,36 @@ const InternalDetailsBlockProvider = (props) => {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const { resource, service } = useBlockRequestContext();
|
const { resource, service } = useBlockRequestContext();
|
||||||
if (service.loading && !field.loaded) {
|
const record = useRecord();
|
||||||
return <Spin />;
|
const currentRecord = service?.data?.data?.[0] || {};
|
||||||
}
|
const detailsBLockValue = useMemo(() => {
|
||||||
field.loaded = true;
|
return {
|
||||||
return (
|
|
||||||
<DetailsBlockContext.Provider
|
|
||||||
value={{
|
|
||||||
action,
|
action,
|
||||||
form,
|
form,
|
||||||
field,
|
field,
|
||||||
service,
|
service,
|
||||||
resource,
|
resource,
|
||||||
}}
|
};
|
||||||
>
|
}, [action, field, form, resource, service]);
|
||||||
<RecordProvider record={service?.data?.data?.[0] || {}}>{props.children}</RecordProvider>
|
|
||||||
|
const { filter } = useParsedFilter({
|
||||||
|
filterOption: service?.params?.[0]?.filter,
|
||||||
|
currentRecord: { ...currentRecord, __parent: record, __collectionName: props.collection },
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
if (!_.isEmpty(filter)) {
|
||||||
|
service?.run({ ...service?.params?.[0], filter });
|
||||||
|
}
|
||||||
|
}, [JSON.stringify(filter)]);
|
||||||
|
|
||||||
|
if (service.loading && !field.loaded) {
|
||||||
|
return <Spin />;
|
||||||
|
}
|
||||||
|
field.loaded = true;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DetailsBlockContext.Provider value={detailsBLockValue}>
|
||||||
|
<RecordProvider record={currentRecord}>{props.children}</RecordProvider>
|
||||||
</DetailsBlockContext.Provider>
|
</DetailsBlockContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -53,9 +70,12 @@ export const useDetailsBlockProps = () => {
|
|||||||
const ctx = useDetailsBlockContext();
|
const ctx = useDetailsBlockContext();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ctx.service.loading) {
|
if (!ctx.service.loading) {
|
||||||
ctx.form.reset().then(() => {
|
ctx.form
|
||||||
|
.reset()
|
||||||
|
.then(() => {
|
||||||
ctx.form.setValues(ctx.service?.data?.data?.[0] || {});
|
ctx.form.setValues(ctx.service?.data?.data?.[0] || {});
|
||||||
});
|
})
|
||||||
|
.catch(console.error);
|
||||||
}
|
}
|
||||||
}, [ctx.service.loading]);
|
}, [ctx.service.loading]);
|
||||||
return {
|
return {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { createForm } from '@formily/core';
|
import { createForm } from '@formily/core';
|
||||||
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import { isEmpty } from 'lodash';
|
import _, { isEmpty } from 'lodash';
|
||||||
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
||||||
import { useCollection } from '../collection-manager';
|
import { useCollection } from '../collection-manager';
|
||||||
import { RecordProvider, useRecord } from '../record-provider';
|
import { RecordProvider, useRecord } from '../record-provider';
|
||||||
@ -13,7 +13,7 @@ import { FormActiveFieldsProvider } from './hooks';
|
|||||||
export const FormBlockContext = createContext<any>({});
|
export const FormBlockContext = createContext<any>({});
|
||||||
|
|
||||||
const InternalFormBlockProvider = (props) => {
|
const InternalFormBlockProvider = (props) => {
|
||||||
const { action, readPretty, params } = props;
|
const { action, readPretty, params, association } = props;
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const form = useMemo(
|
const form = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -25,13 +25,8 @@ const InternalFormBlockProvider = (props) => {
|
|||||||
const { resource, service, updateAssociationValues } = useBlockRequestContext();
|
const { resource, service, updateAssociationValues } = useBlockRequestContext();
|
||||||
const formBlockRef = useRef();
|
const formBlockRef = useRef();
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
if (service.loading && Object.keys(form?.initialValues)?.length === 0 && action) {
|
const formBlockValue = useMemo(() => {
|
||||||
return <Spin />;
|
return {
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormBlockContext.Provider
|
|
||||||
value={{
|
|
||||||
params,
|
params,
|
||||||
action,
|
action,
|
||||||
form,
|
form,
|
||||||
@ -42,21 +37,39 @@ const InternalFormBlockProvider = (props) => {
|
|||||||
resource,
|
resource,
|
||||||
updateAssociationValues,
|
updateAssociationValues,
|
||||||
formBlockRef,
|
formBlockRef,
|
||||||
}}
|
};
|
||||||
>
|
}, [action, field, form, params, resource, service, updateAssociationValues]);
|
||||||
{readPretty ? (
|
|
||||||
<RecordProvider parent={isEmpty(record?.__parent) ? record : record?.__parent} record={service?.data?.data}>
|
if (service.loading && Object.keys(form?.initialValues)?.length === 0 && action) {
|
||||||
|
return <Spin />;
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = (
|
||||||
<div ref={formBlockRef}>
|
<div ref={formBlockRef}>
|
||||||
<RenderChildrenWithDataTemplates form={form} />
|
<RenderChildrenWithDataTemplates form={form} />
|
||||||
</div>
|
</div>
|
||||||
</RecordProvider>
|
|
||||||
) : (
|
|
||||||
<div ref={formBlockRef}>
|
|
||||||
<RenderChildrenWithDataTemplates form={form} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</FormBlockContext.Provider>
|
|
||||||
);
|
);
|
||||||
|
if (readPretty) {
|
||||||
|
content = (
|
||||||
|
<RecordProvider parent={isEmpty(record?.__parent) ? record : record?.__parent} record={service?.data?.data}>
|
||||||
|
{content}
|
||||||
|
</RecordProvider>
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
formBlockValue.type === 'create' &&
|
||||||
|
// 点击关系表格区块的 Add new 按钮,在弹窗中新增的表单区块,是不需要重置 record 的。在这里用 record 是否为空来判断
|
||||||
|
!_.isEmpty(_.omit(record, ['__parent', '__collectionName'])) &&
|
||||||
|
// association 不为空,说明是关系区块
|
||||||
|
association
|
||||||
|
) {
|
||||||
|
content = (
|
||||||
|
<RecordProvider parent={record} record={{}}>
|
||||||
|
{content}
|
||||||
|
</RecordProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <FormBlockContext.Provider value={formBlockValue}>{content}</FormBlockContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,10 +3,11 @@ import { FormContext, useField, useFieldSchema } from '@formily/react';
|
|||||||
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { useCollectionManager } from '../collection-manager';
|
import { useCollectionManager } from '../collection-manager';
|
||||||
import { useFilterBlock } from '../filter-provider/FilterProvider';
|
import { useFilterBlock } from '../filter-provider/FilterProvider';
|
||||||
|
import { useRecord } from '../record-provider';
|
||||||
import { FixedBlockWrapper, SchemaComponentOptions, removeNullCondition } from '../schema-component';
|
import { FixedBlockWrapper, SchemaComponentOptions, removeNullCondition } from '../schema-component';
|
||||||
import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider';
|
import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider';
|
||||||
import { mergeFilter } from './SharedFilterProvider';
|
import { mergeFilter } from './SharedFilterProvider';
|
||||||
import { findFilterTargets } from './hooks';
|
import { findFilterTargets, useParsedFilter } from './hooks';
|
||||||
|
|
||||||
export const TableBlockContext = createContext<any>({});
|
export const TableBlockContext = createContext<any>({});
|
||||||
export function getIdsWithChildren(nodes) {
|
export function getIdsWithChildren(nodes) {
|
||||||
@ -74,9 +75,11 @@ const InternalTableBlockProvider = (props: Props) => {
|
|||||||
|
|
||||||
export const TableBlockProvider = (props) => {
|
export const TableBlockProvider = (props) => {
|
||||||
const resourceName = props.resource;
|
const resourceName = props.resource;
|
||||||
const params = { ...props.params };
|
const params = useMemo(() => ({ ...props.params }), [props.params]);
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { getCollection, getCollectionField } = useCollectionManager();
|
const { getCollection, getCollectionField } = useCollectionManager();
|
||||||
|
const record = useRecord();
|
||||||
|
|
||||||
const collection = getCollection(props.collection);
|
const collection = getCollection(props.collection);
|
||||||
const { treeTable } = fieldSchema?.['x-decorator-props'] || {};
|
const { treeTable } = fieldSchema?.['x-decorator-props'] || {};
|
||||||
if (props.dragSort) {
|
if (props.dragSort) {
|
||||||
@ -99,12 +102,22 @@ export const TableBlockProvider = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const form = useMemo(() => createForm(), [treeTable]);
|
const form = useMemo(() => createForm(), [treeTable]);
|
||||||
|
const { filter: parsedFilter } = useParsedFilter({
|
||||||
|
filterOption: params?.filter,
|
||||||
|
currentRecord: { __parent: record, __collectionName: props.collection },
|
||||||
|
});
|
||||||
|
const paramsWithFilter = useMemo(() => {
|
||||||
|
return {
|
||||||
|
...params,
|
||||||
|
filter: parsedFilter,
|
||||||
|
};
|
||||||
|
}, [parsedFilter, params]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SchemaComponentOptions scope={{ treeTable }}>
|
<SchemaComponentOptions scope={{ treeTable }}>
|
||||||
<FormContext.Provider value={form}>
|
<FormContext.Provider value={form}>
|
||||||
<BlockProvider data-testid="table-block" {...props} params={params} runWhenParamsChanged>
|
<BlockProvider data-testid="table-block" {...props} params={paramsWithFilter} runWhenParamsChanged>
|
||||||
<InternalTableBlockProvider {...props} childrenColumnName={childrenColumnName} params={params} />
|
<InternalTableBlockProvider {...props} childrenColumnName={childrenColumnName} params={paramsWithFilter} />
|
||||||
</BlockProvider>
|
</BlockProvider>
|
||||||
</FormContext.Provider>
|
</FormContext.Provider>
|
||||||
</SchemaComponentOptions>
|
</SchemaComponentOptions>
|
||||||
|
@ -26,6 +26,7 @@ import { mergeFilter } from '../SharedFilterProvider';
|
|||||||
import { TableFieldResource } from '../TableFieldProvider';
|
import { TableFieldResource } from '../TableFieldProvider';
|
||||||
|
|
||||||
export * from './useFormActiveFields';
|
export * from './useFormActiveFields';
|
||||||
|
export * from './useParsedFilter';
|
||||||
|
|
||||||
export const usePickActionProps = () => {
|
export const usePickActionProps = () => {
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
@ -587,8 +588,9 @@ export const useCustomizeBulkUpdateActionProps = () => {
|
|||||||
const actionField = useField();
|
const actionField = useField();
|
||||||
const { modal } = App.useApp();
|
const { modal } = App.useApp();
|
||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
const localVariables = useLocalVariables();
|
const record = useRecord();
|
||||||
const { name, getField } = useCollection();
|
const { name, getField } = useCollection();
|
||||||
|
const localVariables = useLocalVariables({ currentRecord: { __parent: record, __collectionName: name } });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async onClick() {
|
async onClick() {
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
import { reaction } from '@formily/reactive';
|
||||||
|
import { flatten } from '@nocobase/utils/client';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useParseDataScopeFilter } from '../../schema-settings';
|
||||||
|
import { DEBOUNCE_WAIT } from '../../variables';
|
||||||
|
import { getPath } from '../../variables/utils/getPath';
|
||||||
|
import { isVariable } from '../../variables/utils/isVariable';
|
||||||
|
import { useFormBlockContext } from '../FormBlockProvider';
|
||||||
|
|
||||||
|
export function useParsedFilter({ filterOption, currentRecord }: { filterOption: any; currentRecord?: any }) {
|
||||||
|
const { parseFilter } = useParseDataScopeFilter({ currentRecord });
|
||||||
|
const [filter, setFilter] = useState({});
|
||||||
|
const { form } = useFormBlockContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!filterOption) return;
|
||||||
|
|
||||||
|
const _run = async () => {
|
||||||
|
const result = await parseFilter(filterOption);
|
||||||
|
setFilter(result);
|
||||||
|
};
|
||||||
|
_run();
|
||||||
|
const run = _.debounce(_run, DEBOUNCE_WAIT);
|
||||||
|
|
||||||
|
reaction(() => {
|
||||||
|
// 这一步主要是为了使 reaction 能够收集到依赖
|
||||||
|
const flat = flatten(filterOption, {
|
||||||
|
breakOn({ key }) {
|
||||||
|
return key.startsWith('$') && key !== '$and' && key !== '$or';
|
||||||
|
},
|
||||||
|
transformValue(value) {
|
||||||
|
if (!isVariable(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
const result = _.get({ $nForm: form?.values }, getPath(value));
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return flat;
|
||||||
|
}, run);
|
||||||
|
}, [JSON.stringify(filterOption)]);
|
||||||
|
|
||||||
|
return { filter };
|
||||||
|
}
|
@ -79,7 +79,10 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema
|
|||||||
export const useValuesFromRecord = (options) => {
|
export const useValuesFromRecord = (options) => {
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
const result = useRequest(
|
const result = useRequest(
|
||||||
() => Promise.resolve({ data: { ...omit(record, ['__parent']), category: record?.category.map((v) => v.id) } }),
|
() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: { ...omit(record, ['__parent', '__collectionName']), category: record?.category.map((v) => v.id) },
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
manual: true,
|
manual: true,
|
||||||
|
@ -23,7 +23,7 @@ export const useCancelAction = () => {
|
|||||||
|
|
||||||
export const useValuesFromRecord = (options) => {
|
export const useValuesFromRecord = (options) => {
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
const result = useRequest(() => Promise.resolve({ data: omit(record, ['__parent']) }), {
|
const result = useRequest(() => Promise.resolve({ data: omit(record, ['__parent', '__collectionName']) }), {
|
||||||
...options,
|
...options,
|
||||||
manual: true,
|
manual: true,
|
||||||
});
|
});
|
||||||
|
@ -61,6 +61,11 @@ export const FilterBlockProvider: React.FC = ({ children }) => {
|
|||||||
return <FilterContext.Provider value={{ dataBlocks, setDataBlocks }}>{children}</FilterContext.Provider>;
|
return <FilterContext.Provider value={{ dataBlocks, setDataBlocks }}>{children}</FilterContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于收集记录当前页面中的数据区块的信息
|
||||||
|
* @param param0
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export const FilterBlockRecord = ({
|
export const FilterBlockRecord = ({
|
||||||
children,
|
children,
|
||||||
params,
|
params,
|
||||||
|
@ -619,6 +619,7 @@ export default {
|
|||||||
"Dynamic value": "Dynamic value",
|
"Dynamic value": "Dynamic value",
|
||||||
"Current user": "Current user",
|
"Current user": "Current user",
|
||||||
"Current record": "Current record",
|
"Current record": "Current record",
|
||||||
|
"Current parent record": "Current parent record",
|
||||||
"Current time": "Current time",
|
"Current time": "Current time",
|
||||||
"System variables": "System variables",
|
"System variables": "System variables",
|
||||||
"Date variables": "Date variables",
|
"Date variables": "Date variables",
|
||||||
|
@ -603,6 +603,7 @@ export default {
|
|||||||
"Dynamic value": "Valor dinámico",
|
"Dynamic value": "Valor dinámico",
|
||||||
"Current user": "Usuario actual",
|
"Current user": "Usuario actual",
|
||||||
"Current record": "Registro actual",
|
"Current record": "Registro actual",
|
||||||
|
"Current parent record": "Registro padre actual",
|
||||||
"Current time": "Hora actual",
|
"Current time": "Hora actual",
|
||||||
"System variables": "Variables del sistema",
|
"System variables": "Variables del sistema",
|
||||||
"Date variables": "Variables de fecha",
|
"Date variables": "Variables de fecha",
|
||||||
|
@ -600,6 +600,7 @@ export default {
|
|||||||
"Dynamic value": "Valeur dynamique",
|
"Dynamic value": "Valeur dynamique",
|
||||||
"Current user": "Utilisateur actuel",
|
"Current user": "Utilisateur actuel",
|
||||||
"Current record": "Enregistrement actuel",
|
"Current record": "Enregistrement actuel",
|
||||||
|
"Current parent record": "Enregistrement parent actuel",
|
||||||
"Current time": "Heure actuelle",
|
"Current time": "Heure actuelle",
|
||||||
"System variables": "Variables système",
|
"System variables": "Variables système",
|
||||||
"Date variables": "Variables de date",
|
"Date variables": "Variables de date",
|
||||||
|
@ -502,6 +502,7 @@ export default {
|
|||||||
"Dynamic value": "動的値",
|
"Dynamic value": "動的値",
|
||||||
"Current user": "現在のユーザー",
|
"Current user": "現在のユーザー",
|
||||||
"Current record": "現在のレコード",
|
"Current record": "現在のレコード",
|
||||||
|
"Current parent record": "現在の親レコード",
|
||||||
"Popup close method": "ポップアップを閉じる方法",
|
"Popup close method": "ポップアップを閉じる方法",
|
||||||
"Automatic close": "自動で閉じる",
|
"Automatic close": "自動で閉じる",
|
||||||
"Manually close": "手動で閉じる",
|
"Manually close": "手動で閉じる",
|
||||||
|
@ -508,6 +508,7 @@ export default {
|
|||||||
"Single select and radio fields can be used as the grouping field": "Campos de seleção única e de rádio podem ser usados como o campo de agrupamento",
|
"Single select and radio fields can be used as the grouping field": "Campos de seleção única e de rádio podem ser usados como o campo de agrupamento",
|
||||||
"Tab name": "Nome da aba",
|
"Tab name": "Nome da aba",
|
||||||
"Current record blocks": "Blocos de registro atual",
|
"Current record blocks": "Blocos de registro atual",
|
||||||
|
"Current parent record": "Registro pai atual",
|
||||||
"Popup message": "Mensagem pop-up",
|
"Popup message": "Mensagem pop-up",
|
||||||
"Delete role": "Excluir função",
|
"Delete role": "Excluir função",
|
||||||
"Role display name": "Nome de exibição da função",
|
"Role display name": "Nome de exibição da função",
|
||||||
|
@ -439,6 +439,7 @@ export default {
|
|||||||
"Dynamic value": "Динамическое значение",
|
"Dynamic value": "Динамическое значение",
|
||||||
"Current user": "Текущий пользователь",
|
"Current user": "Текущий пользователь",
|
||||||
"Current record": "Текущая запись",
|
"Current record": "Текущая запись",
|
||||||
|
"Current parent record": "Текущая родительская запись",
|
||||||
"Popup close method": "Метод закрытия всплывающего окна",
|
"Popup close method": "Метод закрытия всплывающего окна",
|
||||||
"Automatic close": "Автоматическое закрытие",
|
"Automatic close": "Автоматическое закрытие",
|
||||||
"Manually close": "Ручное закрытие",
|
"Manually close": "Ручное закрытие",
|
||||||
|
@ -438,6 +438,7 @@ export default {
|
|||||||
"Dynamic value": "Dinamik değer",
|
"Dynamic value": "Dinamik değer",
|
||||||
"Current user": "Seçili kullanıcı",
|
"Current user": "Seçili kullanıcı",
|
||||||
"Current record": "Seçili kayıt",
|
"Current record": "Seçili kayıt",
|
||||||
|
"Current parent record": "Seçili üst kayıt",
|
||||||
"Popup close method": "Açılır pencere kapatma metodu",
|
"Popup close method": "Açılır pencere kapatma metodu",
|
||||||
"Automatic close": "Otomatik kapat",
|
"Automatic close": "Otomatik kapat",
|
||||||
"Manually close": "Manuel kapat",
|
"Manually close": "Manuel kapat",
|
||||||
|
@ -620,6 +620,7 @@ export default {
|
|||||||
"Dynamic value": "Динамічне значення",
|
"Dynamic value": "Динамічне значення",
|
||||||
"Current user": "Поточний користувач",
|
"Current user": "Поточний користувач",
|
||||||
"Current record": "Поточний запис",
|
"Current record": "Поточний запис",
|
||||||
|
"Current parent record": "Поточний батьківський запис",
|
||||||
"Current time": "Поточний час",
|
"Current time": "Поточний час",
|
||||||
"System variables": "Системні змінні",
|
"System variables": "Системні змінні",
|
||||||
"Date variables": "Змінні дати",
|
"Date variables": "Змінні дати",
|
||||||
|
@ -661,6 +661,7 @@ export default {
|
|||||||
'Dynamic value': '动态值',
|
'Dynamic value': '动态值',
|
||||||
'Current user': '当前用户',
|
'Current user': '当前用户',
|
||||||
'Current record': '当前记录',
|
'Current record': '当前记录',
|
||||||
|
"Current parent record": "当前父记录",
|
||||||
'Current time': '当前时间',
|
'Current time': '当前时间',
|
||||||
Now: '现在',
|
Now: '现在',
|
||||||
'Popup close method': '弹窗关闭方式',
|
'Popup close method': '弹窗关闭方式',
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
|
import { useCollection } from '../collection-manager';
|
||||||
import { useCurrentUserContext } from '../user';
|
import { useCurrentUserContext } from '../user';
|
||||||
|
|
||||||
export const RecordContext = createContext({});
|
export const RecordContext = createContext({});
|
||||||
export const RecordIndexContext = createContext(null);
|
export const RecordIndexContext = createContext(null);
|
||||||
|
|
||||||
export const RecordProvider: React.FC<{ record: any; parent?: any }> = (props) => {
|
export const RecordProvider: React.FC<{ record: any; parent?: any; collectionName?: string }> = (props) => {
|
||||||
const { record, children, parent = false } = props;
|
const { record, children, collectionName, parent = false } = props;
|
||||||
|
const { name: __collectionName } = useCollection();
|
||||||
const __parent = useContext(RecordContext);
|
const __parent = useContext(RecordContext);
|
||||||
const value = { ...record };
|
const value = { ...record };
|
||||||
value['__parent'] = parent ? parent : __parent;
|
value['__parent'] = parent ? parent : __parent;
|
||||||
|
value['__collectionName'] = collectionName || __collectionName;
|
||||||
return <RecordContext.Provider value={value}>{children}</RecordContext.Provider>;
|
return <RecordContext.Provider value={value}>{children}</RecordContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useActionContext } from '../..';
|
import { useActionContext } from '../..';
|
||||||
import { useDesignable } from '../../';
|
import { useDesignable } from '../../';
|
||||||
import { Icon } from '../../../icon';
|
import { Icon } from '../../../icon';
|
||||||
import { useRecord } from '../../../record-provider';
|
import { RecordProvider, useRecord } 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';
|
||||||
@ -52,7 +52,7 @@ export const Action: ComposedAction = observer(
|
|||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
const values = useRecord();
|
const record = useRecord();
|
||||||
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 disabled = form.disabled || field.disabled || field.data?.disabled || props.disabled;
|
const disabled = form.disabled || field.disabled || field.data?.disabled || props.disabled;
|
||||||
@ -61,7 +61,12 @@ export const Action: ComposedAction = observer(
|
|||||||
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 } as any });
|
const localVariables = useLocalVariables({ currentForm: { values: record } as any });
|
||||||
|
|
||||||
|
// fix https://nocobase.height.app/T-2259
|
||||||
|
const shouldResetRecord = ['create', 'customize:bulkUpdate', 'customize:bulkEdit', 'customize:create'].includes(
|
||||||
|
fieldSchema['x-action'],
|
||||||
|
);
|
||||||
|
|
||||||
let actionTitle = title || compile(fieldSchema.title);
|
let actionTitle = title || compile(fieldSchema.title);
|
||||||
actionTitle = lodash.isString(actionTitle) ? t(actionTitle) : actionTitle;
|
actionTitle = lodash.isString(actionTitle) ? t(actionTitle) : actionTitle;
|
||||||
@ -75,13 +80,13 @@ export const Action: ComposedAction = observer(
|
|||||||
operator: h.operator,
|
operator: h.operator,
|
||||||
field,
|
field,
|
||||||
condition: v.condition,
|
condition: v.condition,
|
||||||
values,
|
values: record,
|
||||||
variables,
|
variables,
|
||||||
localVariables,
|
localVariables,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [JSON.stringify(linkageRules), values, designable, field]);
|
}, [JSON.stringify(linkageRules), record, designable, field]);
|
||||||
|
|
||||||
const handleButtonClick = useCallback(
|
const handleButtonClick = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
@ -142,7 +147,7 @@ export const Action: ComposedAction = observer(
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return wrapSSR(
|
const result = (
|
||||||
<ActionContextProvider
|
<ActionContextProvider
|
||||||
button={renderButton()}
|
button={renderButton()}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
@ -158,7 +163,17 @@ export const Action: ComposedAction = observer(
|
|||||||
{!popover && renderButton()}
|
{!popover && renderButton()}
|
||||||
{!popover && props.children}
|
{!popover && props.children}
|
||||||
{element}
|
{element}
|
||||||
</ActionContextProvider>,
|
</ActionContextProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
return wrapSSR(
|
||||||
|
shouldResetRecord ? (
|
||||||
|
<RecordProvider parent={record} record={{}}>
|
||||||
|
{result}
|
||||||
|
</RecordProvider>
|
||||||
|
) : (
|
||||||
|
result
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{ displayName: 'Action' },
|
{ displayName: 'Action' },
|
||||||
|
@ -15,7 +15,6 @@ import { DEBOUNCE_WAIT } from '../../../variables';
|
|||||||
import { getPath } from '../../../variables/utils/getPath';
|
import { getPath } from '../../../variables/utils/getPath';
|
||||||
import { isVariable } from '../../../variables/utils/isVariable';
|
import { isVariable } from '../../../variables/utils/isVariable';
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable } from '../../hooks';
|
||||||
import { removeNullCondition } from '../filter';
|
|
||||||
import { AssociationFieldContext } from './context';
|
import { AssociationFieldContext } from './context';
|
||||||
|
|
||||||
export const useInsertSchema = (component) => {
|
export const useInsertSchema = (component) => {
|
||||||
|
@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { FixedBlockDesignerItem, removeNullCondition, useDesignable } from '../..';
|
import { FixedBlockDesignerItem, removeNullCondition, useDesignable } from '../..';
|
||||||
import { useCalendarBlockContext, useFormBlockContext } from '../../../block-provider';
|
import { useCalendarBlockContext, useFormBlockContext } from '../../../block-provider';
|
||||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
|
import { RecordProvider, useRecord } from '../../../record-provider';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
import { useSchemaTemplate } from '../../../schema-templates';
|
import { useSchemaTemplate } from '../../../schema-templates';
|
||||||
|
|
||||||
@ -17,10 +18,12 @@ export const CalendarDesigner = () => {
|
|||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const template = useSchemaTemplate();
|
const template = useSchemaTemplate();
|
||||||
|
const record = useRecord();
|
||||||
const fieldNames = fieldSchema?.['x-decorator-props']?.['fieldNames'] || {};
|
const fieldNames = fieldSchema?.['x-decorator-props']?.['fieldNames'] || {};
|
||||||
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<RecordProvider parent={record} record={{}}>
|
||||||
<GeneralSchemaDesigner template={template} title={title || name}>
|
<GeneralSchemaDesigner template={template} title={title || name}>
|
||||||
<SchemaSettings.BlockTitleItem />
|
<SchemaSettings.BlockTitleItem />
|
||||||
<SchemaSettings.SelectItem
|
<SchemaSettings.SelectItem
|
||||||
@ -131,5 +134,6 @@ export const CalendarDesigner = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</GeneralSchemaDesigner>
|
</GeneralSchemaDesigner>
|
||||||
|
</RecordProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -735,7 +735,7 @@ FormItem.FilterFormDesigner = FilterFormDesigner;
|
|||||||
|
|
||||||
function useIsAddNewForm() {
|
function useIsAddNewForm() {
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
const isAddNewForm = _.isEmpty(_.omit(record, '__parent'));
|
const isAddNewForm = _.isEmpty(_.omit(record, ['__parent', '__collectionName']));
|
||||||
|
|
||||||
return isAddNewForm;
|
return isAddNewForm;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ const useLazyLoadAssociationFieldOfForm = () => {
|
|||||||
|
|
||||||
const cloneRecord = { ...record };
|
const cloneRecord = { ...record };
|
||||||
delete cloneRecord['__parent'];
|
delete cloneRecord['__parent'];
|
||||||
|
delete cloneRecord['__collectionName'];
|
||||||
|
|
||||||
if (_.isEmpty(cloneRecord) || !variables || record[schemaName] != null) {
|
if (_.isEmpty(cloneRecord) || !variables || record[schemaName] != null) {
|
||||||
return;
|
return;
|
||||||
|
@ -2,7 +2,8 @@ import { FormLayout } from '@formily/antd-v5';
|
|||||||
import { createForm } from '@formily/core';
|
import { createForm } from '@formily/core';
|
||||||
import { FormContext, useField } from '@formily/react';
|
import { FormContext, useField } from '@formily/react';
|
||||||
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
||||||
import { BlockProvider, useBlockRequestContext } from '../../../block-provider';
|
import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider';
|
||||||
|
import { useRecord } from '../../../record-provider';
|
||||||
import useStyles from './GridCard.Decorator.style';
|
import useStyles from './GridCard.Decorator.style';
|
||||||
export const GridCardBlockContext = createContext<any>({});
|
export const GridCardBlockContext = createContext<any>({});
|
||||||
|
|
||||||
@ -41,8 +42,22 @@ const InternalGridCardBlockProvider = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const GridCardBlockProvider = (props) => {
|
export const GridCardBlockProvider = (props) => {
|
||||||
|
const { params } = props;
|
||||||
|
const record = useRecord();
|
||||||
|
|
||||||
|
const { filter: parsedFilter } = useParsedFilter({
|
||||||
|
filterOption: params?.filter,
|
||||||
|
currentRecord: { __parent: record, __collectionName: props.collection },
|
||||||
|
});
|
||||||
|
const paramsWithFilter = useMemo(() => {
|
||||||
|
return {
|
||||||
|
...params,
|
||||||
|
filter: parsedFilter,
|
||||||
|
};
|
||||||
|
}, [parsedFilter, params]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BlockProvider data-testid="grid-card-block" {...props}>
|
<BlockProvider data-testid="grid-card-block" {...props} params={paramsWithFilter}>
|
||||||
<InternalGridCardBlockProvider {...props} />
|
<InternalGridCardBlockProvider {...props} />
|
||||||
</BlockProvider>
|
</BlockProvider>
|
||||||
);
|
);
|
||||||
|
@ -6,6 +6,7 @@ import React, { useMemo } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useFormBlockContext } from '../../../block-provider';
|
import { useFormBlockContext } from '../../../block-provider';
|
||||||
import { useCollection, useSortFields } from '../../../collection-manager';
|
import { useCollection, useSortFields } from '../../../collection-manager';
|
||||||
|
import { RecordProvider, useRecord } from '../../../record-provider';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
import { useSchemaTemplate } from '../../../schema-templates';
|
import { useSchemaTemplate } from '../../../schema-templates';
|
||||||
import { SchemaComponentOptions } from '../../core';
|
import { SchemaComponentOptions } from '../../core';
|
||||||
@ -27,6 +28,7 @@ export const GridCardDesigner = () => {
|
|||||||
const field = useField();
|
const field = useField();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const sortFields = useSortFields(name);
|
const sortFields = useSortFields(name);
|
||||||
|
const record = useRecord();
|
||||||
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
||||||
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
||||||
const columnCount = field.decoratorProps.columnCount || defaultColumnCount;
|
const columnCount = field.decoratorProps.columnCount || defaultColumnCount;
|
||||||
@ -70,6 +72,8 @@ export const GridCardDesigner = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
|
// fix https://nocobase.height.app/T-2259
|
||||||
|
<RecordProvider parent={record} record={{}}>
|
||||||
<GeneralSchemaDesigner template={template} title={title || name}>
|
<GeneralSchemaDesigner template={template} title={title || name}>
|
||||||
<SchemaComponentOptions components={{ Slider }}>
|
<SchemaComponentOptions components={{ Slider }}>
|
||||||
<SchemaSettings.ModalItem
|
<SchemaSettings.ModalItem
|
||||||
@ -224,5 +228,6 @@ export const GridCardDesigner = () => {
|
|||||||
/>
|
/>
|
||||||
</SchemaComponentOptions>
|
</SchemaComponentOptions>
|
||||||
</GeneralSchemaDesigner>
|
</GeneralSchemaDesigner>
|
||||||
|
</RecordProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,8 @@ import { FormLayout } from '@formily/antd-v5';
|
|||||||
import { createForm } from '@formily/core';
|
import { createForm } from '@formily/core';
|
||||||
import { FormContext, useField } from '@formily/react';
|
import { FormContext, useField } from '@formily/react';
|
||||||
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
||||||
import { BlockProvider, useBlockRequestContext } from '../../../block-provider';
|
import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider';
|
||||||
|
import { useRecord } from '../../../record-provider';
|
||||||
|
|
||||||
export const ListBlockContext = createContext<any>({});
|
export const ListBlockContext = createContext<any>({});
|
||||||
|
|
||||||
@ -51,8 +52,22 @@ const InternalListBlockProvider = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ListBlockProvider = (props) => {
|
export const ListBlockProvider = (props) => {
|
||||||
|
const { params } = props;
|
||||||
|
const record = useRecord();
|
||||||
|
|
||||||
|
const { filter: parsedFilter } = useParsedFilter({
|
||||||
|
filterOption: params?.filter,
|
||||||
|
currentRecord: { __parent: record, __collectionName: props.collection },
|
||||||
|
});
|
||||||
|
const paramsWithFilter = useMemo(() => {
|
||||||
|
return {
|
||||||
|
...params,
|
||||||
|
filter: parsedFilter,
|
||||||
|
};
|
||||||
|
}, [parsedFilter, params]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BlockProvider data-testid="list-block" {...props}>
|
<BlockProvider data-testid="list-block" {...props} params={paramsWithFilter}>
|
||||||
<InternalListBlockProvider {...props} />
|
<InternalListBlockProvider {...props} />
|
||||||
</BlockProvider>
|
</BlockProvider>
|
||||||
);
|
);
|
||||||
|
@ -5,6 +5,7 @@ import React from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useFormBlockContext } from '../../../block-provider';
|
import { useFormBlockContext } from '../../../block-provider';
|
||||||
import { useCollection, useSortFields } from '../../../collection-manager';
|
import { useCollection, useSortFields } from '../../../collection-manager';
|
||||||
|
import { RecordProvider, useRecord } from '../../../record-provider';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
import { useSchemaTemplate } from '../../../schema-templates';
|
import { useSchemaTemplate } from '../../../schema-templates';
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable } from '../../hooks';
|
||||||
@ -19,6 +20,7 @@ export const ListDesigner = () => {
|
|||||||
const field = useField();
|
const field = useField();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const sortFields = useSortFields(name);
|
const sortFields = useSortFields(name);
|
||||||
|
const record = useRecord();
|
||||||
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
||||||
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
||||||
const sort = defaultSort?.map((item: string) => {
|
const sort = defaultSort?.map((item: string) => {
|
||||||
@ -33,6 +35,8 @@ export const ListDesigner = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
|
// fix https://nocobase.height.app/T-2259
|
||||||
|
<RecordProvider parent={record} record={{}}>
|
||||||
<GeneralSchemaDesigner template={template} title={title || name}>
|
<GeneralSchemaDesigner template={template} title={title || name}>
|
||||||
<SchemaSettings.BlockTitleItem />
|
<SchemaSettings.BlockTitleItem />
|
||||||
<SchemaSettings.DataScope
|
<SchemaSettings.DataScope
|
||||||
@ -170,5 +174,6 @@ export const ListDesigner = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</GeneralSchemaDesigner>
|
</GeneralSchemaDesigner>
|
||||||
|
</RecordProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -7,6 +7,7 @@ import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
|||||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
import { useSortFields } from '../../../collection-manager/action-hooks';
|
import { useSortFields } from '../../../collection-manager/action-hooks';
|
||||||
import { FilterBlockType } from '../../../filter-provider/utils';
|
import { FilterBlockType } from '../../../filter-provider/utils';
|
||||||
|
import { RecordProvider, useRecord } from '../../../record-provider';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
import { useSchemaTemplate } from '../../../schema-templates';
|
import { useSchemaTemplate } from '../../../schema-templates';
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable } from '../../hooks';
|
||||||
@ -23,6 +24,8 @@ export const TableBlockDesigner = () => {
|
|||||||
const { service } = useTableBlockContext();
|
const { service } = useTableBlockContext();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
|
const record = useRecord();
|
||||||
|
|
||||||
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
||||||
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
||||||
const supportTemplate = !fieldSchema?.['x-decorator-props']?.disableTemplate;
|
const supportTemplate = !fieldSchema?.['x-decorator-props']?.disableTemplate;
|
||||||
@ -64,6 +67,8 @@ export const TableBlockDesigner = () => {
|
|||||||
[dn, field.decoratorProps, fieldSchema, service],
|
[dn, field.decoratorProps, fieldSchema, service],
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
// fix https://nocobase.height.app/T-2259
|
||||||
|
<RecordProvider parent={record} record={{}}>
|
||||||
<GeneralSchemaDesigner template={template} title={title || name}>
|
<GeneralSchemaDesigner template={template} title={title || name}>
|
||||||
<SchemaSettings.BlockTitleItem />
|
<SchemaSettings.BlockTitleItem />
|
||||||
{collection?.tree && collectionField?.collectionName === collectionField?.target && (
|
{collection?.tree && collectionField?.collectionName === collectionField?.target && (
|
||||||
@ -241,5 +246,6 @@ export const TableBlockDesigner = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</GeneralSchemaDesigner>
|
</GeneralSchemaDesigner>
|
||||||
|
</RecordProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
import { Schema } from '@formily/json-schema';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { CollectionFieldOptions } from '../../../collection-manager';
|
||||||
|
import { useBaseVariable } from './useBaseVariable';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
collectionField: CollectionFieldOptions;
|
||||||
|
schema: any;
|
||||||
|
collectionName: string;
|
||||||
|
noDisabled?: boolean;
|
||||||
|
/** 消费变量值的字段 */
|
||||||
|
targetFieldSchema?: Schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useParentRecordVariable = (props: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const currentRecordVariable = useBaseVariable({
|
||||||
|
collectionField: props.collectionField,
|
||||||
|
uiSchema: props.schema,
|
||||||
|
name: '$nParentRecord',
|
||||||
|
title: t('Current parent record'),
|
||||||
|
collectionName: props.collectionName,
|
||||||
|
noDisabled: props.noDisabled,
|
||||||
|
targetFieldSchema: props.targetFieldSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
return currentRecordVariable;
|
||||||
|
};
|
@ -1,13 +1,14 @@
|
|||||||
import { Form } from '@formily/core';
|
import { Form } from '@formily/core';
|
||||||
import { ISchema, Schema } from '@formily/react';
|
import { ISchema, Schema } from '@formily/react';
|
||||||
|
import _ from 'lodash';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useFormBlockType } from '../../../block-provider/FormBlockProvider';
|
|
||||||
import { CollectionFieldOptions, useCollection } from '../../../collection-manager';
|
import { CollectionFieldOptions, useCollection } from '../../../collection-manager';
|
||||||
import { useFlag } from '../../../flag-provider';
|
import { useFlag } from '../../../flag-provider';
|
||||||
import { useBlockCollection } from './useBlockCollection';
|
import { useBlockCollection } from './useBlockCollection';
|
||||||
import { useDateVariable } from './useDateVariable';
|
import { useDateVariable } from './useDateVariable';
|
||||||
import { useFormVariable } from './useFormVariable';
|
import { useFormVariable } from './useFormVariable';
|
||||||
import { useIterationVariable } from './useIterationVariable';
|
import { useIterationVariable } from './useIterationVariable';
|
||||||
|
import { useParentRecordVariable } from './useParentRecordVariable';
|
||||||
import { useRecordVariable } from './useRecordVariable';
|
import { useRecordVariable } from './useRecordVariable';
|
||||||
import { useUserVariable } from './useUserVariable';
|
import { useUserVariable } from './useUserVariable';
|
||||||
|
|
||||||
@ -44,11 +45,12 @@ export const useVariableOptions = ({
|
|||||||
operator,
|
operator,
|
||||||
noDisabled,
|
noDisabled,
|
||||||
targetFieldSchema,
|
targetFieldSchema,
|
||||||
|
record,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { name: blockCollectionName } = useBlockCollection();
|
const { name: blockCollectionName = record?.__collectionName } = useBlockCollection();
|
||||||
const { isInSubForm, isInSubTable } = useFlag() || {};
|
const { isInSubForm, isInSubTable } = useFlag() || {};
|
||||||
const { type: formBlockType } = useFormBlockType();
|
|
||||||
const { name } = useCollection();
|
const { name } = useCollection();
|
||||||
|
const blockParentCollectionName = record?.__parent?.__collectionName;
|
||||||
const userVariable = useUserVariable({
|
const userVariable = useUserVariable({
|
||||||
maxDepth: 3,
|
maxDepth: 3,
|
||||||
uiSchema: uiSchema,
|
uiSchema: uiSchema,
|
||||||
@ -78,6 +80,13 @@ export const useVariableOptions = ({
|
|||||||
noDisabled,
|
noDisabled,
|
||||||
targetFieldSchema,
|
targetFieldSchema,
|
||||||
});
|
});
|
||||||
|
const currentParentRecordVariable = useParentRecordVariable({
|
||||||
|
schema: uiSchema,
|
||||||
|
collectionName: blockParentCollectionName,
|
||||||
|
collectionField,
|
||||||
|
noDisabled,
|
||||||
|
targetFieldSchema,
|
||||||
|
});
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return [
|
return [
|
||||||
@ -85,7 +94,10 @@ export const useVariableOptions = ({
|
|||||||
dateVariable,
|
dateVariable,
|
||||||
form && !form.readPretty && formVariable,
|
form && !form.readPretty && formVariable,
|
||||||
(isInSubForm || isInSubTable) && iterationVariable,
|
(isInSubForm || isInSubTable) && iterationVariable,
|
||||||
formBlockType === 'update' && currentRecordVariable,
|
blockCollectionName && !_.isEmpty(_.omit(record, ['__parent', '__collectionName'])) && currentRecordVariable,
|
||||||
|
blockParentCollectionName &&
|
||||||
|
!_.isEmpty(_.omit(record?.__parent, ['__parent', '__collectionName'])) &&
|
||||||
|
currentParentRecordVariable,
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
}, [
|
}, [
|
||||||
userVariable,
|
userVariable,
|
||||||
@ -95,6 +107,10 @@ export const useVariableOptions = ({
|
|||||||
isInSubForm,
|
isInSubForm,
|
||||||
isInSubTable,
|
isInSubTable,
|
||||||
iterationVariable,
|
iterationVariable,
|
||||||
|
blockCollectionName,
|
||||||
|
record,
|
||||||
currentRecordVariable,
|
currentRecordVariable,
|
||||||
|
blockParentCollectionName,
|
||||||
|
currentParentRecordVariable,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
@ -9,14 +9,15 @@ interface Props {
|
|||||||
* 需要排除的变量名称,例如:['$user', '$date']
|
* 需要排除的变量名称,例如:['$user', '$date']
|
||||||
* 被排除的变量不会被解析,会按原值返回
|
* 被排除的变量不会被解析,会按原值返回
|
||||||
*/
|
*/
|
||||||
exclude: string[];
|
exclude?: string[];
|
||||||
|
currentRecord?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 建议变量名统一命名为 `$n` 开头,以防止与 formily 内置变量冲突
|
// TODO: 建议变量名统一命名为 `$n` 开头,以防止与 formily 内置变量冲突
|
||||||
const defaultExclude = ['$user', '$date', '$nDate'];
|
const defaultExclude = ['$user', '$date', '$nDate'];
|
||||||
|
|
||||||
const useParseDataScopeFilter = ({ exclude }: Props = { exclude: defaultExclude }) => {
|
const useParseDataScopeFilter = ({ exclude = defaultExclude, currentRecord }: Props = {}) => {
|
||||||
const localVariables = useLocalVariables();
|
const localVariables = useLocalVariables({ currentRecord });
|
||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
|
|
||||||
const parseFilter = useCallback(
|
const parseFilter = useCallback(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Form } from '@formily/core';
|
import { Form } from '@formily/core';
|
||||||
import _ from 'lodash';
|
|
||||||
import React, { useContext, useMemo } from 'react';
|
import React, { useContext, useMemo } from 'react';
|
||||||
import { useFormBlockContext } from '../../block-provider';
|
import { useFormBlockContext } from '../../block-provider';
|
||||||
import { useCollection } from '../../collection-manager';
|
import { useCollection } from '../../collection-manager';
|
||||||
@ -42,12 +41,6 @@ const useLocalVariables = (props?: Props) => {
|
|||||||
name = props.collectionName;
|
name = props.collectionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
let blockRecord = currentRecord;
|
|
||||||
// 获取到最顶层的 record,即当前区块所在的 record
|
|
||||||
while (!_.isEmpty(blockRecord.__parent)) {
|
|
||||||
blockRecord = blockRecord.__parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return (
|
return (
|
||||||
[
|
[
|
||||||
@ -57,7 +50,7 @@ const useLocalVariables = (props?: Props) => {
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
name: 'currentRecord',
|
name: 'currentRecord',
|
||||||
ctx: blockRecord,
|
ctx: currentRecord,
|
||||||
collectionName: name,
|
collectionName: name,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -66,7 +59,7 @@ const useLocalVariables = (props?: Props) => {
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
ctx: form?.values || blockRecord,
|
ctx: form?.values || currentRecord,
|
||||||
collectionName: name,
|
collectionName: name,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -80,8 +73,13 @@ const useLocalVariables = (props?: Props) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '$nRecord',
|
name: '$nRecord',
|
||||||
ctx: blockRecord,
|
ctx: currentRecord,
|
||||||
collectionName: name,
|
collectionName: currentRecord?.__collectionName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '$nParentRecord',
|
||||||
|
ctx: currentRecord?.__parent,
|
||||||
|
collectionName: currentRecord?.__parent?.__collectionName,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '$nForm',
|
name: '$nForm',
|
||||||
@ -91,7 +89,7 @@ const useLocalVariables = (props?: Props) => {
|
|||||||
iterationCtx && { name: '$iteration', ctx: iterationCtx, collectionName: currentCollectionName },
|
iterationCtx && { name: '$iteration', ctx: iterationCtx, collectionName: currentCollectionName },
|
||||||
] as VariableOption[]
|
] as VariableOption[]
|
||||||
).filter(Boolean);
|
).filter(Boolean);
|
||||||
}, [blockRecord, name, form?.values, iterationCtx, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中
|
}, [currentRecord, name, form?.values, iterationCtx, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useLocalVariables;
|
export default useLocalVariables;
|
||||||
|
@ -148,7 +148,6 @@ export function useTriggerWorkflowsActionProps() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
async onClick() {
|
async onClick() {
|
||||||
const fieldNames = fields.map((field) => field.name);
|
|
||||||
const {
|
const {
|
||||||
assignedValues: originalAssignedValues = {},
|
assignedValues: originalAssignedValues = {},
|
||||||
onSuccess,
|
onSuccess,
|
||||||
|
Loading…
Reference in New Issue
Block a user