@thoughtspot/visual-embed-sdk 1.24.0 → 1.24.2

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 (245) hide show
  1. package/cjs/package.json +2 -3
  2. package/cjs/src/embed/app.d.ts +23 -1
  3. package/cjs/src/embed/app.d.ts.map +1 -1
  4. package/cjs/src/embed/app.js +5 -1
  5. package/cjs/src/embed/app.js.map +1 -1
  6. package/cjs/src/embed/base.d.ts +3 -4
  7. package/cjs/src/embed/base.d.ts.map +1 -1
  8. package/cjs/src/embed/base.js +3 -4
  9. package/cjs/src/embed/base.js.map +1 -1
  10. package/cjs/src/embed/liveboard.d.ts +23 -1
  11. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  12. package/cjs/src/embed/liveboard.js +11 -1
  13. package/cjs/src/embed/liveboard.js.map +1 -1
  14. package/cjs/src/embed/sage.d.ts +2 -1
  15. package/cjs/src/embed/sage.d.ts.map +1 -1
  16. package/cjs/src/embed/sage.js +1 -0
  17. package/cjs/src/embed/sage.js.map +1 -1
  18. package/cjs/src/embed/search-bar.d.ts +2 -1
  19. package/cjs/src/embed/search-bar.d.ts.map +1 -1
  20. package/cjs/src/embed/search-bar.js +1 -0
  21. package/cjs/src/embed/search-bar.js.map +1 -1
  22. package/cjs/src/embed/search.d.ts +2 -1
  23. package/cjs/src/embed/search.d.ts.map +1 -1
  24. package/cjs/src/embed/search.js +1 -0
  25. package/cjs/src/embed/search.js.map +1 -1
  26. package/cjs/src/embed/ts-embed.d.ts +1 -0
  27. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  28. package/cjs/src/embed/ts-embed.js +4 -10
  29. package/cjs/src/embed/ts-embed.js.map +1 -1
  30. package/cjs/src/embed/ts-embed.spec.js +49 -2
  31. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  32. package/cjs/src/index.d.ts +3 -2
  33. package/cjs/src/index.d.ts.map +1 -1
  34. package/cjs/src/index.js +3 -1
  35. package/cjs/src/index.js.map +1 -1
  36. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  37. package/cjs/src/mixpanel-service.js +2 -0
  38. package/cjs/src/mixpanel-service.js.map +1 -1
  39. package/cjs/src/mixpanel-service.spec.js +1 -0
  40. package/cjs/src/mixpanel-service.spec.js.map +1 -1
  41. package/cjs/src/types.d.ts +46 -39
  42. package/cjs/src/types.d.ts.map +1 -1
  43. package/cjs/src/types.js +7 -13
  44. package/cjs/src/types.js.map +1 -1
  45. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts +5 -0
  46. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -0
  47. package/cjs/src/utils/graphql/answerService/answer-queries.js +80 -0
  48. package/cjs/src/utils/graphql/answerService/answer-queries.js.map +1 -0
  49. package/cjs/src/utils/graphql/answerService/answerService.d.ts +61 -0
  50. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -0
  51. package/cjs/src/utils/graphql/answerService/answerService.js +182 -0
  52. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -0
  53. package/cjs/src/utils/graphql/answerService/answerService.spec.d.ts +2 -0
  54. package/cjs/src/utils/graphql/answerService/answerService.spec.d.ts.map +1 -0
  55. package/cjs/src/utils/graphql/answerService/answerService.spec.js +201 -0
  56. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -0
  57. package/cjs/src/utils/graphql/graphql-request.d.ts +15 -0
  58. package/cjs/src/utils/graphql/graphql-request.d.ts.map +1 -0
  59. package/cjs/src/utils/graphql/graphql-request.js +40 -0
  60. package/cjs/src/utils/graphql/graphql-request.js.map +1 -0
  61. package/cjs/src/utils/graphql/sourceService.d.ts +8 -0
  62. package/cjs/src/utils/graphql/sourceService.d.ts.map +1 -0
  63. package/cjs/src/utils/graphql/sourceService.js +69 -0
  64. package/cjs/src/utils/graphql/sourceService.js.map +1 -0
  65. package/cjs/src/utils/graphql/sourceService.spec.d.ts +2 -0
  66. package/cjs/src/utils/graphql/sourceService.spec.d.ts.map +1 -0
  67. package/cjs/src/utils/graphql/sourceService.spec.js +12 -0
  68. package/cjs/src/utils/graphql/sourceService.spec.js.map +1 -0
  69. package/cjs/src/utils/processData.d.ts.map +1 -1
  70. package/cjs/src/utils/processData.js +7 -11
  71. package/cjs/src/utils/processData.js.map +1 -1
  72. package/cjs/src/utils/processData.spec.js +13 -17
  73. package/cjs/src/utils/processData.spec.js.map +1 -1
  74. package/cjs/src/utils.d.ts +6 -0
  75. package/cjs/src/utils.d.ts.map +1 -1
  76. package/cjs/src/utils.js +27 -2
  77. package/cjs/src/utils.js.map +1 -1
  78. package/cjs/src/utils.spec.js +10 -0
  79. package/cjs/src/utils.spec.js.map +1 -1
  80. package/dist/src/embed/app.d.ts +23 -1
  81. package/dist/src/embed/app.d.ts.map +1 -1
  82. package/dist/src/embed/base.d.ts +3 -4
  83. package/dist/src/embed/base.d.ts.map +1 -1
  84. package/dist/src/embed/liveboard.d.ts +23 -1
  85. package/dist/src/embed/liveboard.d.ts.map +1 -1
  86. package/dist/src/embed/sage.d.ts +2 -1
  87. package/dist/src/embed/sage.d.ts.map +1 -1
  88. package/dist/src/embed/search-bar.d.ts +2 -1
  89. package/dist/src/embed/search-bar.d.ts.map +1 -1
  90. package/dist/src/embed/search.d.ts +2 -1
  91. package/dist/src/embed/search.d.ts.map +1 -1
  92. package/dist/src/embed/ts-embed.d.ts +1 -0
  93. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  94. package/dist/src/index.d.ts +3 -2
  95. package/dist/src/index.d.ts.map +1 -1
  96. package/dist/src/mixpanel-service.d.ts.map +1 -1
  97. package/dist/src/types.d.ts +46 -39
  98. package/dist/src/types.d.ts.map +1 -1
  99. package/dist/src/utils/graphql/answerService/answer-queries.d.ts +5 -0
  100. package/dist/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -0
  101. package/dist/src/utils/graphql/answerService/answerService.d.ts +61 -0
  102. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -0
  103. package/dist/src/utils/graphql/answerService/answerService.spec.d.ts +2 -0
  104. package/dist/src/utils/graphql/answerService/answerService.spec.d.ts.map +1 -0
  105. package/dist/src/utils/graphql/graphql-request.d.ts +15 -0
  106. package/dist/src/utils/graphql/graphql-request.d.ts.map +1 -0
  107. package/dist/src/utils/graphql/sourceService.d.ts +8 -0
  108. package/dist/src/utils/graphql/sourceService.d.ts.map +1 -0
  109. package/dist/src/utils/graphql/sourceService.spec.d.ts +2 -0
  110. package/dist/src/utils/graphql/sourceService.spec.d.ts.map +1 -0
  111. package/dist/src/utils/processData.d.ts.map +1 -1
  112. package/dist/src/utils.d.ts +6 -0
  113. package/dist/src/utils.d.ts.map +1 -1
  114. package/dist/tsembed-react.es.js +400 -81
  115. package/dist/tsembed-react.js +400 -81
  116. package/dist/tsembed.es.js +452 -89
  117. package/dist/tsembed.js +452 -88
  118. package/dist/visual-embed-sdk-react-full.d.ts +158 -49
  119. package/dist/visual-embed-sdk-react.d.ts +158 -49
  120. package/dist/visual-embed-sdk.d.ts +158 -49
  121. package/lib/package.json +2 -3
  122. package/lib/src/embed/app.d.ts +23 -1
  123. package/lib/src/embed/app.d.ts.map +1 -1
  124. package/lib/src/embed/app.js +5 -1
  125. package/lib/src/embed/app.js.map +1 -1
  126. package/lib/src/embed/base.d.ts +3 -4
  127. package/lib/src/embed/base.d.ts.map +1 -1
  128. package/lib/src/embed/base.js +3 -4
  129. package/lib/src/embed/base.js.map +1 -1
  130. package/lib/src/embed/liveboard.d.ts +23 -1
  131. package/lib/src/embed/liveboard.d.ts.map +1 -1
  132. package/lib/src/embed/liveboard.js +11 -1
  133. package/lib/src/embed/liveboard.js.map +1 -1
  134. package/lib/src/embed/sage.d.ts +2 -1
  135. package/lib/src/embed/sage.d.ts.map +1 -1
  136. package/lib/src/embed/sage.js +1 -0
  137. package/lib/src/embed/sage.js.map +1 -1
  138. package/lib/src/embed/search-bar.d.ts +2 -1
  139. package/lib/src/embed/search-bar.d.ts.map +1 -1
  140. package/lib/src/embed/search-bar.js +1 -0
  141. package/lib/src/embed/search-bar.js.map +1 -1
  142. package/lib/src/embed/search.d.ts +2 -1
  143. package/lib/src/embed/search.d.ts.map +1 -1
  144. package/lib/src/embed/search.js +1 -0
  145. package/lib/src/embed/search.js.map +1 -1
  146. package/lib/src/embed/ts-embed.d.ts +1 -0
  147. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  148. package/lib/src/embed/ts-embed.js +4 -10
  149. package/lib/src/embed/ts-embed.js.map +1 -1
  150. package/lib/src/embed/ts-embed.spec.js +49 -2
  151. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  152. package/lib/src/index.d.ts +3 -2
  153. package/lib/src/index.d.ts.map +1 -1
  154. package/lib/src/index.js +2 -1
  155. package/lib/src/index.js.map +1 -1
  156. package/lib/src/mixpanel-service.d.ts.map +1 -1
  157. package/lib/src/mixpanel-service.js +2 -0
  158. package/lib/src/mixpanel-service.js.map +1 -1
  159. package/lib/src/mixpanel-service.spec.js +1 -0
  160. package/lib/src/mixpanel-service.spec.js.map +1 -1
  161. package/lib/src/types.d.ts +46 -39
  162. package/lib/src/types.d.ts.map +1 -1
  163. package/lib/src/types.js +6 -12
  164. package/lib/src/types.js.map +1 -1
  165. package/lib/src/utils/graphql/answerService/answer-queries.d.ts +5 -0
  166. package/lib/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -0
  167. package/lib/src/utils/graphql/answerService/answer-queries.js +77 -0
  168. package/lib/src/utils/graphql/answerService/answer-queries.js.map +1 -0
  169. package/lib/src/utils/graphql/answerService/answerService.d.ts +61 -0
  170. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -0
  171. package/lib/src/utils/graphql/answerService/answerService.js +177 -0
  172. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -0
  173. package/lib/src/utils/graphql/answerService/answerService.spec.d.ts +2 -0
  174. package/lib/src/utils/graphql/answerService/answerService.spec.d.ts.map +1 -0
  175. package/lib/src/utils/graphql/answerService/answerService.spec.js +199 -0
  176. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -0
  177. package/lib/src/utils/graphql/graphql-request.d.ts +15 -0
  178. package/lib/src/utils/graphql/graphql-request.d.ts.map +1 -0
  179. package/lib/src/utils/graphql/graphql-request.js +36 -0
  180. package/lib/src/utils/graphql/graphql-request.js.map +1 -0
  181. package/lib/src/utils/graphql/sourceService.d.ts +8 -0
  182. package/lib/src/utils/graphql/sourceService.d.ts.map +1 -0
  183. package/lib/src/utils/graphql/sourceService.js +65 -0
  184. package/lib/src/utils/graphql/sourceService.js.map +1 -0
  185. package/lib/src/utils/graphql/sourceService.spec.d.ts +2 -0
  186. package/lib/src/utils/graphql/sourceService.spec.d.ts.map +1 -0
  187. package/lib/src/utils/graphql/sourceService.spec.js +10 -0
  188. package/lib/src/utils/graphql/sourceService.spec.js.map +1 -0
  189. package/lib/src/utils/processData.d.ts.map +1 -1
  190. package/lib/src/utils/processData.js +8 -12
  191. package/lib/src/utils/processData.js.map +1 -1
  192. package/lib/src/utils/processData.spec.js +14 -18
  193. package/lib/src/utils/processData.spec.js.map +1 -1
  194. package/lib/src/utils.d.ts +6 -0
  195. package/lib/src/utils.d.ts.map +1 -1
  196. package/lib/src/utils.js +24 -1
  197. package/lib/src/utils.js.map +1 -1
  198. package/lib/src/utils.spec.js +10 -0
  199. package/lib/src/utils.spec.js.map +1 -1
  200. package/lib/src/visual-embed-sdk.d.ts +164 -50
  201. package/package.json +4 -5
  202. package/src/embed/app.ts +30 -1
  203. package/src/embed/base.ts +3 -4
  204. package/src/embed/liveboard.ts +36 -1
  205. package/src/embed/sage.ts +9 -4
  206. package/src/embed/search-bar.tsx +12 -1
  207. package/src/embed/search.ts +7 -1
  208. package/src/embed/ts-embed.spec.ts +51 -2
  209. package/src/embed/ts-embed.ts +4 -12
  210. package/src/index.ts +5 -0
  211. package/src/mixpanel-service.spec.ts +1 -0
  212. package/src/mixpanel-service.ts +1 -0
  213. package/src/types.ts +50 -40
  214. package/src/utils/graphql/answerService/answer-queries.ts +80 -0
  215. package/src/utils/graphql/answerService/answerService.spec.ts +231 -0
  216. package/src/utils/graphql/answerService/answerService.ts +234 -0
  217. package/src/utils/graphql/graphql-request.ts +45 -0
  218. package/src/utils/graphql/sourceService.spec.ts +10 -0
  219. package/src/utils/graphql/sourceService.ts +71 -0
  220. package/src/utils/processData.spec.ts +15 -25
  221. package/src/utils/processData.ts +13 -15
  222. package/src/utils.spec.ts +13 -0
  223. package/src/utils.ts +25 -1
  224. package/cjs/src/utils/answerService.d.ts +0 -10
  225. package/cjs/src/utils/answerService.d.ts.map +0 -1
  226. package/cjs/src/utils/answerService.js +0 -61
  227. package/cjs/src/utils/answerService.js.map +0 -1
  228. package/cjs/src/utils/answerService.spec.d.ts +0 -2
  229. package/cjs/src/utils/answerService.spec.d.ts.map +0 -1
  230. package/cjs/src/utils/answerService.spec.js +0 -31
  231. package/cjs/src/utils/answerService.spec.js.map +0 -1
  232. package/dist/src/utils/answerService.d.ts +0 -10
  233. package/dist/src/utils/answerService.d.ts.map +0 -1
  234. package/dist/src/utils/answerService.spec.d.ts +0 -2
  235. package/dist/src/utils/answerService.spec.d.ts.map +0 -1
  236. package/lib/src/utils/answerService.d.ts +0 -10
  237. package/lib/src/utils/answerService.d.ts.map +0 -1
  238. package/lib/src/utils/answerService.js +0 -57
  239. package/lib/src/utils/answerService.js.map +0 -1
  240. package/lib/src/utils/answerService.spec.d.ts +0 -2
  241. package/lib/src/utils/answerService.spec.d.ts.map +0 -1
  242. package/lib/src/utils/answerService.spec.js +0 -29
  243. package/lib/src/utils/answerService.spec.js.map +0 -1
  244. package/src/utils/answerService.spec.ts +0 -41
  245. package/src/utils/answerService.ts +0 -63
