mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 01:56:16 +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
|
||||
.reset()
|
||||
.then(() => {
|
||||
ctx.form.setInitialValues(data || {});
|
||||
ctx.form.setValues(data || {});
|
||||
})
|
||||
.catch(console.error);
|
||||
|
@ -17,7 +17,10 @@ import { PopupVisibleProvider, PopupVisibleProviderContext } from '../../schema-
|
||||
* @param props
|
||||
* @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: visibleWithURL, setVisible: setVisibleWithURL } = useContext(PopupVisibleProviderContext) || {
|
||||
visible: false,
|
||||
@ -26,10 +29,11 @@ export const PopupContextProvider: React.FC = (props) => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const _setVisible = useCallback(
|
||||
(value: boolean): void => {
|
||||
props.setVisible?.(value);
|
||||
setVisible?.(value);
|
||||
setVisibleWithURL?.(value);
|
||||
},
|
||||
[setVisibleWithURL],
|
||||
[props, setVisibleWithURL],
|
||||
);
|
||||
const openMode = fieldSchema['x-component-props']?.['openMode'] || 'drawer';
|
||||
const openSize = fieldSchema['x-component-props']?.['openSize'];
|
||||
@ -37,7 +41,7 @@ export const PopupContextProvider: React.FC = (props) => {
|
||||
return (
|
||||
<PopupVisibleProvider visible={false}>
|
||||
<ActionContextProvider
|
||||
visible={visible || visibleWithURL}
|
||||
visible={props.visible || visible || visibleWithURL}
|
||||
setVisible={_setVisible}
|
||||
openMode={openMode}
|
||||
openSize={openSize}
|
||||
|
@ -33,7 +33,7 @@ interface PopupsVisibleProviderProps {
|
||||
setVisible?: (value: boolean) => void;
|
||||
}
|
||||
|
||||
interface PopupProps {
|
||||
export interface PopupProps {
|
||||
params: PopupParams;
|
||||
context: PopupContext;
|
||||
/**
|
||||
|
@ -7,13 +7,31 @@
|
||||
* 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.
|
||||
* @returns The popup settings.
|
||||
*/
|
||||
export const usePopupSettings = () => {
|
||||
const { enableURL } = React.useContext(PopupSettingsContext);
|
||||
|
||||
const isPopupVisibleControlledByURL = useCallback(() => {
|
||||
const pathname = window.location.pathname;
|
||||
const hash = window.location.hash;
|
||||
@ -21,8 +39,8 @@ export const usePopupSettings = () => {
|
||||
const isNewMobileMode = pathname?.includes('/m/');
|
||||
const isPCMode = pathname?.includes('/admin/');
|
||||
|
||||
return (isPCMode || isNewMobileMode) && !isOldMobileMode;
|
||||
}, []);
|
||||
return (isPCMode || isNewMobileMode) && !isOldMobileMode && enableURL;
|
||||
}, [enableURL]);
|
||||
|
||||
return {
|
||||
/** 弹窗窗口的显隐是否由 URL 控制 */
|
||||
|
@ -15,3 +15,4 @@ export * from './Page.Settings';
|
||||
export { PagePopups } from './PagePopups';
|
||||
export { storePopupContext } from './pagePopupUtils';
|
||||
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
|
||||
* @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 location = useLocationNoUpdate();
|
||||
const fieldSchema = useFieldSchema();
|
||||
@ -141,14 +150,16 @@ export const usePopupUtils = () => {
|
||||
const { params: popupParams } = useCurrentPopupContext();
|
||||
const service = useDataBlockRequest();
|
||||
const { isPopupVisibleControlledByURL } = usePopupSettings();
|
||||
const { setVisible: setVisibleFromAction } = useContext(ActionContext);
|
||||
const { setVisible: _setVisibleFromAction } = useContext(ActionContext);
|
||||
const { updatePopupContext } = usePopupContextInActionOrAssociationField();
|
||||
const currentPopupContext = useCurrentPopupContext();
|
||||
const getSourceId = useCallback(
|
||||
(_parentRecordData?: Record<string, any>) =>
|
||||
(_parentRecordData || parentRecord?.data)?.[cm.getSourceKeyByAssociation(association)],
|
||||
[parentRecord, association],
|
||||
);
|
||||
const currentPopupUidWithoutOpened = fieldSchema?.['x-uid'];
|
||||
|
||||
const setVisibleFromAction = options.setVisible || _setVisibleFromAction;
|
||||
|
||||
const getNewPathname = useCallback(
|
||||
({
|
||||
@ -199,6 +210,7 @@ export const usePopupUtils = () => {
|
||||
parentRecordData,
|
||||
collectionNameUsedInURL,
|
||||
popupUidUsedInURL,
|
||||
customActionSchema,
|
||||
}: {
|
||||
recordData?: Record<string, any>;
|
||||
parentRecordData?: Record<string, any>;
|
||||
@ -206,11 +218,13 @@ export const usePopupUtils = () => {
|
||||
collectionNameUsedInURL?: string;
|
||||
/** if this value exists, it will be saved in the URL */
|
||||
popupUidUsedInURL?: string;
|
||||
customActionSchema?: ISchema;
|
||||
} = {}) => {
|
||||
if (!isPopupVisibleControlledByURL()) {
|
||||
return setVisibleFromAction?.(true);
|
||||
}
|
||||
|
||||
const currentPopupUidWithoutOpened = customActionSchema?.['x-uid'] || fieldSchema?.['x-uid'];
|
||||
const sourceId = getSourceId(parentRecordData);
|
||||
|
||||
recordData = recordData || record?.data;
|
||||
@ -227,7 +241,7 @@ export const usePopupUtils = () => {
|
||||
}
|
||||
|
||||
storePopupContext(currentPopupUidWithoutOpened, {
|
||||
schema: fieldSchema,
|
||||
schema: customActionSchema || fieldSchema,
|
||||
record: new CollectionRecord({ isNew: false, data: recordData }),
|
||||
parentRecord: parentRecordData ? new CollectionRecord({ isNew: false, data: parentRecordData }) : parentRecord,
|
||||
service,
|
||||
@ -237,7 +251,7 @@ export const usePopupUtils = () => {
|
||||
sourceId,
|
||||
});
|
||||
|
||||
updatePopupContext(getPopupContext());
|
||||
updatePopupContext(getPopupContext(), customActionSchema);
|
||||
|
||||
navigate(withSearchParams(`${url}${pathname}`));
|
||||
},
|
||||
@ -256,7 +270,6 @@ export const usePopupUtils = () => {
|
||||
isPopupVisibleControlledByURL,
|
||||
getSourceId,
|
||||
getPopupContext,
|
||||
currentPopupUidWithoutOpened,
|
||||
],
|
||||
);
|
||||
|
||||
@ -317,6 +330,7 @@ export const usePopupUtils = () => {
|
||||
closePopup,
|
||||
savePopupSchemaToSchema,
|
||||
getPopupSchemaFromSchema,
|
||||
context: currentPopupContext,
|
||||
/**
|
||||
* @deprecated
|
||||
* TODO: remove this
|
||||
|
@ -29,18 +29,19 @@ export const usePopupContextInActionOrAssociationField = () => {
|
||||
const { dn } = useDesignable();
|
||||
|
||||
const updatePopupContext = useCallback(
|
||||
(context: PopupContext) => {
|
||||
(context: PopupContext, customSchema?: ISchema) => {
|
||||
customSchema = customSchema || fieldSchema;
|
||||
context = _.omitBy(context, _.isNil) as PopupContext;
|
||||
|
||||
if (_.isEqual(context, getPopupContextFromActionOrAssociationFieldSchema(fieldSchema))) {
|
||||
if (_.isEqual(context, getPopupContextFromActionOrAssociationFieldSchema(customSchema))) {
|
||||
return;
|
||||
}
|
||||
|
||||
fieldSchema[CONTEXT_SCHEMA_KEY] = context;
|
||||
customSchema[CONTEXT_SCHEMA_KEY] = context;
|
||||
|
||||
return dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
'x-uid': customSchema['x-uid'],
|
||||
[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 { bulkEditActionSettings, deprecatedBulkEditActionSettings } from './BulkEditAction.Settings';
|
||||
import { BulkEditActionDecorator } from './BulkEditActionDecorator';
|
||||
import { BulkEditActionInitializer } from './BulkEditActionInitializer';
|
||||
import {
|
||||
BulkEditBlockInitializers_deprecated,
|
||||
@ -25,7 +26,7 @@ import { BulkEditField } from './component/BulkEditField';
|
||||
import { useCustomizeBulkEditActionProps } from './utils';
|
||||
export class PluginActionBulkEditClient extends Plugin {
|
||||
async load() {
|
||||
this.app.addComponents({ BulkEditField });
|
||||
this.app.addComponents({ BulkEditField, BulkEditActionDecorator });
|
||||
this.app.addScopes({ useCustomizeBulkEditActionProps });
|
||||
this.app.schemaSettingsManager.add(deprecatedBulkEditActionSettings);
|
||||
this.app.schemaSettingsManager.add(bulkEditActionSettings);
|
||||
@ -45,7 +46,7 @@ export class PluginActionBulkEditClient extends Plugin {
|
||||
Component: BulkEditActionInitializer,
|
||||
schema: {
|
||||
'x-align': 'right',
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
'x-decorator': 'BulkEditActionDecorator',
|
||||
'x-action': 'customize:bulkEdit',
|
||||
'x-toolbar': 'ActionSchemaToolbar',
|
||||
'x-settings': 'actionSettings:bulkEdit',
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
ActionContextProvider,
|
||||
CollectionProvider_deprecated,
|
||||
FormBlockContext,
|
||||
PopupSettingsProvider,
|
||||
RecordProvider,
|
||||
fetchTemplateData,
|
||||
useACLActionParamsContext,
|
||||
@ -203,7 +204,9 @@ export const DuplicateAction = observer(
|
||||
{/* 这里的 record 就是弹窗中创建表单的 sourceRecord */}
|
||||
<RecordProvider record={{ ...parentRecordData, __collection: duplicateCollection || __collection }}>
|
||||
<ActionContextProvider value={{ ...ctx, visible, setVisible }}>
|
||||
<RecursionField schema={fieldSchema} basePath={field.address} onlyRenderProperties />
|
||||
<PopupSettingsProvider enableURL={false}>
|
||||
<RecursionField schema={fieldSchema} basePath={field.address} onlyRenderProperties />
|
||||
</PopupSettingsProvider>
|
||||
</ActionContextProvider>
|
||||
</RecordProvider>
|
||||
</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',
|
||||
title: '{{ t("Duplicate") }}',
|
||||
'x-component': 'Action.Link',
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
'x-decorator': 'DuplicateActionDecorator',
|
||||
'x-component-props': {
|
||||
openMode: defaultOpenMode,
|
||||
component: 'DuplicateAction',
|
||||
|
@ -10,6 +10,7 @@
|
||||
import { Plugin, useActionAvailable } from '@nocobase/client';
|
||||
import { DuplicateAction } from './DuplicateAction';
|
||||
import { deprecatedDuplicateActionSettings, duplicateActionSettings } from './DuplicateAction.Settings';
|
||||
import { DuplicateActionDecorator } from './DuplicateActionDecorator';
|
||||
import { DuplicateActionInitializer } from './DuplicateActionInitializer';
|
||||
import { DuplicatePluginProvider } from './DuplicatePluginProvider';
|
||||
|
||||
@ -19,6 +20,7 @@ export class PluginActionDuplicateClient extends Plugin {
|
||||
this.app.addComponents({
|
||||
DuplicateActionInitializer,
|
||||
DuplicateAction,
|
||||
DuplicateActionDecorator,
|
||||
});
|
||||
this.app.schemaSettingsManager.add(deprecatedDuplicateActionSettings);
|
||||
this.app.schemaSettingsManager.add(duplicateActionSettings);
|
||||
@ -31,7 +33,7 @@ export class PluginActionDuplicateClient extends Plugin {
|
||||
'x-action': 'duplicate',
|
||||
'x-toolbar': 'ActionSchemaToolbar',
|
||||
'x-settings': 'actionSettings:duplicate',
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
'x-decorator': 'DuplicateActionDecorator',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
},
|
||||
|
@ -10,12 +10,12 @@
|
||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import { RecursionField, Schema, observer, useFieldSchema } from '@formily/react';
|
||||
import {
|
||||
ActionContextProvider,
|
||||
PopupContextProvider,
|
||||
RecordProvider,
|
||||
VariablePopupRecordProvider,
|
||||
getLabelFormatValue,
|
||||
useCollection,
|
||||
useCollectionParentRecordData,
|
||||
usePopupUtils,
|
||||
useProps,
|
||||
withDynamicSchemaProps,
|
||||
} from '@nocobase/client';
|
||||
@ -23,10 +23,11 @@ import { parseExpression } from 'cron-parser';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import dayjs from 'dayjs';
|
||||
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 * as dates from 'react-big-calendar/lib/utils/dates';
|
||||
import { i18nt, useTranslation } from '../../locale';
|
||||
import { CalendarRecordViewer, findEventSchema } from './CalendarRecordViewer';
|
||||
import Header from './components/Header';
|
||||
import { CalendarToolbarContext } from './context';
|
||||
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]);
|
||||
};
|
||||
|
||||
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(
|
||||
observer(
|
||||
(props: any) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { openPopup } = usePopupUtils({
|
||||
setVisible,
|
||||
});
|
||||
|
||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
const { dataSource, fieldNames, showLunar } = useProps(props);
|
||||
const height = useCalenderHeight();
|
||||
const [date, setDate] = useState<Date>(new Date());
|
||||
const [view, setView] = useState<View>('month');
|
||||
const events = useEvents(dataSource, fieldNames, date, view);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [record, setRecord] = useState<any>({});
|
||||
const { wrapSSR, hashId, componentCls: containerClassName } = useStyle();
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
const fieldSchema = useFieldSchema();
|
||||
|
||||
const components = useMemo(() => {
|
||||
return {
|
||||
@ -247,50 +218,57 @@ export const Calendar: any = withDynamicSchemaProps(
|
||||
};
|
||||
return wrapSSR(
|
||||
<div className={`${hashId} ${containerClassName}`} style={{ height: height || 700 }}>
|
||||
<GlobalStyle />
|
||||
<CalendarRecordViewer visible={visible} setVisible={setVisible} record={record} />
|
||||
<BigCalendar
|
||||
popup
|
||||
selectable
|
||||
events={events}
|
||||
view={view}
|
||||
views={Weeks}
|
||||
date={date}
|
||||
step={60}
|
||||
showMultiDayTimes
|
||||
messages={messages}
|
||||
onNavigate={setDate}
|
||||
onView={setView}
|
||||
onSelectSlot={(slotInfo) => {
|
||||
console.log('onSelectSlot', slotInfo);
|
||||
}}
|
||||
onDoubleClickEvent={() => {
|
||||
console.log('onDoubleClickEvent');
|
||||
}}
|
||||
onSelectEvent={(event) => {
|
||||
const record = dataSource?.find((item) => item[fieldNames.id] === event.id);
|
||||
if (!record) {
|
||||
return;
|
||||
}
|
||||
record.__event = { ...event, start: formatDate(dayjs(event.start)), end: formatDate(dayjs(event.end)) };
|
||||
|
||||
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);
|
||||
<PopupContextProvider visible={visible} setVisible={setVisible}>
|
||||
<GlobalStyle />
|
||||
<RecordProvider record={record} parent={parentRecordData}>
|
||||
<CalendarRecordViewer />
|
||||
</RecordProvider>
|
||||
<BigCalendar
|
||||
popup
|
||||
selectable
|
||||
events={events}
|
||||
view={view}
|
||||
views={Weeks}
|
||||
date={date}
|
||||
step={60}
|
||||
showMultiDayTimes
|
||||
messages={messages}
|
||||
onNavigate={setDate}
|
||||
onView={setView}
|
||||
onSelectSlot={(slotInfo) => {
|
||||
console.log('onSelectSlot', slotInfo);
|
||||
}}
|
||||
onDoubleClickEvent={() => {
|
||||
console.log('onDoubleClickEvent');
|
||||
}}
|
||||
onSelectEvent={(event) => {
|
||||
const record = dataSource?.find((item) => item[fieldNames.id] === event.id);
|
||||
if (!record) {
|
||||
return;
|
||||
}
|
||||
return `${local.format(start, 'YYYY-M', culture)} - ${local.format(end, 'YYYY-M', culture)}`;
|
||||
},
|
||||
}}
|
||||
components={components}
|
||||
localizer={localizer}
|
||||
/>
|
||||
record.__event = { ...event, start: formatDate(dayjs(event.start)), end: formatDate(dayjs(event.end)) };
|
||||
|
||||
setRecord(record);
|
||||
openPopup({
|
||||
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>,
|
||||
);
|
||||
},
|
||||
|
@ -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 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(
|
||||
(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' },
|
||||
);
|
||||
|
@ -8,11 +8,28 @@
|
||||
*/
|
||||
|
||||
import { observer } from '@formily/react';
|
||||
import {
|
||||
PopupContextProvider,
|
||||
useActionContext,
|
||||
useCollection,
|
||||
useCollectionRecordData,
|
||||
VariablePopupRecordProvider,
|
||||
} from '@nocobase/client';
|
||||
import React from 'react';
|
||||
|
||||
export const Event = observer(
|
||||
(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' },
|
||||
);
|
||||
|
@ -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 { RecursionField, Schema, useFieldSchema } from '@formily/react';
|
||||
import { RecursionField, useFieldSchema } from '@formily/react';
|
||||
import {
|
||||
ActionContextProvider,
|
||||
PopupContextProvider,
|
||||
RecordProvider,
|
||||
VariablePopupRecordProvider,
|
||||
useAPIClient,
|
||||
useBlockRequestContext,
|
||||
useCollection,
|
||||
useCollectionParentRecordData,
|
||||
useCurrentAppInfo,
|
||||
useDesignable,
|
||||
usePopupUtils,
|
||||
useProps,
|
||||
useTableBlockContext,
|
||||
useToken,
|
||||
@ -26,7 +25,7 @@ import {
|
||||
} from '@nocobase/client';
|
||||
import { Spin, message } from 'antd';
|
||||
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 { useGanttBlockContext } from '../../GanttBlockProvider';
|
||||
import { convertToBarTasks } from '../../helpers/bar-helper';
|
||||
@ -41,6 +40,7 @@ import { GridProps } from '../grid/grid';
|
||||
import { HorizontalScroll } from '../other/horizontal-scroll';
|
||||
import { StandardTooltipContent, Tooltip } from '../other/tooltip';
|
||||
import { VerticalScroll } from '../other/vertical-scroll';
|
||||
import { GanttRecordViewer } from './GanttRecordViewer';
|
||||
import useStyles from './style';
|
||||
import { TaskGantt } from './task-gantt';
|
||||
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;
|
||||
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) => {
|
||||
await resource.update({
|
||||
filterByTk: task.id,
|
||||
@ -160,7 +133,11 @@ export const Gantt: any = withDynamicSchemaProps((props: any) => {
|
||||
return { viewMode, dates: seedDates(startDate, endDate, viewMode) };
|
||||
});
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { openPopup } = usePopupUtils({
|
||||
setVisible,
|
||||
});
|
||||
const [record, setRecord] = useState<any>({});
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
const [currentViewDate, setCurrentViewDate] = useState<Date | undefined>(undefined);
|
||||
const [taskListWidth, setTaskListWidth] = useState(0);
|
||||
const [svgContainerWidth, setSvgContainerWidth] = useState(0);
|
||||
@ -473,7 +450,10 @@ export const Gantt: any = withDynamicSchemaProps((props: any) => {
|
||||
return;
|
||||
}
|
||||
setRecord(recordData);
|
||||
setVisible(true);
|
||||
openPopup({
|
||||
recordData,
|
||||
customActionSchema: fieldSchema.properties.detail,
|
||||
});
|
||||
};
|
||||
const gridProps: GridProps = {
|
||||
columnWidth,
|
||||
@ -536,55 +516,59 @@ export const Gantt: any = withDynamicSchemaProps((props: any) => {
|
||||
`)}
|
||||
ref={ganttRef}
|
||||
>
|
||||
<GanttRecordViewer visible={visible} setVisible={setVisible} record={record} />
|
||||
<RecursionField name={'anctionBar'} schema={fieldSchema.properties.toolBar} />
|
||||
<RecursionField name={'table'} schema={fieldSchema.properties.table} />
|
||||
<div className={styles.wrapper} onKeyDown={handleKeyDown} tabIndex={0} ref={wrapperRef}>
|
||||
<TaskGantt
|
||||
gridProps={gridProps}
|
||||
calendarProps={calendarProps}
|
||||
barProps={barProps}
|
||||
ganttHeight={ganttHeight}
|
||||
scrollY={scrollY}
|
||||
scrollX={scrollX}
|
||||
ref={verticalGanttContainerRef}
|
||||
/>
|
||||
{ganttEvent.changedTask && (
|
||||
<Tooltip
|
||||
arrowIndent={arrowIndent}
|
||||
rowHeight={rowHeight}
|
||||
svgContainerHeight={svgContainerHeight}
|
||||
svgContainerWidth={svgContainerWidth}
|
||||
fontFamily={fontFamily}
|
||||
fontSize={fontSize}
|
||||
scrollX={scrollX}
|
||||
<PopupContextProvider visible={visible} setVisible={setVisible}>
|
||||
<RecordProvider record={record} parent={parentRecordData}>
|
||||
<GanttRecordViewer />
|
||||
</RecordProvider>
|
||||
<RecursionField name={'anctionBar'} schema={fieldSchema.properties.toolBar} />
|
||||
<RecursionField name={'table'} schema={fieldSchema.properties.table} />
|
||||
<div className={styles.wrapper} onKeyDown={handleKeyDown} tabIndex={0} ref={wrapperRef}>
|
||||
<TaskGantt
|
||||
gridProps={gridProps}
|
||||
calendarProps={calendarProps}
|
||||
barProps={barProps}
|
||||
ganttHeight={ganttHeight}
|
||||
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}
|
||||
taskListWidth={taskListWidth}
|
||||
TooltipContent={TooltipContent}
|
||||
scroll={scrollY}
|
||||
onScroll={handleScrollY}
|
||||
rtl={rtl}
|
||||
svgWidth={svgWidth}
|
||||
/>
|
||||
)}
|
||||
<VerticalScroll
|
||||
ganttFullHeight={ganttFullHeight}
|
||||
ganttHeight={ganttHeight}
|
||||
headerHeight={headerHeight}
|
||||
scroll={scrollY}
|
||||
onScroll={handleScrollY}
|
||||
rtl={rtl}
|
||||
/>
|
||||
<Spin spinning={loading} style={{ visibility: 'hidden' }}>
|
||||
<HorizontalScroll
|
||||
svgWidth={svgWidth}
|
||||
taskListWidth={taskListWidth}
|
||||
scroll={scrollX}
|
||||
rtl={rtl}
|
||||
onScroll={handleScrollX}
|
||||
/>
|
||||
</Spin>
|
||||
</div>
|
||||
<Spin spinning={loading} style={{ visibility: 'hidden' }}>
|
||||
<HorizontalScroll
|
||||
svgWidth={svgWidth}
|
||||
taskListWidth={taskListWidth}
|
||||
scroll={scrollX}
|
||||
rtl={rtl}
|
||||
onScroll={handleScrollX}
|
||||
/>
|
||||
</Spin>
|
||||
</div>
|
||||
</PopupContextProvider>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -8,15 +8,29 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
PopupContextProvider,
|
||||
useCollection_deprecated,
|
||||
useCollectionManager_deprecated,
|
||||
usePopupUtils,
|
||||
useProps,
|
||||
withDynamicSchemaProps,
|
||||
} from '@nocobase/client';
|
||||
import React, { useMemo } from 'react';
|
||||
import { MapBlockComponent } from '../components';
|
||||
import { MapBlockDrawer } from '../components/MapBlockDrawer';
|
||||
|
||||
export const MapBlock = withDynamicSchemaProps((props) => {
|
||||
const { context } = usePopupUtils();
|
||||
|
||||
// only render the popup
|
||||
if (context.currentLevel) {
|
||||
return (
|
||||
<PopupContextProvider>
|
||||
<MapBlockDrawer />
|
||||
</PopupContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
const { fieldNames } = useProps(props);
|
||||
|
||||
|
@ -8,11 +8,8 @@
|
||||
*/
|
||||
|
||||
import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons';
|
||||
import { RecursionField, useFieldSchema } from '@formily/react';
|
||||
import {
|
||||
ActionContextProvider,
|
||||
RecordProvider,
|
||||
VariablePopupRecordProvider,
|
||||
css,
|
||||
getLabelFormatValue,
|
||||
useCollection,
|
||||
@ -21,14 +18,16 @@ import {
|
||||
useCollection_deprecated,
|
||||
useCompile,
|
||||
useFilterAPI,
|
||||
usePopupUtils,
|
||||
useProps,
|
||||
} from '@nocobase/client';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
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 { useMapTranslation } from '../../locale';
|
||||
import { getSource } from '../../utils';
|
||||
import { MapBlockDrawer } from '../MapBlockDrawer';
|
||||
import { AMapComponent, AMapForwardedRefProps } from './Map';
|
||||
|
||||
export const AMapBlock = (props) => {
|
||||
@ -50,6 +49,9 @@ export const AMapBlock = (props) => {
|
||||
const selectingModeRef = useRef(selectingMode);
|
||||
selectingModeRef.current = selectingMode;
|
||||
const { fields } = useCollection();
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
const { openPopup } = usePopupUtils();
|
||||
|
||||
const labelUiSchema = fields.find((v) => v.name === fieldNames?.marker)?.uiSchema;
|
||||
const setOverlayOptions = (overlay: AMap.Polygon | AMap.Marker, state?: boolean) => {
|
||||
const extData = overlay.getExtData();
|
||||
@ -199,6 +201,9 @@ export const AMapBlock = (props) => {
|
||||
|
||||
if (data) {
|
||||
setRecord(data);
|
||||
openPopup({
|
||||
recordData: data,
|
||||
});
|
||||
}
|
||||
};
|
||||
o.on('click', onClick);
|
||||
@ -244,7 +249,17 @@ export const AMapBlock = (props) => {
|
||||
});
|
||||
events.forEach((e) => e());
|
||||
};
|
||||
}, [dataSource, isMapInitialization, fieldNames, name, primaryKey, collectionField.type, isConnected, lineSort]);
|
||||
}, [
|
||||
dataSource,
|
||||
isMapInitialization,
|
||||
fieldNames,
|
||||
name,
|
||||
primaryKey,
|
||||
collectionField.type,
|
||||
isConnected,
|
||||
lineSort,
|
||||
openPopup,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
@ -307,7 +322,9 @@ export const AMapBlock = (props) => {
|
||||
</Space>
|
||||
) : null}
|
||||
</div>
|
||||
<MapBlockDrawer record={record} setVisible={setRecord} />
|
||||
<RecordProvider record={record} parent={parentRecordData}>
|
||||
<MapBlockDrawer />
|
||||
</RecordProvider>
|
||||
<AMapComponent
|
||||
{...collectionField?.uiSchema?.['x-component-props']}
|
||||
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) {
|
||||
if ((marker as AMap.Marker).dom) {
|
||||
(marker as AMap.Marker).dom.style.filter = 'none';
|
||||
|
@ -8,11 +8,8 @@
|
||||
*/
|
||||
|
||||
import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/icons';
|
||||
import { RecursionField, Schema, useFieldSchema } from '@formily/react';
|
||||
import {
|
||||
ActionContextProvider,
|
||||
RecordProvider,
|
||||
VariablePopupRecordProvider,
|
||||
css,
|
||||
getLabelFormatValue,
|
||||
useCollection,
|
||||
@ -21,14 +18,16 @@ import {
|
||||
useCollection_deprecated,
|
||||
useCompile,
|
||||
useFilterAPI,
|
||||
usePopupUtils,
|
||||
useProps,
|
||||
} from '@nocobase/client';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
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 { useMapTranslation } from '../../locale';
|
||||
import { getSource } from '../../utils';
|
||||
import { MapBlockDrawer } from '../MapBlockDrawer';
|
||||
import { GoogleMapForwardedRefProps, GoogleMapsComponent, OverlayOptions } from './Map';
|
||||
import { getIcon } from './utils';
|
||||
|
||||
@ -69,8 +68,10 @@ export const GoogleMapsBlock = (props) => {
|
||||
const overlaysRef = useRef<google.maps.MVCObject[]>([]);
|
||||
selectingModeRef.current = selectingMode;
|
||||
const { fields } = useCollection();
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
const labelUiSchema = fields.find((v) => v.name === fieldNames?.marker)?.uiSchema;
|
||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
const { openPopup } = usePopupUtils();
|
||||
|
||||
const setOverlayOptions = (overlay: google.maps.MVCObject, state?: boolean) => {
|
||||
const selected = typeof state !== 'undefined' ? !state : overlay.get(OVERLAY_SELECtED);
|
||||
@ -234,6 +235,9 @@ export const GoogleMapsBlock = (props) => {
|
||||
|
||||
if (data) {
|
||||
setRecord(data);
|
||||
openPopup({
|
||||
recordData: data,
|
||||
});
|
||||
}
|
||||
};
|
||||
o.addListener('click', onClick);
|
||||
@ -291,7 +295,7 @@ export const GoogleMapsBlock = (props) => {
|
||||
});
|
||||
events.forEach((e) => e());
|
||||
};
|
||||
}, [dataSource, isMapInitialization, markerName, collectionField.type, isConnected]);
|
||||
}, [dataSource, isMapInitialization, markerName, collectionField.type, isConnected, openPopup]);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
@ -354,7 +358,9 @@ export const GoogleMapsBlock = (props) => {
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
<MapBlockDrawer record={record} setVisible={setRecord} />
|
||||
<RecordProvider record={record} parent={parentRecordData}>
|
||||
<MapBlockDrawer />
|
||||
</RecordProvider>
|
||||
</>
|
||||
)}
|
||||
<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) {
|
||||
if (target instanceof google.maps.Marker) {
|
||||
return target.setIcon(getIcon(defaultImage));
|
||||
|
@ -7,6 +7,7 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { PopupContextProvider } from '@nocobase/client';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useMapTranslation } from '../locale';
|
||||
import { AMapBlock } from './AMap';
|
||||
@ -29,5 +30,9 @@ export const MapBlockComponent: React.FC<any> = (props) => {
|
||||
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