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',