@thoughtspot/visual-embed-sdk 1.24.0-dev → 1.24.0-preRender.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 (239) hide show
  1. package/cjs/package.json +2 -3
  2. package/cjs/src/embed/TsEmbed.d.ts +302 -0
  3. package/cjs/src/embed/TsEmbed.d.ts.map +1 -0
  4. package/cjs/src/embed/TsEmbed.js +851 -0
  5. package/cjs/src/embed/TsEmbed.js.map +1 -0
  6. package/cjs/src/embed/app.d.ts +4 -1
  7. package/cjs/src/embed/app.d.ts.map +1 -1
  8. package/cjs/src/embed/app.js +9 -2
  9. package/cjs/src/embed/app.js.map +1 -1
  10. package/cjs/src/embed/base.d.ts +2 -0
  11. package/cjs/src/embed/base.d.ts.map +1 -1
  12. package/cjs/src/embed/base.js +2 -0
  13. package/cjs/src/embed/base.js.map +1 -1
  14. package/cjs/src/embed/liveboard.d.ts +3 -2
  15. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  16. package/cjs/src/embed/liveboard.js +6 -5
  17. package/cjs/src/embed/liveboard.js.map +1 -1
  18. package/cjs/src/embed/sage.d.ts +4 -1
  19. package/cjs/src/embed/sage.d.ts.map +1 -1
  20. package/cjs/src/embed/sage.js +9 -2
  21. package/cjs/src/embed/sage.js.map +1 -1
  22. package/cjs/src/embed/search-bar.d.ts +1 -0
  23. package/cjs/src/embed/search-bar.d.ts.map +1 -1
  24. package/cjs/src/embed/search-bar.js +1 -0
  25. package/cjs/src/embed/search-bar.js.map +1 -1
  26. package/cjs/src/embed/search.d.ts +5 -1
  27. package/cjs/src/embed/search.d.ts.map +1 -1
  28. package/cjs/src/embed/search.js +10 -2
  29. package/cjs/src/embed/search.js.map +1 -1
  30. package/cjs/src/embed/ts-embed.d.ts +14 -7
  31. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  32. package/cjs/src/embed/ts-embed.js +94 -63
  33. package/cjs/src/embed/ts-embed.js.map +1 -1
  34. package/cjs/src/embed/ts-embed.spec.js +47 -0
  35. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  36. package/cjs/src/index.d.ts +3 -2
  37. package/cjs/src/index.d.ts.map +1 -1
  38. package/cjs/src/index.js +3 -1
  39. package/cjs/src/index.js.map +1 -1
  40. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  41. package/cjs/src/mixpanel-service.js +2 -0
  42. package/cjs/src/mixpanel-service.js.map +1 -1
  43. package/cjs/src/mixpanel-service.spec.js +1 -0
  44. package/cjs/src/mixpanel-service.spec.js.map +1 -1
  45. package/cjs/src/react/index.d.ts +5 -1
  46. package/cjs/src/react/index.d.ts.map +1 -1
  47. package/cjs/src/react/index.js +8 -8
  48. package/cjs/src/react/index.js.map +1 -1
  49. package/cjs/src/types.d.ts +60 -19
  50. package/cjs/src/types.d.ts.map +1 -1
  51. package/cjs/src/types.js +7 -13
  52. package/cjs/src/types.js.map +1 -1
  53. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts +5 -0
  54. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -0
  55. package/cjs/src/utils/graphql/answerService/answer-queries.js +80 -0
  56. package/cjs/src/utils/graphql/answerService/answer-queries.js.map +1 -0
  57. package/cjs/src/utils/graphql/answerService/answerService.d.ts +61 -0
  58. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -0
  59. package/cjs/src/utils/graphql/answerService/answerService.js +182 -0
  60. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -0
  61. package/cjs/src/utils/graphql/answerService/answerService.spec.d.ts +2 -0
  62. package/cjs/src/utils/graphql/answerService/answerService.spec.d.ts.map +1 -0
  63. package/cjs/src/utils/graphql/answerService/answerService.spec.js +201 -0
  64. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -0
  65. package/cjs/src/utils/graphql/graphql-request.d.ts +15 -0
  66. package/cjs/src/utils/graphql/graphql-request.d.ts.map +1 -0
  67. package/cjs/src/utils/graphql/graphql-request.js +40 -0
  68. package/cjs/src/utils/graphql/graphql-request.js.map +1 -0
  69. package/cjs/src/utils/graphql/sourceService.d.ts +8 -0
  70. package/cjs/src/utils/graphql/sourceService.d.ts.map +1 -0
  71. package/cjs/src/utils/graphql/sourceService.js +69 -0
  72. package/cjs/src/utils/graphql/sourceService.js.map +1 -0
  73. package/cjs/src/utils/graphql/sourceService.spec.d.ts +2 -0
  74. package/cjs/src/utils/graphql/sourceService.spec.d.ts.map +1 -0
  75. package/cjs/src/utils/graphql/sourceService.spec.js +12 -0
  76. package/cjs/src/utils/graphql/sourceService.spec.js.map +1 -0
  77. package/cjs/src/utils/processData.d.ts.map +1 -1
  78. package/cjs/src/utils/processData.js +7 -11
  79. package/cjs/src/utils/processData.js.map +1 -1
  80. package/cjs/src/utils/processData.spec.js +13 -17
  81. package/cjs/src/utils/processData.spec.js.map +1 -1
  82. package/cjs/src/utils.d.ts +6 -0
  83. package/cjs/src/utils.d.ts.map +1 -1
  84. package/cjs/src/utils.js +26 -1
  85. package/cjs/src/utils.js.map +1 -1
  86. package/dist/src/embed/app.d.ts +4 -1
  87. package/dist/src/embed/app.d.ts.map +1 -1
  88. package/dist/src/embed/base.d.ts +2 -0
  89. package/dist/src/embed/base.d.ts.map +1 -1
  90. package/dist/src/embed/liveboard.d.ts +3 -2
  91. package/dist/src/embed/liveboard.d.ts.map +1 -1
  92. package/dist/src/embed/sage.d.ts +4 -1
  93. package/dist/src/embed/sage.d.ts.map +1 -1
  94. package/dist/src/embed/search-bar.d.ts +1 -0
  95. package/dist/src/embed/search-bar.d.ts.map +1 -1
  96. package/dist/src/embed/search.d.ts +5 -1
  97. package/dist/src/embed/search.d.ts.map +1 -1
  98. package/dist/src/embed/ts-embed.d.ts +14 -7
  99. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  100. package/dist/src/index.d.ts +3 -2
  101. package/dist/src/index.d.ts.map +1 -1
  102. package/dist/src/mixpanel-service.d.ts.map +1 -1
  103. package/dist/src/react/index.d.ts +5 -1
  104. package/dist/src/react/index.d.ts.map +1 -1
  105. package/dist/src/types.d.ts +60 -19
  106. package/dist/src/types.d.ts.map +1 -1
  107. package/dist/src/utils/graphql/answerService/answer-queries.d.ts +5 -0
  108. package/dist/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -0
  109. package/dist/src/utils/graphql/answerService/answerService.d.ts +61 -0
  110. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -0
  111. package/dist/src/utils/graphql/answerService/answerService.spec.d.ts +2 -0
  112. package/dist/src/utils/graphql/answerService/answerService.spec.d.ts.map +1 -0
  113. package/dist/src/utils/graphql/graphql-request.d.ts +15 -0
  114. package/dist/src/utils/graphql/graphql-request.d.ts.map +1 -0
  115. package/dist/src/utils/graphql/sourceService.d.ts +8 -0
  116. package/dist/src/utils/graphql/sourceService.d.ts.map +1 -0
  117. package/dist/src/utils/graphql/sourceService.spec.d.ts +2 -0
  118. package/dist/src/utils/graphql/sourceService.spec.d.ts.map +1 -0
  119. package/dist/src/utils/processData.d.ts.map +1 -1
  120. package/dist/src/utils.d.ts +6 -0
  121. package/dist/src/utils.d.ts.map +1 -1
  122. package/dist/tsembed-react.es.js +513 -150
  123. package/dist/tsembed-react.js +516 -149
  124. package/dist/tsembed.es.js +556 -146
  125. package/dist/tsembed.js +556 -145
  126. package/dist/visual-embed-sdk-react-full.d.ts +152 -33
  127. package/dist/visual-embed-sdk-react.d.ts +152 -33
  128. package/dist/visual-embed-sdk.d.ts +147 -32
  129. package/lib/package.json +2 -3
  130. package/lib/src/embed/TsEmbed.d.ts +302 -0
  131. package/lib/src/embed/TsEmbed.d.ts.map +1 -0
  132. package/lib/src/embed/TsEmbed.js +847 -0
  133. package/lib/src/embed/TsEmbed.js.map +1 -0
  134. package/lib/src/embed/app.d.ts +4 -1
  135. package/lib/src/embed/app.d.ts.map +1 -1
  136. package/lib/src/embed/app.js +9 -2
  137. package/lib/src/embed/app.js.map +1 -1
  138. package/lib/src/embed/base.d.ts +2 -0
  139. package/lib/src/embed/base.d.ts.map +1 -1
  140. package/lib/src/embed/base.js +2 -0
  141. package/lib/src/embed/base.js.map +1 -1
  142. package/lib/src/embed/liveboard.d.ts +3 -2
  143. package/lib/src/embed/liveboard.d.ts.map +1 -1
  144. package/lib/src/embed/liveboard.js +6 -5
  145. package/lib/src/embed/liveboard.js.map +1 -1
  146. package/lib/src/embed/sage.d.ts +4 -1
  147. package/lib/src/embed/sage.d.ts.map +1 -1
  148. package/lib/src/embed/sage.js +9 -2
  149. package/lib/src/embed/sage.js.map +1 -1
  150. package/lib/src/embed/search-bar.d.ts +1 -0
  151. package/lib/src/embed/search-bar.d.ts.map +1 -1
  152. package/lib/src/embed/search-bar.js +1 -0
  153. package/lib/src/embed/search-bar.js.map +1 -1
  154. package/lib/src/embed/search.d.ts +5 -1
  155. package/lib/src/embed/search.d.ts.map +1 -1
  156. package/lib/src/embed/search.js +10 -2
  157. package/lib/src/embed/search.js.map +1 -1
  158. package/lib/src/embed/ts-embed.d.ts +14 -7
  159. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  160. package/lib/src/embed/ts-embed.js +94 -63
  161. package/lib/src/embed/ts-embed.js.map +1 -1
  162. package/lib/src/embed/ts-embed.spec.js +47 -0
  163. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  164. package/lib/src/index.d.ts +3 -2
  165. package/lib/src/index.d.ts.map +1 -1
  166. package/lib/src/index.js +2 -1
  167. package/lib/src/index.js.map +1 -1
  168. package/lib/src/mixpanel-service.d.ts.map +1 -1
  169. package/lib/src/mixpanel-service.js +2 -0
  170. package/lib/src/mixpanel-service.js.map +1 -1
  171. package/lib/src/mixpanel-service.spec.js +1 -0
  172. package/lib/src/mixpanel-service.spec.js.map +1 -1
  173. package/lib/src/react/index.d.ts +5 -1
  174. package/lib/src/react/index.d.ts.map +1 -1
  175. package/lib/src/react/index.js +7 -7
  176. package/lib/src/react/index.js.map +1 -1
  177. package/lib/src/types.d.ts +60 -19
  178. package/lib/src/types.d.ts.map +1 -1
  179. package/lib/src/types.js +6 -12
  180. package/lib/src/types.js.map +1 -1
  181. package/lib/src/utils/graphql/answerService/answer-queries.d.ts +5 -0
  182. package/lib/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -0
  183. package/lib/src/utils/graphql/answerService/answer-queries.js +77 -0
  184. package/lib/src/utils/graphql/answerService/answer-queries.js.map +1 -0
  185. package/lib/src/utils/graphql/answerService/answerService.d.ts +61 -0
  186. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -0
  187. package/lib/src/utils/graphql/answerService/answerService.js +177 -0
  188. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -0
  189. package/lib/src/utils/graphql/answerService/answerService.spec.d.ts +2 -0
  190. package/lib/src/utils/graphql/answerService/answerService.spec.d.ts.map +1 -0
  191. package/lib/src/utils/graphql/answerService/answerService.spec.js +199 -0
  192. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -0
  193. package/lib/src/utils/graphql/graphql-request.d.ts +15 -0
  194. package/lib/src/utils/graphql/graphql-request.d.ts.map +1 -0
  195. package/lib/src/utils/graphql/graphql-request.js +36 -0
  196. package/lib/src/utils/graphql/graphql-request.js.map +1 -0
  197. package/lib/src/utils/graphql/sourceService.d.ts +8 -0
  198. package/lib/src/utils/graphql/sourceService.d.ts.map +1 -0
  199. package/lib/src/utils/graphql/sourceService.js +65 -0
  200. package/lib/src/utils/graphql/sourceService.js.map +1 -0
  201. package/lib/src/utils/graphql/sourceService.spec.d.ts +2 -0
  202. package/lib/src/utils/graphql/sourceService.spec.d.ts.map +1 -0
  203. package/lib/src/utils/graphql/sourceService.spec.js +10 -0
  204. package/lib/src/utils/graphql/sourceService.spec.js.map +1 -0
  205. package/lib/src/utils/processData.d.ts.map +1 -1
  206. package/lib/src/utils/processData.js +8 -12
  207. package/lib/src/utils/processData.js.map +1 -1
  208. package/lib/src/utils/processData.spec.js +14 -18
  209. package/lib/src/utils/processData.spec.js.map +1 -1
  210. package/lib/src/utils.d.ts +6 -0
  211. package/lib/src/utils.d.ts.map +1 -1
  212. package/lib/src/utils.js +23 -0
  213. package/lib/src/utils.js.map +1 -1
  214. package/lib/src/visual-embed-sdk.d.ts +153 -33
  215. package/package.json +2 -3
  216. package/src/embed/app.ts +13 -6
  217. package/src/embed/base.ts +2 -0
  218. package/src/embed/liveboard.ts +7 -5
  219. package/src/embed/sage.ts +13 -2
  220. package/src/embed/search-bar.tsx +2 -0
  221. package/src/embed/search.ts +14 -2
  222. package/src/embed/ts-embed.spec.ts +49 -0
  223. package/src/embed/ts-embed.ts +116 -64
  224. package/src/index.ts +5 -0
  225. package/src/mixpanel-service.spec.ts +1 -0
  226. package/src/mixpanel-service.ts +1 -0
  227. package/src/react/index.tsx +50 -45
  228. package/src/types.ts +64 -21
  229. package/src/utils/graphql/answerService/answer-queries.ts +80 -0
  230. package/src/utils/graphql/answerService/answerService.spec.ts +231 -0
  231. package/src/utils/graphql/answerService/answerService.ts +234 -0
  232. package/src/utils/graphql/graphql-request.ts +45 -0
  233. package/src/utils/graphql/sourceService.spec.ts +10 -0
  234. package/src/utils/graphql/sourceService.ts +71 -0
  235. package/src/utils/processData.spec.ts +15 -25
  236. package/src/utils/processData.ts +13 -15
  237. package/src/utils.ts +24 -0
  238. package/src/utils/answerService.spec.ts +0 -41
  239. package/src/utils/answerService.ts +0 -63
