test-chat-sdk 0.0.0

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 (208) hide show
  1. package/.prettierrc.js +24 -0
  2. package/README.md +46 -0
  3. package/config/env.js +104 -0
  4. package/config/getHttpsConfig.js +66 -0
  5. package/config/jest/babelTransform.js +29 -0
  6. package/config/jest/cssTransform.js +14 -0
  7. package/config/jest/fileTransform.js +40 -0
  8. package/config/modules.js +134 -0
  9. package/config/paths.js +77 -0
  10. package/config/webpack/persistentCache/createEnvironmentHash.js +9 -0
  11. package/config/webpack.config.js +785 -0
  12. package/config/webpackDevServer.config.js +127 -0
  13. package/dist/Chat/AgentList/index.d.ts +9 -0
  14. package/dist/Chat/ChatFooter/index.d.ts +17 -0
  15. package/dist/Chat/Conversation/index.d.ts +11 -0
  16. package/dist/Chat/MessageContainer/index.d.ts +19 -0
  17. package/dist/Chat/MobileAgents/index.d.ts +11 -0
  18. package/dist/Chat/components/AgentTip/index.d.ts +8 -0
  19. package/dist/Chat/components/ConversationModal/index.d.ts +10 -0
  20. package/dist/Chat/components/CopilotAvatar/index.d.ts +2 -0
  21. package/dist/Chat/components/Message.d.ts +10 -0
  22. package/dist/Chat/components/RecommendQuestions/index.d.ts +6 -0
  23. package/dist/Chat/components/Text.d.ts +9 -0
  24. package/dist/Chat/constants.d.ts +19 -0
  25. package/dist/Chat/index.d.ts +17 -0
  26. package/dist/Chat/service.d.ts +11 -0
  27. package/dist/Chat/type.d.ts +97 -0
  28. package/dist/Copilot/constants.d.ts +11 -0
  29. package/dist/Copilot/index.d.ts +13 -0
  30. package/dist/ShowCase/index.d.ts +8 -0
  31. package/dist/ShowCase/service.d.ts +2 -0
  32. package/dist/ShowCase/type.d.ts +11 -0
  33. package/dist/common/constants.d.ts +58 -0
  34. package/dist/common/env.d.ts +3 -0
  35. package/dist/common/type.d.ts +247 -0
  36. package/dist/components/ChatItem/ExecuteItem.d.ts +25 -0
  37. package/dist/components/ChatItem/ExpandParseTip.d.ts +20 -0
  38. package/dist/components/ChatItem/FilterItem.d.ts +17 -0
  39. package/dist/components/ChatItem/Loading.d.ts +2 -0
  40. package/dist/components/ChatItem/ParseTip.d.ts +26 -0
  41. package/dist/components/ChatItem/ParseTipUtils.d.ts +10 -0
  42. package/dist/components/ChatItem/SimilarQuestionItem.d.ts +10 -0
  43. package/dist/components/ChatItem/SqlItem.d.ts +17 -0
  44. package/dist/components/ChatItem/SwitchEntity.d.ts +9 -0
  45. package/dist/components/ChatItem/Text.d.ts +6 -0
  46. package/dist/components/ChatItem/Typing.d.ts +2 -0
  47. package/dist/components/ChatItem/index.d.ts +33 -0
  48. package/dist/components/ChatMsg/ApplyAuth/index.d.ts +7 -0
  49. package/dist/components/ChatMsg/Bar/index.d.ts +13 -0
  50. package/dist/components/ChatMsg/DateOptions/index.d.ts +9 -0
  51. package/dist/components/ChatMsg/FilterSection/index.d.ts +8 -0
  52. package/dist/components/ChatMsg/MarkDown/index.d.ts +10 -0
  53. package/dist/components/ChatMsg/Message/index.d.ts +18 -0
  54. package/dist/components/ChatMsg/MetricCard/PeriodCompareItem.d.ts +7 -0
  55. package/dist/components/ChatMsg/MetricCard/index.d.ts +10 -0
  56. package/dist/components/ChatMsg/MetricTrend/MetricInfo.d.ts +8 -0
  57. package/dist/components/ChatMsg/MetricTrend/MetricTrendChart.d.ts +14 -0
  58. package/dist/components/ChatMsg/MetricTrend/MultiMetricsTrendChart.d.ts +12 -0
  59. package/dist/components/ChatMsg/MetricTrend/index.d.ts +16 -0
  60. package/dist/components/ChatMsg/NoPermissionChart/index.d.ts +8 -0
  61. package/dist/components/ChatMsg/Pie/PieChart.d.ts +11 -0
  62. package/dist/components/ChatMsg/Pie/index.d.ts +14 -0
  63. package/dist/components/ChatMsg/Table/index.d.ts +12 -0
  64. package/dist/components/ChatMsg/Text/index.d.ts +9 -0
  65. package/dist/components/ChatMsg/WebPage/index.d.ts +8 -0
  66. package/dist/components/ChatMsg/index.d.ts +15 -0
  67. package/dist/components/DrillDownDimensions/DimensionSection.d.ts +11 -0
  68. package/dist/components/DrillDownDimensions/index.d.ts +13 -0
  69. package/dist/components/IconFont/index.d.ts +3 -0
  70. package/dist/components/MetricOptions/index.d.ts +11 -0
  71. package/dist/components/RecommendOptions/index.d.ts +9 -0
  72. package/dist/components/Tools/FeedbackModal.d.ts +9 -0
  73. package/dist/components/Tools/index.d.ts +12 -0
  74. package/dist/demo/Chat.d.ts +2 -0
  75. package/dist/demo/ChatDemo.d.ts +4 -0
  76. package/dist/demo/CopilotDemo.d.ts +2 -0
  77. package/dist/hooks/index.d.ts +3 -0
  78. package/dist/hooks/useComposing.d.ts +5 -0
  79. package/dist/hooks/useExportByEcharts.d.ts +10 -0
  80. package/dist/hooks/useMethodRegister.d.ts +4 -0
  81. package/dist/index.d.ts +10 -0
  82. package/dist/index.es.js +1 -0
  83. package/dist/service/axiosInstance.d.ts +3 -0
  84. package/dist/service/index.d.ts +25 -0
  85. package/dist/utils/utils.d.ts +45 -0
  86. package/package.json +214 -0
  87. package/public/favicon.ico +0 -0
  88. package/public/index.html +43 -0
  89. package/public/manifest.json +15 -0
  90. package/public/robots.txt +3 -0
  91. package/rollup/rollup.config.mjs +37 -0
  92. package/rollup/rollup.esm.config.mjs +21 -0
  93. package/rollup/rollup.umd.config.mjs +30 -0
  94. package/scripts/build.js +217 -0
  95. package/scripts/start.js +154 -0
  96. package/scripts/test.js +52 -0
  97. package/src/Chat/AgentList/index.tsx +52 -0
  98. package/src/Chat/AgentList/style.module.less +83 -0
  99. package/src/Chat/ChatFooter/index.tsx +423 -0
  100. package/src/Chat/ChatFooter/style.module.less +225 -0
  101. package/src/Chat/Conversation/index.tsx +236 -0
  102. package/src/Chat/Conversation/style.module.less +171 -0
  103. package/src/Chat/MessageContainer/index.tsx +145 -0
  104. package/src/Chat/MessageContainer/style.module.less +53 -0
  105. package/src/Chat/MobileAgents/index.tsx +62 -0
  106. package/src/Chat/MobileAgents/style.module.less +55 -0
  107. package/src/Chat/components/AgentTip/index.tsx +48 -0
  108. package/src/Chat/components/AgentTip/style.module.less +44 -0
  109. package/src/Chat/components/ConversationModal/index.tsx +65 -0
  110. package/src/Chat/components/CopilotAvatar/index.tsx +8 -0
  111. package/src/Chat/components/CopilotAvatar/style.module.less +13 -0
  112. package/src/Chat/components/Message.tsx +38 -0
  113. package/src/Chat/components/RecommendQuestions/index.tsx +64 -0
  114. package/src/Chat/components/RecommendQuestions/style.module.less +36 -0
  115. package/src/Chat/components/Text.tsx +42 -0
  116. package/src/Chat/components/style.module.less +311 -0
  117. package/src/Chat/constants.ts +37 -0
  118. package/src/Chat/index.tsx +526 -0
  119. package/src/Chat/service.ts +49 -0
  120. package/src/Chat/style.module.less +119 -0
  121. package/src/Chat/type.ts +107 -0
  122. package/src/Copilot/constants.ts +11 -0
  123. package/src/Copilot/index.tsx +149 -0
  124. package/src/Copilot/style.module.less +151 -0
  125. package/src/ShowCase/index.tsx +120 -0
  126. package/src/ShowCase/service.ts +12 -0
  127. package/src/ShowCase/style.module.less +46 -0
  128. package/src/ShowCase/type.ts +14 -0
  129. package/src/common/constants.ts +93 -0
  130. package/src/common/env.ts +5 -0
  131. package/src/common/type.ts +270 -0
  132. package/src/components/ChatItem/ExecuteItem.tsx +210 -0
  133. package/src/components/ChatItem/ExpandParseTip.tsx +333 -0
  134. package/src/components/ChatItem/FilterItem.tsx +209 -0
  135. package/src/components/ChatItem/Loading.tsx +14 -0
  136. package/src/components/ChatItem/ParseTip.tsx +322 -0
  137. package/src/components/ChatItem/ParseTipUtils.tsx +205 -0
  138. package/src/components/ChatItem/SimilarQuestionItem.tsx +84 -0
  139. package/src/components/ChatItem/SqlItem.tsx +410 -0
  140. package/src/components/ChatItem/SwitchEntity.tsx +52 -0
  141. package/src/components/ChatItem/Text.tsx +17 -0
  142. package/src/components/ChatItem/Typing.tsx +19 -0
  143. package/src/components/ChatItem/index.tsx +843 -0
  144. package/src/components/ChatItem/style.less +670 -0
  145. package/src/components/ChatMsg/ApplyAuth/index.tsx +30 -0
  146. package/src/components/ChatMsg/ApplyAuth/style.less +13 -0
  147. package/src/components/ChatMsg/Bar/index.tsx +208 -0
  148. package/src/components/ChatMsg/Bar/style.less +60 -0
  149. package/src/components/ChatMsg/DateOptions/index.tsx +46 -0
  150. package/src/components/ChatMsg/DateOptions/style.less +43 -0
  151. package/src/components/ChatMsg/FilterSection/index.tsx +42 -0
  152. package/src/components/ChatMsg/FilterSection/style.less +37 -0
  153. package/src/components/ChatMsg/MarkDown/index.tsx +26 -0
  154. package/src/components/ChatMsg/MarkDown/style.less +9 -0
  155. package/src/components/ChatMsg/Message/index.tsx +105 -0
  156. package/src/components/ChatMsg/Message/style.less +119 -0
  157. package/src/components/ChatMsg/MetricCard/PeriodCompareItem.tsx +29 -0
  158. package/src/components/ChatMsg/MetricCard/index.tsx +80 -0
  159. package/src/components/ChatMsg/MetricCard/style.less +126 -0
  160. package/src/components/ChatMsg/MetricTrend/MetricInfo.tsx +60 -0
  161. package/src/components/ChatMsg/MetricTrend/MetricTrendChart.tsx +235 -0
  162. package/src/components/ChatMsg/MetricTrend/MultiMetricsTrendChart.tsx +162 -0
  163. package/src/components/ChatMsg/MetricTrend/index.tsx +127 -0
  164. package/src/components/ChatMsg/MetricTrend/style.less +195 -0
  165. package/src/components/ChatMsg/NoPermissionChart/index.tsx +28 -0
  166. package/src/components/ChatMsg/NoPermissionChart/style.less +26 -0
  167. package/src/components/ChatMsg/Pie/PieChart.tsx +120 -0
  168. package/src/components/ChatMsg/Pie/index.tsx +88 -0
  169. package/src/components/ChatMsg/Pie/style.less +43 -0
  170. package/src/components/ChatMsg/Table/index.tsx +103 -0
  171. package/src/components/ChatMsg/Table/style.less +131 -0
  172. package/src/components/ChatMsg/Text/index.tsx +70 -0
  173. package/src/components/ChatMsg/Text/style.less +38 -0
  174. package/src/components/ChatMsg/WebPage/index.tsx +125 -0
  175. package/src/components/ChatMsg/index.tsx +428 -0
  176. package/src/components/ChatMsg/style.less +28 -0
  177. package/src/components/DrillDownDimensions/DimensionSection.tsx +99 -0
  178. package/src/components/DrillDownDimensions/index.tsx +76 -0
  179. package/src/components/DrillDownDimensions/style.less +64 -0
  180. package/src/components/IconFont/index.tsx +7 -0
  181. package/src/components/MetricOptions/index.tsx +75 -0
  182. package/src/components/MetricOptions/style.less +69 -0
  183. package/src/components/RecommendOptions/index.tsx +126 -0
  184. package/src/components/RecommendOptions/style.less +24 -0
  185. package/src/components/Tools/FeedbackModal.tsx +55 -0
  186. package/src/components/Tools/index.tsx +126 -0
  187. package/src/components/Tools/style.less +67 -0
  188. package/src/demo/Chat.tsx +73 -0
  189. package/src/demo/ChatDemo.tsx +14 -0
  190. package/src/demo/CopilotDemo.tsx +43 -0
  191. package/src/demo/style.module.less +19 -0
  192. package/src/hooks/index.ts +3 -0
  193. package/src/hooks/useComposing.ts +31 -0
  194. package/src/hooks/useExportByEcharts.ts +41 -0
  195. package/src/hooks/useMethodRegister.ts +25 -0
  196. package/src/index.tsx +44 -0
  197. package/src/service/axiosInstance.ts +58 -0
  198. package/src/service/index.ts +174 -0
  199. package/src/setupProxy.js +18 -0
  200. package/src/setupTests.ts +5 -0
  201. package/src/styles/global.less +52 -0
  202. package/src/styles/index.less +39 -0
  203. package/src/styles/reboot.less +14 -0
  204. package/src/styles/variables.less +80 -0
  205. package/src/typings.d.ts +179 -0
  206. package/src/utils/utils.ts +346 -0
  207. package/tsconfig.build.json +20 -0
  208. package/tsconfig.json +27 -0
