@nocobase/plugin-data-visualization 0.10.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +88 -0
  3. package/client.d.ts +3 -0
  4. package/client.js +65 -0
  5. package/lib/client/Settings.d.ts +2 -0
  6. package/lib/client/Settings.js +81 -0
  7. package/lib/client/block/ChartBlock.d.ts +2 -0
  8. package/lib/client/block/ChartBlock.js +73 -0
  9. package/lib/client/block/ChartBlockDesigner.d.ts +2 -0
  10. package/lib/client/block/ChartBlockDesigner.js +35 -0
  11. package/lib/client/block/ChartBlockInitializer.d.ts +6 -0
  12. package/lib/client/block/ChartBlockInitializer.js +114 -0
  13. package/lib/client/block/ChartConfigure.d.ts +33 -0
  14. package/lib/client/block/ChartConfigure.js +501 -0
  15. package/lib/client/block/formatters.d.ts +15 -0
  16. package/lib/client/block/formatters.js +58 -0
  17. package/lib/client/block/index.d.ts +4 -0
  18. package/lib/client/block/index.js +49 -0
  19. package/lib/client/block/schemas/configure.d.ts +4 -0
  20. package/lib/client/block/schemas/configure.js +492 -0
  21. package/lib/client/block/transformers.d.ts +6 -0
  22. package/lib/client/block/transformers.js +69 -0
  23. package/lib/client/hooks.d.ts +312 -0
  24. package/lib/client/hooks.js +275 -0
  25. package/lib/client/index.d.ts +5 -0
  26. package/lib/client/index.js +70 -0
  27. package/lib/client/locale/en-US.d.ts +23 -0
  28. package/lib/client/locale/en-US.js +29 -0
  29. package/lib/client/locale/index.d.ts +3 -0
  30. package/lib/client/locale/index.js +39 -0
  31. package/lib/client/locale/ja-JP.d.ts +2 -0
  32. package/lib/client/locale/ja-JP.js +8 -0
  33. package/lib/client/locale/pt-BR.d.ts +23 -0
  34. package/lib/client/locale/pt-BR.js +29 -0
  35. package/lib/client/locale/ru-RU.d.ts +2 -0
  36. package/lib/client/locale/ru-RU.js +8 -0
  37. package/lib/client/locale/tr-TR.d.ts +2 -0
  38. package/lib/client/locale/tr-TR.js +8 -0
  39. package/lib/client/locale/zh-CN.d.ts +70 -0
  40. package/lib/client/locale/zh-CN.js +76 -0
  41. package/lib/client/renderer/ChartLibrary.d.ts +71 -0
  42. package/lib/client/renderer/ChartLibrary.js +140 -0
  43. package/lib/client/renderer/ChartRenderer.d.ts +7 -0
  44. package/lib/client/renderer/ChartRenderer.js +258 -0
  45. package/lib/client/renderer/ChartRendererProvider.d.ts +43 -0
  46. package/lib/client/renderer/ChartRendererProvider.js +38 -0
  47. package/lib/client/renderer/index.d.ts +4 -0
  48. package/lib/client/renderer/index.js +49 -0
  49. package/lib/client/renderer/library/AntdLibrary.d.ts +2 -0
  50. package/lib/client/renderer/library/AntdLibrary.js +123 -0
  51. package/lib/client/renderer/library/G2PlotLibrary.d.ts +2 -0
  52. package/lib/client/renderer/library/G2PlotLibrary.js +288 -0
  53. package/lib/client/renderer/library/index.d.ts +3 -0
  54. package/lib/client/renderer/library/index.js +15 -0
  55. package/lib/client/utils.d.ts +96 -0
  56. package/lib/client/utils.js +137 -0
  57. package/lib/index.d.ts +1 -0
  58. package/lib/index.js +13 -0
  59. package/lib/server/actions/formatter.d.ts +3 -0
  60. package/lib/server/actions/formatter.js +44 -0
  61. package/lib/server/actions/query.d.ts +86 -0
  62. package/lib/server/actions/query.js +326 -0
  63. package/lib/server/index.d.ts +1 -0
  64. package/lib/server/index.js +13 -0
  65. package/lib/server/plugin.d.ts +13 -0
  66. package/lib/server/plugin.js +64 -0
  67. package/package.json +23 -0
  68. package/server.d.ts +3 -0
  69. package/server.js +65 -0
  70. package/src/client/Settings.tsx +43 -0
  71. package/src/client/__tests__/chart-configure.test.tsx +14 -0
  72. package/src/client/__tests__/chart-library.test.ts +78 -0
  73. package/src/client/__tests__/chart-renderer.test.tsx +30 -0
  74. package/src/client/__tests__/hooks.test.ts +261 -0
  75. package/src/client/block/ChartBlock.tsx +22 -0
  76. package/src/client/block/ChartBlockDesigner.tsx +19 -0
  77. package/src/client/block/ChartBlockInitializer.tsx +83 -0
  78. package/src/client/block/ChartConfigure.tsx +450 -0
  79. package/src/client/block/formatters.ts +70 -0
  80. package/src/client/block/index.ts +4 -0
  81. package/src/client/block/schemas/configure.ts +474 -0
  82. package/src/client/block/transformers.ts +52 -0
  83. package/src/client/hooks.ts +239 -0
  84. package/src/client/index.tsx +41 -0
  85. package/src/client/locale/en-US.ts +23 -0
  86. package/src/client/locale/index.ts +19 -0
  87. package/src/client/locale/ja-JP.ts +1 -0
  88. package/src/client/locale/pt-BR.ts +23 -0
  89. package/src/client/locale/ru-RU.ts +1 -0
  90. package/src/client/locale/tr-TR.ts +1 -0
  91. package/src/client/locale/zh-CN.ts +71 -0
  92. package/src/client/renderer/ChartLibrary.tsx +178 -0
  93. package/src/client/renderer/ChartRenderer.tsx +201 -0
  94. package/src/client/renderer/ChartRendererProvider.tsx +58 -0
  95. package/src/client/renderer/index.ts +4 -0
  96. package/src/client/renderer/library/AntdLibrary.tsx +94 -0
  97. package/src/client/renderer/library/G2PlotLibrary.tsx +236 -0
  98. package/src/client/renderer/library/index.tsx +4 -0
  99. package/src/client/utils.ts +102 -0
  100. package/src/index.ts +1 -0
  101. package/src/server/__tests__/api.test.ts +105 -0
  102. package/src/server/__tests__/formatter.test.ts +49 -0
  103. package/src/server/__tests__/query.test.ts +220 -0
  104. package/src/server/actions/formatter.ts +49 -0
  105. package/src/server/actions/query.ts +285 -0
  106. package/src/server/collections/.gitkeep +0 -0
  107. package/src/server/index.ts +1 -0
  108. package/src/server/plugin.ts +37 -0