package/src/types.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import { CustomCssVariables } from './css-variables';
11
+ import type { SessionInterface } from './utils/graphql/answerService/answerService';
11
12
 
12
13
  /**
13
14
  * The authentication mechanism for allowing access to the
@@ -532,7 +533,7 @@ export interface EmbedConfig {
532
533
  }
533
534
 
534
535
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
535
- export interface LayoutConfig {}
536
+ export interface LayoutConfig { }
536
537
 
537
538
  /**
538
539
  * Embedded iFrame configuration
@@ -756,6 +757,13 @@ export interface ViewConfig {
756
757
  * @version SDK: 1.27.0 | Thoughtspot: 9.8.0.cl
757
758
  */
758
759
  hiddenHomepageModules?: HomepageModule[];
760
+ /**
761
+ * reordering the home page modules
762
+ * eg: reorderedHomepageModules = [HomepageModule.MyLibrary, HomepageModule.Watchlist]
763
+ *
764
+ * @version SDK: 1.28.0 | Thoughtspot: 9.9.0.cl
765
+ */
766
+ reorderedHomepageModules?: HomepageModule[];
759
767
  /**
760
768
  * The list of tab IDs to show in the embedded.
761
769
  * Only this Tabs will be shown in their respective LBs.
@@ -785,9 +793,20 @@ export interface ViewConfig {
785
793
  */
