mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 06:59:26 +08:00
feat(data-vi): allow to add refresh button and set auto refresh interval (#5112)
* feat(data-vi): allow to set auto refresh interval for charts * feat(data-vi): allow to add refresh button and set auto refresh interval * fix: build * fix: bug * chore: optimize global auto refresh * chore: remove console.log * fix: remove console log
This commit is contained in:
parent
dfe517e737
commit
61f95f78c2
@ -14,6 +14,7 @@ import { ChartDataProvider } from './ChartDataProvider';
|
|||||||
import { ChartRenderer, ChartRendererProvider } from '../renderer';
|
import { ChartRenderer, ChartRendererProvider } from '../renderer';
|
||||||
import { ChartFilterBlockProvider, ChartFilterBlockDesigner } from '../filter';
|
import { ChartFilterBlockProvider, ChartFilterBlockDesigner } from '../filter';
|
||||||
import { ChartFilterProvider } from '../filter/FilterProvider';
|
import { ChartFilterProvider } from '../filter/FilterProvider';
|
||||||
|
import { RefreshButton } from '../initializers/RefreshAction';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
|
||||||
export const ChartV2Block: React.FC = (props) => {
|
export const ChartV2Block: React.FC = (props) => {
|
||||||
@ -24,7 +25,13 @@ export const ChartV2Block: React.FC = (props) => {
|
|||||||
value={{ ...schemaInitializerContextData, visible: initialVisible, setVisible: setInitialVisible }}
|
value={{ ...schemaInitializerContextData, visible: initialVisible, setVisible: setInitialVisible }}
|
||||||
>
|
>
|
||||||
<SchemaComponentOptions
|
<SchemaComponentOptions
|
||||||
components={{ ChartRenderer, ChartRendererProvider, ChartFilterBlockProvider, ChartFilterBlockDesigner }}
|
components={{
|
||||||
|
ChartRenderer,
|
||||||
|
ChartRendererProvider,
|
||||||
|
ChartFilterBlockProvider,
|
||||||
|
ChartFilterBlockDesigner,
|
||||||
|
RefreshButton,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={css`
|
className={css`
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
SchemaSettingsBlockTitleItem,
|
SchemaSettingsBlockTitleItem,
|
||||||
SchemaSettingsDivider,
|
SchemaSettingsDivider,
|
||||||
SchemaSettingsRemove,
|
SchemaSettingsRemove,
|
||||||
SchemaSettingsSelectItem,
|
|
||||||
SchemaSettingsSwitchItem,
|
SchemaSettingsSwitchItem,
|
||||||
useDesignable,
|
useDesignable,
|
||||||
useToken,
|
useToken,
|
||||||
|
@ -120,7 +120,18 @@ export const ChartV2BlockInitializer: React.FC = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
'x-designer': 'ChartV2BlockDesigner',
|
'x-designer': 'ChartV2BlockDesigner',
|
||||||
|
'x-decorator': 'ChartBlockProvider',
|
||||||
properties: {
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 'var(--nb-designer-offset)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-initializer': 'chartBlock:configureActions',
|
||||||
|
},
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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 React from 'react';
|
||||||
|
import { BlockRefreshButton } from '../initializers/BlockRefreshAction';
|
||||||
|
import { SchemaComponentOptions } from '@nocobase/client';
|
||||||
|
import { GlobalAutoRefreshProvider } from './GlobalAutoRefreshProvider';
|
||||||
|
|
||||||
|
export const ChartBlockProvider: React.FC = (props) => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions
|
||||||
|
components={{
|
||||||
|
BlockRefreshButton,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<GlobalAutoRefreshProvider> {props.children}</GlobalAutoRefreshProvider>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
};
|
@ -34,6 +34,7 @@ export const ChartDataProvider: React.FC = (props) => {
|
|||||||
const removeChart = useMemoizedFn((uid: string) => {
|
const removeChart = useMemoizedFn((uid: string) => {
|
||||||
setCharts((charts) => ({ ...charts, [uid]: undefined }));
|
setCharts((charts) => ({ ...charts, [uid]: undefined }));
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChartDataContext.Provider value={{ charts, addChart, removeChart }}>{props.children}</ChartDataContext.Provider>
|
<ChartDataContext.Provider value={{ charts, addChart, removeChart }}>{props.children}</ChartDataContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* 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 React, { useEffect, useRef, useState } from 'react';
|
||||||
|
import { useMemoizedFn } from 'ahooks';
|
||||||
|
|
||||||
|
export const GlobalAutoRefreshContext = React.createContext<{
|
||||||
|
addChart: (uid: string, chart: { service: any }) => void;
|
||||||
|
removeChart: (uid: string) => void;
|
||||||
|
autoRefresh: number | boolean;
|
||||||
|
setAutoRefresh: (autoRefresh: number | boolean) => void;
|
||||||
|
refreshCharts: () => void;
|
||||||
|
}>({} as any);
|
||||||
|
|
||||||
|
export const GlobalAutoRefreshProvider: React.FC = (props) => {
|
||||||
|
const [autoRefresh, setAutoRefresh] = useState<number | boolean>(false);
|
||||||
|
const charts = useRef<{ [uid: string]: { service: any; selfAutoRefresh?: boolean } }>({});
|
||||||
|
const addChart = useMemoizedFn((uid: string, { service }) => {
|
||||||
|
charts.current[uid] = { service };
|
||||||
|
});
|
||||||
|
const removeChart = useMemoizedFn((uid: string) => {
|
||||||
|
const chart = charts.current[uid];
|
||||||
|
if (!chart) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
charts.current[uid] = { service: chart.service, selfAutoRefresh: true };
|
||||||
|
});
|
||||||
|
const refreshCharts = useMemoizedFn(() => {
|
||||||
|
for (const chart of Object.values(charts.current)) {
|
||||||
|
chart?.service.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
if (!autoRefresh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const timer = setInterval(
|
||||||
|
() => {
|
||||||
|
const refreshCharts = Object.values(charts.current).filter((chart) => !chart.selfAutoRefresh);
|
||||||
|
for (const chart of refreshCharts) {
|
||||||
|
chart?.service.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(autoRefresh as number) * 1000,
|
||||||
|
);
|
||||||
|
return () => clearInterval(timer);
|
||||||
|
}, [autoRefresh]);
|
||||||
|
return (
|
||||||
|
<GlobalAutoRefreshContext.Provider value={{ addChart, removeChart, autoRefresh, setAutoRefresh, refreshCharts }}>
|
||||||
|
{props.children}
|
||||||
|
</GlobalAutoRefreshContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
@ -10,3 +10,5 @@
|
|||||||
export * from './ChartBlock';
|
export * from './ChartBlock';
|
||||||
export * from './ChartBlockDesigner';
|
export * from './ChartBlockDesigner';
|
||||||
export * from './ChartBlockInitializer';
|
export * from './ChartBlockInitializer';
|
||||||
|
export * from './ChartBlockProvider';
|
||||||
|
export * from './GlobalAutoRefreshProvider';
|
||||||
|
@ -42,7 +42,7 @@ export const ChartConfigProvider: React.FC = (props) => {
|
|||||||
return (
|
return (
|
||||||
<ChartConfigContext.Provider value={{ visible, setVisible, current, setCurrent }}>
|
<ChartConfigContext.Provider value={{ visible, setVisible, current, setCurrent }}>
|
||||||
{props.children}
|
{props.children}
|
||||||
<ChartRendererProvider {...current.field?.decoratorProps}>
|
<ChartRendererProvider {...current.field?.decoratorProps} disableAutoRefresh={true}>
|
||||||
<ChartConfigure insert={(schema, options) => insertAdjacent('beforeEnd', schema, options)} />
|
<ChartConfigure insert={(schema, options) => insertAdjacent('beforeEnd', schema, options)} />
|
||||||
</ChartRendererProvider>
|
</ChartRendererProvider>
|
||||||
</ChartConfigContext.Provider>
|
</ChartConfigContext.Provider>
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
ChartV2Block,
|
ChartV2Block,
|
||||||
ChartV2BlockDesigner,
|
ChartV2BlockDesigner,
|
||||||
ChartV2BlockInitializer,
|
ChartV2BlockInitializer,
|
||||||
|
ChartBlockProvider,
|
||||||
chartInitializers,
|
chartInitializers,
|
||||||
chartInitializers_deprecated,
|
chartInitializers_deprecated,
|
||||||
} from './block';
|
} from './block';
|
||||||
@ -25,6 +26,12 @@ import {
|
|||||||
chartFilterItemInitializers_deprecated,
|
chartFilterItemInitializers_deprecated,
|
||||||
} from './filter';
|
} from './filter';
|
||||||
import { lang } from './locale';
|
import { lang } from './locale';
|
||||||
|
import { chartActionsInitializer } from './initializers/chartActions';
|
||||||
|
import { chartActionRefreshSettings } from './settings/chartActionRefresh';
|
||||||
|
import { useChartRefreshActionProps } from './initializers/RefreshAction';
|
||||||
|
import { chartBlockActionsInitializer } from './initializers/chartBlockActions';
|
||||||
|
import { useChartBlockRefreshActionProps } from './initializers/BlockRefreshAction';
|
||||||
|
import { chartBlockActionRefreshSettings } from './settings/chartBlockActionRefresh';
|
||||||
|
|
||||||
class PluginDataVisualiztionClient extends Plugin {
|
class PluginDataVisualiztionClient extends Plugin {
|
||||||
public charts: ChartGroup = new ChartGroup();
|
public charts: ChartGroup = new ChartGroup();
|
||||||
@ -36,14 +43,22 @@ class PluginDataVisualiztionClient extends Plugin {
|
|||||||
ChartV2BlockInitializer,
|
ChartV2BlockInitializer,
|
||||||
ChartV2BlockDesigner,
|
ChartV2BlockDesigner,
|
||||||
ChartV2Block,
|
ChartV2Block,
|
||||||
|
ChartBlockProvider,
|
||||||
|
});
|
||||||
|
this.app.addScopes({
|
||||||
|
useChartRefreshActionProps,
|
||||||
|
useChartBlockRefreshActionProps,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.schemaInitializerManager.add(chartInitializers_deprecated);
|
this.app.schemaInitializerManager.add(chartInitializers_deprecated);
|
||||||
this.app.schemaInitializerManager.add(chartInitializers);
|
this.app.schemaInitializerManager.add(chartInitializers);
|
||||||
this.app.schemaInitializerManager.add(chartFilterItemInitializers_deprecated);
|
this.app.schemaInitializerManager.add(chartFilterItemInitializers_deprecated);
|
||||||
this.app.schemaInitializerManager.add(chartFilterItemInitializers);
|
this.app.schemaInitializerManager.add(chartFilterItemInitializers);
|
||||||
this.app.schemaInitializerManager.add(chartFilterActionInitializers_deprecated);
|
this.app.schemaInitializerManager.add(chartFilterActionInitializers_deprecated);
|
||||||
this.app.schemaInitializerManager.add(chartFilterActionInitializers);
|
this.app.schemaInitializerManager.add(chartFilterActionInitializers);
|
||||||
|
this.app.schemaInitializerManager.add(chartActionsInitializer);
|
||||||
|
this.app.schemaInitializerManager.add(chartBlockActionsInitializer);
|
||||||
|
this.app.schemaSettingsManager.add(chartActionRefreshSettings);
|
||||||
|
this.app.schemaSettingsManager.add(chartBlockActionRefreshSettings);
|
||||||
|
|
||||||
const blockInitializers = this.app.schemaInitializerManager.get('page:addBlock');
|
const blockInitializers = this.app.schemaInitializerManager.get('page:addBlock');
|
||||||
blockInitializers?.add('dataBlocks.chartV2', {
|
blockInitializers?.add('dataBlocks.chartV2', {
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* 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 { ActionInitializer } from '@nocobase/client';
|
||||||
|
import React, { forwardRef, useContext, useEffect } from 'react';
|
||||||
|
import { useChartsTranslation } from '../locale';
|
||||||
|
import { Dropdown, MenuProps } from 'antd';
|
||||||
|
import { DownOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||||
|
import { useFieldSchema } from '@formily/react';
|
||||||
|
import { GlobalAutoRefreshContext } from '../block/GlobalAutoRefreshProvider';
|
||||||
|
|
||||||
|
export const BlockRefreshButton: React.FC = forwardRef<HTMLButtonElement | HTMLAnchorElement, any>((props, ref) => {
|
||||||
|
const { t } = useChartsTranslation();
|
||||||
|
const { autoRefresh, setAutoRefresh } = useContext(GlobalAutoRefreshContext);
|
||||||
|
const interval = {
|
||||||
|
5: '5s',
|
||||||
|
10: '10s',
|
||||||
|
30: '30s',
|
||||||
|
60: '1m',
|
||||||
|
300: '5m',
|
||||||
|
900: '15m',
|
||||||
|
1800: '30m',
|
||||||
|
3600: '1h',
|
||||||
|
7200: '2h',
|
||||||
|
86400: '1d',
|
||||||
|
};
|
||||||
|
const items: MenuProps['items'] = Object.entries(interval).map(([key, label]) => ({
|
||||||
|
key,
|
||||||
|
label,
|
||||||
|
onClick: () => setAutoRefresh(+key),
|
||||||
|
}));
|
||||||
|
return (
|
||||||
|
<Dropdown.Button
|
||||||
|
{...props}
|
||||||
|
menu={{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
key: 'off',
|
||||||
|
label: t('Off'),
|
||||||
|
onClick: () => setAutoRefresh(false),
|
||||||
|
},
|
||||||
|
...items,
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
icon={<DownOutlined />}
|
||||||
|
buttonsRender={([_, rightButton]) => [
|
||||||
|
_,
|
||||||
|
React.cloneElement(
|
||||||
|
rightButton as React.ReactElement<any, string>,
|
||||||
|
{ iconPosition: 'end' },
|
||||||
|
autoRefresh ? interval[autoRefresh as number] : null,
|
||||||
|
),
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<ReloadOutlined />
|
||||||
|
{t('Refresh')}
|
||||||
|
{props.children}
|
||||||
|
</Dropdown.Button>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useChartBlockRefreshActionProps = () => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { setAutoRefresh, refreshCharts } = useContext(GlobalAutoRefreshContext);
|
||||||
|
useEffect(() => {
|
||||||
|
setAutoRefresh(fieldSchema['x-decorator-props']?.autoRefresh);
|
||||||
|
return () => {
|
||||||
|
setAutoRefresh(false);
|
||||||
|
};
|
||||||
|
}, [fieldSchema, setAutoRefresh]);
|
||||||
|
return {
|
||||||
|
onClick: () => {
|
||||||
|
refreshCharts?.();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BlockRefreshActionInitializer = (props) => {
|
||||||
|
const schema = {
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-use-component-props': 'useChartBlockRefreshActionProps',
|
||||||
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
|
'x-settings': 'chartBlockActionSettings:refresh',
|
||||||
|
'x-component-props': {
|
||||||
|
component: 'BlockRefreshButton',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return <ActionInitializer {...props} schema={schema} />;
|
||||||
|
};
|
@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
* 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 React, { forwardRef, useContext, useEffect } from 'react';
|
||||||
|
import { ActionInitializer, useDesignable } from '@nocobase/client';
|
||||||
|
import { ChartRendererContext } from '../renderer';
|
||||||
|
import { Dropdown, MenuProps } from 'antd';
|
||||||
|
import { DownOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||||
|
import { useFieldSchema } from '@formily/react';
|
||||||
|
import { useChartsTranslation } from '../locale';
|
||||||
|
|
||||||
|
export const RefreshButton: React.FC = forwardRef<HTMLButtonElement | HTMLAnchorElement, any>((props, ref) => {
|
||||||
|
const { t } = useChartsTranslation();
|
||||||
|
const { autoRefresh, setAutoRefresh, showActionBar } = useContext(ChartRendererContext);
|
||||||
|
const { designable } = useDesignable();
|
||||||
|
const interval = {
|
||||||
|
5: '5s',
|
||||||
|
10: '10s',
|
||||||
|
30: '30s',
|
||||||
|
60: '1m',
|
||||||
|
300: '5m',
|
||||||
|
900: '15m',
|
||||||
|
1800: '30m',
|
||||||
|
3600: '1h',
|
||||||
|
7200: '2h',
|
||||||
|
86400: '1d',
|
||||||
|
};
|
||||||
|
const items: MenuProps['items'] = Object.entries(interval).map(([key, label]) => ({
|
||||||
|
key,
|
||||||
|
label,
|
||||||
|
onClick: () => setAutoRefresh(+key),
|
||||||
|
}));
|
||||||
|
return showActionBar || designable ? (
|
||||||
|
<Dropdown.Button
|
||||||
|
{...props}
|
||||||
|
menu={{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
key: 'off',
|
||||||
|
label: t('Off'),
|
||||||
|
onClick: () => setAutoRefresh(false),
|
||||||
|
},
|
||||||
|
...items,
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
icon={<DownOutlined />}
|
||||||
|
buttonsRender={([_, rightButton]) => [
|
||||||
|
_,
|
||||||
|
React.cloneElement(
|
||||||
|
rightButton as React.ReactElement<any, string>,
|
||||||
|
{ iconPosition: 'end' },
|
||||||
|
autoRefresh ? interval[autoRefresh as number] : null,
|
||||||
|
),
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<ReloadOutlined />
|
||||||
|
{props.children}
|
||||||
|
</Dropdown.Button>
|
||||||
|
) : null;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useChartRefreshActionProps = () => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { service, setAutoRefresh } = useContext(ChartRendererContext);
|
||||||
|
useEffect(() => {
|
||||||
|
setAutoRefresh(fieldSchema['x-component-props']?.autoRefresh);
|
||||||
|
return () => {
|
||||||
|
setAutoRefresh(false);
|
||||||
|
};
|
||||||
|
}, [fieldSchema, setAutoRefresh]);
|
||||||
|
return {
|
||||||
|
onClick: service.refresh,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RefreshActionInitializer = (props) => {
|
||||||
|
const schema = {
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-use-component-props': 'useChartRefreshActionProps',
|
||||||
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
|
'x-settings': 'chartActionSettings:refresh',
|
||||||
|
'x-component-props': {
|
||||||
|
size: 'small',
|
||||||
|
component: 'RefreshButton',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return <ActionInitializer {...props} schema={schema} />;
|
||||||
|
};
|
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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 { SchemaInitializer } from '@nocobase/client';
|
||||||
|
import { lang } from '../locale';
|
||||||
|
import { RefreshActionInitializer } from './RefreshAction';
|
||||||
|
|
||||||
|
export const chartActionsInitializer = new SchemaInitializer({
|
||||||
|
name: 'chart:configureActions',
|
||||||
|
title: lang('Configure actions'),
|
||||||
|
icon: 'SettingOutlined',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'refresh',
|
||||||
|
title: lang('Refresh'),
|
||||||
|
Component: RefreshActionInitializer,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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 { SchemaInitializer } from '@nocobase/client';
|
||||||
|
import { lang } from '../locale';
|
||||||
|
import { BlockRefreshActionInitializer } from './BlockRefreshAction';
|
||||||
|
|
||||||
|
export const chartBlockActionsInitializer = new SchemaInitializer({
|
||||||
|
name: 'chartBlock:configureActions',
|
||||||
|
title: lang('Configure actions'),
|
||||||
|
icon: 'SettingOutlined',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'refresh',
|
||||||
|
title: lang('Refresh'),
|
||||||
|
Component: BlockRefreshActionInitializer,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
@ -7,32 +7,35 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useField, useFieldSchema } from '@formily/react';
|
import { useAPIClient } from '@nocobase/client';
|
||||||
import {
|
|
||||||
GeneralSchemaDesigner,
|
|
||||||
SchemaSettingsBlockTitleItem,
|
|
||||||
SchemaSettingsDivider,
|
|
||||||
SchemaSettingsItem,
|
|
||||||
SchemaSettingsRemove,
|
|
||||||
gridRowColWrap,
|
|
||||||
useAPIClient,
|
|
||||||
useCollection_deprecated,
|
|
||||||
useDataSource,
|
|
||||||
useDesignable,
|
|
||||||
} from '@nocobase/client';
|
|
||||||
import { Empty, Result, Spin, Typography } from 'antd';
|
import { Empty, Result, Spin, Typography } from 'antd';
|
||||||
import React, { useContext, useEffect, useRef } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
import { ChartConfigContext } from '../configure';
|
|
||||||
import { useData, useFieldTransformer, useFieldsWithAssociation } from '../hooks';
|
import { useData, useFieldTransformer, useFieldsWithAssociation } from '../hooks';
|
||||||
import { useChartsTranslation } from '../locale';
|
import { useChartsTranslation } from '../locale';
|
||||||
import { createRendererSchema, getField } from '../utils';
|
import { getField } from '../utils';
|
||||||
import { ChartRendererContext } from './ChartRendererProvider';
|
import { ChartRendererContext } from './ChartRendererProvider';
|
||||||
import { useChart } from '../chart/group';
|
import { useChart } from '../chart/group';
|
||||||
import { ChartDataContext } from '../block/ChartDataProvider';
|
|
||||||
import { Schema } from '@formily/react';
|
import { Schema } from '@formily/react';
|
||||||
|
import { ChartRendererDesigner } from './ChartRendererDesigner';
|
||||||
const { Paragraph, Text } = Typography;
|
const { Paragraph, Text } = Typography;
|
||||||
|
|
||||||
|
const ErrorFallback = ({ error }) => {
|
||||||
|
const { t } = useChartsTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ backgroundColor: 'white' }}>
|
||||||
|
<Result status="error" title={t('Render Failed')} subTitle={t('Please check the configuration.')}>
|
||||||
|
<Paragraph copyable>
|
||||||
|
<Text type="danger" style={{ whiteSpace: 'pre-line', textAlign: 'center' }}>
|
||||||
|
{error.message}
|
||||||
|
</Text>
|
||||||
|
</Paragraph>
|
||||||
|
</Result>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const ChartRenderer: React.FC & {
|
export const ChartRenderer: React.FC & {
|
||||||
Designer: React.FC;
|
Designer: React.FC;
|
||||||
} = (props) => {
|
} = (props) => {
|
||||||
@ -84,64 +87,4 @@ export const ChartRenderer: React.FC & {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
ChartRenderer.Designer = function Designer() {
|
ChartRenderer.Designer = ChartRendererDesigner;
|
||||||
const { t } = useChartsTranslation();
|
|
||||||
const { setVisible, setCurrent } = useContext(ChartConfigContext);
|
|
||||||
const { removeChart } = useContext(ChartDataContext);
|
|
||||||
const { service } = useContext(ChartRendererContext);
|
|
||||||
const field = useField();
|
|
||||||
const schema = useFieldSchema();
|
|
||||||
const { insertAdjacent } = useDesignable();
|
|
||||||
const dataSource = useDataSource();
|
|
||||||
const { name, title } = useCollection_deprecated();
|
|
||||||
return (
|
|
||||||
<GeneralSchemaDesigner disableInitializer title={title || name}>
|
|
||||||
<SchemaSettingsItem
|
|
||||||
title="Configure"
|
|
||||||
key="configure"
|
|
||||||
onClick={async () => {
|
|
||||||
setCurrent({ schema, field, dataSource: dataSource.key, collection: name, service, data: service.data });
|
|
||||||
setVisible(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Configure')}
|
|
||||||
</SchemaSettingsItem>
|
|
||||||
<SchemaSettingsItem
|
|
||||||
title="Duplicate"
|
|
||||||
key="duplicate"
|
|
||||||
onClick={() => insertAdjacent('afterEnd', gridRowColWrap(createRendererSchema(schema?.['x-decorator-props'])))}
|
|
||||||
>
|
|
||||||
{t('Duplicate')}
|
|
||||||
</SchemaSettingsItem>
|
|
||||||
{/* <SchemaSettingsBlockTitleItem /> */}
|
|
||||||
<SchemaSettingsDivider />
|
|
||||||
<SchemaSettingsRemove
|
|
||||||
// removeParentsIfNoChildren
|
|
||||||
breakRemoveOn={{
|
|
||||||
'x-component': 'ChartV2Block',
|
|
||||||
}}
|
|
||||||
confirm={{
|
|
||||||
onOk: () => {
|
|
||||||
removeChart(schema['x-uid']);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</GeneralSchemaDesigner>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ErrorFallback = ({ error }) => {
|
|
||||||
const { t } = useChartsTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ backgroundColor: 'white' }}>
|
|
||||||
<Result status="error" title={t('Render Failed')} subTitle={t('Please check the configuration.')}>
|
|
||||||
<Paragraph copyable>
|
|
||||||
<Text type="danger" style={{ whiteSpace: 'pre-line', textAlign: 'center' }}>
|
|
||||||
{error.message}
|
|
||||||
</Text>
|
|
||||||
</Paragraph>
|
|
||||||
</Result>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* 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 { useField, useFieldSchema } from '@formily/react';
|
||||||
|
import {
|
||||||
|
GeneralSchemaDesigner,
|
||||||
|
SchemaSettingsDivider,
|
||||||
|
SchemaSettingsItem,
|
||||||
|
SchemaSettingsRemove,
|
||||||
|
SchemaSettingsSelectItem,
|
||||||
|
gridRowColWrap,
|
||||||
|
useCollection_deprecated,
|
||||||
|
useDataSource,
|
||||||
|
useDesignable,
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { ChartConfigContext } from '../configure';
|
||||||
|
import { useChartsTranslation } from '../locale';
|
||||||
|
import { createRendererSchema } from '../utils';
|
||||||
|
import { ChartRendererContext } from './ChartRendererProvider';
|
||||||
|
import { ChartDataContext } from '../block/ChartDataProvider';
|
||||||
|
|
||||||
|
export function ChartRendererDesigner() {
|
||||||
|
const { t } = useChartsTranslation();
|
||||||
|
const { setVisible, setCurrent } = useContext(ChartConfigContext);
|
||||||
|
const { removeChart } = useContext(ChartDataContext);
|
||||||
|
const { service } = useContext(ChartRendererContext);
|
||||||
|
const field = useField();
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
const { insertAdjacent } = useDesignable();
|
||||||
|
const dataSource = useDataSource();
|
||||||
|
const { name, title } = useCollection_deprecated();
|
||||||
|
return (
|
||||||
|
<GeneralSchemaDesigner disableInitializer title={title || name}>
|
||||||
|
<SchemaSettingsItem
|
||||||
|
title="Configure"
|
||||||
|
key="configure"
|
||||||
|
onClick={async () => {
|
||||||
|
setCurrent({ schema, field, dataSource: dataSource.key, collection: name, service, data: service.data });
|
||||||
|
setVisible(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('Configure')}
|
||||||
|
</SchemaSettingsItem>
|
||||||
|
<SchemaSettingsItem
|
||||||
|
title="Duplicate"
|
||||||
|
key="duplicate"
|
||||||
|
onClick={() => insertAdjacent('afterEnd', gridRowColWrap(createRendererSchema(schema?.['x-decorator-props'])))}
|
||||||
|
>
|
||||||
|
{t('Duplicate')}
|
||||||
|
</SchemaSettingsItem>
|
||||||
|
{/* <SchemaSettingsBlockTitleItem /> */}
|
||||||
|
<SchemaSettingsDivider />
|
||||||
|
<SchemaSettingsRemove
|
||||||
|
// removeParentsIfNoChildren
|
||||||
|
breakRemoveOn={{
|
||||||
|
'x-component': 'ChartV2Block',
|
||||||
|
}}
|
||||||
|
confirm={{
|
||||||
|
onOk: () => {
|
||||||
|
removeChart(schema['x-uid']);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</GeneralSchemaDesigner>
|
||||||
|
);
|
||||||
|
}
|
@ -13,16 +13,14 @@ import {
|
|||||||
DEFAULT_DATA_SOURCE_KEY,
|
DEFAULT_DATA_SOURCE_KEY,
|
||||||
MaybeCollectionProvider,
|
MaybeCollectionProvider,
|
||||||
useAPIClient,
|
useAPIClient,
|
||||||
useDataSourceManager,
|
|
||||||
useParsedFilter,
|
|
||||||
useRequest,
|
useRequest,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext, useEffect } from 'react';
|
||||||
import { parseField, removeUnparsableFilter } from '../utils';
|
import { parseField, removeUnparsableFilter } from '../utils';
|
||||||
import { ChartDataContext } from '../block/ChartDataProvider';
|
import { ChartDataContext } from '../block/ChartDataProvider';
|
||||||
import { ConfigProvider } from 'antd';
|
|
||||||
import { useChartFilter } from '../hooks';
|
import { useChartFilter } from '../hooks';
|
||||||
import { ChartFilterContext } from '../filter/FilterProvider';
|
import { ChartFilterContext } from '../filter/FilterProvider';
|
||||||
|
import { GlobalAutoRefreshContext } from '../block/GlobalAutoRefreshProvider';
|
||||||
|
|
||||||
export type MeasureProps = {
|
export type MeasureProps = {
|
||||||
field: string | string[];
|
field: string | string[];
|
||||||
@ -66,26 +64,36 @@ export type ChartRendererProps = {
|
|||||||
chartType: string;
|
chartType: string;
|
||||||
general: any;
|
general: any;
|
||||||
advanced: any;
|
advanced: any;
|
||||||
|
title?: string;
|
||||||
|
bordered?: boolean;
|
||||||
};
|
};
|
||||||
transform?: TransformProps[];
|
transform?: TransformProps[];
|
||||||
mode?: 'builder' | 'sql';
|
mode?: 'builder' | 'sql';
|
||||||
|
disableAutoRefresh?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ChartRendererContext = createContext<
|
export const ChartRendererContext = createContext<
|
||||||
{
|
{
|
||||||
service: any;
|
service: any;
|
||||||
data?: any[];
|
data?: any[];
|
||||||
|
autoRefresh?: number | boolean;
|
||||||
|
setAutoRefresh?: (autoRefresh: number | boolean) => void;
|
||||||
|
showActionBar?: boolean;
|
||||||
} & ChartRendererProps
|
} & ChartRendererProps
|
||||||
>({} as any);
|
>({} as any);
|
||||||
ChartRendererContext.displayName = 'ChartRendererContext';
|
ChartRendererContext.displayName = 'ChartRendererContext';
|
||||||
|
|
||||||
export const ChartRendererProvider: React.FC<ChartRendererProps> = (props) => {
|
export const ChartRendererProvider: React.FC<ChartRendererProps> = (props) => {
|
||||||
const { query, config, collection, transform, dataSource = DEFAULT_DATA_SOURCE_KEY } = props;
|
const { query, config, collection, transform, dataSource = DEFAULT_DATA_SOURCE_KEY, disableAutoRefresh } = props;
|
||||||
const { addChart } = useContext(ChartDataContext);
|
const { addChart } = useContext(ChartDataContext);
|
||||||
|
const { addChart: addGlobalAutoRefreshChart, removeChart: removeGlobalAutoRefreshChart } =
|
||||||
|
useContext(GlobalAutoRefreshContext);
|
||||||
const { ready, form, enabled } = useContext(ChartFilterContext);
|
const { ready, form, enabled } = useContext(ChartFilterContext);
|
||||||
const { getFilter, hasFilter, appendFilter, parseFilter } = useChartFilter();
|
const { getFilter, hasFilter, appendFilter, parseFilter } = useChartFilter();
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
|
const [autoRefresh, setAutoRefresh] = React.useState<number | boolean>(false);
|
||||||
|
const [showActionBar, setShowActionBar] = React.useState<boolean>(false);
|
||||||
const service = useRequest(
|
const service = useRequest(
|
||||||
async (dataSource, collection, query, manual) => {
|
async (dataSource, collection, query, manual) => {
|
||||||
if (!(collection && query?.measures?.length)) return;
|
if (!(collection && query?.measures?.length)) return;
|
||||||
@ -133,6 +141,9 @@ export const ChartRendererProvider: React.FC<ChartRendererProps> = (props) => {
|
|||||||
} finally {
|
} finally {
|
||||||
if (!manual && schema?.['x-uid']) {
|
if (!manual && schema?.['x-uid']) {
|
||||||
addChart(schema?.['x-uid'], { dataSource, collection, service, query });
|
addChart(schema?.['x-uid'], { dataSource, collection, service, query });
|
||||||
|
if (!autoRefresh) {
|
||||||
|
addGlobalAutoRefreshChart?.(schema?.['x-uid'], { service });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -144,11 +155,41 @@ export const ChartRendererProvider: React.FC<ChartRendererProps> = (props) => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (disableAutoRefresh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!autoRefresh) {
|
||||||
|
addGlobalAutoRefreshChart?.(schema?.['x-uid'], { service });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
removeGlobalAutoRefreshChart?.(schema?.['x-uid']);
|
||||||
|
const refresh = autoRefresh as number;
|
||||||
|
const timer = setInterval(service.refresh, refresh * 1000);
|
||||||
|
return () => {
|
||||||
|
clearInterval(timer);
|
||||||
|
};
|
||||||
|
}, [autoRefresh, disableAutoRefresh]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CollectionManagerProvider dataSource={dataSource}>
|
<CollectionManagerProvider dataSource={dataSource}>
|
||||||
<MaybeCollectionProvider collection={collection}>
|
<MaybeCollectionProvider collection={collection}>
|
||||||
<ChartRendererContext.Provider value={{ dataSource, collection, config, transform, service, query }}>
|
<ChartRendererContext.Provider
|
||||||
{props.children}
|
value={{
|
||||||
|
dataSource,
|
||||||
|
collection,
|
||||||
|
config,
|
||||||
|
transform,
|
||||||
|
service,
|
||||||
|
query,
|
||||||
|
autoRefresh,
|
||||||
|
setAutoRefresh,
|
||||||
|
showActionBar,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div onMouseOver={() => setShowActionBar(true)} onMouseOut={() => setShowActionBar(false)}>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
</ChartRendererContext.Provider>
|
</ChartRendererContext.Provider>
|
||||||
</MaybeCollectionProvider>
|
</MaybeCollectionProvider>
|
||||||
</CollectionManagerProvider>
|
</CollectionManagerProvider>
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* 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 { useField } from '@formily/react';
|
||||||
|
import { SchemaSettingsSelectItem } from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
import { useChartsTranslation } from '../locale';
|
||||||
|
|
||||||
|
export const AutoRefreshItem: React.FC<{
|
||||||
|
value: number | boolean;
|
||||||
|
onChange?: (value: any) => void;
|
||||||
|
}> = (props) => {
|
||||||
|
const { t } = useChartsTranslation();
|
||||||
|
return (
|
||||||
|
<SchemaSettingsSelectItem
|
||||||
|
title={t('Auto refresh')}
|
||||||
|
value={props.value}
|
||||||
|
onChange={props.onChange}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: t('Off'),
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '5s',
|
||||||
|
value: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '10s',
|
||||||
|
value: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '30s',
|
||||||
|
value: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1m',
|
||||||
|
value: 60,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '5m',
|
||||||
|
value: 300,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '15m',
|
||||||
|
value: 900,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '30m',
|
||||||
|
value: 1800,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1h',
|
||||||
|
value: 3600,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '2h',
|
||||||
|
value: 7200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1d',
|
||||||
|
value: 86400,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* 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 React, { useContext } from 'react';
|
||||||
|
import { SchemaSettings, useDesignable } from '@nocobase/client';
|
||||||
|
import { useChartsTranslation } from '../locale';
|
||||||
|
import { AutoRefreshItem } from './AutoRefreshItem';
|
||||||
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { ChartRendererContext } from '../renderer';
|
||||||
|
|
||||||
|
export const chartActionRefreshSettings = new SchemaSettings({
|
||||||
|
name: 'chartActionSettings:refresh',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'refresh',
|
||||||
|
Component: () => {
|
||||||
|
const field = useField();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const { setAutoRefresh } = useContext(ChartRendererContext);
|
||||||
|
return (
|
||||||
|
<AutoRefreshItem
|
||||||
|
value={field.componentProps?.autoRefresh || false}
|
||||||
|
onChange={(v) => {
|
||||||
|
setAutoRefresh(v);
|
||||||
|
field.componentProps = {
|
||||||
|
...field.componentProps,
|
||||||
|
autoRefresh: v,
|
||||||
|
};
|
||||||
|
fieldSchema['x-component-props'] = field.componentProps;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-component-props': field.componentProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'divider',
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'delete',
|
||||||
|
type: 'remove',
|
||||||
|
useComponentProps() {
|
||||||
|
const { t } = useChartsTranslation();
|
||||||
|
return {
|
||||||
|
removeParentsIfNoChildren: true,
|
||||||
|
breakRemoveOn: (s) => {
|
||||||
|
return s['x-component'] === 'Space' || s['x-component'].endsWith('ActionBar');
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
title: t('Delete action'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* 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 React, { useContext } from 'react';
|
||||||
|
import { SchemaSettings, useDesignable } from '@nocobase/client';
|
||||||
|
import { useChartsTranslation } from '../locale';
|
||||||
|
import { AutoRefreshItem } from './AutoRefreshItem';
|
||||||
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { GlobalAutoRefreshContext } from '../block';
|
||||||
|
|
||||||
|
export const chartBlockActionRefreshSettings = new SchemaSettings({
|
||||||
|
name: 'chartBlockActionSettings:refresh',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'refresh',
|
||||||
|
Component: () => {
|
||||||
|
const field = useField();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const { setAutoRefresh } = useContext(GlobalAutoRefreshContext);
|
||||||
|
return (
|
||||||
|
<AutoRefreshItem
|
||||||
|
value={field.decoratorProps?.autoRefresh || false}
|
||||||
|
onChange={(v) => {
|
||||||
|
setAutoRefresh(v);
|
||||||
|
field.decoratorProps = {
|
||||||
|
...field.decoratorProps,
|
||||||
|
autoRefresh: v,
|
||||||
|
};
|
||||||
|
fieldSchema['x-decorator-props'] = field.decoratorProps;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': field.decoratorProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'divider',
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'delete',
|
||||||
|
type: 'remove',
|
||||||
|
useComponentProps() {
|
||||||
|
const { t } = useChartsTranslation();
|
||||||
|
return {
|
||||||
|
removeParentsIfNoChildren: true,
|
||||||
|
breakRemoveOn: (s) => {
|
||||||
|
return s['x-component'] === 'Space' || s['x-component'].endsWith('ActionBar');
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
title: t('Delete action'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
@ -12,7 +12,8 @@ import { uid } from '@formily/shared';
|
|||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import { SelectedField } from './configure';
|
import { SelectedField } from './configure';
|
||||||
import { FieldOption } from './hooks';
|
import { FieldOption } from './hooks';
|
||||||
import { QueryProps } from './renderer';
|
import { ChartRendererContext, QueryProps } from './renderer';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
export const createRendererSchema = (decoratorProps: any, componentProps = {}) => {
|
export const createRendererSchema = (decoratorProps: any, componentProps = {}) => {
|
||||||
const { collection, config } = decoratorProps;
|
const { collection, config } = decoratorProps;
|
||||||
@ -31,6 +32,26 @@ export const createRendererSchema = (decoratorProps: any, componentProps = {}) =
|
|||||||
},
|
},
|
||||||
'x-initializer': 'charts:addBlock',
|
'x-initializer': 'charts:addBlock',
|
||||||
properties: {
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'div',
|
||||||
|
'x-decorator-props': {
|
||||||
|
style: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
zIndex: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginRight: 'var(--nb-designer-offset)',
|
||||||
|
marginTop: 'var(--nb-designer-offset)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-initializer': 'chart:configureActions',
|
||||||
|
},
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'ChartRenderer',
|
'x-component': 'ChartRenderer',
|
||||||
|
@ -95,5 +95,6 @@
|
|||||||
"Fixed height": "Fixed height",
|
"Fixed height": "Fixed height",
|
||||||
"Show background": "Show background",
|
"Show background": "Show background",
|
||||||
"Show padding": "Show padding",
|
"Show padding": "Show padding",
|
||||||
"Distinct": "Distinct"
|
"Distinct": "Distinct",
|
||||||
|
"Auto refresh": "Auto refresh"
|
||||||
}
|
}
|
||||||
|
@ -96,5 +96,6 @@
|
|||||||
"Fixed height": "固定高度",
|
"Fixed height": "固定高度",
|
||||||
"Show background": "显示背景",
|
"Show background": "显示背景",
|
||||||
"Show padding": "显示内边距",
|
"Show padding": "显示内边距",
|
||||||
"Distinct": "去重"
|
"Distinct": "去重",
|
||||||
|
"Auto refresh": "自动刷新"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user