mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 04:15:19 +00:00
feat: add support for opening via URL (#5098)
Some checks are pending
auto-merge / push-commit (push) Waiting to run
Build Docker Image / build-and-push (push) Waiting to run
Build Pro Image / app-token (push) Waiting to run
Build Pro Image / build-and-push (push) Blocked by required conditions
deploy client docs / Build (push) Waiting to run
E2E / Build (push) Waiting to run
E2E / Core and plugins (push) Blocked by required conditions
E2E / plugin-workflow (push) Blocked by required conditions
E2E / plugin-workflow-approval (push) Blocked by required conditions
E2E / plugin-data-source-main (push) Blocked by required conditions
E2E / Comment on PR (push) Blocked by required conditions
NocoBase Backend Test / sqlite-test (20, false) (push) Waiting to run
NocoBase Backend Test / sqlite-test (20, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, nocobase, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, nocobase, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, public, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, public, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, nocobase, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, nocobase, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, public, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, public, true) (push) Waiting to run
NocoBase Backend Test / mysql-test (20, false) (push) Waiting to run
NocoBase Backend Test / mysql-test (20, true) (push) Waiting to run
NocoBase Backend Test / mariadb-test (20, false) (push) Waiting to run
NocoBase Backend Test / mariadb-test (20, true) (push) Waiting to run
NocoBase FrontEnd Test / frontend-test (18) (push) Waiting to run
Test on Windows / build (push) Waiting to run
Some checks are pending
auto-merge / push-commit (push) Waiting to run
Build Docker Image / build-and-push (push) Waiting to run
Build Pro Image / app-token (push) Waiting to run
Build Pro Image / build-and-push (push) Blocked by required conditions
deploy client docs / Build (push) Waiting to run
E2E / Build (push) Waiting to run
E2E / Core and plugins (push) Blocked by required conditions
E2E / plugin-workflow (push) Blocked by required conditions
E2E / plugin-workflow-approval (push) Blocked by required conditions
E2E / plugin-data-source-main (push) Blocked by required conditions
E2E / Comment on PR (push) Blocked by required conditions
NocoBase Backend Test / sqlite-test (20, false) (push) Waiting to run
NocoBase Backend Test / sqlite-test (20, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, nocobase, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, nocobase, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, public, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, public, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, nocobase, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, nocobase, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, public, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, public, true) (push) Waiting to run
NocoBase Backend Test / mysql-test (20, false) (push) Waiting to run
NocoBase Backend Test / mysql-test (20, true) (push) Waiting to run
NocoBase Backend Test / mariadb-test (20, false) (push) Waiting to run
NocoBase Backend Test / mariadb-test (20, true) (push) Waiting to run
NocoBase FrontEnd Test / frontend-test (18) (push) Waiting to run
Test on Windows / build (push) Waiting to run
* feat(map): add support for opening via URL * feat(calendar): add support for opening via URL * feat(gantt): add support for opening via URL * fix(duplicate,bulk-edit): resolve issues with popups * fix: useDetailsBlockProps --------- Co-authored-by: katherinehhh <katherine_15995@163.com>
This commit is contained in:
parent
ce3d6ac233
commit
dec3c838a3
@ -141,6 +141,7 @@ export const useDetailsBlockProps = () => {
|
|||||||
ctx.form
|
ctx.form
|
||||||
.reset()
|
.reset()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
ctx.form.setInitialValues(data || {});
|
||||||
ctx.form.setValues(data || {});
|
ctx.form.setValues(data || {});
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
|
@ -17,7 +17,10 @@ import { PopupVisibleProvider, PopupVisibleProviderContext } from '../../schema-
|
|||||||
* @param props
|
* @param props
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const PopupContextProvider: React.FC = (props) => {
|
export const PopupContextProvider: React.FC<{
|
||||||
|
visible?: boolean;
|
||||||
|
setVisible?: (visible: boolean) => void;
|
||||||
|
}> = (props) => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { visible: visibleWithURL, setVisible: setVisibleWithURL } = useContext(PopupVisibleProviderContext) || {
|
const { visible: visibleWithURL, setVisible: setVisibleWithURL } = useContext(PopupVisibleProviderContext) || {
|
||||||
visible: false,
|
visible: false,
|
||||||
@ -26,10 +29,11 @@ export const PopupContextProvider: React.FC = (props) => {
|
|||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const _setVisible = useCallback(
|
const _setVisible = useCallback(
|
||||||
(value: boolean): void => {
|
(value: boolean): void => {
|
||||||
|
props.setVisible?.(value);
|
||||||
setVisible?.(value);
|
setVisible?.(value);
|
||||||
setVisibleWithURL?.(value);
|
setVisibleWithURL?.(value);
|
||||||
},
|
},
|
||||||
[setVisibleWithURL],
|
[props, setVisibleWithURL],
|
||||||
);
|
);
|
||||||
const openMode = fieldSchema['x-component-props']?.['openMode'] || 'drawer';
|
const openMode = fieldSchema['x-component-props']?.['openMode'] || 'drawer';
|
||||||
const openSize = fieldSchema['x-component-props']?.['openSize'];
|
const openSize = fieldSchema['x-component-props']?.['openSize'];
|
||||||
@ -37,7 +41,7 @@ export const PopupContextProvider: React.FC = (props) => {
|
|||||||
return (
|
return (
|
||||||
<PopupVisibleProvider visible={false}>
|
<PopupVisibleProvider visible={false}>
|
||||||
<ActionContextProvider
|
<ActionContextProvider
|
||||||
visible={visible || visibleWithURL}
|
visible={props.visible || visible || visibleWithURL}
|
||||||
setVisible={_setVisible}
|
setVisible={_setVisible}
|
||||||
openMode={openMode}
|
openMode={openMode}
|
||||||
openSize={openSize}
|
openSize={openSize}
|
||||||
|
@ -33,7 +33,7 @@ interface PopupsVisibleProviderProps {
|
|||||||
setVisible?: (value: boolean) => void;
|
setVisible?: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PopupProps {
|
export interface PopupProps {
|
||||||
params: PopupParams;
|
params: PopupParams;
|
||||||
context: PopupContext;
|
context: PopupContext;
|
||||||
/**
|
/**
|
||||||
|
@ -7,13 +7,31 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback } from 'react';
|
import React, { FC, useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
|
const PopupSettingsContext = React.createContext({
|
||||||
|
enableURL: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PopupSettingsProvider: FC<{
|
||||||
|
/**
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
enableURL?: boolean;
|
||||||
|
}> = (props) => {
|
||||||
|
const { enableURL = true } = props;
|
||||||
|
const value = useMemo(() => ({ enableURL }), [enableURL]);
|
||||||
|
|
||||||
|
return <PopupSettingsContext.Provider value={value}>{props.children}</PopupSettingsContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for accessing the popup settings.
|
* Hook for accessing the popup settings.
|
||||||
* @returns The popup settings.
|
* @returns The popup settings.
|
||||||
*/
|
*/
|
||||||
export const usePopupSettings = () => {
|
export const usePopupSettings = () => {
|
||||||
|
const { enableURL } = React.useContext(PopupSettingsContext);
|
||||||
|
|
||||||
const isPopupVisibleControlledByURL = useCallback(() => {
|
const isPopupVisibleControlledByURL = useCallback(() => {
|
||||||
const pathname = window.location.pathname;
|
const pathname = window.location.pathname;
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
@ -21,8 +39,8 @@ export const usePopupSettings = () => {
|
|||||||
const isNewMobileMode = pathname?.includes('/m/');
|
const isNewMobileMode = pathname?.includes('/m/');
|
||||||
const isPCMode = pathname?.includes('/admin/');
|
const isPCMode = pathname?.includes('/admin/');
|
||||||
|
|
||||||
return (isPCMode || isNewMobileMode) && !isOldMobileMode;
|
return (isPCMode || isNewMobileMode) && !isOldMobileMode && enableURL;
|
||||||
}, []);
|
}, [enableURL]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/** 弹窗窗口的显隐是否由 URL 控制 */
|
/** 弹窗窗口的显隐是否由 URL 控制 */
|
||||||
|
@ -15,3 +15,4 @@ export * from './Page.Settings';
|
|||||||
export { PagePopups } from './PagePopups';
|
export { PagePopups } from './PagePopups';
|
||||||
export { storePopupContext } from './pagePopupUtils';
|
export { storePopupContext } from './pagePopupUtils';
|
||||||
export * from './PageTab.Settings';
|
export * from './PageTab.Settings';
|
||||||
|
export { PopupSettingsProvider } from './PopupSettingsProvider';
|
||||||
|
@ -127,7 +127,16 @@ export const getPopupPathFromParams = (params: PopupParams) => {
|
|||||||
* Note: use this hook in a plugin is not recommended
|
* Note: use this hook in a plugin is not recommended
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const usePopupUtils = () => {
|
export const usePopupUtils = (
|
||||||
|
options: {
|
||||||
|
/**
|
||||||
|
* when the popup does not support opening via URL, you can control the display status of the popup through this method
|
||||||
|
* @param visible
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setVisible?: (visible: boolean) => void;
|
||||||
|
} = {},
|
||||||
|
) => {
|
||||||
const navigate = useNavigateNoUpdate();
|
const navigate = useNavigateNoUpdate();
|
||||||
const location = useLocationNoUpdate();
|
const location = useLocationNoUpdate();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
@ -141,14 +150,16 @@ export const usePopupUtils = () => {
|
|||||||
const { params: popupParams } = useCurrentPopupContext();
|
const { params: popupParams } = useCurrentPopupContext();
|
||||||
const service = useDataBlockRequest();
|
const service = useDataBlockRequest();
|
||||||
const { isPopupVisibleControlledByURL } = usePopupSettings();
|
const { isPopupVisibleControlledByURL } = usePopupSettings();
|
||||||
const { setVisible: setVisibleFromAction } = useContext(ActionContext);
|
const { setVisible: _setVisibleFromAction } = useContext(ActionContext);
|
||||||
const { updatePopupContext } = usePopupContextInActionOrAssociationField();
|
const { updatePopupContext } = usePopupContextInActionOrAssociationField();
|
||||||
|
const currentPopupContext = useCurrentPopupContext();
|
||||||
const getSourceId = useCallback(
|
const getSourceId = useCallback(
|
||||||
(_parentRecordData?: Record<string, any>) =>
|
(_parentRecordData?: Record<string, any>) =>
|
||||||
(_parentRecordData || parentRecord?.data)?.[cm.getSourceKeyByAssociation(association)],
|
(_parentRecordData || parentRecord?.data)?.[cm.getSourceKeyByAssociation(association)],
|
||||||
[parentRecord, association],
|
[parentRecord, association],
|
||||||
);
|
);
|
||||||
const currentPopupUidWithoutOpened = fieldSchema?.['x-uid'];
|
|
||||||
|
const setVisibleFromAction = options.setVisible || _setVisibleFromAction;
|
||||||
|
|
||||||
const getNewPathname = useCallback(
|
const getNewPathname = useCallback(
|
||||||
({
|
({
|
||||||
@ -199,6 +210,7 @@ export const usePopupUtils = () => {
|
|||||||
parentRecordData,
|
parentRecordData,
|
||||||
collectionNameUsedInURL,
|
collectionNameUsedInURL,
|
||||||
popupUidUsedInURL,
|
popupUidUsedInURL,
|
||||||
|
customActionSchema,
|
||||||
}: {
|
}: {
|
||||||
recordData?: Record<string, any>;
|
recordData?: Record<string, any>;
|
||||||
parentRecordData?: Record<string, any>;
|
parentRecordData?: Record<string, any>;
|
||||||
@ -206,11 +218,13 @@ export const usePopupUtils = () => {
|
|||||||
collectionNameUsedInURL?: string;
|
collectionNameUsedInURL?: string;
|
||||||
/** if this value exists, it will be saved in the URL */
|
/** if this value exists, it will be saved in the URL */
|
||||||
popupUidUsedInURL?: string;
|
popupUidUsedInURL?: string;
|
||||||
|
customActionSchema?: ISchema;
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
if (!isPopupVisibleControlledByURL()) {
|
if (!isPopupVisibleControlledByURL()) {
|
||||||
return setVisibleFromAction?.(true);
|
return setVisibleFromAction?.(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentPopupUidWithoutOpened = customActionSchema?.['x-uid'] || fieldSchema?.['x-uid'];
|
||||||
const sourceId = getSourceId(parentRecordData);
|
const sourceId = getSourceId(parentRecordData);
|
||||||
|
|
||||||
recordData = recordData || record?.data;
|
recordData = recordData || record?.data;
|
||||||
@ -227,7 +241,7 @@ export const usePopupUtils = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
storePopupContext(currentPopupUidWithoutOpened, {
|
storePopupContext(currentPopupUidWithoutOpened, {
|
||||||
schema: fieldSchema,
|
schema: customActionSchema || fieldSchema,
|
||||||
record: new CollectionRecord({ isNew: false, data: recordData }),
|
record: new CollectionRecord({ isNew: false, data: recordData }),
|
||||||
parentRecord: parentRecordData ? new CollectionRecord({ isNew: false, data: parentRecordData }) : parentRecord,
|
parentRecord: parentRecordData ? new CollectionRecord({ isNew: false, data: parentRecordData }) : parentRecord,
|
||||||
service,
|
service,
|
||||||
@ -237,7 +251,7 @@ export const usePopupUtils = () => {
|
|||||||
sourceId,
|
sourceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
updatePopupContext(getPopupContext());
|
updatePopupContext(getPopupContext(), customActionSchema);
|
||||||
|
|
||||||
navigate(withSearchParams(`${url}${pathname}`));
|
navigate(withSearchParams(`${url}${pathname}`));
|
||||||
},
|
},
|
||||||
@ -256,7 +270,6 @@ export const usePopupUtils = () => {
|
|||||||
isPopupVisibleControlledByURL,
|
isPopupVisibleControlledByURL,
|
||||||
getSourceId,
|
getSourceId,
|
||||||
getPopupContext,
|
getPopupContext,
|
||||||
currentPopupUidWithoutOpened,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -317,6 +330,7 @@ export const usePopupUtils = () => {
|
|||||||
closePopup,
|
closePopup,
|
||||||
savePopupSchemaToSchema,
|
savePopupSchemaToSchema,
|
||||||
getPopupSchemaFromSchema,
|
getPopupSchemaFromSchema,
|
||||||
|
context: currentPopupContext,
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* TODO: remove this
|
* TODO: remove this
|
||||||
|
@ -29,18 +29,19 @@ export const usePopupContextInActionOrAssociationField = () => {
|
|||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
|
|
||||||
const updatePopupContext = useCallback(
|
const updatePopupContext = useCallback(
|
||||||
(context: PopupContext) => {
|
(context: PopupContext, customSchema?: ISchema) => {
|
||||||
|
customSchema = customSchema || fieldSchema;
|
||||||
context = _.omitBy(context, _.isNil) as PopupContext;
|
context = _.omitBy(context, _.isNil) as PopupContext;
|
||||||
|
|
||||||
if (_.isEqual(context, getPopupContextFromActionOrAssociationFieldSchema(fieldSchema))) {
|
if (_.isEqual(context, getPopupContextFromActionOrAssociationFieldSchema(customSchema))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldSchema[CONTEXT_SCHEMA_KEY] = context;
|
customSchema[CONTEXT_SCHEMA_KEY] = context;
|
||||||
|
|
||||||
return dn.emit('patch', {
|
return dn.emit('patch', {
|
||||||
schema: {
|
schema: {
|
||||||
'x-uid': fieldSchema['x-uid'],
|
'x-uid': customSchema['x-uid'],
|
||||||
[CONTEXT_SCHEMA_KEY]: context,
|
[CONTEXT_SCHEMA_KEY]: context,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ACLActionProvider, PopupSettingsProvider } from '@nocobase/client';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
|
export const BulkEditActionDecorator: FC = (props) => {
|
||||||
|
return (
|
||||||
|
<PopupSettingsProvider enableURL={false}>
|
||||||
|
<ACLActionProvider>{props.children}</ACLActionProvider>
|
||||||
|
</PopupSettingsProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
import { Plugin, useActionAvailable } from '@nocobase/client';
|
import { Plugin, useActionAvailable } from '@nocobase/client';
|
||||||
import { bulkEditActionSettings, deprecatedBulkEditActionSettings } from './BulkEditAction.Settings';
|
import { bulkEditActionSettings, deprecatedBulkEditActionSettings } from './BulkEditAction.Settings';
|
||||||
|
import { BulkEditActionDecorator } from './BulkEditActionDecorator';
|
||||||
import { BulkEditActionInitializer } from './BulkEditActionInitializer';
|
import { BulkEditActionInitializer } from './BulkEditActionInitializer';
|
||||||
import {
|
import {
|
||||||
BulkEditBlockInitializers_deprecated,
|
BulkEditBlockInitializers_deprecated,
|
||||||
@ -25,7 +26,7 @@ import { BulkEditField } from './component/BulkEditField';
|
|||||||
import { useCustomizeBulkEditActionProps } from './utils';
|
import { useCustomizeBulkEditActionProps } from './utils';
|
||||||
export class PluginActionBulkEditClient extends Plugin {
|
export class PluginActionBulkEditClient extends Plugin {
|
||||||
async load() {
|
async load() {
|
||||||
this.app.addComponents({ BulkEditField });
|
this.app.addComponents({ BulkEditField, BulkEditActionDecorator });
|
||||||
this.app.addScopes({ useCustomizeBulkEditActionProps });
|
this.app.addScopes({ useCustomizeBulkEditActionProps });
|
||||||
this.app.schemaSettingsManager.add(deprecatedBulkEditActionSettings);
|
this.app.schemaSettingsManager.add(deprecatedBulkEditActionSettings);
|
||||||
this.app.schemaSettingsManager.add(bulkEditActionSettings);
|
this.app.schemaSettingsManager.add(bulkEditActionSettings);
|
||||||
@ -45,7 +46,7 @@ export class PluginActionBulkEditClient extends Plugin {
|
|||||||
Component: BulkEditActionInitializer,
|
Component: BulkEditActionInitializer,
|
||||||
schema: {
|
schema: {
|
||||||
'x-align': 'right',
|
'x-align': 'right',
|
||||||
'x-decorator': 'ACLActionProvider',
|
'x-decorator': 'BulkEditActionDecorator',
|
||||||
'x-action': 'customize:bulkEdit',
|
'x-action': 'customize:bulkEdit',
|
||||||
'x-toolbar': 'ActionSchemaToolbar',
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
'x-settings': 'actionSettings:bulkEdit',
|
'x-settings': 'actionSettings:bulkEdit',
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
ActionContextProvider,
|
ActionContextProvider,
|
||||||
CollectionProvider_deprecated,
|
CollectionProvider_deprecated,
|
||||||
FormBlockContext,
|
FormBlockContext,
|
||||||
|
PopupSettingsProvider,
|
||||||
RecordProvider,
|
RecordProvider,
|
||||||
fetchTemplateData,
|
fetchTemplateData,
|
||||||
useACLActionParamsContext,
|
useACLActionParamsContext,
|
||||||
@ -203,7 +204,9 @@ export const DuplicateAction = observer(
|
|||||||
{/* 这里的 record 就是弹窗中创建表单的 sourceRecord */}
|
{/* 这里的 record 就是弹窗中创建表单的 sourceRecord */}
|
||||||
<RecordProvider record={{ ...parentRecordData, __collection: duplicateCollection || __collection }}>
|
<RecordProvider record={{ ...parentRecordData, __collection: duplicateCollection || __collection }}>
|
||||||
<ActionContextProvider value={{ ...ctx, visible, setVisible }}>
|
<ActionContextProvider value={{ ...ctx, visible, setVisible }}>
|
||||||
<RecursionField schema={fieldSchema} basePath={field.address} onlyRenderProperties />
|
<PopupSettingsProvider enableURL={false}>
|
||||||
|
<RecursionField schema={fieldSchema} basePath={field.address} onlyRenderProperties />
|
||||||
|
</PopupSettingsProvider>
|
||||||
</ActionContextProvider>
|
</ActionContextProvider>
|
||||||
</RecordProvider>
|
</RecordProvider>
|
||||||
</CollectionProvider_deprecated>
|
</CollectionProvider_deprecated>
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ACLActionProvider } from '@nocobase/client';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
|
export const DuplicateActionDecorator: FC = (props) => {
|
||||||
|
return <ACLActionProvider>{props.children}</ACLActionProvider>;
|
||||||
|
};
|
@ -19,7 +19,7 @@ export const DuplicateActionInitializer = (props) => {
|
|||||||
'x-acl-action': 'create',
|
'x-acl-action': 'create',
|
||||||
title: '{{ t("Duplicate") }}',
|
title: '{{ t("Duplicate") }}',
|
||||||
'x-component': 'Action.Link',
|
'x-component': 'Action.Link',
|
||||||
'x-decorator': 'ACLActionProvider',
|
'x-decorator': 'DuplicateActionDecorator',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
openMode: defaultOpenMode,
|
openMode: defaultOpenMode,
|
||||||
component: 'DuplicateAction',
|
component: 'DuplicateAction',
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import { Plugin, useActionAvailable } from '@nocobase/client';
|
import { Plugin, useActionAvailable } from '@nocobase/client';
|
||||||
import { DuplicateAction } from './DuplicateAction';
|
import { DuplicateAction } from './DuplicateAction';
|
||||||
import { deprecatedDuplicateActionSettings, duplicateActionSettings } from './DuplicateAction.Settings';
|
import { deprecatedDuplicateActionSettings, duplicateActionSettings } from './DuplicateAction.Settings';
|
||||||
|
import { DuplicateActionDecorator } from './DuplicateActionDecorator';
|
||||||
import { DuplicateActionInitializer } from './DuplicateActionInitializer';
|
import { DuplicateActionInitializer } from './DuplicateActionInitializer';
|
||||||
import { DuplicatePluginProvider } from './DuplicatePluginProvider';
|
import { DuplicatePluginProvider } from './DuplicatePluginProvider';
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ export class PluginActionDuplicateClient extends Plugin {
|
|||||||
this.app.addComponents({
|
this.app.addComponents({
|
||||||
DuplicateActionInitializer,
|
DuplicateActionInitializer,
|
||||||
DuplicateAction,
|
DuplicateAction,
|
||||||
|
DuplicateActionDecorator,
|
||||||
});
|
});
|
||||||
this.app.schemaSettingsManager.add(deprecatedDuplicateActionSettings);
|
this.app.schemaSettingsManager.add(deprecatedDuplicateActionSettings);
|
||||||
this.app.schemaSettingsManager.add(duplicateActionSettings);
|
this.app.schemaSettingsManager.add(duplicateActionSettings);
|
||||||
@ -31,7 +33,7 @@ export class PluginActionDuplicateClient extends Plugin {
|
|||||||
'x-action': 'duplicate',
|
'x-action': 'duplicate',
|
||||||
'x-toolbar': 'ActionSchemaToolbar',
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
'x-settings': 'actionSettings:duplicate',
|
'x-settings': 'actionSettings:duplicate',
|
||||||
'x-decorator': 'ACLActionProvider',
|
'x-decorator': 'DuplicateActionDecorator',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
},
|
},
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
|
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
|
||||||
import { RecursionField, Schema, observer, useFieldSchema } from '@formily/react';
|
import { RecursionField, Schema, observer, useFieldSchema } from '@formily/react';
|
||||||
import {
|
import {
|
||||||
ActionContextProvider,
|
PopupContextProvider,
|
||||||
RecordProvider,
|
RecordProvider,
|
||||||
VariablePopupRecordProvider,
|
|
||||||
getLabelFormatValue,
|
getLabelFormatValue,
|
||||||
useCollection,
|
useCollection,
|
||||||
useCollectionParentRecordData,
|
useCollectionParentRecordData,
|
||||||
|
usePopupUtils,
|
||||||
useProps,
|
useProps,
|
||||||
withDynamicSchemaProps,
|
withDynamicSchemaProps,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
@ -23,10 +23,11 @@ import { parseExpression } from 'cron-parser';
|
|||||||
import type { Dayjs } from 'dayjs';
|
import type { Dayjs } from 'dayjs';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { Calendar as BigCalendar, View, dayjsLocalizer } from 'react-big-calendar';
|
import { Calendar as BigCalendar, View, dayjsLocalizer } from 'react-big-calendar';
|
||||||
import * as dates from 'react-big-calendar/lib/utils/dates';
|
import * as dates from 'react-big-calendar/lib/utils/dates';
|
||||||
import { i18nt, useTranslation } from '../../locale';
|
import { i18nt, useTranslation } from '../../locale';
|
||||||
|
import { CalendarRecordViewer, findEventSchema } from './CalendarRecordViewer';
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import { CalendarToolbarContext } from './context';
|
import { CalendarToolbarContext } from './context';
|
||||||
import GlobalStyle from './global.style';
|
import GlobalStyle from './global.style';
|
||||||
@ -160,54 +161,24 @@ const useEvents = (dataSource: any, fieldNames: any, date: Date, view: (typeof W
|
|||||||
}, [dataSource, fieldNames.start, fieldNames.end, fieldNames.id, fieldNames.title, date, view, t]);
|
}, [dataSource, fieldNames.start, fieldNames.end, fieldNames.id, fieldNames.title, date, view, t]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CalendarRecordViewer = (props) => {
|
|
||||||
const { visible, setVisible, record } = props;
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const collection = useCollection();
|
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const eventSchema: Schema = useMemo(
|
|
||||||
() =>
|
|
||||||
fieldSchema.reduceProperties((buf, current) => {
|
|
||||||
if (current['x-component'].endsWith('.Event')) {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}, null),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const close = useCallback(() => {
|
|
||||||
setVisible(false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
eventSchema && (
|
|
||||||
<DeleteEventContext.Provider value={{ close }}>
|
|
||||||
<ActionContextProvider value={{ visible, setVisible }}>
|
|
||||||
<RecordProvider record={record} parent={parentRecordData}>
|
|
||||||
<VariablePopupRecordProvider recordData={record} collection={collection}>
|
|
||||||
<RecursionField schema={eventSchema} name={eventSchema.name} />
|
|
||||||
</VariablePopupRecordProvider>
|
|
||||||
</RecordProvider>
|
|
||||||
</ActionContextProvider>
|
|
||||||
</DeleteEventContext.Provider>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Calendar: any = withDynamicSchemaProps(
|
export const Calendar: any = withDynamicSchemaProps(
|
||||||
observer(
|
observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { openPopup } = usePopupUtils({
|
||||||
|
setVisible,
|
||||||
|
});
|
||||||
|
|
||||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||||
const { dataSource, fieldNames, showLunar } = useProps(props);
|
const { dataSource, fieldNames, showLunar } = useProps(props);
|
||||||
const height = useCalenderHeight();
|
const height = useCalenderHeight();
|
||||||
const [date, setDate] = useState<Date>(new Date());
|
const [date, setDate] = useState<Date>(new Date());
|
||||||
const [view, setView] = useState<View>('month');
|
const [view, setView] = useState<View>('month');
|
||||||
const events = useEvents(dataSource, fieldNames, date, view);
|
const events = useEvents(dataSource, fieldNames, date, view);
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const [record, setRecord] = useState<any>({});
|
const [record, setRecord] = useState<any>({});
|
||||||
const { wrapSSR, hashId, componentCls: containerClassName } = useStyle();
|
const { wrapSSR, hashId, componentCls: containerClassName } = useStyle();
|
||||||
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
|
||||||
const components = useMemo(() => {
|
const components = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
@ -247,50 +218,57 @@ export const Calendar: any = withDynamicSchemaProps(
|
|||||||
};
|
};
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<div className={`${hashId} ${containerClassName}`} style={{ height: height || 700 }}>
|
<div className={`${hashId} ${containerClassName}`} style={{ height: height || 700 }}>
|
||||||
<GlobalStyle />
|
<PopupContextProvider visible={visible} setVisible={setVisible}>
|
||||||
<CalendarRecordViewer visible={visible} setVisible={setVisible} record={record} />
|
<GlobalStyle />
|
||||||
<BigCalendar
|
<RecordProvider record={record} parent={parentRecordData}>
|
||||||
popup
|
<CalendarRecordViewer />
|
||||||
selectable
|
</RecordProvider>
|
||||||
events={events}
|
<BigCalendar
|
||||||
view={view}
|
popup
|
||||||
views={Weeks}
|
selectable
|
||||||
date={date}
|
events={events}
|
||||||
step={60}
|
view={view}
|
||||||
showMultiDayTimes
|
views={Weeks}
|
||||||
messages={messages}
|
date={date}
|
||||||
onNavigate={setDate}
|
step={60}
|
||||||
onView={setView}
|
showMultiDayTimes
|
||||||
onSelectSlot={(slotInfo) => {
|
messages={messages}
|
||||||
console.log('onSelectSlot', slotInfo);
|
onNavigate={setDate}
|
||||||
}}
|
onView={setView}
|
||||||
onDoubleClickEvent={() => {
|
onSelectSlot={(slotInfo) => {
|
||||||
console.log('onDoubleClickEvent');
|
console.log('onSelectSlot', slotInfo);
|
||||||
}}
|
}}
|
||||||
onSelectEvent={(event) => {
|
onDoubleClickEvent={() => {
|
||||||
const record = dataSource?.find((item) => item[fieldNames.id] === event.id);
|
console.log('onDoubleClickEvent');
|
||||||
if (!record) {
|
}}
|
||||||
return;
|
onSelectEvent={(event) => {
|
||||||
}
|
const record = dataSource?.find((item) => item[fieldNames.id] === event.id);
|
||||||
record.__event = { ...event, start: formatDate(dayjs(event.start)), end: formatDate(dayjs(event.end)) };
|
if (!record) {
|
||||||
|
return;
|
||||||
setRecord(record);
|
|
||||||
setVisible(true);
|
|
||||||
}}
|
|
||||||
formats={{
|
|
||||||
monthHeaderFormat: 'YYYY-M',
|
|
||||||
agendaDateFormat: 'M-DD',
|
|
||||||
dayHeaderFormat: 'YYYY-M-DD',
|
|
||||||
dayRangeHeaderFormat: ({ start, end }, culture, local) => {
|
|
||||||
if (dates.eq(start, end, 'month')) {
|
|
||||||
return local.format(start, 'YYYY-M', culture);
|
|
||||||
}
|
}
|
||||||
return `${local.format(start, 'YYYY-M', culture)} - ${local.format(end, 'YYYY-M', culture)}`;
|
record.__event = { ...event, start: formatDate(dayjs(event.start)), end: formatDate(dayjs(event.end)) };
|
||||||
},
|
|
||||||
}}
|
setRecord(record);
|
||||||
components={components}
|
openPopup({
|
||||||
localizer={localizer}
|
recordData: record,
|
||||||
/>
|
customActionSchema: findEventSchema(fieldSchema),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
formats={{
|
||||||
|
monthHeaderFormat: 'YYYY-M',
|
||||||
|
agendaDateFormat: 'M-DD',
|
||||||
|
dayHeaderFormat: 'YYYY-M-DD',
|
||||||
|
dayRangeHeaderFormat: ({ start, end }, culture, local) => {
|
||||||
|
if (dates.eq(start, end, 'month')) {
|
||||||
|
return local.format(start, 'YYYY-M', culture);
|
||||||
|
}
|
||||||
|
return `${local.format(start, 'YYYY-M', culture)} - ${local.format(end, 'YYYY-M', culture)}`;
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
components={components}
|
||||||
|
localizer={localizer}
|
||||||
|
/>
|
||||||
|
</PopupContextProvider>
|
||||||
</div>,
|
</div>,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RecursionField, Schema, useFieldSchema } from '@formily/react';
|
||||||
|
import React, { FC, useMemo } from 'react';
|
||||||
|
|
||||||
|
export const CalendarRecordViewer: FC = (props) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const eventSchema: Schema = useMemo(() => findEventSchema(fieldSchema), [fieldSchema]);
|
||||||
|
|
||||||
|
if (!eventSchema) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <RecursionField schema={eventSchema} name={eventSchema.name} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function findEventSchema(schema: Schema) {
|
||||||
|
if (schema['x-component'].endsWith('.Event')) {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
return schema.reduceProperties((buf, current) => {
|
||||||
|
if (current['x-component'].endsWith('.Event')) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}, null);
|
||||||
|
}
|
@ -8,11 +8,35 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { observer } from '@formily/react';
|
import { observer } from '@formily/react';
|
||||||
import React from 'react';
|
import {
|
||||||
|
PopupContextProvider,
|
||||||
|
useActionContext,
|
||||||
|
useCollection,
|
||||||
|
useCollectionRecordData,
|
||||||
|
VariablePopupRecordProvider,
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { DeleteEventContext } from './Calendar';
|
||||||
|
|
||||||
export const Event = observer(
|
export const Event = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
return <>{props.children}</>;
|
const { visible, setVisible } = useActionContext();
|
||||||
|
const recordData = useCollectionRecordData();
|
||||||
|
const collection = useCollection();
|
||||||
|
|
||||||
|
const close = useCallback(() => {
|
||||||
|
setVisible(false);
|
||||||
|
}, [setVisible]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopupContextProvider visible={visible} setVisible={setVisible}>
|
||||||
|
<DeleteEventContext.Provider value={{ close }}>
|
||||||
|
<VariablePopupRecordProvider recordData={recordData} collection={collection}>
|
||||||
|
{props.children}
|
||||||
|
</VariablePopupRecordProvider>
|
||||||
|
</DeleteEventContext.Provider>
|
||||||
|
</PopupContextProvider>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{ displayName: 'Event' },
|
{ displayName: 'Event' },
|
||||||
);
|
);
|
||||||
|
@ -8,11 +8,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { observer } from '@formily/react';
|
import { observer } from '@formily/react';
|
||||||
|
import {
|
||||||
|
PopupContextProvider,
|
||||||
|
useActionContext,
|
||||||
|
useCollection,
|
||||||
|
useCollectionRecordData,
|
||||||
|
VariablePopupRecordProvider,
|
||||||
|
} from '@nocobase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const Event = observer(
|
export const Event = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
return <>{props.children}</>;
|
const { visible, setVisible } = useActionContext();
|
||||||
|
const recordData = useCollectionRecordData();
|
||||||
|
const collection = useCollection();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopupContextProvider visible={visible} setVisible={setVisible}>
|
||||||
|
<VariablePopupRecordProvider recordData={recordData} collection={collection}>
|
||||||
|
{props.children}
|
||||||
|
</VariablePopupRecordProvider>
|
||||||
|
</PopupContextProvider>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{ displayName: 'Event' },
|
{ displayName: 'Event' },
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RecursionField, useFieldSchema } from '@formily/react';
|
||||||
|
import { Schema } from '@nocobase/utils';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
|
export const GanttRecordViewer: FC = (props) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const eventSchema: Schema = fieldSchema.properties.detail;
|
||||||
|
|
||||||
|
if (!eventSchema) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <RecursionField schema={eventSchema} name={eventSchema.name} />;
|
||||||
|
};
|
@ -8,17 +8,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { RecursionField, Schema, useFieldSchema } from '@formily/react';
|
import { RecursionField, useFieldSchema } from '@formily/react';
|
||||||
import {
|
import {
|
||||||
ActionContextProvider,
|
PopupContextProvider,
|
||||||
RecordProvider,
|
RecordProvider,
|
||||||
VariablePopupRecordProvider,
|
|
||||||
useAPIClient,
|
useAPIClient,
|
||||||
useBlockRequestContext,
|
useBlockRequestContext,
|
||||||
useCollection,
|
|
||||||
useCollectionParentRecordData,
|
useCollectionParentRecordData,
|
||||||
useCurrentAppInfo,
|
useCurrentAppInfo,
|
||||||
useDesignable,
|
useDesignable,
|
||||||
|
usePopupUtils,
|
||||||
useProps,
|
useProps,
|
||||||
useTableBlockContext,
|
useTableBlockContext,
|
||||||
useToken,
|
useToken,
|
||||||
@ -26,7 +25,7 @@ import {
|
|||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { Spin, message } from 'antd';
|
import { Spin, message } from 'antd';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import React, { SyntheticEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { SyntheticEvent, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useGanttBlockContext } from '../../GanttBlockProvider';
|
import { useGanttBlockContext } from '../../GanttBlockProvider';
|
||||||
import { convertToBarTasks } from '../../helpers/bar-helper';
|
import { convertToBarTasks } from '../../helpers/bar-helper';
|
||||||
@ -41,6 +40,7 @@ import { GridProps } from '../grid/grid';
|
|||||||
import { HorizontalScroll } from '../other/horizontal-scroll';
|
import { HorizontalScroll } from '../other/horizontal-scroll';
|
||||||
import { StandardTooltipContent, Tooltip } from '../other/tooltip';
|
import { StandardTooltipContent, Tooltip } from '../other/tooltip';
|
||||||
import { VerticalScroll } from '../other/vertical-scroll';
|
import { VerticalScroll } from '../other/vertical-scroll';
|
||||||
|
import { GanttRecordViewer } from './GanttRecordViewer';
|
||||||
import useStyles from './style';
|
import useStyles from './style';
|
||||||
import { TaskGantt } from './task-gantt';
|
import { TaskGantt } from './task-gantt';
|
||||||
import { TaskGanttContentProps } from './task-gantt-content';
|
import { TaskGanttContentProps } from './task-gantt-content';
|
||||||
@ -49,34 +49,7 @@ const getColumnWidth = (dataSetLength: any, clientWidth: any) => {
|
|||||||
const columnWidth = clientWidth / dataSetLength > 50 ? Math.floor(clientWidth / dataSetLength) + 20 : 50;
|
const columnWidth = clientWidth / dataSetLength > 50 ? Math.floor(clientWidth / dataSetLength) + 20 : 50;
|
||||||
return columnWidth;
|
return columnWidth;
|
||||||
};
|
};
|
||||||
export const DeleteEventContext = React.createContext({
|
|
||||||
close: () => {},
|
|
||||||
});
|
|
||||||
const GanttRecordViewer = (props) => {
|
|
||||||
const { visible, setVisible, record } = props;
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const collection = useCollection();
|
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const eventSchema: Schema = fieldSchema.properties.detail;
|
|
||||||
const close = useCallback(() => {
|
|
||||||
setVisible(false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
eventSchema && (
|
|
||||||
<DeleteEventContext.Provider value={{ close }}>
|
|
||||||
<ActionContextProvider value={{ visible, setVisible }}>
|
|
||||||
<RecordProvider record={record} parent={parentRecordData}>
|
|
||||||
<VariablePopupRecordProvider recordData={record} collection={collection}>
|
|
||||||
<RecursionField schema={eventSchema} name={eventSchema.name} />
|
|
||||||
</VariablePopupRecordProvider>
|
|
||||||
</RecordProvider>
|
|
||||||
</ActionContextProvider>
|
|
||||||
</DeleteEventContext.Provider>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const debounceHandleTaskChange = debounce(async (task: Task, resource, fieldNames, service, t) => {
|
const debounceHandleTaskChange = debounce(async (task: Task, resource, fieldNames, service, t) => {
|
||||||
await resource.update({
|
await resource.update({
|
||||||
filterByTk: task.id,
|
filterByTk: task.id,
|
||||||
@ -160,7 +133,11 @@ export const Gantt: any = withDynamicSchemaProps((props: any) => {
|
|||||||
return { viewMode, dates: seedDates(startDate, endDate, viewMode) };
|
return { viewMode, dates: seedDates(startDate, endDate, viewMode) };
|
||||||
});
|
});
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { openPopup } = usePopupUtils({
|
||||||
|
setVisible,
|
||||||
|
});
|
||||||
const [record, setRecord] = useState<any>({});
|
const [record, setRecord] = useState<any>({});
|
||||||
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
const [currentViewDate, setCurrentViewDate] = useState<Date | undefined>(undefined);
|
const [currentViewDate, setCurrentViewDate] = useState<Date | undefined>(undefined);
|
||||||
const [taskListWidth, setTaskListWidth] = useState(0);
|
const [taskListWidth, setTaskListWidth] = useState(0);
|
||||||
const [svgContainerWidth, setSvgContainerWidth] = useState(0);
|
const [svgContainerWidth, setSvgContainerWidth] = useState(0);
|
||||||
@ -473,7 +450,10 @@ export const Gantt: any = withDynamicSchemaProps((props: any) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setRecord(recordData);
|
setRecord(recordData);
|
||||||
setVisible(true);
|
openPopup({
|
||||||
|
recordData,
|
||||||
|
customActionSchema: fieldSchema.properties.detail,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const gridProps: GridProps = {
|
const gridProps: GridProps = {
|
||||||
columnWidth,
|
columnWidth,
|
||||||
@ -536,55 +516,59 @@ export const Gantt: any = withDynamicSchemaProps((props: any) => {
|
|||||||
`)}
|
`)}
|
||||||
ref={ganttRef}
|
ref={ganttRef}
|
||||||
>
|
>
|
||||||
<GanttRecordViewer visible={visible} setVisible={setVisible} record={record} />
|
<PopupContextProvider visible={visible} setVisible={setVisible}>
|
||||||
<RecursionField name={'anctionBar'} schema={fieldSchema.properties.toolBar} />
|
<RecordProvider record={record} parent={parentRecordData}>
|
||||||
<RecursionField name={'table'} schema={fieldSchema.properties.table} />
|
<GanttRecordViewer />
|
||||||
<div className={styles.wrapper} onKeyDown={handleKeyDown} tabIndex={0} ref={wrapperRef}>
|
</RecordProvider>
|
||||||
<TaskGantt
|
<RecursionField name={'anctionBar'} schema={fieldSchema.properties.toolBar} />
|
||||||
gridProps={gridProps}
|
<RecursionField name={'table'} schema={fieldSchema.properties.table} />
|
||||||
calendarProps={calendarProps}
|
<div className={styles.wrapper} onKeyDown={handleKeyDown} tabIndex={0} ref={wrapperRef}>
|
||||||
barProps={barProps}
|
<TaskGantt
|
||||||
ganttHeight={ganttHeight}
|
gridProps={gridProps}
|
||||||
scrollY={scrollY}
|
calendarProps={calendarProps}
|
||||||
scrollX={scrollX}
|
barProps={barProps}
|
||||||
ref={verticalGanttContainerRef}
|
ganttHeight={ganttHeight}
|
||||||
/>
|
|
||||||
{ganttEvent.changedTask && (
|
|
||||||
<Tooltip
|
|
||||||
arrowIndent={arrowIndent}
|
|
||||||
rowHeight={rowHeight}
|
|
||||||
svgContainerHeight={svgContainerHeight}
|
|
||||||
svgContainerWidth={svgContainerWidth}
|
|
||||||
fontFamily={fontFamily}
|
|
||||||
fontSize={fontSize}
|
|
||||||
scrollX={scrollX}
|
|
||||||
scrollY={scrollY}
|
scrollY={scrollY}
|
||||||
task={ganttEvent.changedTask}
|
scrollX={scrollX}
|
||||||
|
ref={verticalGanttContainerRef}
|
||||||
|
/>
|
||||||
|
{ganttEvent.changedTask && (
|
||||||
|
<Tooltip
|
||||||
|
arrowIndent={arrowIndent}
|
||||||
|
rowHeight={rowHeight}
|
||||||
|
svgContainerHeight={svgContainerHeight}
|
||||||
|
svgContainerWidth={svgContainerWidth}
|
||||||
|
fontFamily={fontFamily}
|
||||||
|
fontSize={fontSize}
|
||||||
|
scrollX={scrollX}
|
||||||
|
scrollY={scrollY}
|
||||||
|
task={ganttEvent.changedTask}
|
||||||
|
headerHeight={headerHeight}
|
||||||
|
taskListWidth={taskListWidth}
|
||||||
|
TooltipContent={TooltipContent}
|
||||||
|
rtl={rtl}
|
||||||
|
svgWidth={svgWidth}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<VerticalScroll
|
||||||
|
ganttFullHeight={ganttFullHeight}
|
||||||
|
ganttHeight={ganttHeight}
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
taskListWidth={taskListWidth}
|
scroll={scrollY}
|
||||||
TooltipContent={TooltipContent}
|
onScroll={handleScrollY}
|
||||||
rtl={rtl}
|
rtl={rtl}
|
||||||
svgWidth={svgWidth}
|
|
||||||
/>
|
/>
|
||||||
)}
|
<Spin spinning={loading} style={{ visibility: 'hidden' }}>
|
||||||
<VerticalScroll
|
<HorizontalScroll
|
||||||
ganttFullHeight={ganttFullHeight}
|
svgWidth={svgWidth}
|
||||||
ganttHeight={ganttHeight}
|
taskListWidth={taskListWidth}
|
||||||
headerHeight={headerHeight}
|
scroll={scrollX}
|
||||||
scroll={scrollY}
|
rtl={rtl}
|
||||||
onScroll={handleScrollY}
|
onScroll={handleScrollX}
|
||||||
rtl={rtl}
|
/>
|
||||||
/>
|
</Spin>
|
||||||
<Spin spinning={loading} style={{ visibility: 'hidden' }}>
|
</div>
|
||||||
<HorizontalScroll
|
</PopupContextProvider>
|
||||||
svgWidth={svgWidth}
|
|
||||||
taskListWidth={taskListWidth}
|
|
||||||
scroll={scrollX}
|
|
||||||
rtl={rtl}
|
|
||||||
onScroll={handleScrollX}
|
|
||||||
/>
|
|
||||||
</Spin>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -8,15 +8,29 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
PopupContextProvider,
|
||||||
useCollection_deprecated,
|
useCollection_deprecated,
|
||||||
useCollectionManager_deprecated,
|
useCollectionManager_deprecated,
|
||||||
|
usePopupUtils,
|
||||||
useProps,
|
useProps,
|
||||||
withDynamicSchemaProps,
|
withDynamicSchemaProps,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { MapBlockComponent } from '../components';
|
import { MapBlockComponent } from '../components';
|
||||||
|
import { MapBlockDrawer } from '../components/MapBlockDrawer';
|
||||||
|
|
||||||
export const MapBlock = withDynamicSchemaProps((props) => {
|
export const MapBlock = withDynamicSchemaProps((props) => {
|
||||||
|
const { context } = usePopupUtils();
|
||||||
|
|
||||||
|
// only render the popup
|
||||||
|
if (context.currentLevel) {
|
||||||
|
return (
|
||||||
|
<PopupContextProvider>
|
||||||
|
<MapBlockDrawer />
|
||||||
|
</PopupContextProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||||
const { fieldNames } = useProps(props);
|
const { fieldNames } = useProps(props);
|
||||||
|
|
||||||
|
@ -8,11 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons';
|
import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons';
|
||||||
import { RecursionField, useFieldSchema } from '@formily/react';
|
|
||||||
import {
|
import {
|
||||||
ActionContextProvider,
|
|
||||||
RecordProvider,
|
RecordProvider,
|
||||||
VariablePopupRecordProvider,
|
|
||||||
css,
|
css,
|
||||||
getLabelFormatValue,
|
getLabelFormatValue,
|
||||||
useCollection,
|
useCollection,
|
||||||
@ -21,14 +18,16 @@ import {
|
|||||||
useCollection_deprecated,
|
useCollection_deprecated,
|
||||||
useCompile,
|
useCompile,
|
||||||
useFilterAPI,
|
useFilterAPI,
|
||||||
|
usePopupUtils,
|
||||||
useProps,
|
useProps,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Button, Space } from 'antd';
|
import { Button, Space } from 'antd';
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { defaultImage, selectedImage } from '../../constants';
|
import { defaultImage, selectedImage } from '../../constants';
|
||||||
import { useMapTranslation } from '../../locale';
|
import { useMapTranslation } from '../../locale';
|
||||||
import { getSource } from '../../utils';
|
import { getSource } from '../../utils';
|
||||||
|
import { MapBlockDrawer } from '../MapBlockDrawer';
|
||||||
import { AMapComponent, AMapForwardedRefProps } from './Map';
|
import { AMapComponent, AMapForwardedRefProps } from './Map';
|
||||||
|
|
||||||
export const AMapBlock = (props) => {
|
export const AMapBlock = (props) => {
|
||||||
@ -50,6 +49,9 @@ export const AMapBlock = (props) => {
|
|||||||
const selectingModeRef = useRef(selectingMode);
|
const selectingModeRef = useRef(selectingMode);
|
||||||
selectingModeRef.current = selectingMode;
|
selectingModeRef.current = selectingMode;
|
||||||
const { fields } = useCollection();
|
const { fields } = useCollection();
|
||||||
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
|
const { openPopup } = usePopupUtils();
|
||||||
|
|
||||||
const labelUiSchema = fields.find((v) => v.name === fieldNames?.marker)?.uiSchema;
|
const labelUiSchema = fields.find((v) => v.name === fieldNames?.marker)?.uiSchema;
|
||||||
const setOverlayOptions = (overlay: AMap.Polygon | AMap.Marker, state?: boolean) => {
|
const setOverlayOptions = (overlay: AMap.Polygon | AMap.Marker, state?: boolean) => {
|
||||||
const extData = overlay.getExtData();
|
const extData = overlay.getExtData();
|
||||||
@ -199,6 +201,9 @@ export const AMapBlock = (props) => {
|
|||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
setRecord(data);
|
setRecord(data);
|
||||||
|
openPopup({
|
||||||
|
recordData: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
o.on('click', onClick);
|
o.on('click', onClick);
|
||||||
@ -244,7 +249,17 @@ export const AMapBlock = (props) => {
|
|||||||
});
|
});
|
||||||
events.forEach((e) => e());
|
events.forEach((e) => e());
|
||||||
};
|
};
|
||||||
}, [dataSource, isMapInitialization, fieldNames, name, primaryKey, collectionField.type, isConnected, lineSort]);
|
}, [
|
||||||
|
dataSource,
|
||||||
|
isMapInitialization,
|
||||||
|
fieldNames,
|
||||||
|
name,
|
||||||
|
primaryKey,
|
||||||
|
collectionField.type,
|
||||||
|
isConnected,
|
||||||
|
lineSort,
|
||||||
|
openPopup,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -307,7 +322,9 @@ export const AMapBlock = (props) => {
|
|||||||
</Space>
|
</Space>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<MapBlockDrawer record={record} setVisible={setRecord} />
|
<RecordProvider record={record} parent={parentRecordData}>
|
||||||
|
<MapBlockDrawer />
|
||||||
|
</RecordProvider>
|
||||||
<AMapComponent
|
<AMapComponent
|
||||||
{...collectionField?.uiSchema?.['x-component-props']}
|
{...collectionField?.uiSchema?.['x-component-props']}
|
||||||
ref={mapRefCallback}
|
ref={mapRefCallback}
|
||||||
@ -324,35 +341,6 @@ export const AMapBlock = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MapBlockDrawer = (props) => {
|
|
||||||
const { setVisible, record } = props;
|
|
||||||
const collection = useCollection();
|
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const schema = useMemo(
|
|
||||||
() =>
|
|
||||||
fieldSchema.reduceProperties((buf, current) => {
|
|
||||||
if (current.name === 'drawer') {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}, null),
|
|
||||||
[fieldSchema],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
schema && (
|
|
||||||
<ActionContextProvider value={{ visible: !!record, setVisible }}>
|
|
||||||
<RecordProvider record={record} parent={parentRecordData}>
|
|
||||||
<VariablePopupRecordProvider recordData={record} collection={collection}>
|
|
||||||
<RecursionField schema={schema} name={schema.name} />
|
|
||||||
</VariablePopupRecordProvider>
|
|
||||||
</RecordProvider>
|
|
||||||
</ActionContextProvider>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function clearSelected(marker: AMap.Marker | AMap.Polygon | AMap.Polyline | AMap.Circle) {
|
function clearSelected(marker: AMap.Marker | AMap.Polygon | AMap.Polyline | AMap.Circle) {
|
||||||
if ((marker as AMap.Marker).dom) {
|
if ((marker as AMap.Marker).dom) {
|
||||||
(marker as AMap.Marker).dom.style.filter = 'none';
|
(marker as AMap.Marker).dom.style.filter = 'none';
|
||||||
|
@ -8,11 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons';
|
import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons';
|
||||||
import { RecursionField, Schema, useFieldSchema } from '@formily/react';
|
|
||||||
import {
|
import {
|
||||||
ActionContextProvider,
|
|
||||||
RecordProvider,
|
RecordProvider,
|
||||||
VariablePopupRecordProvider,
|
|
||||||
css,
|
css,
|
||||||
getLabelFormatValue,
|
getLabelFormatValue,
|
||||||
useCollection,
|
useCollection,
|
||||||
@ -21,14 +18,16 @@ import {
|
|||||||
useCollection_deprecated,
|
useCollection_deprecated,
|
||||||
useCompile,
|
useCompile,
|
||||||
useFilterAPI,
|
useFilterAPI,
|
||||||
|
usePopupUtils,
|
||||||
useProps,
|
useProps,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Button, Space } from 'antd';
|
import { Button, Space } from 'antd';
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { defaultImage, selectedImage } from '../../constants';
|
import { defaultImage, selectedImage } from '../../constants';
|
||||||
import { useMapTranslation } from '../../locale';
|
import { useMapTranslation } from '../../locale';
|
||||||
import { getSource } from '../../utils';
|
import { getSource } from '../../utils';
|
||||||
|
import { MapBlockDrawer } from '../MapBlockDrawer';
|
||||||
import { GoogleMapForwardedRefProps, GoogleMapsComponent, OverlayOptions } from './Map';
|
import { GoogleMapForwardedRefProps, GoogleMapsComponent, OverlayOptions } from './Map';
|
||||||
import { getIcon } from './utils';
|
import { getIcon } from './utils';
|
||||||
|
|
||||||
@ -69,8 +68,10 @@ export const GoogleMapsBlock = (props) => {
|
|||||||
const overlaysRef = useRef<google.maps.MVCObject[]>([]);
|
const overlaysRef = useRef<google.maps.MVCObject[]>([]);
|
||||||
selectingModeRef.current = selectingMode;
|
selectingModeRef.current = selectingMode;
|
||||||
const { fields } = useCollection();
|
const { fields } = useCollection();
|
||||||
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
const labelUiSchema = fields.find((v) => v.name === fieldNames?.marker)?.uiSchema;
|
const labelUiSchema = fields.find((v) => v.name === fieldNames?.marker)?.uiSchema;
|
||||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||||
|
const { openPopup } = usePopupUtils();
|
||||||
|
|
||||||
const setOverlayOptions = (overlay: google.maps.MVCObject, state?: boolean) => {
|
const setOverlayOptions = (overlay: google.maps.MVCObject, state?: boolean) => {
|
||||||
const selected = typeof state !== 'undefined' ? !state : overlay.get(OVERLAY_SELECtED);
|
const selected = typeof state !== 'undefined' ? !state : overlay.get(OVERLAY_SELECtED);
|
||||||
@ -234,6 +235,9 @@ export const GoogleMapsBlock = (props) => {
|
|||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
setRecord(data);
|
setRecord(data);
|
||||||
|
openPopup({
|
||||||
|
recordData: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
o.addListener('click', onClick);
|
o.addListener('click', onClick);
|
||||||
@ -291,7 +295,7 @@ export const GoogleMapsBlock = (props) => {
|
|||||||
});
|
});
|
||||||
events.forEach((e) => e());
|
events.forEach((e) => e());
|
||||||
};
|
};
|
||||||
}, [dataSource, isMapInitialization, markerName, collectionField.type, isConnected]);
|
}, [dataSource, isMapInitialization, markerName, collectionField.type, isConnected, openPopup]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -354,7 +358,9 @@ export const GoogleMapsBlock = (props) => {
|
|||||||
) : null}
|
) : null}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
<MapBlockDrawer record={record} setVisible={setRecord} />
|
<RecordProvider record={record} parent={parentRecordData}>
|
||||||
|
<MapBlockDrawer />
|
||||||
|
</RecordProvider>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<GoogleMapsComponent
|
<GoogleMapsComponent
|
||||||
@ -373,35 +379,6 @@ export const GoogleMapsBlock = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MapBlockDrawer = (props) => {
|
|
||||||
const { setVisible, record } = props;
|
|
||||||
const collection = useCollection();
|
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const schema: Schema = useMemo(
|
|
||||||
() =>
|
|
||||||
fieldSchema.reduceProperties((buf, current) => {
|
|
||||||
if (current.name === 'drawer') {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}, null),
|
|
||||||
[fieldSchema],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
schema && (
|
|
||||||
<ActionContextProvider value={{ visible: !!record, setVisible }}>
|
|
||||||
<RecordProvider record={record} parent={parentRecordData}>
|
|
||||||
<VariablePopupRecordProvider recordData={record} collection={collection}>
|
|
||||||
<RecursionField schema={schema} name={schema.name} />
|
|
||||||
</VariablePopupRecordProvider>
|
|
||||||
</RecordProvider>
|
|
||||||
</ActionContextProvider>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function clearSelected(target: google.maps.Polygon) {
|
function clearSelected(target: google.maps.Polygon) {
|
||||||
if (target instanceof google.maps.Marker) {
|
if (target instanceof google.maps.Marker) {
|
||||||
return target.setIcon(getIcon(defaultImage));
|
return target.setIcon(getIcon(defaultImage));
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { PopupContextProvider } from '@nocobase/client';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useMapTranslation } from '../locale';
|
import { useMapTranslation } from '../locale';
|
||||||
import { AMapBlock } from './AMap';
|
import { AMapBlock } from './AMap';
|
||||||
@ -29,5 +30,9 @@ export const MapBlockComponent: React.FC<any> = (props) => {
|
|||||||
return <div>{t(`The ${mapType} cannot found`)}</div>;
|
return <div>{t(`The ${mapType} cannot found`)}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Component {...props} />;
|
return (
|
||||||
|
<PopupContextProvider>
|
||||||
|
<Component {...props} />
|
||||||
|
</PopupContextProvider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RecursionField, useFieldSchema } from '@formily/react';
|
||||||
|
import { useCollection, useCollectionRecordData, VariablePopupRecordProvider } from '@nocobase/client';
|
||||||
|
import React, { FC, useMemo } from 'react';
|
||||||
|
|
||||||
|
export const MapBlockDrawer: FC = (props) => {
|
||||||
|
const recordData = useCollectionRecordData();
|
||||||
|
const collection = useCollection();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const schema = useMemo(
|
||||||
|
() =>
|
||||||
|
fieldSchema.reduceProperties((buf, current) => {
|
||||||
|
if (current.name === 'drawer') {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}, null),
|
||||||
|
[fieldSchema],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!schema) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VariablePopupRecordProvider recordData={recordData} collection={collection}>
|
||||||
|
<RecursionField schema={schema} name={schema.name} />
|
||||||
|
</VariablePopupRecordProvider>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user