786
794
  hiddenHomeLeftNavItems?: HomeLeftNavItem[];
787
795
  /**
788
- * TBD
796
+ * PreRender id to be used for PreRendering the embed.
797
+ * Use PreRender to render the embed in the background and then
798
+ * show or hide the rendered embed using showPreRender or hidePreRender respectively.
799
+ *
800
+ * @example
801
+ * ```js
802
+ * const embed = new LiveboardEmbed('#embed', {
803
+ * ... // other liveboard view config
804
+ * preRenderId: "preRenderId-123"
805
+ * });
806
+ * embed.showPreRender();
807
+ * ```
808
+ * @version SDK: 1.25.0 | Thoughtspot: 9.6.0.cl
789
809
  */
790
-
791
810
  preRenderId?: string;
792
811
  }
793
812
 
@@ -921,27 +940,27 @@ export enum HomepageModule {
921
940
  /**
922
941
  * Search bar
923
942
  */
924
- Search = 'search',
943
+ Search = 'SEARCH',
925
944
  /**
926
945
  * kPI watchlist module
927
946
  */
928
- Watchlist = 'watchlist',
947
+ Watchlist = 'WATCHLIST',
929
948
  /**
930
949
  * favorite objects
931
950
  */
932
- Favorite = 'favorite',
951
+ Favorite = 'FAVORITE',
933
952
  /**
934
953
  * List of answers and liveboards
935
954
  */
936
- MyLibrary = 'mylibrary',
955
+ MyLibrary = 'MY_LIBRARY',
937
956
  /**
938
957
  * Trending list
939
958
  */
940
- Trending = 'trending',
959
+ Trending = 'TRENDING',
941
960
  /**
942
961
  * Learning videos
943
962
  */
944
- Learning = 'learning',
963
+ Learning = 'LEARNING',
945
964
  }