@@ -0,0 +1,201 @@
1
+ import { useField, useFieldSchema } from '@formily/react';
2
+ import {
3
+ GeneralSchemaDesigner,
4
+ gridRowColWrap,
5
+ SchemaSettings,
6
+ useAPIClient,
7
+ useCollection,
8
+ useDesignable,
9
+ useRequest,
10
+ } from '@nocobase/client';
11
+ import { Empty, Result, Typography } from 'antd';
12
+ import React, { useContext, useEffect, useState } from 'react';
13
+ import { ErrorBoundary } from 'react-error-boundary';
14
+ import { ChartConfigContext } from '../block';
15
+ import { useFieldsWithAssociation, useFieldTransformer } from '../hooks';
16
+ import { useChartsTranslation } from '../locale';
17
+ import { createRendererSchema, getField, parseField, processData } from '../utils';
18
+ import { useCharts } from './ChartLibrary';
19
+ import { ChartRendererContext, DimensionProps, MeasureProps, QueryProps } from './ChartRendererProvider';
20
+ const { Paragraph, Text } = Typography;
21
+
22
+ export const ChartRenderer: React.FC<{
23
+ configuring?: boolean;
24
+ runQuery?: any;
25
+ }> & {
26
+ Designer: React.FC;
27
+ } = (props) => {
28
+ const { t } = useChartsTranslation();
29
+ const { setData: setQueryData, current } = useContext(ChartConfigContext);
30
+ const { query, config, collection, transform } = useContext(ChartRendererContext);
31
+ const { configuring, runQuery } = props;
32
+ const general = config?.general || {};
33
+ const advanced = config?.advanced || {};
34
+ const schema = useFieldSchema();
35
+ const currentSchema = schema || current?.schema;
36
+ const fields = useFieldsWithAssociation(collection);
37
+ const api = useAPIClient();
38
+ const [data, setData] = useState<any[]>([]);
39
+ const { runAsync } = useRequest(
40
+ (query) =>
41
+ api
42
+ .request({
43
+ url: 'charts:query',
44
+ method: 'POST',
45
+ data: {
46
+ uid: currentSchema?.['x-uid'],
47
+ collection,
48
+ ...query,
49
+ dimensions: (query?.dimensions || []).map((item: DimensionProps) => {
50
+ const dimension = { ...item };
51
+ if (item.format && !item.alias) {
52
+ const { alias } = parseField(item.field);
53
+ dimension.alias = alias;
54
+ }
55
+ return dimension;
56
+ }),
57
+ measures: (query?.measures || []).map((item: MeasureProps) => {
58
+ const measure = { ...item };
59
+ if (item.aggregation && !item.alias) {
60
+ const { alias } = parseField(item.field);
61
+ measure.alias = alias;
62
+ }
63
+ return measure;
64
+ }),
65
+ },
66
+ })
67
+ .then((res) => {
68
+ const data = res?.data?.data || [];
69
+ return processData(fields, data, { t });
70
+ }),
71
+ {
72
+ manual: true,
73
+ onSuccess: (data) => {
74
+ setData(data);
75
+ },
76
+ onFinally(params, data, error: any) {
77
+ if (!configuring) {
78
+ return;
79
+ }
80
+ if (error) {
81
+ const message = error?.response?.data?.errors?.map?.((error: any) => error.message).join('\n');
82
+ setQueryData(message || error.message);
83
+ return;
84
+ }
85
+ setQueryData(data);
86
+ },
87
+ },
88
+ );
89
+
90
+ useEffect(() => {
91
+ setData([]);
92
+ const run = async (query: QueryProps) => {
93
+ if (
94
+ query?.measures?.length
95
+ // || (query?.sql?.fields && query?.sql?.clauses)
96
+ ) {
97
+ await runAsync(query);
98
+ }
99
+ };
100
+ if (runQuery) {
101
+ runQuery.current = run;
102
+ }
103
+ run(query);
104
+ }, [query, runAsync, runQuery]);
105
+
106
+ const charts = useCharts();
107
+ const chart = charts[config?.chartType];
108
+ const Component = chart?.component;
109
+ const locale = api.auth.getLocale();
110
+ const transformers = useFieldTransformer(transform, locale);
111
+ const info = {
112
+ data,
113
+ general,
114
+ advanced,
115
+ fieldProps: Object.keys(data[0] || {}).reduce((props, name) => {
116
+ if (!props[name]) {
117
+ const field = getField(fields, name.split('.'));
118
+ const transformer = transformers[name];
119
+ props[name] = { ...field, transformer };
120
+ }
121
+ return props;
122
+ }, {}),
123
+ locale,
124
+ };
125
+ const componentProps = chart?.useProps?.(info) || info;
126
+ const C = () =>
127
+ Component ? (
128
+ <ErrorBoundary
129
+ onError={(error) => {
130
+ console.error(error);
131
+ }}
132
+ FallbackComponent={ErrorFallback}
133
+ >
134
+ <Component {...componentProps} />
135
+ </ErrorBoundary>
136
+ ) : (
137
+ <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('Please configure chart')} />
138
+ );
139
+
140
+ return data && data.length ? (
141
+ <C />
142
+ ) : (
143
+ <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('Please configure and run query')} />
144
+ );
145
+ };
146
+
147
+ ChartRenderer.Designer = function Designer() {
148
+ const { t } = useChartsTranslation();
149
+ const { setVisible, setCurrent } = useContext(ChartConfigContext);
150
+ const field = useField();
151
+ const schema = useFieldSchema();
152
+ const { insertAdjacent } = useDesignable();
153
+ const { name, title } = useCollection();
154
+ return (
155
+ <GeneralSchemaDesigner disableInitializer title={title || name}>
156
+ <SchemaSettings.Item
157
+ key="configure"
158
+ onClick={() => {
159
+ setCurrent({ schema, field, collection: name });
160
+ setVisible(true);
161
+ }}
162
+ >
163
+ {t('Configure')}
164
+ </SchemaSettings.Item>
165
+ <SchemaSettings.Item
166
+ key="duplicate"
167
+ onClick={() =>
168
+ insertAdjacent('afterEnd', createRendererSchema(schema?.['x-decorator-props']), {
169
+ wrap: gridRowColWrap,
170
+ })
171
+ }
172
+ >
173
+ {t('Duplicate')}
174
+ </SchemaSettings.Item>
175
+ <SchemaSettings.BlockTitleItem />
176
+ <SchemaSettings.Divider />
177
+ <SchemaSettings.Remove
178
+ // removeParentsIfNoChildren
179
+ breakRemoveOn={{
180
+ 'x-component': 'ChartV2Block',
181
+ }}
182
+ />
183
+ </GeneralSchemaDesigner>
184
+ );
185
+ };
186
+
187
+ const ErrorFallback = ({ error }) => {
188
+ const { t } = useChartsTranslation();
189
+
190
+ return (
191
+ <div style={{ backgroundColor: 'white' }}>
192
+ <Result status="error" title={t('Render Failed')} subTitle={t('Please check the configuration.')}>
193
+ <Paragraph copyable>
194
+ <Text type="danger" style={{ whiteSpace: 'pre-line', textAlign: 'center' }}>
195
+ {error.message}
196
+ </Text>
197
+ </Paragraph>
198
+ </Result>
199
+ </div>
200
+ );
201
+ };
@@ -0,0 +1,58 @@
1
+ import { MaybeCollectionProvider } from '@nocobase/client';
2
+ import React, { createContext } from 'react';
3
+
4
+ export type MeasureProps = {
5
+ field: string | string[];
6
+ aggregation?: string;
7
+ alias?: string;
8
+ };
9
+
10
+ export type DimensionProps = {
11
+ field: string | string[];
12
+ alias?: string;
13
+ format?: string;
14
+ };
15
+
16
+ export type TransformProps = {
17
+ field: string;
18
+ type: string;
19
+ format: string;
20
+ };
21
+
22
+ export type QueryProps = Partial<{
23
+ measures: MeasureProps[];
24
+ dimensions: DimensionProps[];
25
+ orders: {
26
+ field: string;
27
+ order: 'asc' | 'desc';
28
+ }[];
29
+ filter: any;
30
+ limit: number;
31
+ sql: {
32
+ fields?: string;
33
+ clauses?: string;
34
+ };
35
+ }>;
36
+
37
+ export type ChartRendererProps = {
38
+ collection: string;
39
+ query?: QueryProps;
40
+ config?: {
41
+ chartType: string;
42
+ general: any;
43
+ advanced: any;
44
+ };
45
+ transform?: TransformProps[];
46
+ mode?: 'builder' | 'sql';
47
+ };
48
+
49
+ export const ChartRendererContext = createContext<ChartRendererProps>({} as any);
50
+
51
+ export const ChartRendererProvider: React.FC<ChartRendererProps> = (props) => {
52
+ const { collection } = props;
53
+ return (
54
+ <MaybeCollectionProvider collection={collection}>
55
+ <ChartRendererContext.Provider value={{ ...props }}>{props.children}</ChartRendererContext.Provider>
56
+ </MaybeCollectionProvider>
57
+ );
58
+ };
@@ -0,0 +1,4 @@
1
+ export * from './ChartLibrary';
2
+ export * from './ChartRenderer';
3
+ export * from './ChartRendererProvider';
4
+ export * from './library';
@@ -0,0 +1,94 @@
1
+ import { Statistic, Table } from 'antd';
2
+ import { lang } from '../../locale';
3
+ import { Charts, infer } from '../ChartLibrary';
4
+
5
+ export const AntdLibrary: Charts = {
6
+ statistic: {
7
+ name: lang('Statistic'),
8
+ component: Statistic,
9
+ schema: {
10
+ type: 'object',
11
+ properties: {
12
+ field: {
13
+ title: lang('Field'),
14
+ type: 'string',
15
+ 'x-decorator': 'FormItem',
16
+ 'x-component': 'Select',
17
+ 'x-reactions': '{{ useChartFields }}',
18
+ required: true,
19
+ },
20
+ title: {
21
+ title: lang('Title'),
22
+ type: 'string',
23
+ 'x-decorator': 'FormItem',
24
+ 'x-component': 'Input',
25
+ },
26
+ },
27
+ },
28
+ init: (fields, { measures, dimensions }) => {
29
+ const { yField } = infer(fields, { measures, dimensions });
30
+ return {
31
+ general: {
32
+ field: yField?.value,
33
+ title: yField?.label,
34
+ },
35
+ };
36
+ },
37
+ useProps: ({ data, fieldProps, general, advanced }) => {
38
+ const record = data[0] || {};
39
+ const field = general?.field;
40
+ const props = fieldProps[field];
41
+ return {
42
+ value: record[field],
43
+ formatter: props?.transformer,
44
+ ...general,
45
+ ...advanced,
46
+ };
47
+ },
48
+ reference: {
49
+ title: lang('Statistic'),
50
+ link: 'https://ant.design/components/statistic/',
51
+ },
52
+ },
53
+ table: {
54
+ name: lang('Table'),
55
+ component: Table,
56
+ useProps: ({ data, fieldProps, general, advanced }) => {
57
+ const columns = data.length
58
+ ? Object.keys(data[0]).map((item) => ({
59
+ title: fieldProps[item]?.label || item,
60
+ dataIndex: item,
61
+ key: item,
62
+ }))
63
+ : [];
64
+ const dataSource = data.map((item: any) => {
65
+ Object.keys(item).map((key: string) => {
66
+ const props = fieldProps[key];
67
+ if (props?.transformer) {
68
+ item[key] = props.transformer(item[key]);
69
+ }
70
+ });
71
+ return item;
72
+ });
73
+ const pageSize = advanced?.pagination?.pageSize || 10;
74
+ return {
75
+ bordered: true,
76
+ size: 'middle',
77
+ pagination:
78
+ dataSource.length < pageSize
79
+ ? false
80
+ : {
81
+ pageSize,
82
+ },
83
+ dataSource,
84
+ columns,
85
+ ...general,
86
+ ...advanced,
87
+ };
88
+ },
89
+ reference: {
90
+ title: lang('Table'),
91
+ link: 'https://ant.design/components/table/',
92
+ },
93
+ },
94
+ };
@@ -0,0 +1,236 @@
1
+ import { Area, Bar, Column, DualAxes, Line, Pie, Scatter } from '@ant-design/plots';
2
+ import { lang } from '../../locale';
3
+ import { Charts, commonInit, infer, usePropsFunc } from '../ChartLibrary';
4
+ const init = commonInit;
5
+
6
+ const basicSchema = {
7
+ type: 'object',
8
+ properties: {
9
+ xField: {
10
+ title: lang('xField'),
11
+ type: 'string',
12
+ 'x-decorator': 'FormItem',
13
+ 'x-component': 'Select',
14
+ 'x-reactions': '{{ useChartFields }}',
15
+ required: true,
16
+ },
17
+ yField: {
18
+ title: lang('yField'),
19
+ type: 'string',
20
+ 'x-decorator': 'FormItem',
21
+ 'x-component': 'Select',
22
+ 'x-reactions': '{{ useChartFields }}',
23
+ required: true,
24
+ },
25
+ seriesField: {
26
+ title: lang('seriesField'),
27
+ type: 'string',
28
+ 'x-decorator': 'FormItem',
29
+ 'x-component': 'Select',
30
+ 'x-reactions': '{{ useChartFields }}',
31
+ },
32
+ },
33
+ };
34
+
35
+ const useProps: usePropsFunc = ({ data, fieldProps, general, advanced }) => {
36
+ const meta = {};
37
+ Object.entries(fieldProps).forEach(([key, props]) => {
38
+ meta[key] = {
39
+ formatter: props.transformer,
40
+ alias: props.label,
41
+ };
42
+ });
43
+ return {
44
+ data,
45
+ meta,
46
+ ...general,
47
+ ...advanced,
48
+ };
49
+ };
50
+
51
+ export const G2PlotLibrary: Charts = {
52
+ line: {
53
+ name: lang('Line Chart'),
54
+ component: Line,
55
+ schema: basicSchema,
56
+ init,
57
+ useProps,
58
+ reference: {
59
+ title: lang('Line Chart'),
60
+ link: 'https://g2plot.antv.antgroup.com/api/plots/bar',
61
+ },
62
+ },
63
+ area: {
64
+ name: lang('Area Chart'),
65
+ component: Area,
66
+ schema: basicSchema,
67
+ init,
68
+ useProps,
69
+ reference: {
70
+ title: lang('Area Chart'),
71
+ link: 'https://g2plot.antv.antgroup.com/api/plots/area',
72
+ },
73
+ },
74
+ column: {
75
+ name: lang('Column Chart'),
76
+ component: Column,
77
+ schema: basicSchema,
78
+ init,
79
+ useProps,
80
+ reference: {
81
+ title: lang('Column Chart'),
82
+ link: 'https://g2plot.antv.antgroup.com/api/plots/column',
83
+ },
84
+ },
85
+ bar: {
86
+ name: lang('Bar Chart'),
87
+ component: Bar,
88
+ schema: basicSchema,
89
+ init: (fields, { measures, dimensions }) => {
90
+ const { xField, yField, seriesField } = infer(fields, { measures, dimensions });
91
+ return {
92
+ general: {
93
+ xField: yField?.value,
94
+ yField: xField?.value,
95
+ seriesField: seriesField?.value,
96
+ },
97
+ };
98
+ },
99
+ useProps,
100
+ reference: {
101
+ title: lang('Bar Chart'),
102
+ link: 'https://g2plot.antv.antgroup.com/api/plots/bar',
103
+ },
104
+ },
105
+ pie: {
106
+ name: lang('Pie Chart'),
107
+ component: Pie,
108
+ schema: {
109
+ type: 'object',
110
+ properties: {
111
+ angleField: {
112
+ title: lang('angleField'),
113
+ type: 'string',
114
+ 'x-decorator': 'FormItem',
115
+ 'x-component': 'Select',
116
+ 'x-reactions': '{{ useChartFields }}',
117
+ required: true,
118
+ },
119
+ colorField: {
120
+ title: lang('colorField'),
121
+ type: 'string',
122
+ 'x-decorator': 'FormItem',
123
+ 'x-component': 'Select',
124
+ 'x-reactions': '{{ useChartFields }}',
125
+ required: true,
126
+ },
127
+ },
128
+ },
129
+ init: (fields, { measures, dimensions }) => {
130
+ const { xField, yField } = infer(fields, { measures, dimensions });
131
+ return {
132
+ general: {
133
+ colorField: xField?.value,
134
+ angleField: yField?.value,
135
+ },
136
+ };
137
+ },
138
+ useProps,
139
+ reference: {
140
+ title: lang('Pie Chart'),
141
+ link: 'https://g2plot.antv.antgroup.com/api/plots/pie',
142
+ },
143
+ },
144
+ dualAxes: {
145
+ name: lang('Dual Axes Chart'),
146
+ component: DualAxes,
147
+ useProps: ({ data, fieldProps, general, advanced }) => {
148
+ return {
149
+ ...useProps({ data, fieldProps, general, advanced }),
150
+ data: [data, data],
151
+ };
152
+ },
153
+ schema: {
154
+ type: 'object',
155
+ properties: {
156
+ xField: {
157
+ title: lang('xField'),
158
+ type: 'string',
159
+ 'x-decorator': 'FormItem',
160
+ 'x-component': 'Select',
161
+ 'x-reactions': '{{ useChartFields }}',
162
+ required: true,
163
+ },
164
+ yField: {
165
+ title: lang('yField'),
166
+ type: 'array',
167
+ 'x-decorator': 'FormItem',
168
+ 'x-component': 'ArrayItems',
169
+ items: {
170
+ type: 'void',
171
+ 'x-component': 'Space',
172
+ properties: {
173
+ sort: {
174
+ type: 'void',
175
+ 'x-decorator': 'FormItem',
176
+ 'x-component': 'ArrayItems.SortHandle',
177
+ },
178
+ input: {
179
+ type: 'string',
180
+ 'x-decorator': 'FormItem',
181
+ 'x-component': 'Select',
182
+ 'x-reactions': '{{ useChartFields }}',
183
+ 'x-component-props': {
184
+ style: {
185
+ 'min-width': '200px',
186
+ },
187
+ },
188
+ required: true,
189
+ },
190
+ remove: {
191
+ type: 'void',
192
+ 'x-decorator': 'FormItem',
193
+ 'x-component': 'ArrayItems.Remove',
194
+ },
195
+ },
196
+ },
197
+ properties: {
198
+ add: {
199
+ type: 'void',
200
+ title: lang('Add'),
201
+ 'x-component': 'ArrayItems.Addition',
202
+ },
203
+ },
204
+ },
205
+ },
206
+ },
207
+ init: (fields, { measures, dimensions }) => {
208
+ const { xField, yFields } = infer(fields, { measures, dimensions });
209
+ return {
210
+ general: {
211
+ xField: xField?.value,
212
+ yField: yFields?.map((f) => f.value).slice(0, 2) || [],
213
+ },
214
+ };
215
+ },
216
+ reference: {
217
+ title: lang('Dual Axes Chart'),
218
+ link: 'https://g2plot.antv.antgroup.com/api/plots/dual-axes',
219
+ },
220
+ },
221
+ // gauge: {
222
+ // name: lang('Gauge Chart'),
223
+ // component: Gauge,
224
+ // },
225
+ scatter: {
226
+ name: lang('Scatter Chart'),
227
+ component: Scatter,
228
+ schema: basicSchema,
229
+ init,
230
+ useProps,
231
+ reference: {
232
+ title: lang('Scatter Chart'),
233
+ link: 'https://g2plot.antv.antgroup.com/api/plots/scatter',
234
+ },
235
+ },
236
+ };
@@ -0,0 +1,4 @@
1
+ import { AntdLibrary } from './AntdLibrary';
2
+ import { G2PlotLibrary } from './G2PlotLibrary';
3
+
4
+ export const InternalLibrary = { ...G2PlotLibrary, ...AntdLibrary };
@@ -0,0 +1,102 @@
1
+ import { Schema } from '@formily/react';
2
+ import { uid } from '@formily/shared';
3
+ import { SelectedField } from './block';
4
+ import { FieldOption } from './hooks';
5
+ import { QueryProps } from './renderer';
6
+
7
+ export const createRendererSchema = (decoratorProps: any, componentProps = {}) => {
8
+ const { collection } = decoratorProps;
9
+ return {
10
+ type: 'void',
11
+ 'x-decorator': 'ChartRendererProvider',
12
+ 'x-decorator-props': decoratorProps,
13
+ 'x-acl-action': `${collection}:list`,
14
+ 'x-designer': 'ChartRenderer.Designer',
15
+ 'x-component': 'CardItem',
16
+ 'x-component-props': {
17
+ size: 'small',
18
+ },
19
+ 'x-initializer': 'ChartInitializers',
20
+ properties: {
21
+ [uid()]: {
22
+ type: 'void',
23
+ 'x-component': 'ChartRenderer',
24
+ 'x-component-props': componentProps,
25
+ },
26
+ },
27
+ };
28
+ };
29
+
30
+ // For AssociationField, the format of field is [targetField, field]
31
+ export const parseField = (field: string | string[]) => {
32
+ let target: string;
33
+ let name: string;
34
+ if (!Array.isArray(field)) {
35
+ name = field;
36
+ } else if (field.length === 1) {
37
+ name = field[0];
38
+ } else if (field.length > 1) {
39
+ [target, name] = field;
40
+ }
41
+ return { target, name, alias: target ? `${target}.${name}` : name };
42
+ };
43
+
44
+ export const getField = (fields: FieldOption[], field: string | string[]) => {
45
+ const { target, name } = parseField(field);
46
+ if (!target) {
47
+ return fields.find((f) => f.name === name);
48
+ }
49
+ const targetField = fields.find((f) => f.name === target)?.targetFields?.find((f) => f.name === name);
50
+ return targetField;
51
+ };
52
+
53
+ export const getSelectedFields = (fields: FieldOption[], query: QueryProps) => {
54
+ // When field alias is set, appends it to the field list
55
+ const process = (selectedFields: SelectedField[]) => {
56
+ return selectedFields.map((selectedField) => {
57
+ const fieldProps = getField(fields, selectedField.field);
58
+ return {
59
+ ...fieldProps,
60
+ key: selectedField.alias || fieldProps?.key,
61
+ label: selectedField.alias || fieldProps?.label,
62
+ value: selectedField.alias || fieldProps?.value,
63
+ };
64
+ });
65
+ };
66
+ const measures = query.measures || [];
67
+ const dimensions = query.dimensions || [];
68
+ // unique
69
+ const map = new Map([...process(measures), ...process(dimensions)].map((item) => [item.value, item]));
70
+ const selectedFields = [...map.values()];
71
+ return selectedFields;
72
+ };
73
+
74
+ export const processData = (fields: FieldOption[], data: any[], scope: any) => {
75
+ const parseEnum = (field: FieldOption, value: any) => {
76
+ const options = field.uiSchema?.enum as { value: string; label: string }[];
77
+ if (!options || !Array.isArray(options)) {
78
+ return value;
79
+ }
80
+ const option = options.find((option) => option.value === value);
81
+ return Schema.compile(option?.label || value, scope);
82
+ };
83
+ return data.map((record) => {
84
+ const processed = {};
85
+ Object.entries(record).forEach(([key, value]) => {
86
+ const field = getField(fields, key.split('.'));
87
+ if (!field) {
88
+ processed[key] = value;
89
+ return;
90
+ }
91
+ switch (field.interface) {
92
+ case 'select':
93
+ case 'radioGroup':
94
+ processed[key] = parseEnum(field, value);
95
+ break;
96
+ default:
97
+ processed[key] = value;
98
+ }
99
+ });
100
+ return processed;
101
+ });
102
+ };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from './server';