@@ -0,0 +1,234 @@
1
+ import type { ColumnValue, VizPoint } from '../../../types';
2
+ import { deepMerge, removeTypename } from '../../../utils';
3
+ import { graphqlQuery } from '../graphql-request';
4
+ import { getSourceDetail } from '../sourceService';
5
+ import * as queries from './answer-queries';
6
+
7
+ export interface SessionInterface {
8
+ sessionId: string;
9
+ genNo: number;
10
+ acSession: { sessionId: string; genNo: number };
11
+ }
12
+
13
+ // eslint-disable-next-line no-shadow
14
+ export enum OperationType {
15
+ GetChartWithData = 'GetChartWithData',
16
+ GetTableWithHeadlineData = 'GetTableWithHeadlineData',
17
+ }
18
+
19
+ interface UnderlyingDataPoint {
20
+ columnId: string;
21
+ dataValue: any;
22
+ }
23
+
24
+ /**
25
+ * Class representing the answer service provided with the
26
+ * custom action payload. This service could be used to run
27
+ * graphql queries in the context of the answer on which the
28
+ * custom action was triggered.
29
+ *
30
+ * @example
31
+ * ```js
32
+ * embed.on(EmbedEvent.CustomAction, e => {
33
+ * const underlying = await e.answerService.getUnderlyingDataForPoint([
34
+ * 'col name 1'
35
+ * ]);
36
+ * const data = await underlying.fetchData(0, 100);
37
+ * })
38
+ * ```
39
+ * @version
40
+ * ThoughtSpot: 9.9.0.cl / SDK: 1.25.0
41
+ */
42
+ export class AnswerService {
43
+ constructor(
44
+ private session: SessionInterface,
45
+ private answer: any,
46
+ private thoughtSpotHost: string,
47
+ private selectedPoints?: VizPoint[],
48
+ ) {
49
+ this.session = removeTypename(session);
50
+ }
51
+
52
+ public async getSourceDetail() {
53
+ const sourceId = this.answer.sources[0].header.guid;
54
+ return getSourceDetail(
55
+ this.thoughtSpotHost,
56
+ sourceId,
57
+ );
58
+ }
59
+
60
+ public async removeColumns(columnIds: string[]) {
61
+ return this.executeQuery(
62
+ queries.removeColumns,
63
+ {
64
+ logicalColumnIds: columnIds,
65
+ },
66
+ );
67
+ }
68
+
69
+ public async addColumns(columnIds: string[]) {
70
+ return this.executeQuery(
71
+ queries.addColumns,
72
+ {
73
+ columns: columnIds.map((colId) => ({ logicalColumnId: colId })),
74
+ },
75
+ );
76
+ }
77
+
78
+ public async fetchData(offset = 0, size = 1000) {
79
+ const { answer } = await this.executeQuery(
80
+ queries.getAnswerData,
81
+ {
82
+ deadline: 0,
83
+ dataPaginationParams: {
84
+ isClientPaginated: true,
85
+ offset,
86
+ size,
87
+ },
88
+ },
89
+ );
90
+ const { columns, data } = answer.visualizations[0];
91
+ return {
92
+ columns,
93
+ data,
94
+ };
95
+ }
96
+
97
+ /**
98
+ *
99
+ * @param userLocale
100
+ * @param omitInfo Omit the download Info on top of the CSV
101
+ * @returns Response
102
+ */
103
+ public async fetchCSVBlob(userLocale = 'en-us', omitInfo = false): Promise<Response> {
104
+ if (omitInfo) {
105
+ console.warn('omitInfo not supported yet.');
106
+ }
107
+ const fetchUrl = `${this.thoughtSpotHost}/prism/download/answer/csv?sessionId=${this.session.sessionId}&genNo=${this.session.genNo}&userLocale=${userLocale}&exportFileName=data&omitInfo=${omitInfo}`;
108
+ return fetch(fetchUrl, {
109
+ credentials: 'include',
110
+ });
111
+ }
112
+
113
+ public async getUnderlyingDataForPoint(
114
+ outputColumnNames: string[],
115
+ selectedPoints?: UnderlyingDataPoint[],
116
+ ): Promise<AnswerService> {
117
+ if (!selectedPoints && !this.selectedPoints) {
118
+ throw new Error('Needs to be triggered in context of a point');
119
+ }
120
+
121
+ if (!selectedPoints) {
122
+ selectedPoints = getSelectedPointsForUnderlyingDataQuery(
123
+ this.selectedPoints,
124
+ );
125
+ }
126
+
127
+ const sourceDetail = await this.getSourceDetail();
128
+ const ouputColumnGuids = getGuidsFromColumnNames(sourceDetail, outputColumnNames);
129
+ const unAggAnswer = await graphqlQuery({
130
+ query: queries.getUnaggregatedAnswerSession,
131
+ variables: {
132
+ session: this.session,
133
+ columns: selectedPoints,
134
+ },
135
+ thoughtSpotHost: this.thoughtSpotHost,
136
+ });
137
+ const unaggAnswerSession = new AnswerService(
138
+ unAggAnswer.id,
139
+ unAggAnswer.answer,
140
+ this.thoughtSpotHost,
141
+ );
142
+ const currentColumns: Set<string> = new Set(
143
+ unAggAnswer.answer.visualizations[0].columns
144
+ .map(
145
+ (c: any) => c.column.referencedColumns[0].guid,
146
+ ),
147
+ );
148
+
149
+ const columnsToAdd = [...ouputColumnGuids].filter((col) => !currentColumns.has(col));
150
+ if (columnsToAdd.length) {
151
+ await unaggAnswerSession.addColumns(columnsToAdd);
152
+ }
153
+
154
+ const columnsToRemove = [...currentColumns].filter((col) => !ouputColumnGuids.has(col));
155
+ if (columnsToRemove.length) {
156
+ await unaggAnswerSession.removeColumns(columnsToRemove);
157
+ }
158
+
159
+ return unaggAnswerSession;
160
+ }
161
+
162
+ public async executeQuery(query: string, variables: any): Promise<any> {
163
+ const data = await graphqlQuery({
164
+ query,
165
+ variables: {
166
+ session: this.session,
167
+ ...variables,
168
+ },
169
+ thoughtSpotHost: this.thoughtSpotHost,
170
+ isCompositeQuery: false,
171
+ });
172
+
173
+ this.session = deepMerge(this.session, data?.id || {}) as unknown as SessionInterface;
174
+ return data;
175
+ }
176
+
177
+ public getSession() {
178
+ return this.session;
179
+ }
180
+ }
181
+
182
+ /**
183
+ *
184
+ * @param sourceDetail
185
+ * @param colNames
186
+ */
187
+ function getGuidsFromColumnNames(sourceDetail: any, colNames: string[]) {
188
+ const cols = sourceDetail.columns.reduce((colSet: any, col: any) => {
189
+ colSet[col.name] = col;
190
+ return colSet;
191
+ }, {});
192
+
193
+ return new Set(colNames.map((colName) => {
194
+ const col = cols[colName];
195
+ return col.id;
196
+ }));
197
+ }
198
+
199
+ /**
200
+ *
201
+ * @param selectedPoints
202
+ */
203
+ function getSelectedPointsForUnderlyingDataQuery(
204
+ selectedPoints: VizPoint[],
205
+ ): UnderlyingDataPoint[] {
206
+ const underlyingDataPoint: UnderlyingDataPoint[] = [];
207
+ /**
208
+ *
209
+ * @param colVal
210
+ */
211
+ function addPointFromColVal(colVal: ColumnValue) {
212
+ const dataType = colVal.column.dataType;
213
+ const id = colVal.column.id;
214
+ let dataValue;
215
+ if (dataType === 'DATE') {
216
+ dataValue = [{
217
+ epochRange: {
218
+ startEpoch: colVal.value,
219
+ },
220
+ }];
221
+ } else {
222
+ dataValue = [{ value: colVal.value }];
223
+ }
224
+ underlyingDataPoint.push({
225
+ columnId: colVal.column.id,
226
+ dataValue,
227
+ });
228
+ }
229
+
230
+ selectedPoints.forEach((p) => {
231
+ p.selectedAttributes.forEach(addPointFromColVal);
232
+ });
233
+ return underlyingDataPoint;
234
+ }
@@ -0,0 +1,45 @@
1
+ import { getOperationNameFromQuery } from '../../utils';
2
+
3
+ /**
4
+ *
5
+ * @param root0
6
+ * @param root0.query
7
+ * @param root0.variables
8
+ * @param root0.thoughtSpotHost
9
+ * @param root0.isCompositeQuery
10
+ */
11
+ export async function graphqlQuery({
12
+ query,
13
+ variables,
14
+ thoughtSpotHost,
15
+ isCompositeQuery = false,
16
+ }: {
17
+ query: string,
18
+ variables: any,
19
+ thoughtSpotHost: string,
20
+ isCompositeQuery?: boolean
21
+ }) {
22
+ const operationName = getOperationNameFromQuery(query);
23
+ try {
24
+ const response = await fetch(`${thoughtSpotHost}/prism/?op=${operationName}`, {
25
+ method: 'POST',
26
+ headers: {
27
+ 'content-type': 'application/json;charset=UTF-8',
28
+ 'x-requested-by': 'ThoughtSpot',
29
+ accept: '*/*',
30
+ 'accept-language': 'en-us',
31
+ },
32
+ body: JSON.stringify({
33
+ operationName,
34
+ query,
35
+ variables,
36
+ }),
37
+ credentials: 'include',
38
+ });
39
+ const result = await response.json();
40
+ const dataValues = Object.values(result.data);
41
+ return (isCompositeQuery) ? result.data : dataValues[0];
42
+ } catch (error) {
43
+ return error;
44
+ }
45
+ }
@@ -0,0 +1,10 @@
1
+ import 'jest-fetch-mock';
2
+ import { getSourceDetail } from './sourceService';
3
+
4
+ describe('Source service tests', () => {
5
+ test('Should return source detail and cache it', async () => {
6
+ await getSourceDetail('https://tshost', 'id');
7
+ await getSourceDetail('https://tshost', 'id');
8
+ expect(fetchMock).toBeCalledTimes(1);
9
+ });
10
+ });
@@ -0,0 +1,71 @@
1
+ import { graphqlQuery } from './graphql-request';
2
+
3
+ export const getSourceDetailQuery = `
4
+ query GetSourceDetail($ids: [GUID!]!) {
5
+ getSourceDetailById(ids: $ids, type: LOGICAL_TABLE) {
6
+ id
7
+ name
8
+ description
9
+ authorName
10
+ authorDisplayName
11
+ isExternal
12
+ type
13
+ created
14
+ modified
15
+ columns {
16
+ id
17
+ name
18
+ author
19
+ authorDisplayName
20
+ description
21
+ dataType
22
+ type
23
+ modified
24
+ ownerName
25
+ owner
26
+ dataRecency
27
+ sources {
28
+ tableId
29
+ tableName
30
+ columnId
31
+ columnName
32
+ __typename
33
+ }
34
+ synonyms
35
+ cohortAnswerId
36
+ __typename
37
+ }
38
+ relationships
39
+ destinationRelationships
40
+ dataSourceId
41
+ __typename
42
+ }
43
+ }
44
+ `;
45
+
46
+ const sourceDetailCache = new Map<string, any>();
47
+
48
+ /**
49
+ *
50
+ * @param thoughtSpotHost
51
+ * @param sourceId
52
+ */
53
+ export async function getSourceDetail(
54
+ thoughtSpotHost: string,
55
+ sourceId: string,
56
+ ): Promise<any> {
57
+ if (sourceDetailCache.has(sourceId)) {
58
+ return sourceDetailCache.get(sourceId);
59
+ }
60
+ const details = await graphqlQuery({
61
+ query: getSourceDetailQuery,
62
+ variables: {
63
+ ids: [sourceId],
64
+ },
65
+ thoughtSpotHost,
66
+ });
67
+
68
+ const souceDetails = details[0];
69
+ sourceDetailCache.set(sourceId, souceDetails);
70
+ return souceDetails;
71
+ }
@@ -1,8 +1,8 @@
1
1
  import * as processDataInstance from './processData';