946
965
 
947
966
  /**
@@ -3126,18 +3145,6 @@ export enum Action {
3126
3145
  PersonalisedViewsDropdown = 'personalisedViewsDropdown',
3127
3146
  }
3128
3147
 
3129
- export interface SessionInterface {
3130
- sessionId: string;
3131
- genNo: number;
3132
- acSession: { sessionId: string; genNo: number };
3133
- }
3134
-
3135
- // eslint-disable-next-line no-shadow
3136
- export enum OperationType {
3137
- GetChartWithData = 'GetChartWithData',
3138
- GetTableWithHeadlineData = 'GetTableWithHeadlineData',
3139
- }
3140
-
3141
3148
  export interface AnswerServiceType {
3142
3149
  getAnswer?: (offset: number, batchSize: number) => any;
3143
3150
  }
@@ -3156,3 +3163,39 @@ export enum ContextMenuTriggerOptions {
3156
3163
  LEFT_CLICK = 'left-click',
3157
3164
  RIGHT_CLICK = 'right-click',
3158
3165
  }
3166
+
3167
+ export interface ColumnValue {
3168
+ column: {
3169
+ id: string,
3170
+ name: string,
3171
+ dataType: string,
3172
+ [key: string]: any
3173
+ },
3174
+ value: string | number | boolean;
3175
+ }
3176
+
3177
+ export interface VizPoint {
3178
+ selectedAttributes: ColumnValue[],
3179
+ selectedMeasures: ColumnValue[]
3180
+ }
3181
+
3182
+ export interface CustomActionPayload {
3183
+ contextMenuPoints?: {
3184
+ clickedPoint: VizPoint
3185
+ selectedPoints: VizPoint[]
3186
+ };
3187
+ embedAnswerData: {
3188
+ name: string,
3189
+ id: string,
3190
+ sources: {
3191
+ header: {
3192
+ guid: string
3193
+ }
3194
+ },
3195
+ columns: any[],
3196
+ data: any[],
3197
+ [key: string]: any
3198
+ };
3199
+ session: SessionInterface;
3200
+ vizId?: string;
3201
+ }
@@ -0,0 +1,80 @@
1
+ const bachSessionId = `
2
+ id {
3
+ sessionId
4
+ genNo
5
+ acSession {
6
+ sessionId
7
+ genNo
8
+ }
9
+ }
10
+ `;
11
+
12
+ export const getUnaggregatedAnswerSession = `
13
+ mutation GetUnAggregatedAnswerSession($session: BachSessionIdInput!, $columns: [UserPointSelectionInput!]!) {
14
+ Answer__getUnaggregatedAnswer(session: $session, columns: $columns) {
15
+ ${bachSessionId}
16
+ answer {
17
+ visualizations {
18
+ ... on TableViz {
19
+ columns {
20
+ column {
21
+ id
22
+ name
23
+ referencedColumns {
24
+ guid
25
+ displayName
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ `;
35
+
36
+ export const removeColumns = `
37
+ mutation RemoveColumns($session: BachSessionIdInput!, $logicalColumnIds: [GUID!], $columnIds: [GUID!]) {
38
+ Answer__removeColumns(
39
+ session: $session
40
+ logicalColumnIds: $logicalColumnIds
41
+ columnIds: $columnIds
42
+ ) {
43
+ ${bachSessionId}
44
+ }
45
+ }
46
+ `;
47
+
48
+ export const addColumns = `
49
+ mutation AddColumns($session: BachSessionIdInput!, $columns: [AnswerColumnInfo!]!) {
50
+ Answer__addColumn(session: $session, columns: $columns) {
51
+ ${bachSessionId}
52
+ }
53
+ }
54
+ `;
55
+
56
+ export const getAnswerData = `
57
+ query GetTableWithHeadlineData($session: BachSessionIdInput!, $deadline: Int!, $dataPaginationParams: DataPaginationParamsInput!) {
58
+ getAnswer(session: $session) {
59
+ ${bachSessionId}
60
+ answer {
61
+ id
62
+ visualizations {
63
+ id
64
+ ... on TableViz {
65
+ columns {
66
+ column {
67
+ id
68
+ name
69
+ type
70
+ aggregationType
71
+ dataType
72
+ }
73
+ }
74
+ data(deadline: $deadline, pagination: $dataPaginationParams)
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ `;
@@ -0,0 +1,231 @@
1
+ import 'jest-fetch-mock';
2
+ import { VizPoint } from 'src/types';
3
+ import { AnswerService } from './answerService';
4
+ import { getAnswerData, removeColumns } from './answer-queries';
5
+
6
+ const defaultSession = {
7
+ sessionId: 'id',
8
+ genNo: 1,
9
+ acSession: {
10
+ sessionId: 'ac',
11
+ genNo: 0,
12
+ },
13
+ };
14
+ /**
15
+ *
16
+ * @param answer
17
+ * @param point
18
+ */
19
+ function createAnswerService(answer = {}, point?: VizPoint[]) {
20
+ return new AnswerService(
21
+ defaultSession,
22
+ answer,
23
+ 'https://tshost',
24
+ point,
25
+ );
26
+ }
27
+
28
+ describe('Answer service tests', () => {
29
+ beforeEach(() => {
30
+ fetchMock.resetMocks();
31
+ });
32
+ test('Execute query should execute the supplied graphql on the session', async () => {
33
+ fetchMock.mockResponseOnce(JSON.stringify({
34
+ data: {
35
+ Bla: {
36
+ id: {},
37
+ },
38
+ },
39
+ }));
40
+ const answerService = createAnswerService();
41
+ answerService.executeQuery(
42
+ 'query Bla {}',
43
+ { a: 1 },
44
+ );
45
+ expect(fetchMock).toBeCalledWith('https://tshost/prism/?op=Bla', expect.objectContaining({
46
+ body: JSON.stringify({
47
+ operationName: 'Bla',
48
+ query: 'query Bla {}',
49
+ variables: {
50
+ session: defaultSession,
51
+ a: 1,
52
+ },
53
+ }),
54
+ }));
55
+ });
56
+
57
+ test('Should return error when failure', async () => {
58
+ fetchMock.mockRejectOnce(new Error('testError'));
59
+ const answerService = createAnswerService();
60
+ const data = await answerService.executeQuery(
61
+ 'query Bla {}',
62
+ { a: 1 },
63
+ );
64
+ expect(data.message).toBe('testError');
65
+ });
66
+
67
+ test('fetchData should call the right graphql, and return data', async () => {
68
+ fetchMock.mockResponseOnce(JSON.stringify({
69
+ data: {
70
+ getAnswer: {
71
+ id: {},
72
+ answer: {
73
+ visualizations: [{
74
+ columns: [{
75
+ column: {
76
+ id: 'id1',
77
+ },
78
+ }],
79
+ data: {
80
+ foo: 1,
81
+ },
82
+ }],
83
+ },
84
+ },
85
+ },
86
+ }));
87
+ const answerService = createAnswerService();
88
+ const data = await answerService.fetchData(20, 10);
89
+ expect(fetchMock).toHaveBeenCalledWith(
90
+ 'https://tshost/prism/?op=GetTableWithHeadlineData',
91
+ expect.objectContaining({
92
+ body: JSON.stringify({
93
+ operationName: 'GetTableWithHeadlineData',
94
+ query: getAnswerData,
95
+ variables: {
96
+ session: defaultSession,
97
+ deadline: 0,
98
+ dataPaginationParams: {
99
+ isClientPaginated: true,
100
+ offset: 20,
101
+ size: 10,
102
+ },
103
+ },
104
+ }),
105
+ }),
106
+ );
107
+ expect(data.columns[0].column.id).toBe('id1');
108
+ expect(data.data.foo).toBe(1);
109
+ });
110
+
111
+ test('fetchCSVBlob should call the right API', async () => {
112
+ fetchMock.once('Bla');
113
+ const answerService = createAnswerService();
114
+ answerService.fetchCSVBlob(undefined, true);
115
+ expect(fetchMock).toHaveBeenCalledWith(
116
+ `https://tshost/prism/download/answer/csv?sessionId=${defaultSession.sessionId}&genNo=${defaultSession.genNo}&userLocale=en-us&exportFileName=data&omitInfo=true`,
117
+ expect.objectContaining({}),
118
+ );
119
+ });
120
+
121
+ test('getUnderlyingDataForPoint should call the right APIs', async () => {
122
+ fetchMock.mockResponses(
123
+ JSON.stringify({
124
+ data: {
125
+ getSourceDetailById: [{
126
+ columns: [{
127
+ id: 'id1',
128
+ name: 'col1',
129
+ }, {
130
+ id: 'id2',
131
+ name: 'col2',
132
+ }, {
133
+ id: 'id3',
134
+ name: 'col3',
135
+ }],
136
+ }],
137
+ },
138
+ }),
139
+ JSON.stringify({
140
+ data: {
141
+ Answer__getUnaggregatedAnswer: {
142
+ id: {
143
+ ...defaultSession,
144
+ },
145
+ answer: {
146
+ visualizations: [{
147
+ columns: [{
148
+ column: {
149
+ id: 'oid1',
150
+ name: 'col1',
151
+ referencedColumns: [{
152
+ guid: 'id1',
153
+ }],
154
+ },
155
+ }],
156
+ }],
157
+ },
158
+ },
159
+ },
160
+ }),
161
+ JSON.stringify({
162
+ data: {
163
+ Answer__addColumn: {
164
+ id: {
165
+ genNo: 2,
166
+ },
167
+ },
168
+ },
169
+ }),
170
+ JSON.stringify({
171
+ data: {
172
+ Answer__removeColumns: {
173
+ id: {
174
+ genNo: 3,
175
+ },
176
+ },
177
+ },
178
+ }),
179
+ );
180
+ const answerService = createAnswerService({
181
+ sources: [{
182
+ header: {
183
+ guid: 'source1',
184
+ },
185
+ }],
186
+ }, [{
187
+ selectedAttributes: [{
188
+ column: {
189
+ id: 'oid1', // output column id
190
+ name: 'col1',
191
+ dataType: 'CHAR',
192
+ },
193
+ value: '1',
194
+ }, {
195
+ column: {
196
+ id: 'oid3',
197
+ name: 'col3',
198
+ dataType: 'DATE',
199
+ },
200
+ value: 12345,
201
+ }],
202
+ selectedMeasures: [],
203
+ }]);
204
+ const underlying = await answerService.getUnderlyingDataForPoint(['col2']);
205
+ expect(fetchMock).toHaveBeenCalledTimes(4);
206
+ expect(underlying.getSession().genNo).toBe(3);
207
+ expect(fetchMock).toHaveBeenCalledWith(
208
+ 'https://tshost/prism/?op=RemoveColumns',
209
+ expect.objectContaining({
210
+ body: JSON.stringify({
211
+ operationName: 'RemoveColumns',
212
+ query: removeColumns,
213
+ variables: {
214
+ session: {
215
+ ...defaultSession,
216
+ genNo: 2,
217
+ },
218
+ logicalColumnIds: [
219
+ 'id1',
220
+ ],
221
+ },
222
+ }),
223
+ }),
224
+ );
225
+ });
226
+
227
+ test('getUnderlyingDataForPoint should throw when no point is selected', async () => {
228
+ const answerService = createAnswerService({}, null);
229
+ await expect(answerService.getUnderlyingDataForPoint(['col2'])).rejects.toThrow();
230
+ });
231
+ });
@@ -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
+ }