diff --git a/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx b/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx
index 57debf2402..fce00dc17d 100644
--- a/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx
+++ b/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx
@@ -151,7 +151,6 @@ const InternalAssociationSelect = observer(
);
};
- console.log(fieldSchema);
return (
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockDesigner.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockDesigner.tsx
index bd26ad786d..ee8dcbbec4 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockDesigner.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockDesigner.tsx
@@ -20,6 +20,11 @@ import React from 'react';
import { useChartsTranslation } from '../locale';
import { useField, useFieldSchema } from '@formily/react';
+/**
+ * @deprecated
+ * use `chartBlockSettings` instead
+ */
+
export const ChartV2BlockDesigner: React.FC = () => {
const { t } = useChartsTranslation();
const field = useField();
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockInitializer.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockInitializer.tsx
index f3c09a720f..1d4164178b 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockInitializer.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/block/ChartBlockInitializer.tsx
@@ -112,7 +112,7 @@ export const ChartV2BlockInitializer: React.FC = () => {
type: 'void',
'x-component': 'ChartCardItem',
'x-use-component-props': 'useChartBlockCardProps',
- 'x-designer': 'ChartV2BlockDesigner',
+ 'x-settings': 'chart:block',
'x-decorator': 'ChartBlockProvider',
properties: {
actions: {
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockDesigner.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockDesigner.tsx
index 86d5247d65..f767e21cb2 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockDesigner.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockDesigner.tsx
@@ -11,6 +11,10 @@ import { GeneralSchemaDesigner, SchemaSettingsRemove } from '@nocobase/client';
import React from 'react';
import { useChartsTranslation } from '../locale';
+/**
+ * @deprecated
+ * use `chartFilterBlockSettings` instead
+ */
export const ChartFilterBlockDesigner: React.FC = () => {
const { t } = useChartsTranslation();
return (
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockInitializer.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockInitializer.tsx
index f9d332054c..1e0d7e3409 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockInitializer.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterBlockInitializer.tsx
@@ -31,7 +31,8 @@ const createFilterSchema = () => {
'x-component-props': {
size: 'small',
},
- 'x-designer': 'ChartFilterBlockDesigner',
+ 'x-toolbar': 'ChartFilterBlockToolbar',
+ 'x-settings': 'chart:filterForm:block',
properties: {
[uid()]: {
type: 'void',
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemDesigner.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemDesigner.tsx
index 295bd5e3e2..ff0e2bbb1b 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemDesigner.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemDesigner.tsx
@@ -353,6 +353,10 @@ const EditDataScope: React.FC = () => {
);
};
+/**
+ * @deprecated
+ * use `chartFilterItemSettings` instead
+ */
export const ChartFilterItemDesigner: React.FC = () => {
const { getCollectionJoinField } = useCollectionManager_deprecated();
const { getField } = useCollection_deprecated();
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx
index a6e2752c6d..a49c302185 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx
@@ -240,7 +240,8 @@ export const ChartFilterCustomItemInitializer: React.FC<{
title: title,
name: `custom.${name}`,
required: false,
- 'x-designer': 'ChartFilterItemDesigner',
+ 'x-toolbar': 'ChartFilterItemToolbar',
+ 'x-settings': 'chart:filterForm:item',
'x-decorator': 'ChartFilterFormItem',
'x-component-props': {
...(defaultSchema['x-component-props'] || {}),
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts
index b6745f9dc4..38f63266bc 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts
@@ -129,18 +129,21 @@ export const useChartFilter = () => {
title,
name: `${name}.${field.name}`,
required: false,
- 'x-designer': 'ChartFilterItemDesigner',
+ 'x-toolbar': 'ChartFilterItemToolbar',
+ 'x-settings': 'chart:filterForm:item',
'x-component': 'CollectionField',
'x-decorator': 'ChartFilterFormItem',
'x-data-source': dataSource,
'x-collection-field': `${fieldName}.${field.name}`,
+ ...defaultOperator?.schema,
'x-component-props': {
+ utc: false,
+ underFilter: true,
...field.uiSchema?.['x-component-props'],
'filter-operator': defaultOperator,
'data-source': dataSource,
'collection-field': `${fieldName}.${field.name}`,
},
- 'x-filter-operators': defaultOperator?.value,
};
if (field.interface === 'formula') {
const component = getFormulaComponent(field.dataType) || 'Input';
@@ -189,18 +192,21 @@ export const useChartFilter = () => {
type: 'string',
name: `${name}.${child.name}`,
required: false,
- 'x-designer': 'ChartFilterItemDesigner',
+ 'x-settings': 'chart:filterForm:item',
+ 'x-toolbar': 'ChartFilterItemToolbar',
'x-decorator': 'ChartFilterFormItem',
'x-data-source': dataSource,
'x-collection-field': `${fieldName}.${child.name}`,
...child.schema,
title,
+ ...defaultOperator?.schema,
'x-component-props': {
+ utc: false,
+ underFilter: true,
'filter-operator': defaultOperator,
'data-source': dataSource,
'collection-field': `${fieldName}.${child.name}`,
},
- 'x-filter-operators': defaultOperator?.value,
};
if (defaultOperator?.noValue) {
schema = {
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/index.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/index.tsx
index 3398be1e6d..1793841235 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/index.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/index.tsx
@@ -26,13 +26,20 @@ import {
chartFilterItemInitializers_deprecated,
} from './filter';
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';
import { useChartBlockCardProps } from './block/ChartBlock';
+import { chartActionsInitializer } from './initializers/chartActions';
+import {
+ chartActionRefreshSettings,
+ chartBlockActionRefreshSettings,
+ chartBlockSettings,
+ chartFilterBlockSettings,
+ chartFilterItemSettings,
+ chartRendererSettings,
+} from './settings';
+import { chartBlockActionsInitializer } from './initializers/chartBlockActions';
+import { useChartRefreshActionProps } from './initializers/RefreshAction';
+import { useChartBlockRefreshActionProps } from './initializers/BlockRefreshAction';
+import { ChartRendererToolbar, ChartFilterBlockToolbar, ChartFilterItemToolbar } from './toolbar';
import { ChartCardItem } from './block/CardItem';
class PluginDataVisualiztionClient extends Plugin {
@@ -48,6 +55,9 @@ class PluginDataVisualiztionClient extends Plugin {
ChartV2Block,
ChartCardItem,
ChartBlockProvider,
+ ChartRendererToolbar,
+ ChartFilterBlockToolbar,
+ ChartFilterItemToolbar,
});
this.app.addScopes({
useChartBlockCardProps,
@@ -55,16 +65,24 @@ class PluginDataVisualiztionClient extends Plugin {
useChartBlockRefreshActionProps,
});
- this.app.schemaInitializerManager.add(chartInitializers_deprecated);
- this.app.schemaInitializerManager.add(chartInitializers);
- this.app.schemaInitializerManager.add(chartFilterItemInitializers_deprecated);
- this.app.schemaInitializerManager.add(chartFilterItemInitializers);
- this.app.schemaInitializerManager.add(chartFilterActionInitializers_deprecated);
- 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);
+ this.app.schemaInitializerManager.add(
+ chartInitializers_deprecated,
+ chartInitializers,
+ chartFilterItemInitializers_deprecated,
+ chartFilterItemInitializers,
+ chartFilterActionInitializers_deprecated,
+ chartFilterActionInitializers,
+ chartActionsInitializer,
+ chartBlockActionsInitializer,
+ );
+ this.app.schemaSettingsManager.add(
+ chartActionRefreshSettings,
+ chartBlockActionRefreshSettings,
+ chartBlockSettings,
+ chartRendererSettings,
+ chartFilterBlockSettings,
+ chartFilterItemSettings,
+ );
const blockInitializers = this.app.schemaInitializerManager.get('page:addBlock');
blockInitializers?.add('dataBlocks.chartV2', {
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/renderer/ChartRendererDesigner.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/renderer/ChartRendererDesigner.tsx
index 062cdbd950..e4c5d36a96 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/renderer/ChartRendererDesigner.tsx
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/renderer/ChartRendererDesigner.tsx
@@ -25,6 +25,10 @@ import { useChartsTranslation } from '../locale';
import { createRendererSchema } from '../utils';
import { ChartRendererContext } from './ChartRendererProvider';
+/**
+ * @deprecated
+ * use `chartRendererSettings` instead
+ */
export function ChartRendererDesigner() {
const { t } = useChartsTranslation();
const { setVisible, setCurrent } = useContext(ChartConfigContext);
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartBlock.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartBlock.tsx
new file mode 100644
index 0000000000..9ee9bbcc9c
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartBlock.tsx
@@ -0,0 +1,103 @@
+/**
+ * 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 {
+ SchemaSettings,
+ SchemaSettingsBlockTitleItem,
+ SchemaSettingsSwitchItem,
+ useDesignable,
+ useToken,
+} from '@nocobase/client';
+import { useChartsTranslation } from '../locale';
+import { useField, useFieldSchema } from '@formily/react';
+
+export const chartBlockSettings = new SchemaSettings({
+ name: 'chart:block',
+ items: [
+ {
+ name: 'title',
+ Component: SchemaSettingsBlockTitleItem,
+ },
+ {
+ name: 'background',
+ Component: () => {
+ const { t } = useChartsTranslation();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const { dn } = useDesignable();
+ const { token } = useToken();
+
+ return (
+ {
+ const style = {
+ ...field.componentProps.style,
+ background: v ? token.colorBgContainer : 'none',
+ boxShadow: v ? token.boxShadowTertiary : 'none',
+ };
+ field.componentProps.style = style;
+ field.componentProps.bordered = v;
+ fieldSchema['x-component-props'] = field.componentProps;
+ dn.emit('patch', {
+ schema: {
+ ['x-uid']: fieldSchema['x-uid'],
+ 'x-component-props': field.componentProps,
+ },
+ });
+ dn.refresh();
+ }}
+ />
+ );
+ },
+ },
+ {
+ name: 'padding',
+ Component: () => {
+ const { t } = useChartsTranslation();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const { dn } = useDesignable();
+ const { token } = useToken();
+
+ return (
+ {
+ const style = {
+ ...field.componentProps.bodyStyle,
+ padding: v ? `${token.paddingLG}px ${token.paddingLG}px 0` : '5px 0 0',
+ };
+ field.componentProps.bodyStyle = style;
+ 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: 'remove',
+ type: 'remove',
+ },
+ ],
+});
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartFilterBlock.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartFilterBlock.tsx
new file mode 100644
index 0000000000..96db46840b
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartFilterBlock.tsx
@@ -0,0 +1,29 @@
+/**
+ * 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 { SchemaSettings, SchemaSettingsRemove } from '@nocobase/client';
+
+export const chartFilterBlockSettings = new SchemaSettings({
+ name: 'chart:filterForm:block',
+ items: [
+ {
+ name: 'remove',
+ Component: () => {
+ return (
+
+ );
+ },
+ },
+ ],
+});
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartFilterItem.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartFilterItem.tsx
new file mode 100644
index 0000000000..81e7d04f28
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartFilterItem.tsx
@@ -0,0 +1,574 @@
+/**
+ * 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 {
+ EditDescription,
+ GeneralSchemaDesigner,
+ SchemaSettingsItem,
+ SchemaSettingsDivider,
+ SchemaSettingsModalItem,
+ SchemaSettingsRemove,
+ VariablesContext,
+ useCollection_deprecated,
+ useCollectionManager_deprecated,
+ useCompile,
+ useDesignable,
+ SchemaSettingsSelectItem,
+ CollectionFieldOptions_deprecated,
+ DEFAULT_DATA_SOURCE_KEY,
+ useIsAssociationField,
+ SchemaSettingsDataScope,
+ removeNullCondition,
+ useFormBlockContext,
+ useLocalVariables,
+ SchemaSettings,
+ useApp,
+ useIsFileField,
+} from '@nocobase/client';
+import { useChartsTranslation } from '../locale';
+import { Schema, useField, useFieldSchema, ISchema } from '@formily/react';
+import { Field } from '@formily/core';
+import _ from 'lodash';
+import { ChartFilterContext } from '../filter/FilterProvider';
+import { getPropsSchemaByComponent, setDefaultValue } from '../filter/utils';
+import { ChartFilterVariableInput } from '../filter/FilterVariableInput';
+import { useChartDataSource, useChartFilter, useCollectionJoinFieldTitle } from '../hooks';
+import { Typography } from 'antd';
+import { getFormulaInterface } from '../utils';
+const { Text } = Typography;
+
+function useFieldComponentName(): string {
+ const field = useField();
+ const isFileField = useIsFileField();
+ const { getCollectionJoinField } = useCollectionManager_deprecated();
+ const { getField } = useCollection_deprecated();
+ const fieldSchema = useFieldSchema();
+ const fieldName = fieldSchema.name as string;
+ const collectionField = getField(fieldName) || getCollectionJoinField(fieldSchema['x-collection-field']);
+
+ const map = {
+ // AssociationField 的 mode 默认值是 Select
+ AssociationField: 'Select',
+ };
+ const fieldComponentName =
+ fieldSchema?.['x-component-props']?.['mode'] ||
+ field?.componentProps?.['mode'] ||
+ (isFileField ? 'FileManager' : '') ||
+ fieldSchema?.['x-component-props']?.['component'] ||
+ collectionField?.uiSchema?.['x-component'];
+ return map[fieldComponentName] || fieldComponentName;
+}
+
+const EditTitle = () => {
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const { t } = useChartsTranslation();
+ const { dn } = useDesignable();
+ const { setField } = useContext(ChartFilterContext);
+
+ return (
+ {
+ if (title) {
+ field.title = title;
+ fieldSchema.title = title;
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ title: fieldSchema.title,
+ },
+ });
+ setField(fieldSchema.name as string, { title });
+ }
+ dn.refresh();
+ }}
+ />
+ );
+};
+
+const EditOperator = () => {
+ const compile = useCompile();
+ const fieldSchema = useFieldSchema();
+ const field = useField();
+ const { t } = useChartsTranslation();
+ const { dn } = useDesignable();
+ const { setField } = useContext(ChartFilterContext);
+ const fieldName = fieldSchema['x-collection-field'];
+ const dataSource = fieldSchema['x-data-source'] || DEFAULT_DATA_SOURCE_KEY;
+ const { cm, fim } = useChartDataSource(dataSource);
+ if (!cm) {
+ return null;
+ }
+
+ const getOperators = (props: CollectionFieldOptions_deprecated) => {
+ let fieldInterface = props?.interface;
+ if (fieldInterface === 'formula') {
+ fieldInterface = getFormulaInterface(props.dataType) || props.dataType;
+ }
+ const interfaceConfig = fim.getFieldInterface(fieldInterface);
+ const operatorList = interfaceConfig?.filterable?.operators || [];
+ return { operatorList, interfaceConfig };
+ };
+
+ let props = cm.getCollectionField(fieldName);
+ let { operatorList, interfaceConfig } = getOperators(props);
+ if (!operatorList.length) {
+ const names = fieldName.split('.');
+ const name = names.pop();
+ if (names.length < 2) {
+ return null;
+ }
+ props = cm.getCollectionField(names.join('.'));
+ if (!props) {
+ return null;
+ }
+ const res = getOperators(props);
+ operatorList = res.operatorList;
+ interfaceConfig = res.interfaceConfig;
+ if (!interfaceConfig) {
+ return null;
+ }
+ const children = interfaceConfig?.filterable.children || [];
+ const child = children.find((item: any) => item.name === name);
+ operatorList = child?.operators || [];
+ }
+ if (!operatorList.length) {
+ return null;
+ }
+ const defaultComponent = interfaceConfig?.default?.uiSchema?.['x-component'] || 'Input';
+ const operator = fieldSchema['x-component-props']?.['filter-operator'];
+
+ const setOperatorComponent = (operator: any, component: any, props = {}) => {
+ const componentProps = field.componentProps || {};
+ field.component = component;
+ field.componentProps = {
+ ...componentProps,
+ 'filter-operator': operator,
+ ...props,
+ };
+ fieldSchema['x-component'] = component;
+ fieldSchema['x-component-props'] = {
+ ...fieldSchema['x-component-props'],
+ 'filter-operator': operator,
+ ...props,
+ };
+ fieldSchema['x-filter-operator'] = operator?.value;
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ 'x-component': component,
+ 'x-component-props': {
+ ...fieldSchema['x-component-props'],
+ 'filter-operator': operator,
+ ...props,
+ },
+ 'x-filter-operator': operator?.value,
+ },
+ });
+ };
+
+ return (
+ {
+ const operator = operatorList.find((item: any) => item.value === op);
+ if (operator.noValue) {
+ setOperatorComponent(operator, 'ChartFilterCheckbox', {
+ content: Schema.compile(operator.label, { t }),
+ });
+ } else if (operator.schema?.['x-component']) {
+ setOperatorComponent(operator, operator.schema['x-component']);
+ } else {
+ setOperatorComponent(operator, defaultComponent);
+ }
+
+ setField(fieldSchema.name as string, { operator });
+ dn.refresh();
+ }}
+ />
+ );
+};
+
+const EditProps = () => {
+ const { t } = useChartsTranslation();
+ const { dn } = useDesignable();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const propsSchema = getPropsSchemaByComponent(fieldSchema['x-component']);
+ return (
+ {
+ field.reset();
+ field.componentProps = props;
+ fieldSchema['x-component-props'] = props;
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ 'x-component-props': props,
+ },
+ });
+ dn.refresh();
+ }}
+ />
+ );
+};
+
+const EditDefaultValue = () => {
+ const { t } = useChartsTranslation();
+ const { dn } = useDesignable();
+ const variables = useContext(VariablesContext);
+ const localVariables = useLocalVariables();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const { getTranslatedTitle } = useChartFilter();
+ const title = getTranslatedTitle(fieldSchema.title);
+ return (
+ {
+ field.setInitialValue(value);
+ fieldSchema.default = value;
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ default: value,
+ },
+ });
+ dn.refresh();
+ setDefaultValue(field, variables, localVariables);
+ }}
+ />
+ );
+};
+
+const EditTitleField = () => {
+ const { getCollectionFields, getCollectionJoinField, getInterface } = useCollectionManager_deprecated();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const { t } = useChartsTranslation();
+ const { dn } = useDesignable();
+ const compile = useCompile();
+ const collectionField = getCollectionJoinField(fieldSchema['x-collection-field']);
+ const targetFields = collectionField?.target
+ ? getCollectionFields(collectionField?.target)
+ : getCollectionFields(collectionField?.targetCollection) ?? [];
+ const options = targetFields
+ .filter((field) => {
+ if (field?.target || field.type === 'boolean') {
+ return false;
+ }
+ const fieldInterface = getInterface(field?.interface);
+ return fieldInterface?.titleUsable;
+ })
+ .map((field) => ({
+ value: field?.name,
+ label: compile(field?.uiSchema?.title) || field?.name,
+ }));
+
+ return options.length > 0 && fieldSchema['x-component'] === 'CollectionField' ? (
+ {
+ const schema = {
+ ['x-uid']: fieldSchema['x-uid'],
+ };
+ const fieldNames = {
+ ...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'],
+ ...field.componentProps.fieldNames,
+ label,
+ };
+ fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
+ fieldSchema['x-component-props']['fieldNames'] = fieldNames;
+ schema['x-component-props'] = fieldSchema['x-component-props'];
+ field.componentProps.fieldNames = fieldSchema['x-component-props'].fieldNames;
+ dn.emit('patch', {
+ schema,
+ });
+ dn.refresh();
+ }}
+ />
+ ) : null;
+};
+
+const EditDataScope: React.FC = () => {
+ const { dn } = useDesignable();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const dataSource = fieldSchema['x-data-source'] || DEFAULT_DATA_SOURCE_KEY;
+ const { form } = useFormBlockContext();
+ const { cm } = useChartDataSource(dataSource);
+ const collectionField = cm.getCollectionField(fieldSchema['x-collection-field']);
+ if (!collectionField) {
+ return null;
+ }
+ return (
+ {
+ filter = removeNullCondition(filter);
+ _.set(field.componentProps, 'service.params.filter', filter);
+ fieldSchema['x-component-props'] = field.componentProps;
+ dn.emit('patch', {
+ schema: {
+ ['x-uid']: fieldSchema['x-uid'],
+ 'x-component-props': field.componentProps,
+ },
+ });
+ }}
+ />
+ );
+};
+
+export const chartFilterItemSettings = new SchemaSettings({
+ name: 'chart:filterForm:item',
+ items: [
+ {
+ name: 'originalTitle',
+ Component: () => {
+ const { t } = useChartsTranslation();
+ const fieldSchema = useFieldSchema();
+ const fieldName = fieldSchema.name as string;
+ const isCustom = fieldName.startsWith('custom.');
+ const dataSource = fieldSchema['x-data-source'] || DEFAULT_DATA_SOURCE_KEY;
+
+ const originalTitle = useCollectionJoinFieldTitle(dataSource, fieldName);
+ if (isCustom) {
+ return null;
+ }
+
+ return (
+ <>
+
+
+ {t('Original field')}: {originalTitle}
+
+
+
+ >
+ );
+ },
+ },
+ {
+ name: 'decoratorOptions',
+ type: 'itemGroup',
+ hideIfNoChildren: true,
+ useComponentProps() {
+ const { t } = useChartsTranslation();
+ return {
+ title: t('Generic properties'),
+ };
+ },
+ useChildren() {
+ return [
+ {
+ name: 'title',
+ Component: EditTitle,
+ },
+ {
+ name: 'displayTitle',
+ type: 'switch',
+ useComponentProps() {
+ const { t } = useChartsTranslation();
+ const { dn } = useDesignable();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+
+ return {
+ title: t('Display title'),
+ checked: fieldSchema['x-decorator-props']?.['showTitle'] ?? true,
+ onChange(checked) {
+ fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
+ fieldSchema['x-decorator-props']['showTitle'] = checked;
+ field.decoratorProps.showTitle = checked;
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ 'x-decorator-props': {
+ ...fieldSchema['x-decorator-props'],
+ showTitle: checked,
+ },
+ },
+ });
+ dn.refresh();
+ },
+ };
+ },
+ },
+ {
+ name: 'description',
+ Component: EditDescription,
+ },
+ {
+ name: 'editTooltip',
+ type: 'modal',
+ useComponentProps() {
+ const { t } = useChartsTranslation();
+ const { dn } = useDesignable();
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+
+ return {
+ title: t('Edit tooltip'),
+ schema: {
+ type: 'object',
+ title: t('Edit tooltip'),
+ properties: {
+ tooltip: {
+ default: fieldSchema?.['x-decorator-props']?.tooltip,
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Input.TextArea',
+ 'x-component-props': {},
+ },
+ },
+ } as ISchema,
+ onSubmit({ tooltip }) {
+ field.decoratorProps.tooltip = tooltip;
+ fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
+ fieldSchema['x-decorator-props']['tooltip'] = tooltip;
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ 'x-decorator-props': fieldSchema['x-decorator-props'],
+ },
+ });
+ dn.refresh();
+ },
+ };
+ },
+ },
+ {
+ name: 'defaultValue',
+ Component: EditDefaultValue,
+ },
+ {
+ name: 'operator',
+ Component: () => {
+ const fieldSchema = useFieldSchema();
+ const fieldName = fieldSchema.name as string;
+ const isCustom = fieldName.startsWith('custom.');
+ if (isCustom) {
+ return null;
+ }
+ return ;
+ },
+ },
+ {
+ name: 'props',
+ Component: () => {
+ const fieldSchema = useFieldSchema();
+ const fieldName = fieldSchema.name as string;
+ const isCustom = fieldName.startsWith('custom.');
+ const hasProps = getPropsSchemaByComponent(fieldSchema['x-component']);
+ if (hasProps && isCustom) {
+ return ;
+ }
+ return null;
+ },
+ },
+ ];
+ },
+ },
+ {
+ name: 'componentOptions',
+ type: 'itemGroup',
+ hideIfNoChildren: true,
+ useComponentProps() {
+ const { t } = useChartsTranslation();
+ return {
+ title: t('Specific properties'),
+ };
+ },
+ useChildren() {
+ const fieldComponentNameMap = {
+ Select: 'FilterSelect',
+ };
+ const app = useApp();
+ const fieldComponentName = useFieldComponentName();
+ const componentSettings = app.schemaSettingsManager.get(
+ `fieldSettings:component:${fieldComponentNameMap[fieldComponentName] || fieldComponentName}`,
+ );
+ return componentSettings?.items || [];
+ },
+ },
+ {
+ name: 'divider',
+ Component: () => {
+ return ;
+ },
+ },
+ {
+ name: 'remove',
+ Component: () => {
+ const { t } = useChartsTranslation();
+
+ return (
+
+ );
+ },
+ },
+ ],
+});
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartRenderer.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartRenderer.tsx
new file mode 100644
index 0000000000..0e97b22ef3
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/chartRenderer.tsx
@@ -0,0 +1,102 @@
+/**
+ * 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 { useField, useFieldSchema } from '@formily/react';
+import {
+ SchemaSettings,
+ SchemaSettingsItem,
+ SchemaSettingsRemove,
+ gridRowColWrap,
+ useDataSource,
+ useCollection,
+ useDesignable,
+} from '@nocobase/client';
+import { ChartDataContext } from '../block/ChartDataProvider';
+import { ChartConfigContext } from '../configure';
+import { useChartsTranslation } from '../locale';
+import { createRendererSchema } from '../utils';
+import { ChartRendererContext } from '../renderer/ChartRendererProvider';
+
+export const chartRendererSettings = new SchemaSettings({
+ name: 'chart:renderer',
+ items: [
+ {
+ name: 'configure',
+ Component: () => {
+ const { t } = useChartsTranslation();
+ const { setVisible, setCurrent } = useContext(ChartConfigContext);
+ const { service } = useContext(ChartRendererContext);
+ const field = useField();
+ const schema = useFieldSchema();
+ const dataSource = useDataSource();
+ const { name } = useCollection();
+
+ return (
+ {
+ setCurrent({ schema, field, dataSource: dataSource.key, collection: name, service, data: service.data });
+ setVisible(true);
+ }}
+ >
+ {t('Configure')}
+
+ );
+ },
+ },
+ {
+ name: 'duplicate',
+ Component: () => {
+ const { t } = useChartsTranslation();
+ const { insertAdjacent, refresh } = useDesignable();
+ const schema = useFieldSchema();
+
+ return (
+ {
+ insertAdjacent('afterEnd', gridRowColWrap(createRendererSchema(schema?.['x-decorator-props'])));
+ refresh({ refreshParentSchema: true });
+ }}
+ >
+ {t('Duplicate')}
+
+ );
+ },
+ },
+ {
+ name: 'divider',
+ type: 'divider',
+ },
+ {
+ name: 'remove',
+ Component: () => {
+ const { removeChart } = useContext(ChartDataContext);
+ const schema = useFieldSchema();
+
+ return (
+ {
+ removeChart(schema['x-uid']);
+ },
+ }}
+ />
+ );
+ },
+ },
+ ],
+});
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/index.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/index.ts
new file mode 100644
index 0000000000..7c4805babc
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/settings/index.ts
@@ -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.
+ */
+
+export { chartActionRefreshSettings } from './chartActionRefresh';
+export { chartBlockActionRefreshSettings } from './chartBlockActionRefresh';
+export { chartBlockSettings } from './chartBlock';
+export { chartRendererSettings } from './chartRenderer';
+export { chartFilterBlockSettings } from './chartFilterBlock';
+export { chartFilterItemSettings } from './chartFilterItem';
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartFilterBlock.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartFilterBlock.tsx
new file mode 100644
index 0000000000..e743ab0b47
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartFilterBlock.tsx
@@ -0,0 +1,18 @@
+/**
+ * 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 { SchemaToolbar } from '@nocobase/client';
+import React from 'react';
+import { useChartsTranslation } from '../locale';
+
+export const ChartFilterBlockToolbar = () => {
+ const { t } = useChartsTranslation();
+
+ return ;
+};
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartFilterItem.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartFilterItem.tsx
new file mode 100644
index 0000000000..e0c56434ce
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartFilterItem.tsx
@@ -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 { SchemaToolbar } from '@nocobase/client';
+import React from 'react';
+
+export const ChartFilterItemToolbar = () => {
+ return ;
+};
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartRenderer.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartRenderer.tsx
new file mode 100644
index 0000000000..b3b3a6f158
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/ChartRenderer.tsx
@@ -0,0 +1,17 @@
+/**
+ * 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 { SchemaToolbar, useCollection } from '@nocobase/client';
+import React from 'react';
+
+export const ChartRendererToolbar = () => {
+ const { name, title } = useCollection();
+
+ return ;
+};
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/index.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/index.ts
new file mode 100644
index 0000000000..3b088f8d36
--- /dev/null
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/toolbar/index.ts
@@ -0,0 +1,12 @@
+/**
+ * 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.
+ */
+
+export * from './ChartRenderer';
+export * from './ChartFilterBlock';
+export * from './ChartFilterItem';
diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/utils.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/utils.ts
index 7db59e21d4..e1f217a8a2 100644
--- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/utils.ts
+++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/utils.ts
@@ -12,8 +12,7 @@ import { uid } from '@formily/shared';
import lodash from 'lodash';
import { SelectedField } from './configure';
import { FieldOption } from './hooks';
-import { ChartRendererContext, QueryProps } from './renderer';
-import { useContext } from 'react';
+import { QueryProps } from './renderer';
export const createRendererSchema = (decoratorProps: any, componentProps = {}) => {
const { collection, config } = decoratorProps;
@@ -23,7 +22,8 @@ export const createRendererSchema = (decoratorProps: any, componentProps = {}) =
'x-decorator': 'ChartRendererProvider',
'x-decorator-props': decoratorProps,
'x-acl-action': `${collection}:list`,
- 'x-designer': 'ChartRenderer.Designer',
+ 'x-toolbar': 'ChartRendererToolbar',
+ 'x-settings': 'chart:renderer',
'x-component': 'CardItem',
'x-component-props': {
size: 'small',