2
- import * as answerServiceInstance from './answerService';
2
+ import * as answerServiceInstance from './graphql/answerService/answerService';
3
3
  import * as auth from '../auth';
4
4
  import * as base from '../embed/base';
5
- import { EmbedEvent, OperationType, AuthType } from '../types';
5
+ import { EmbedEvent, AuthType } from '../types';
6
6
 
7
7
  describe('Unit test for process data', () => {
8
8
  beforeAll(() => {
@@ -16,26 +16,12 @@ describe('Unit test for process data', () => {
16
16
  });
17
17
 
18
18
  const thoughtSpotHost = 'http://localhost';
19
- test('processDataInstance, when operation is GetChartWithData', () => {
20
- const answerService = {};
21
- const processChartData = {
22
- answerService,
23
- data: {
24
- session: 'session',
25
- query: 'query',
26
- operation: OperationType.GetChartWithData,
27
- },
28
- };
29
- jest.spyOn(answerServiceInstance, 'getAnswerServiceInstance').mockReturnValue(
30
- answerService,
31
- );
32
- expect(
33
- processDataInstance.processCustomAction(processChartData, thoughtSpotHost),
34
- ).toStrictEqual(processChartData);
35
- });
36
19
 
37
20
  test('ProcessData, when Action is CustomAction', async () => {
38
- const processedData = { type: EmbedEvent.CustomAction };
21
+ const processedData = {
22
+ type: EmbedEvent.CustomAction,
23
+ data: {},
24
+ };
39
25
  jest.spyOn(processDataInstance, 'processCustomAction').mockImplementation(async () => ({}));
40
26
  expect(
41
27
  processDataInstance.processEventData(
@@ -44,16 +30,20 @@ describe('Unit test for process data', () => {
44
30
  thoughtSpotHost,
45
31
  null,
46
32
  ),
47
- ).toStrictEqual(processedData);
33
+ ).toEqual(expect.objectContaining({
34
+ ...processedData,
35
+ answerService: {
36
+ answer: undefined,
37
+ selectedPoints: undefined,
38
+ session: undefined,
39
+ thoughtSpotHost: 'http://localhost',
40
+ },
41
+ }));
48
42
  });
49
43
 
50
44
  test('ProcessData, when Action is non CustomAction', () => {
51
45
  const processedData = { type: EmbedEvent.Data };
52
46
  jest.spyOn(processDataInstance, 'processCustomAction').mockImplementation(async () => ({}));
53
- jest.spyOn(
54
- answerServiceInstance,
55
- 'getAnswerServiceInstance',
56
- ).mockImplementation(async () => ({}));
57
47
  processDataInstance.processEventData(EmbedEvent.Data, processedData, thoughtSpotHost, null);
58
48
  expect(processDataInstance.processCustomAction).not.toBeCalled();
59
49
  });
@@ -6,8 +6,8 @@ import {
6
6
  notifyLogout,
7
7
  } from '../embed/base';
8
8
  import { AuthFailureType, initSession } from '../auth';
9
- import { AuthType, EmbedEvent, OperationType } from '../types';
10
- import { getAnswerServiceInstance } from './answerService';
9
+ import { AuthType, CustomActionPayload, EmbedEvent } from '../types';
10
+ import { AnswerService } from './graphql/answerService/answerService';
11
11
 
12
12
  /**
13
13
  *
@@ -15,19 +15,17 @@ import { getAnswerServiceInstance } from './answerService';
15
15
  * @param thoughtSpotHost
16
16
  */
17
17
  export function processCustomAction(e: any, thoughtSpotHost: string) {
18
- if (
19
- [OperationType.GetChartWithData, OperationType.GetTableWithHeadlineData].includes(
20
- e.data?.operation,
21
- )
22
- ) {
23
- const { session, query, operation } = e.data;
24
- const answerService = getAnswerServiceInstance(session, query, operation, thoughtSpotHost);
25
- return {
26
- ...e,
27
- answerService,
28
- };
29
- }
30
- return e;
18
+ const { session, embedAnswerData, contextMenuPoints } = e.data as CustomActionPayload;
19
+ const answerService = new AnswerService(
20
+ session,
21
+ embedAnswerData,
22
+ thoughtSpotHost,
23
+ contextMenuPoints?.selectedPoints,
24
+ );
25
+ return {
26
+ ...e,
27
+ answerService,
28
+ };
31
29
  }
32
30
 
33
31
  /**
package/src/utils.spec.ts CHANGED
@@ -32,6 +32,19 @@ describe('unit test for utils', () => {
32
32
  ).toBe('bar=baz');
33
33
  });
34
34
 
35
+ test('getFilterQuery should encode URL params', () => {
36
+ expect(getFilterQuery([])).toBe(null);
37
+
38
+ expect(
39
+ getFilterQuery([
40
+ {
41
+ columnName: 'foo',
42
+ operator: RuntimeFilterOp.NE,
43
+ values: ['bar+'],
44
+ },
45
+ ]),
46
+ ).toBe('col1=foo&op1=NE&val1=bar%2B');
47
+ });
35
48
  test('getFilterQuery', () => {
36
49
  expect(getFilterQuery([])).toBe(null);
37
50
 
package/src/utils.ts CHANGED
@@ -33,7 +33,7 @@ export const getFilterQuery = (runtimeFilters: RuntimeFilter[]): string => {
33
33
  const filterExpr = [];
34
34
  filterExpr.push(`col${index}=${filter.columnName}`);
35
35
  filterExpr.push(`op${index}=${filter.operator}`);
36
- filterExpr.push(filter.values.map((value) => `val${index}=${value}`).join('&'));
36
+ filterExpr.push(filter.values.map((value) => `val${index}=${encodeURIComponent(value)}`).join('&'));
37
37
 
38
38
  return filterExpr.join('&');
39
39
  });
@@ -248,3 +248,27 @@ export function getDOMNode(domSelector: DOMSelector): HTMLElement {
248
248
  }
249
249
 
250
250
  export const deepMerge = (target: any, source: any) => merge(target, source);
251
+
252
+ export const getOperationNameFromQuery = (query: string) => {
253
+ const regex = /(?:query|mutation)\s+(\w+)/;
254
+ const matches = query.match(regex);
255
+ return matches?.[1];
256
+ };
257
+
258
+ /**
259
+ *
260
+ * @param obj
261
+ */
262
+ export function removeTypename(obj: any) {
263
+ if (!obj || typeof obj !== 'object') return obj;
264
+
265
+ // eslint-disable-next-line no-restricted-syntax
266
+ for (const key in obj) {
267
+ if (key === '__typename') {
268
+ delete obj[key];
269
+ } else if (typeof obj[key] === 'object') {
270
+ removeTypename(obj[key]);
271
+ }
272
+ }
273
+ return obj;
274
+ }
@@ -1,10 +0,0 @@
1
- import { SessionInterface } from '../types';
2
- /**
3
- *
4
- * @param session
5
- * @param query
6
- * @param operation
7
- * @param thoughtSpotHost
8
- */
9
- export declare function getAnswerServiceInstance(session: SessionInterface, query: string, operation: string, thoughtSpotHost: string): any;
10
- //# sourceMappingURL=answerService.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"answerService.d.ts","sourceRoot":"","sources":["../../../src/utils/answerService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiB,MAAM,UAAU,CAAC;AAE3D;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACpC,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACxB,GAAG,CAgDL"}
@@ -1,61 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAnswerServiceInstance = void 0;
4
- const types_1 = require("../types");
5
- /**
6
- *
7
- * @param session
8
- * @param query
9
- * @param operation
10
- * @param thoughtSpotHost
11
- */
12
- function getAnswerServiceInstance(session, query, operation, thoughtSpotHost) {
13
- let variable;
14
- const fetchQuery = async (variables) => {
15
- try {
16
- const response = await fetch(`${thoughtSpotHost}/prism/?op=${operation}`, {
17
- method: 'POST',
18
- headers: {
19
- 'content-type': 'application/json;charset=UTF-8',
20
- 'x-requested-by': 'ThoughtSpot',
21
- accept: '*/*',
22
- 'accept-language': 'en-us',
23
- },
24
- body: JSON.stringify({
25
- operationName: operation,
26
- query,
27
- variables,
28
- }),
29
- credentials: 'include',
30
- });
31
- const result = await response.json();
32
- return result.data;
33
- }
34
- catch (error) {
35
- return error;
36
- }
37
- };
38
- const fetchData = (offset, batchSize) => {
39
- if (operation === types_1.OperationType.GetChartWithData) {
40
- variable = { batchSize, offset: offset * batchSize };
41
- }
42
- else {
43
- variable = {
44
- dataPaginationParams: {
45
- isClientPaginated: true,
46
- offset: offset * batchSize,
47
- size: batchSize,
48
- },
49
- };
50
- }
51
- return fetchQuery({
52
- session,
53
- ...variable,
54
- });
55
- };
56
- return {
57
- fetchData,
58
- };
59
- }
60
- exports.getAnswerServiceInstance = getAnswerServiceInstance;
61
- //# sourceMappingURL=answerService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"answerService.js","sourceRoot":"","sources":["../../../src/utils/answerService.ts"],"names":[],"mappings":";;;AAAA,oCAA2D;AAE3D;;;;;;GAMG;AACH,SAAgB,wBAAwB,CACpC,OAAyB,EACzB,KAAa,EACb,SAAiB,EACjB,eAAuB;IAEvB,IAAI,QAAa,CAAC;IAElB,MAAM,UAAU,GAAG,KAAK,EAAE,SAAc,EAAE,EAAE;QACxC,IAAI;YACA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,eAAe,cAAc,SAAS,EAAE,EAAE;gBACtE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACL,cAAc,EAAE,gCAAgC;oBAChD,gBAAgB,EAAE,aAAa;oBAC/B,MAAM,EAAE,KAAK;oBACb,iBAAiB,EAAE,OAAO;iBAC7B;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACjB,aAAa,EAAE,SAAS;oBACxB,KAAK;oBACL,SAAS;iBACZ,CAAC;gBACF,WAAW,EAAE,SAAS;aACzB,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrC,OAAO,MAAM,CAAC,IAAI,CAAC;SACtB;QAAC,OAAO,KAAK,EAAE;YACZ,OAAO,KAAK,CAAC;SAChB;IACL,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,MAAc,EAAE,SAAiB,EAAE,EAAE;QACpD,IAAI,SAAS,KAAK,qBAAa,CAAC,gBAAgB,EAAE;YAC9C,QAAQ,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC;SACxD;aAAM;YACH,QAAQ,GAAG;gBACP,oBAAoB,EAAE;oBAClB,iBAAiB,EAAE,IAAI;oBACvB,MAAM,EAAE,MAAM,GAAG,SAAS;oBAC1B,IAAI,EAAE,SAAS;iBAClB;aACJ,CAAC;SACL;QACD,OAAO,UAAU,CAAC;YACd,OAAO;YACP,GAAG,QAAQ;SACd,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,OAAO;QACH,SAAS;KACZ,CAAC;AACN,CAAC;AArDD,4DAqDC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=answerService.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"answerService.spec.d.ts","sourceRoot":"","sources":["../../../src/utils/answerService.spec.ts"],"names":[],"mappings":""}
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const answerService_1 = require("./answerService");
4
- describe('Unit test for getAnswerServiceInstance', () => {
5
- const session = {
6
- sessionId: '',
7
- genNo: 2,
8
- acSession: { sessionId: '', genNo: 1 },
9
- };
10
- const query = '';
11
- const thoughtSpotHost = 'http://10.79.135.124:3000';
12
- test('fetchData, when api giving answer data', async () => {
13
- const mockAnswerResponse = { data: {} };
14
- global.fetch = jest.fn(() => Promise.resolve({
15
- json: () => mockAnswerResponse,
16
- }));
17
- const answerService = (0, answerService_1.getAnswerServiceInstance)(session, query, 'GetTableWithHeadlineData', thoughtSpotHost);
18
- const answerData = await answerService.fetchData(1, 500);
19
- expect(answerData).toStrictEqual(mockAnswerResponse.data);
20
- expect(answerData).not.toBeInstanceOf(Error);
21
- expect(fetch).toHaveBeenCalledTimes(1);
22
- });
23
- test('fetchData, when api giving error', async () => {
24
- global.fetch = jest.fn(() => Promise.reject(new Error('failure')));
25
- const answerService = (0, answerService_1.getAnswerServiceInstance)(session, query, 'GetChartWithData', thoughtSpotHost);
26
- const answerData = await answerService.fetchData(1, 500);
27
- expect(answerData).toBeInstanceOf(Error);
28
- expect(fetch).toHaveBeenCalledTimes(1);
29
- });
30
- });
31
- //# sourceMappingURL=answerService.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"answerService.spec.js","sourceRoot":"","sources":["../../../src/utils/answerService.spec.ts"],"names":[],"mappings":";;AAAA,mDAA2D;AAE3D,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACpD,MAAM,OAAO,GAAG;QACZ,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;KACzC,CAAC;IACF,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,MAAM,eAAe,GAAG,2BAA2B,CAAC;IAEpD,IAAI,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,kBAAkB,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QACxC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;YACzC,IAAI,EAAE,GAAG,EAAE,CAAC,kBAAkB;SACjC,CAAC,CAAC,CAAC;QACJ,MAAM,aAAa,GAAG,IAAA,wCAAwB,EAC1C,OAAO,EACP,KAAK,EACL,0BAA0B,EAC1B,eAAe,CAClB,CAAC;QACF,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACzD,MAAM,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACnE,MAAM,aAAa,GAAG,IAAA,wCAAwB,EAC1C,OAAO,EACP,KAAK,EACL,kBAAkB,EAClB,eAAe,CAClB,CAAC;QACF,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACzD,MAAM,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -1,10 +0,0 @@
1
- import { SessionInterface } from '../types';
2
- /**
3
- *
4
- * @param session
5
- * @param query
6
- * @param operation
7
- * @param thoughtSpotHost
8
- */
9
- export declare function getAnswerServiceInstance(session: SessionInterface, query: string, operation: string, thoughtSpotHost: string): any;
10
- //# sourceMappingURL=answerService.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"answerService.d.ts","sourceRoot":"","sources":["answerService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiB,MAAM,UAAU,CAAC;AAE3D;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACpC,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACxB,GAAG,CAgDL"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=answerService.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"answerService.spec.d.ts","sourceRoot":"","sources":["answerService.spec.ts"],"names":[],"mappings":""}