@@ -0,0 +1,428 @@
1
+ import Bar from './Bar';
2
+ import MetricCard from './MetricCard';
3
+ import MetricTrend from './MetricTrend';
4
+ import MarkDown from './MarkDown';
5
+ import Table from './Table';
6
+ import { ColumnType, DrillDownDimensionType, FieldType, MsgDataType } from '../../common/type';
7
+ import { useEffect, useState } from 'react';
8
+ import { queryData } from '../../service';
9
+ import classNames from 'classnames';
10
+ import { PREFIX_CLS, MsgContentTypeEnum } from '../../common/constants';
11
+ import Text from './Text';
12
+ import DrillDownDimensions from '../DrillDownDimensions';
13
+ import MetricOptions from '../MetricOptions';
14
+ import { isMobile } from '../../utils/utils';
15
+ import Pie from './Pie';
16
+
17
+ type Props = {
18
+ queryId?: number;
19
+ question: string;
20
+ data: MsgDataType;
21
+ chartIndex: number;
22
+ triggerResize?: boolean;
23
+ forceShowTable?: boolean;
24
+ isSimpleMode?: boolean;
25
+ onMsgContentTypeChange: (msgContentType: MsgContentTypeEnum) => void;
26
+ };
27
+
28
+ const ChatMsg: React.FC<Props> = ({
29
+ queryId,
30
+ question,
31
+ data,
32
+ chartIndex,
33
+ triggerResize,
34
+ forceShowTable = false,
35
+ isSimpleMode,
36
+ onMsgContentTypeChange,
37
+ }) => {
38
+ const { queryColumns, queryResults, chatContext, queryMode } = data || {};
39
+ const { dimensionFilters, elementMatches } = chatContext || {};
40
+
41
+ const [columns, setColumns] = useState<ColumnType[]>([]);
42
+ const [referenceColumn, setReferenceColumn] = useState<ColumnType>();
43
+ const [dataSource, setDataSource] = useState<any[]>(queryResults);
44
+ const [drillDownDimension, setDrillDownDimension] = useState<DrillDownDimensionType>();
45
+ const [secondDrillDownDimension, setSecondDrillDownDimension] =
46
+ useState<DrillDownDimensionType>();
47
+ const [loading, setLoading] = useState(false);
48
+ const [defaultMetricField, setDefaultMetricField] = useState<FieldType>();
49
+ const [activeMetricField, setActiveMetricField] = useState<FieldType>();
50
+ const [dateModeValue, setDateModeValue] = useState<any>();
51
+ const [currentDateOption, setCurrentDateOption] = useState<number>();
52
+
53
+ const prefixCls = `${PREFIX_CLS}-chat-msg`;
54
+
55
+ const updateColumns = (queryColumnsValue: ColumnType[]) => {
56
+ const referenceColumn = queryColumnsValue.find(item => item.showType === 'more');
57
+ setReferenceColumn(referenceColumn);
58
+ setColumns(queryColumnsValue.filter(item => item.showType !== 'more'));
59
+ };
60
+
61
+ useEffect(() => {
62
+ updateColumns(queryColumns);
63
+ setDataSource(queryResults);
64
+ setDefaultMetricField(chatContext?.metrics?.[0]);
65
+ setActiveMetricField(chatContext?.metrics?.[0]);
66
+ setDateModeValue(chatContext?.dateInfo?.dateMode);
67
+ setCurrentDateOption(chatContext?.dateInfo?.unit);
68
+ setDrillDownDimension(undefined);
69
+ setSecondDrillDownDimension(undefined);
70
+ }, [data]);
71
+
72
+ const metricFields = columns.filter(item => item.showType === 'NUMBER');
73
+
74
+ const getMsgContentType = () => {
75
+ const singleData = dataSource.length === 1;
76
+ const dateField = columns.find(item => item.showType === 'DATE' || item.type === 'DATE');
77
+ const categoryField = columns.filter(item => item.showType === 'CATEGORY');
78
+ const metricFields = columns.filter(item => item.showType === 'NUMBER');
79
+ if (!columns) {
80
+ return;
81
+ }
82
+ if (isSimpleMode) {
83
+ return MsgContentTypeEnum.MARKDOWN;
84
+ }
85
+ if (forceShowTable) {
86
+ return MsgContentTypeEnum.TABLE;
87
+ }
88
+ const isDslMetricCard =
89
+ queryMode === 'LLM_S2SQL' && singleData && metricFields.length === 1 && columns.length === 1;
90
+ const isMetricCard = (queryMode.includes('METRIC') || isDslMetricCard) && singleData;
91
+ const isText = !queryColumns?.length;
92
+
93
+ if (isText) {
94
+ return MsgContentTypeEnum.TEXT;
95
+ }
96
+
97
+ if (isMetricCard) {
98
+ return MsgContentTypeEnum.METRIC_CARD;
99
+ }
100
+
101
+ const isTable =
102
+ !isText &&
103
+ !isMetricCard &&
104
+ (categoryField.length > 1 ||
105
+ queryMode === 'TAG_DETAIL' ||
106
+ queryMode === 'ENTITY_DIMENSION' ||
107
+ dataSource?.length === 1 ||
108
+ (categoryField.length === 1 && metricFields.length === 0));
109
+
110
+ if (isTable) {
111
+ return MsgContentTypeEnum.TABLE;
112
+ }
113
+ const isMetricTrend =
114
+ dateField &&
115
+ metricFields.length > 0 &&
116
+ categoryField.length <= 1 &&
117
+ !(metricFields.length > 1 && categoryField.length > 0) &&
118
+ dataSource.some(item => item[dateField.bizName] !== dataSource[0][dateField.bizName]);
119
+
120
+ if (isMetricTrend) {
121
+ return MsgContentTypeEnum.METRIC_TREND;
122
+ }
123
+
124
+ /**
125
+ * For Pie Chart:
126
+ * 1. There should be at least one category field.
127
+ * 2. There should be exactly one metric field.
128
+ * 3. All metric values should be non-negative.
129
+ * 4. limit the number of data points based on device type:
130
+ * - For mobile devices, limit to 5 data points.
131
+ * - For desktop devices, limit to 10 data points.
132
+ */
133
+ const isMetricPie =
134
+ categoryField.length > 0 &&
135
+ metricFields?.length === 1 &&
136
+ (isMobile ? dataSource?.length <= 5 : dataSource?.length <= 10) &&
137
+ dataSource.every(item => item[metricFields[0].bizName] >= 0);
138
+
139
+ if (isMetricPie) {
140
+ return MsgContentTypeEnum.METRIC_PIE;
141
+ }
142
+
143
+ /**
144
+ * For Bar Chart:
145
+ * 1. There should be at least one category field.
146
+ * 2. There should be exactly one metric field.
147
+ * 3. The number of data points should be limited based on device type:
148
+ * - For mobile devices, limit to 5 data points.
149
+ * - For desktop devices, limit to 50 data points.
150
+ * 4. All metric values should be finite numbers.
151
+ */
152
+ const isMetricBar =
153
+ categoryField?.length > 0 &&
154
+ metricFields?.length === 1 &&
155
+ (isMobile ? dataSource?.length <= 5 : dataSource?.length <= 50) &&
156
+ dataSource.every(item => isFinite(Number(item[metricFields[0].bizName])));
157
+
158
+ if (isMetricBar) {
159
+ return MsgContentTypeEnum.METRIC_BAR;
160
+ }
161
+ return MsgContentTypeEnum.TABLE;
162
+ };
163
+
164
+ const getMsgStyle = (type: MsgContentTypeEnum) => {
165
+ if (isMobile) {
166
+ return { maxWidth: 'calc(100vw - 20px)' };
167
+ }
168
+ if (!queryResults?.length || !queryColumns.length) {
169
+ return;
170
+ }
171
+ if (type === MsgContentTypeEnum.METRIC_BAR) {
172
+ return {
173
+ [queryResults.length > 5 ? 'width' : 'minWidth']: queryResults.length * 150,
174
+ };
175
+ }
176
+ if (type === MsgContentTypeEnum.TABLE) {
177
+ return {
178
+ [queryColumns.length > 5 ? 'width' : 'minWidth']: queryColumns.length * 150,
179
+ };
180
+ }
181
+ if (type === MsgContentTypeEnum.METRIC_TREND || type === MsgContentTypeEnum.METRIC_PIE) {
182
+ return { width: 'calc(100vw - 410px)' };
183
+ }
184
+ };
185
+
186
+ useEffect(() => {
187
+ const type = getMsgContentType();
188
+ if (type) {
189
+ onMsgContentTypeChange?.(type);
190
+ }
191
+ }, [data, columns, isSimpleMode]);
192
+
193
+ if (!queryColumns || !queryResults || !columns) {
194
+ return null;
195
+ }
196
+
197
+ const getMsgContent = () => {
198
+ const contentType = getMsgContentType();
199
+ switch (contentType) {
200
+ case MsgContentTypeEnum.TEXT:
201
+ return <Text columns={columns} referenceColumn={referenceColumn} dataSource={dataSource} />;
202
+ case MsgContentTypeEnum.METRIC_CARD:
203
+ return (
204
+ <MetricCard
205
+ data={{ ...data, queryColumns: columns, queryResults: dataSource }}
206
+ question={question}
207
+ loading={loading}
208
+ />
209
+ );
210
+ case MsgContentTypeEnum.TABLE:
211
+ return (
212
+ <Table
213
+ question={question}
214
+ data={{ ...data, queryColumns: columns, queryResults: dataSource }}
215
+ loading={loading}
216
+ />
217
+ );
218
+ case MsgContentTypeEnum.METRIC_TREND:
219
+ return (
220
+ <MetricTrend
221
+ data={{
222
+ ...data,
223
+ queryColumns: columns,
224
+ queryResults: dataSource,
225
+ }}
226
+ question={question}
227
+ loading={loading}
228
+ chartIndex={chartIndex}
229
+ triggerResize={triggerResize}
230
+ activeMetricField={activeMetricField}
231
+ drillDownDimension={drillDownDimension}
232
+ currentDateOption={currentDateOption}
233
+ onSelectDateOption={selectDateOption}
234
+ />
235
+ );
236
+ case MsgContentTypeEnum.METRIC_BAR:
237
+ return (
238
+ <Bar
239
+ data={{ ...data, queryColumns: columns, queryResults: dataSource }}
240
+ question={question}
241
+ triggerResize={triggerResize}
242
+ loading={loading}
243
+ metricField={metricFields[0]}
244
+ />
245
+ );
246
+ case MsgContentTypeEnum.METRIC_PIE:
247
+ const categoryField = columns.find(item => item.showType === 'CATEGORY');
248
+ return (
249
+ <Pie
250
+ data={{ ...data, queryColumns: columns, queryResults: dataSource }}
251
+ question={question}
252
+ triggerResize={triggerResize}
253
+ loading={loading}
254
+ metricField={metricFields[0]}
255
+ categoryField={categoryField!}
256
+ />
257
+ );
258
+ case MsgContentTypeEnum.MARKDOWN:
259
+ return (
260
+ <div style={{ maxHeight: 800 }}>
261
+ <MarkDown markdown={data.textResult} loading={loading} />
262
+ </div>
263
+ );
264
+ default:
265
+ return (
266
+ <Table
267
+ question={question}
268
+ data={{ ...data, queryColumns: columns, queryResults: dataSource }}
269
+ loading={loading}
270
+ />
271
+ );
272
+ }
273
+ };
274
+
275
+ const onLoadData = async (value: any) => {
276
+ setLoading(true);
277
+ const res: any = await queryData({
278
+ ...chatContext,
279
+ ...value,
280
+ queryId,
281
+ parseId: chatContext.id,
282
+ });
283
+ setLoading(false);
284
+ if (res.code === 200) {
285
+ updateColumns(res.data?.queryColumns || []);
286
+ setDataSource(res.data?.queryResults || []);
287
+ }
288
+ };
289
+
290
+ const onSelectDimension = async (dimension?: DrillDownDimensionType) => {
291
+ setLoading(true);
292
+ setDrillDownDimension(dimension);
293
+ onLoadData({
294
+ dateInfo: {
295
+ ...chatContext.dateInfo,
296
+ dateMode: dateModeValue,
297
+ unit: currentDateOption || chatContext.dateInfo?.unit,
298
+ },
299
+ dimensions: dimension
300
+ ? [...(chatContext.dimensions || []), dimension]
301
+ : chatContext.dimensions,
302
+ metrics: [activeMetricField || defaultMetricField],
303
+ });
304
+ };
305
+
306
+ const onSelectSecondDimension = (dimension?: DrillDownDimensionType) => {
307
+ setSecondDrillDownDimension(dimension);
308
+ onLoadData({
309
+ dateInfo: {
310
+ ...chatContext.dateInfo,
311
+ dateMode: dateModeValue,
312
+ unit: currentDateOption || chatContext.dateInfo?.unit,
313
+ },
314
+ dimensions: [
315
+ ...(chatContext.dimensions || []),
316
+ ...(drillDownDimension ? [drillDownDimension] : []),
317
+ ...(dimension ? [dimension] : []),
318
+ ],
319
+ metrics: [activeMetricField || defaultMetricField],
320
+ });
321
+ };
322
+
323
+ const onSwitchMetric = (metricField?: FieldType) => {
324
+ setActiveMetricField(metricField);
325
+ onLoadData({
326
+ dateInfo: {
327
+ ...chatContext.dateInfo,
328
+ dateMode: dateModeValue,
329
+ unit: currentDateOption || chatContext.dateInfo?.unit,
330
+ },
331
+ dimensions: drillDownDimension
332
+ ? [...(chatContext.dimensions || []), drillDownDimension]
333
+ : chatContext.dimensions,
334
+ metrics: [metricField || defaultMetricField],
335
+ });
336
+ };
337
+
338
+ const selectDateOption = (dateOption: number) => {
339
+ setCurrentDateOption(dateOption);
340
+ setDateModeValue('RECENT');
341
+ onLoadData({
342
+ metrics: [activeMetricField || defaultMetricField],
343
+ dimensions: drillDownDimension
344
+ ? [...(chatContext.dimensions || []), drillDownDimension]
345
+ : chatContext.dimensions,
346
+ dateInfo: {
347
+ ...chatContext?.dateInfo,
348
+ dateMode: 'RECENT',
349
+ unit: dateOption,
350
+ },
351
+ });
352
+ };
353
+
354
+ const chartMsgClass = classNames({
355
+ [prefixCls]: ![MsgContentTypeEnum.TABLE, MsgContentTypeEnum.MARKDOWN].includes(
356
+ getMsgContentType() as MsgContentTypeEnum
357
+ ),
358
+ });
359
+
360
+ const entityId = dimensionFilters?.length > 0 ? dimensionFilters[0].value : undefined;
361
+ const entityName = elementMatches?.find((item: any) => item.element?.type === 'ID')?.element
362
+ ?.name;
363
+
364
+ const isEntityMode =
365
+ (queryMode === 'TAG_LIST_FILTER' || queryMode === 'METRIC_TAG') &&
366
+ typeof entityId === 'string' &&
367
+ entityName !== undefined;
368
+
369
+ const existDrillDownDimension =
370
+ (queryMode.includes('METRIC') || queryMode === 'LLM_S2SQL')&&
371
+ getMsgContentType() !== MsgContentTypeEnum.TEXT &&
372
+ !isEntityMode;
373
+
374
+ const recommendMetrics = chatContext?.metrics?.filter(metric =>
375
+ queryColumns.every(queryColumn => queryColumn.bizName !== metric.bizName)
376
+ );
377
+
378
+ const isMultipleMetric =
379
+ (queryMode.includes('METRIC') || queryMode === 'LLM_S2SQL') &&
380
+ recommendMetrics?.length > 0 &&
381
+ queryColumns?.filter(column => column.showType === 'NUMBER').length === 1;
382
+
383
+ const type = getMsgContentType();
384
+ const style = type ? getMsgStyle(type) : undefined;
385
+
386
+ return (
387
+ <div className={chartMsgClass} style={style}>
388
+ {dataSource?.length === 0 ? (
389
+ <div>暂无数据</div>
390
+ ) : (
391
+ <div>
392
+ {getMsgContent()}
393
+ {(isMultipleMetric || existDrillDownDimension) && !isSimpleMode && (
394
+ <div
395
+ className={`${prefixCls}-bottom-tools ${
396
+ getMsgContentType() === MsgContentTypeEnum.METRIC_CARD
397
+ ? `${prefixCls}-metric-card-tools`
398
+ : ''
399
+ } ${isMobile ? 'mobile' : ''}`}
400
+ >
401
+ {isMultipleMetric && (
402
+ <MetricOptions
403
+ metrics={chatContext.metrics}
404
+ defaultMetric={defaultMetricField}
405
+ currentMetric={activeMetricField}
406
+ onSelectMetric={onSwitchMetric}
407
+ />
408
+ )}
409
+ {existDrillDownDimension && (
410
+ <DrillDownDimensions
411
+ drillDownDimensions={data?.recommendedDimensions || []}
412
+ drillDownDimension={drillDownDimension}
413
+ secondDrillDownDimension={secondDrillDownDimension}
414
+ originDimensions={chatContext.dimensions}
415
+ dimensionFilters={chatContext.dimensionFilters}
416
+ onSelectDimension={onSelectDimension}
417
+ onSelectSecondDimension={onSelectSecondDimension}
418
+ />
419
+ )}
420
+ </div>
421
+ )}
422
+ </div>
423
+ )}
424
+ </div>
425
+ );
426
+ };
427
+
428
+ export default ChatMsg;
@@ -0,0 +1,28 @@
1
+ @import '../../styles/index.less';
2
+
3
+ @chat-msg-prefix-cls: ~'@{supersonic-chat-prefix}-chat-msg';
4
+
5
+ .@{chat-msg-prefix-cls} {
6
+ padding: 6px 14px 8px;
7
+ border: 1px solid var(--border-color-base);
8
+ border-radius: 4px;
9
+ background: #f5f8fb;
10
+ max-width: calc(100vw - 410px);
11
+
12
+ &-bottom-tools {
13
+ display: flex;
14
+ align-items: center;
15
+ column-gap: 20px;
16
+ font-size: 14px;
17
+ margin-top: 12px;
18
+ margin-bottom: 2px;
19
+
20
+ &.mobile {
21
+ flex-wrap: wrap;
22
+ }
23
+ }
24
+
25
+ &-metric-card-tools {
26
+ margin-top: 0;
27
+ }
28
+ }
@@ -0,0 +1,99 @@
1
+ import classNames from 'classnames';
2
+ import { CLS_PREFIX } from '../../common/constants';
3
+ import { DrillDownDimensionType } from '../../common/type';
4
+ import { Dropdown, Menu } from 'antd';
5
+ import { DownOutlined } from '@ant-design/icons';
6
+
7
+ type Props = {
8
+ drillDownDimension?: DrillDownDimensionType;
9
+ dimensions: DrillDownDimensionType[];
10
+ isSecondDrillDown?: boolean;
11
+ onSelectDimension: (dimension?: DrillDownDimensionType) => void;
12
+ onCancelDrillDown: () => void;
13
+ };
14
+
15
+ const DEFAULT_DIMENSION_COUNT = 5;
16
+
17
+ const DimensionSection: React.FC<Props> = ({
18
+ drillDownDimension,
19
+ dimensions,
20
+ isSecondDrillDown,
21
+ onSelectDimension,
22
+ onCancelDrillDown,
23
+ }) => {
24
+ const prefixCls = `${CLS_PREFIX}-drill-down-dimensions`;
25
+
26
+ const defaultDimensions = dimensions.slice(0, DEFAULT_DIMENSION_COUNT);
27
+
28
+ if (defaultDimensions.length === 0) {
29
+ return null;
30
+ }
31
+
32
+ return (
33
+ <div className={`${prefixCls}-section`}>
34
+ <div className={`${prefixCls}-title`}>{isSecondDrillDown ? '二级' : '推荐'}下钻维度:</div>
35
+ <div className={`${prefixCls}-content`}>
36
+ {defaultDimensions.map((dimension, index) => {
37
+ const itemNameClass = classNames(`${prefixCls}-content-item-name`, {
38
+ [`${prefixCls}-content-item-active`]: drillDownDimension?.id === dimension.id,
39
+ });
40
+ return (
41
+ <div>
42
+ <span
43
+ className={itemNameClass}
44
+ onClick={() => {
45
+ onSelectDimension(
46
+ drillDownDimension?.id === dimension.id ? undefined : dimension
47
+ );
48
+ }}
49
+ >
50
+ {dimension.name}
51
+ </span>
52
+ {index !== defaultDimensions.length - 1 && <span>、</span>}
53
+ </div>
54
+ );
55
+ })}
56
+ {dimensions.length > DEFAULT_DIMENSION_COUNT && (
57
+ <div>
58
+ <span>、</span>
59
+ <Dropdown
60
+ overlay={
61
+ <Menu>
62
+ {dimensions.slice(DEFAULT_DIMENSION_COUNT).map(dimension => {
63
+ const itemNameClass = classNames({
64
+ [`${prefixCls}-menu-item-active`]: drillDownDimension?.id === dimension.id,
65
+ });
66
+ return (
67
+ <Menu.Item key={dimension.id}>
68
+ <span
69
+ className={itemNameClass}
70
+ onClick={() => {
71
+ onSelectDimension(dimension);
72
+ }}
73
+ >
74
+ {dimension.name}
75
+ </span>
76
+ </Menu.Item>
77
+ );
78
+ })}
79
+ </Menu>
80
+ }
81
+ >
82
+ <span>
83
+ <span className={`${prefixCls}-content-item-name`}>更多</span>
84
+ <DownOutlined className={`${prefixCls}-down-arrow`} />
85
+ </span>
86
+ </Dropdown>
87
+ </div>
88
+ )}
89
+ {drillDownDimension && (
90
+ <div className={`${prefixCls}-cancel-drill-down`} onClick={onCancelDrillDown}>
91
+ 取消{isSecondDrillDown ? '二级' : ''}下钻
92
+ </div>
93
+ )}
94
+ </div>
95
+ </div>
96
+ );
97
+ };
98
+
99
+ export default DimensionSection;
@@ -0,0 +1,76 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { CLS_PREFIX } from '../../common/constants';
3
+ import { DrillDownDimensionType, FilterItemType } from '../../common/type';
4
+ import DimensionSection from './DimensionSection';
5
+
6
+ type Props = {
7
+ drillDownDimensions: DrillDownDimensionType[];
8
+ drillDownDimension?: DrillDownDimensionType;
9
+ secondDrillDownDimension?: DrillDownDimensionType;
10
+ originDimensions?: DrillDownDimensionType[];
11
+ dimensionFilters?: FilterItemType[];
12
+ onSelectDimension: (dimension?: DrillDownDimensionType) => void;
13
+ onSelectSecondDimension: (dimension?: DrillDownDimensionType) => void;
14
+ };
15
+
16
+ const MAX_DIMENSION_COUNT = 20;
17
+
18
+ const DrillDownDimensions: React.FC<Props> = ({
19
+ drillDownDimensions,
20
+ drillDownDimension,
21
+ secondDrillDownDimension,
22
+ originDimensions,
23
+ dimensionFilters,
24
+ onSelectDimension,
25
+ onSelectSecondDimension,
26
+ }) => {
27
+ const [dimensions, setDimensions] = useState<DrillDownDimensionType[]>([]);
28
+
29
+ const prefixCls = `${CLS_PREFIX}-drill-down-dimensions`;
30
+
31
+ const initData = async () => {
32
+ setDimensions(
33
+ drillDownDimensions
34
+ .filter(
35
+ dimension =>
36
+ !dimensionFilters?.some(filter => filter.name === dimension.name) &&
37
+ (!originDimensions || !originDimensions.some(item => item.id === dimension.id))
38
+ )
39
+ .slice(0, MAX_DIMENSION_COUNT)
40
+ );
41
+ };
42
+
43
+ useEffect(() => {
44
+ initData();
45
+ }, []);
46
+
47
+ const cancelDrillDown = () => {
48
+ onSelectDimension(undefined);
49
+ };
50
+
51
+ const cancelSecondDrillDown = () => {
52
+ onSelectSecondDimension(undefined);
53
+ };
54
+
55
+ return (
56
+ <div className={prefixCls}>
57
+ <DimensionSection
58
+ drillDownDimension={drillDownDimension}
59
+ dimensions={dimensions}
60
+ onSelectDimension={onSelectDimension}
61
+ onCancelDrillDown={cancelDrillDown}
62
+ />
63
+ {drillDownDimension && dimensions.length > 1 && (
64
+ <DimensionSection
65
+ drillDownDimension={secondDrillDownDimension}
66
+ dimensions={dimensions.filter(dimension => dimension.id !== drillDownDimension?.id)}
67
+ isSecondDrillDown
68
+ onSelectDimension={onSelectSecondDimension}
69
+ onCancelDrillDown={cancelSecondDrillDown}
70
+ />
71
+ )}
72
+ </div>
73
+ );
74
+ };
75
+
76
+ export default DrillDownDimensions;
@@ -0,0 +1,64 @@
1
+ @import '../../styles/index.less';
2
+
3
+ @drill-down-dimensions-prefix-cls: ~'@{supersonic-chat-prefix}-drill-down-dimensions';
4
+
5
+ .@{drill-down-dimensions-prefix-cls} {
6
+ display: flex;
7
+ align-items: center;
8
+ column-gap: 12px;
9
+
10
+ &-section {
11
+ // width: 100%;
12
+ display: flex;
13
+ align-items: center;
14
+ flex-wrap: wrap;
15
+ column-gap: 6px;
16
+ }
17
+
18
+ &-title {
19
+ color: var(--text-color-third);
20
+ }
21
+
22
+ &-content {
23
+ display: flex;
24
+ align-items: center;
25
+ }
26
+
27
+ &-content-item-name {
28
+ color: var(--chat-blue);
29
+ font-weight: 500;
30
+ border-bottom: 1px solid var(--chat-blue);
31
+ padding: 1px;
32
+ cursor: pointer;
33
+ }
34
+
35
+ &-content-item-active {
36
+ color: #fff;
37
+ border-bottom: none;
38
+ background-color: var(--chat-blue);
39
+ border-radius: 2px;
40
+ }
41
+
42
+ &-menu-item-active {
43
+ color: var(--chat-blue);
44
+ }
45
+
46
+ &-down-arrow {
47
+ color: var(--chat-blue);
48
+ }
49
+
50
+ &-cancel-drill-down {
51
+ margin-left: 20px;
52
+ color: var(--text-color-third);
53
+ cursor: pointer;
54
+ padding: 0 4px;
55
+ border: 1px solid var(--text-color-third);
56
+ border-radius: 4px;
57
+ font-size: 12px;
58
+
59
+ &:hover {
60
+ color: var(--chat-blue);
61
+ border-color: var(--chat-blue);
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,7 @@
1
+ import { createFromIconfontCN } from '@ant-design/icons';
2
+
3
+ const IconFont = createFromIconfontCN({
4
+ scriptUrl: '//at.alicdn.com/t/c/font_4120566_7rwv3aw6wep.js',
5
+ });
6
+
7
+ export default IconFont;