@thoughtspot/visual-embed-sdk 1.52.1 → 1.52.2-beta

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 (241) hide show
  1. package/cjs/package.json +11 -4
  2. package/cjs/src/contracts/host-event-contracts.d.ts +49 -11
  3. package/cjs/src/contracts/host-event-contracts.d.ts.map +1 -1
  4. package/cjs/src/embed/app.d.ts +4 -3
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +1 -1
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +10 -0
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/auto-frame-renderer.js +1 -1
  11. package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
  12. package/cjs/src/embed/auto-frame-renderer.spec.js +24 -13
  13. package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
  14. package/cjs/src/embed/bodyless-conversation.js +1 -1
  15. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  16. package/cjs/src/embed/conversation.d.ts +1 -0
  17. package/cjs/src/embed/conversation.d.ts.map +1 -1
  18. package/cjs/src/embed/conversation.js +4 -4
  19. package/cjs/src/embed/conversation.js.map +1 -1
  20. package/cjs/src/embed/conversation.spec.js +35 -24
  21. package/cjs/src/embed/conversation.spec.js.map +1 -1
  22. package/cjs/src/embed/embedConfig.spec.js +2 -1
  23. package/cjs/src/embed/embedConfig.spec.js.map +1 -1
  24. package/cjs/src/embed/hostEventClient/host-event-client.d.ts +2 -2
  25. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  26. package/cjs/src/embed/hostEventClient/host-event-client.js +16 -10
  27. package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
  28. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +14 -8
  29. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  30. package/cjs/src/embed/hostEventClient/utils.d.ts +9 -0
  31. package/cjs/src/embed/hostEventClient/utils.d.ts.map +1 -1
  32. package/cjs/src/embed/hostEventClient/utils.js +49 -3
  33. package/cjs/src/embed/hostEventClient/utils.js.map +1 -1
  34. package/cjs/src/embed/hostEventClient/utils.spec.js +151 -0
  35. package/cjs/src/embed/hostEventClient/utils.spec.js.map +1 -1
  36. package/cjs/src/embed/liveboard.d.ts +4 -3
  37. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  38. package/cjs/src/embed/liveboard.js +18 -13
  39. package/cjs/src/embed/liveboard.js.map +1 -1
  40. package/cjs/src/embed/liveboard.spec.js +2 -1
  41. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  42. package/cjs/src/embed/search-bar.js +1 -1
  43. package/cjs/src/embed/search-bar.js.map +1 -1
  44. package/cjs/src/embed/search.js +1 -1
  45. package/cjs/src/embed/search.js.map +1 -1
  46. package/cjs/src/embed/search.spec.js +20 -0
  47. package/cjs/src/embed/search.spec.js.map +1 -1
  48. package/cjs/src/embed/spotter-utils.d.ts +8 -1
  49. package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
  50. package/cjs/src/embed/spotter-utils.js +14 -1
  51. package/cjs/src/embed/spotter-utils.js.map +1 -1
  52. package/cjs/src/embed/spotter-utils.spec.js +26 -0
  53. package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
  54. package/cjs/src/embed/ts-embed.d.ts +3 -0
  55. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  56. package/cjs/src/embed/ts-embed.js +108 -29
  57. package/cjs/src/embed/ts-embed.js.map +1 -1
  58. package/cjs/src/embed/ts-embed.spec.js +163 -23
  59. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  60. package/cjs/src/errors.js +1 -1
  61. package/cjs/src/errors.js.map +1 -1
  62. package/cjs/src/index.d.ts +2 -1
  63. package/cjs/src/index.d.ts.map +1 -1
  64. package/cjs/src/index.js +3 -1
  65. package/cjs/src/index.js.map +1 -1
  66. package/cjs/src/react/all-types-export.d.ts +1 -1
  67. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  68. package/cjs/src/react/all-types-export.js +2 -1
  69. package/cjs/src/react/all-types-export.js.map +1 -1
  70. package/cjs/src/types.d.ts +45 -22
  71. package/cjs/src/types.d.ts.map +1 -1
  72. package/cjs/src/types.js +44 -21
  73. package/cjs/src/types.js.map +1 -1
  74. package/cjs/src/utils/authService/tokenizedAuthService.spec.js +2 -1
  75. package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  76. package/cjs/src/utils/custom-actions.spec.js +4 -2
  77. package/cjs/src/utils/custom-actions.spec.js.map +1 -1
  78. package/cjs/src/utils/filterConverter.d.ts +106 -0
  79. package/cjs/src/utils/filterConverter.d.ts.map +1 -0
  80. package/cjs/src/utils/filterConverter.js +215 -0
  81. package/cjs/src/utils/filterConverter.js.map +1 -0
  82. package/cjs/src/utils/filterConverter.spec.d.ts +2 -0
  83. package/cjs/src/utils/filterConverter.spec.d.ts.map +1 -0
  84. package/cjs/src/utils/filterConverter.spec.js +709 -0
  85. package/cjs/src/utils/filterConverter.spec.js.map +1 -0
  86. package/cjs/src/utils/processData.spec.js +2 -1
  87. package/cjs/src/utils/processData.spec.js.map +1 -1
  88. package/dist/{index-C1pmYb5H.js → index-CcBYlGo9.js} +1 -1
  89. package/dist/src/contracts/host-event-contracts.d.ts +49 -11
  90. package/dist/src/contracts/host-event-contracts.d.ts.map +1 -1
  91. package/dist/src/embed/app.d.ts +4 -3
  92. package/dist/src/embed/app.d.ts.map +1 -1
  93. package/dist/src/embed/conversation.d.ts +1 -0
  94. package/dist/src/embed/conversation.d.ts.map +1 -1
  95. package/dist/src/embed/hostEventClient/host-event-client.d.ts +2 -2
  96. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  97. package/dist/src/embed/hostEventClient/utils.d.ts +9 -0
  98. package/dist/src/embed/hostEventClient/utils.d.ts.map +1 -1
  99. package/dist/src/embed/liveboard.d.ts +4 -3
  100. package/dist/src/embed/liveboard.d.ts.map +1 -1
  101. package/dist/src/embed/spotter-utils.d.ts +8 -1
  102. package/dist/src/embed/spotter-utils.d.ts.map +1 -1
  103. package/dist/src/embed/ts-embed.d.ts +3 -0
  104. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  105. package/dist/src/index.d.ts +2 -1
  106. package/dist/src/index.d.ts.map +1 -1
  107. package/dist/src/react/all-types-export.d.ts +1 -1
  108. package/dist/src/react/all-types-export.d.ts.map +1 -1
  109. package/dist/src/types.d.ts +45 -22
  110. package/dist/src/types.d.ts.map +1 -1
  111. package/dist/src/utils/filterConverter.d.ts +106 -0
  112. package/dist/src/utils/filterConverter.d.ts.map +1 -0
  113. package/dist/src/utils/filterConverter.spec.d.ts +2 -0
  114. package/dist/src/utils/filterConverter.spec.d.ts.map +1 -0
  115. package/dist/tsembed-react.es.js +257 -87
  116. package/dist/tsembed-react.js +256 -86
  117. package/dist/tsembed.es.js +466 -89
  118. package/dist/tsembed.js +465 -87
  119. package/dist/visual-embed-sdk-react-full.d.ts +202 -40
  120. package/dist/visual-embed-sdk-react.d.ts +108 -40
  121. package/dist/visual-embed-sdk.d.ts +202 -40
  122. package/lib/package.json +11 -4
  123. package/lib/src/contracts/host-event-contracts.d.ts +49 -11
  124. package/lib/src/contracts/host-event-contracts.d.ts.map +1 -1
  125. package/lib/src/embed/app.d.ts +4 -3
  126. package/lib/src/embed/app.d.ts.map +1 -1
  127. package/lib/src/embed/app.js +1 -1
  128. package/lib/src/embed/app.js.map +1 -1
  129. package/lib/src/embed/app.spec.js +10 -0
  130. package/lib/src/embed/app.spec.js.map +1 -1
  131. package/lib/src/embed/auto-frame-renderer.js +1 -1
  132. package/lib/src/embed/auto-frame-renderer.js.map +1 -1
  133. package/lib/src/embed/auto-frame-renderer.spec.js +24 -13
  134. package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
  135. package/lib/src/embed/bodyless-conversation.js +1 -1
  136. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  137. package/lib/src/embed/conversation.d.ts +1 -0
  138. package/lib/src/embed/conversation.d.ts.map +1 -1
  139. package/lib/src/embed/conversation.js +5 -5
  140. package/lib/src/embed/conversation.js.map +1 -1
  141. package/lib/src/embed/conversation.spec.js +35 -24
  142. package/lib/src/embed/conversation.spec.js.map +1 -1
  143. package/lib/src/embed/embedConfig.spec.js +2 -1
  144. package/lib/src/embed/embedConfig.spec.js.map +1 -1
  145. package/lib/src/embed/hostEventClient/host-event-client.d.ts +2 -2
  146. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  147. package/lib/src/embed/hostEventClient/host-event-client.js +17 -11
  148. package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
  149. package/lib/src/embed/hostEventClient/host-event-client.spec.js +14 -8
  150. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  151. package/lib/src/embed/hostEventClient/utils.d.ts +9 -0
  152. package/lib/src/embed/hostEventClient/utils.d.ts.map +1 -1
  153. package/lib/src/embed/hostEventClient/utils.js +47 -2
  154. package/lib/src/embed/hostEventClient/utils.js.map +1 -1
  155. package/lib/src/embed/hostEventClient/utils.spec.js +152 -1
  156. package/lib/src/embed/hostEventClient/utils.spec.js.map +1 -1
  157. package/lib/src/embed/liveboard.d.ts +4 -3
  158. package/lib/src/embed/liveboard.d.ts.map +1 -1
  159. package/lib/src/embed/liveboard.js +18 -13
  160. package/lib/src/embed/liveboard.js.map +1 -1
  161. package/lib/src/embed/liveboard.spec.js +2 -1
  162. package/lib/src/embed/liveboard.spec.js.map +1 -1
  163. package/lib/src/embed/search-bar.js +1 -1
  164. package/lib/src/embed/search-bar.js.map +1 -1
  165. package/lib/src/embed/search.js +1 -1
  166. package/lib/src/embed/search.js.map +1 -1
  167. package/lib/src/embed/search.spec.js +20 -0
  168. package/lib/src/embed/search.spec.js.map +1 -1
  169. package/lib/src/embed/spotter-utils.d.ts +8 -1
  170. package/lib/src/embed/spotter-utils.d.ts.map +1 -1
  171. package/lib/src/embed/spotter-utils.js +12 -0
  172. package/lib/src/embed/spotter-utils.js.map +1 -1
  173. package/lib/src/embed/spotter-utils.spec.js +27 -1
  174. package/lib/src/embed/spotter-utils.spec.js.map +1 -1
  175. package/lib/src/embed/ts-embed.d.ts +3 -0
  176. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  177. package/lib/src/embed/ts-embed.js +108 -29
  178. package/lib/src/embed/ts-embed.js.map +1 -1
  179. package/lib/src/embed/ts-embed.spec.js +164 -24
  180. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  181. package/lib/src/errors.js +1 -1
  182. package/lib/src/errors.js.map +1 -1
  183. package/lib/src/index.d.ts +2 -1
  184. package/lib/src/index.d.ts.map +1 -1
  185. package/lib/src/index.js +2 -1
  186. package/lib/src/index.js.map +1 -1
  187. package/lib/src/react/all-types-export.d.ts +1 -1
  188. package/lib/src/react/all-types-export.d.ts.map +1 -1
  189. package/lib/src/react/all-types-export.js +1 -1
  190. package/lib/src/react/all-types-export.js.map +1 -1
  191. package/lib/src/types.d.ts +45 -22
  192. package/lib/src/types.d.ts.map +1 -1
  193. package/lib/src/types.js +44 -21
  194. package/lib/src/types.js.map +1 -1
  195. package/lib/src/utils/authService/tokenizedAuthService.spec.js +2 -1
  196. package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  197. package/lib/src/utils/custom-actions.spec.js +4 -2
  198. package/lib/src/utils/custom-actions.spec.js.map +1 -1
  199. package/lib/src/utils/filterConverter.d.ts +106 -0
  200. package/lib/src/utils/filterConverter.d.ts.map +1 -0
  201. package/lib/src/utils/filterConverter.js +210 -0
  202. package/lib/src/utils/filterConverter.js.map +1 -0
  203. package/lib/src/utils/filterConverter.spec.d.ts +2 -0
  204. package/lib/src/utils/filterConverter.spec.d.ts.map +1 -0
  205. package/lib/src/utils/filterConverter.spec.js +707 -0
  206. package/lib/src/utils/filterConverter.spec.js.map +1 -0
  207. package/lib/src/utils/processData.spec.js +2 -1
  208. package/lib/src/utils/processData.spec.js.map +1 -1
  209. package/lib/src/visual-embed-sdk.d.ts +202 -40
  210. package/package.json +11 -4
  211. package/src/contracts/host-event-contracts.ts +55 -11
  212. package/src/embed/app.spec.ts +15 -0
  213. package/src/embed/app.ts +5 -4
  214. package/src/embed/auto-frame-renderer.spec.ts +24 -13
  215. package/src/embed/auto-frame-renderer.ts +1 -1
  216. package/src/embed/bodyless-conversation.ts +1 -1
  217. package/src/embed/conversation.spec.ts +38 -27
  218. package/src/embed/conversation.ts +5 -5
  219. package/src/embed/embedConfig.spec.ts +2 -1
  220. package/src/embed/hostEventClient/host-event-client.spec.ts +14 -8
  221. package/src/embed/hostEventClient/host-event-client.ts +18 -10
  222. package/src/embed/hostEventClient/utils.spec.ts +176 -1
  223. package/src/embed/hostEventClient/utils.ts +51 -2
  224. package/src/embed/liveboard.spec.ts +4 -3
  225. package/src/embed/liveboard.ts +22 -16
  226. package/src/embed/search-bar.tsx +1 -1
  227. package/src/embed/search.spec.ts +23 -0
  228. package/src/embed/search.ts +1 -1
  229. package/src/embed/spotter-utils.spec.ts +29 -0
  230. package/src/embed/spotter-utils.ts +16 -0
  231. package/src/embed/ts-embed.spec.ts +204 -23
  232. package/src/embed/ts-embed.ts +114 -28
  233. package/src/errors.ts +1 -1
  234. package/src/index.ts +10 -0
  235. package/src/react/all-types-export.ts +4 -0
  236. package/src/types.ts +44 -21
  237. package/src/utils/authService/tokenizedAuthService.spec.ts +2 -1
  238. package/src/utils/custom-actions.spec.ts +4 -2
  239. package/src/utils/filterConverter.spec.ts +801 -0
  240. package/src/utils/filterConverter.ts +304 -0
  241. package/src/utils/processData.spec.ts +2 -1
@@ -0,0 +1,709 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const types_1 = require("../types");
4
+ const utils_1 = require("../embed/hostEventClient/utils");
5
+ const filterConverter_1 = require("./filterConverter");
6
+ describe('convertFilterChangedToUpdateFiltersPayload', () => {
7
+ test('returns an empty filters array for an empty payload', () => {
8
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)({})).toEqual({ filters: [] });
9
+ });
10
+ test('returns an empty filters array for null/undefined input', () => {
11
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(null)).toEqual({ filters: [] });
12
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(undefined)).toEqual({ filters: [] });
13
+ });
14
+ test('converts runtime filters as-is', () => {
15
+ const payload = {
16
+ runtimeFilters: [
17
+ { columnName: 'state', operator: types_1.RuntimeFilterOp.EQ, values: ['california'] },
18
+ ],
19
+ };
20
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
21
+ filters: [
22
+ { columnName: 'state', operator: types_1.RuntimeFilterOp.EQ, values: ['california'] },
23
+ ],
24
+ });
25
+ });
26
+ test('converts a simple attribute filter (filterContent)', () => {
27
+ const payload = {
28
+ liveboardFilters: [
29
+ {
30
+ columnInfo: { name: 'item type' },
31
+ filters: [
32
+ {
33
+ filterContent: [
34
+ {
35
+ filterType: 'IN',
36
+ value: [{ key: 'bags' }, { key: 'shirts' }],
37
+ },
38
+ ],
39
+ },
40
+ ],
41
+ },
42
+ ],
43
+ };
44
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
45
+ filters: [
46
+ { columnName: 'item type', operator: 'IN', values: ['bags', 'shirts'] },
47
+ ],
48
+ });
49
+ });
50
+ test('includes negate when set on a filterContent filter', () => {
51
+ const payload = {
52
+ liveboardFilters: [
53
+ {
54
+ columnInfo: { name: 'region' },
55
+ filters: [
56
+ {
57
+ filterContent: [
58
+ {
59
+ filterType: 'EQ',
60
+ negate: true,
61
+ value: [{ key: 'west' }],
62
+ },
63
+ ],
64
+ },
65
+ ],
66
+ },
67
+ ],
68
+ };
69
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
70
+ filters: [
71
+ { columnName: 'region', operator: 'EQ', values: ['west'], negate: true },
72
+ ],
73
+ });
74
+ });
75
+ test('skips a filter group with no columnInfo.name', () => {
76
+ const payload = {
77
+ liveboardFilters: [
78
+ {
79
+ filters: [
80
+ { filterContent: [{ filterType: 'EQ', value: [{ key: 'x' }] }] },
81
+ ],
82
+ },
83
+ ],
84
+ };
85
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
86
+ });
87
+ test('skips a filter with neither filterContent nor dateFilterContent', () => {
88
+ const payload = {
89
+ liveboardFilters: [
90
+ {
91
+ columnInfo: { name: 'region' },
92
+ filters: [{}],
93
+ },
94
+ ],
95
+ };
96
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
97
+ });
98
+ test('converts an EXACT_DATE filter using epoch', () => {
99
+ const payload = {
100
+ liveboardFilters: [
101
+ {
102
+ columnInfo: { name: 'date' },
103
+ filters: [
104
+ {
105
+ dateFilterContent: [
106
+ {
107
+ dateFilter: { type: 'EXACT_DATE', op: 'EQ', epoch: '1690847400' },
108
+ },
109
+ ],
110
+ },
111
+ ],
112
+ },
113
+ ],
114
+ };
115
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
116
+ filters: [
117
+ {
118
+ columnName: 'date', operator: 'EQ', values: [1690847400], type: 'EXACT_DATE',
119
+ },
120
+ ],
121
+ });
122
+ });
123
+ test('converts an EXACT_DATE_RANGE filter using dateRange epochs', () => {
124
+ const payload = {
125
+ liveboardFilters: [
126
+ {
127
+ columnInfo: { name: 'date' },
128
+ filters: [
129
+ {
130
+ dateFilterContent: [
131
+ {
132
+ dateFilter: {
133
+ type: 'EXACT_DATE_RANGE',
134
+ op: 'BW_INC',
135
+ dateRange: { lowEpoch: '100', highEpoch: '200' },
136
+ },
137
+ },
138
+ ],
139
+ },
140
+ ],
141
+ },
142
+ ],
143
+ };
144
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
145
+ filters: [
146
+ {
147
+ columnName: 'date', operator: 'BW_INC', values: [100, 200], type: 'EXACT_DATE_RANGE',
148
+ },
149
+ ],
150
+ });
151
+ });
152
+ test('converts a MONTH_YEAR filter', () => {
153
+ const payload = {
154
+ liveboardFilters: [
155
+ {
156
+ columnInfo: { name: 'date' },
157
+ filters: [
158
+ {
159
+ dateFilterContent: [
160
+ {
161
+ dateFilter: {
162
+ type: 'MONTH_YEAR', op: 'EQ', monthName: 'JULY', yearName: '2023',
163
+ },
164
+ },
165
+ ],
166
+ },
167
+ ],
168
+ },
169
+ ],
170
+ };
171
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
172
+ filters: [
173
+ {
174
+ columnName: 'date', operator: 'EQ', values: ['JULY', '2023'], type: 'MONTH_YEAR',
175
+ },
176
+ ],
177
+ });
178
+ });
179
+ test('converts a QUARTER_YEAR filter', () => {
180
+ const payload = {
181
+ liveboardFilters: [
182
+ {
183
+ columnInfo: { name: 'date' },
184
+ filters: [
185
+ {
186
+ dateFilterContent: [
187
+ {
188
+ dateFilter: {
189
+ type: 'QUARTER_YEAR', op: 'EQ', quarterName: 'Q1', yearName: '2023',
190
+ },
191
+ },
192
+ ],
193
+ },
194
+ ],
195
+ },
196
+ ],
197
+ };
198
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
199
+ filters: [
200
+ {
201
+ columnName: 'date', operator: 'EQ', values: ['Q1', '2023'], type: 'QUARTER_YEAR',
202
+ },
203
+ ],
204
+ });
205
+ });
206
+ test('converts a YEAR_ONLY filter', () => {
207
+ const payload = {
208
+ liveboardFilters: [
209
+ {
210
+ columnInfo: { name: 'date' },
211
+ filters: [
212
+ {
213
+ dateFilterContent: [
214
+ { dateFilter: { type: 'YEAR_ONLY', op: 'EQ', yearName: '2023' } },
215
+ ],
216
+ },
217
+ ],
218
+ },
219
+ ],
220
+ };
221
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
222
+ filters: [
223
+ { columnName: 'date', operator: 'EQ', values: ['2023'], type: 'YEAR_ONLY' },
224
+ ],
225
+ });
226
+ });
227
+ test('converts a LAST_N_PERIOD filter with datePeriod and includeCurrentPeriod', () => {
228
+ const payload = {
229
+ liveboardFilters: [
230
+ {
231
+ columnInfo: { name: 'date' },
232
+ filters: [
233
+ {
234
+ dateFilterContent: [
235
+ {
236
+ negate: true,
237
+ dateFilter: {
238
+ type: 'LAST_N_PERIOD',
239
+ op: 'EQ',
240
+ number: 3,
241
+ datePeriod: 'MONTH',
242
+ includeCurrentPeriod: true,
243
+ },
244
+ },
245
+ ],
246
+ },
247
+ ],
248
+ },
249
+ ],
250
+ };
251
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
252
+ filters: [
253
+ {
254
+ columnName: 'date',
255
+ operator: 'EQ',
256
+ values: [3],
257
+ type: 'LAST_N_PERIOD',
258
+ datePeriod: 'MONTH',
259
+ includeCurrentPeriod: true,
260
+ negate: true,
261
+ },
262
+ ],
263
+ });
264
+ });
265
+ test('converts a period-only date filter (e.g. TODAY) with empty values', () => {
266
+ const payload = {
267
+ liveboardFilters: [
268
+ {
269
+ columnInfo: { name: 'date' },
270
+ filters: [
271
+ {
272
+ dateFilterContent: [
273
+ { dateFilter: { type: 'TODAY', op: 'EQ' } },
274
+ ],
275
+ },
276
+ ],
277
+ },
278
+ ],
279
+ };
280
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
281
+ filters: [
282
+ { columnName: 'date', operator: 'EQ', values: [], type: 'TODAY' },
283
+ ],
284
+ });
285
+ });
286
+ test('skips a dateFilterContent entry with no type', () => {
287
+ const payload = {
288
+ liveboardFilters: [
289
+ {
290
+ columnInfo: { name: 'date' },
291
+ filters: [
292
+ { dateFilterContent: [{ dateFilter: {} }] },
293
+ ],
294
+ },
295
+ ],
296
+ };
297
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
298
+ });
299
+ test('defaults operator to EQ when dateFilter.op is missing', () => {
300
+ const payload = {
301
+ liveboardFilters: [
302
+ {
303
+ columnInfo: { name: 'date' },
304
+ filters: [
305
+ { dateFilterContent: [{ dateFilter: { type: 'TODAY' } }] },
306
+ ],
307
+ },
308
+ ],
309
+ };
310
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
311
+ filters: [
312
+ { columnName: 'date', operator: types_1.RuntimeFilterOp.EQ, values: [], type: 'TODAY' },
313
+ ],
314
+ });
315
+ });
316
+ test('converts every filterContent entry on a filter, not just the first', () => {
317
+ const payload = {
318
+ liveboardFilters: [
319
+ {
320
+ columnInfo: { name: 'quantity' },
321
+ filters: [
322
+ {
323
+ filterContent: [
324
+ { filterType: 'GE', value: [{ key: 5 }] },
325
+ { filterType: 'LE', value: [{ key: 10 }] },
326
+ ],
327
+ },
328
+ ],
329
+ },
330
+ ],
331
+ };
332
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
333
+ filters: [
334
+ { columnName: 'quantity', operator: 'GE', values: [5] },
335
+ { columnName: 'quantity', operator: 'LE', values: [10] },
336
+ ],
337
+ });
338
+ });
339
+ test('converts every Filter entry in a filter group, not just the first', () => {
340
+ const payload = {
341
+ liveboardFilters: [
342
+ {
343
+ columnInfo: { name: 'region' },
344
+ filters: [
345
+ { filterContent: [{ filterType: 'EQ', value: [{ key: 'west' }] }] },
346
+ { filterContent: [{ filterType: 'EQ', value: [{ key: 'east' }] }] },
347
+ ],
348
+ },
349
+ ],
350
+ };
351
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
352
+ filters: [
353
+ { columnName: 'region', operator: 'EQ', values: ['west'] },
354
+ { columnName: 'region', operator: 'EQ', values: ['east'] },
355
+ ],
356
+ });
357
+ });
358
+ test('keeps falsy-but-defined filter values such as 0 and false', () => {
359
+ const payload = {
360
+ liveboardFilters: [
361
+ {
362
+ columnInfo: { name: 'flag' },
363
+ filters: [
364
+ {
365
+ filterContent: [
366
+ { filterType: 'IN', value: [{ key: 0 }, { key: false }] },
367
+ ],
368
+ },
369
+ ],
370
+ },
371
+ ],
372
+ };
373
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
374
+ filters: [
375
+ { columnName: 'flag', operator: 'IN', values: [0, false] },
376
+ ],
377
+ });
378
+ });
379
+ test('skips an EXACT_DATE filter missing its epoch instead of emitting empty values', () => {
380
+ const payload = {
381
+ liveboardFilters: [
382
+ {
383
+ columnInfo: { name: 'date' },
384
+ filters: [
385
+ { dateFilterContent: [{ dateFilter: { type: 'EXACT_DATE', op: 'EQ' } }] },
386
+ ],
387
+ },
388
+ ],
389
+ };
390
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
391
+ });
392
+ test('skips a MONTH_YEAR filter missing yearName instead of emitting empty values', () => {
393
+ const payload = {
394
+ liveboardFilters: [
395
+ {
396
+ columnInfo: { name: 'date' },
397
+ filters: [
398
+ {
399
+ dateFilterContent: [
400
+ { dateFilter: { type: 'MONTH_YEAR', op: 'EQ', monthName: 'JULY' } },
401
+ ],
402
+ },
403
+ ],
404
+ },
405
+ ],
406
+ };
407
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
408
+ });
409
+ test('skips an unrecognized date filter type rather than guessing', () => {
410
+ const payload = {
411
+ liveboardFilters: [
412
+ {
413
+ columnInfo: { name: 'date' },
414
+ filters: [
415
+ { dateFilterContent: [{ dateFilter: { type: 'SOME_FUTURE_TYPE', op: 'EQ' } }] },
416
+ ],
417
+ },
418
+ ],
419
+ };
420
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
421
+ });
422
+ test('output satisfies isValidUpdateFiltersPayload', () => {
423
+ const payload = {
424
+ liveboardFilters: [
425
+ {
426
+ columnInfo: { name: 'item type' },
427
+ filters: [
428
+ { filterContent: [{ filterType: 'IN', value: [{ key: 'bags' }] }] },
429
+ ],
430
+ },
431
+ ],
432
+ runtimeFilters: [
433
+ { columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
434
+ ],
435
+ };
436
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload);
437
+ expect((0, utils_1.isValidUpdateFiltersPayload)(converted)).toBe(true);
438
+ });
439
+ test('combines multiple liveboard filters and runtime filters', () => {
440
+ const payload = {
441
+ liveboardFilters: [
442
+ {
443
+ columnInfo: { name: 'item type' },
444
+ filters: [
445
+ { filterContent: [{ filterType: 'IN', value: [{ key: 'bags' }] }] },
446
+ ],
447
+ },
448
+ ],
449
+ runtimeFilters: [
450
+ { columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
451
+ ],
452
+ };
453
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
454
+ filters: [
455
+ { columnName: 'item type', operator: 'IN', values: ['bags'] },
456
+ { columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
457
+ ],
458
+ });
459
+ });
460
+ // The payload arrives as JSON from the embedded app, so an absent field can
461
+ // be `null` rather than omitted. `Number(null)` is 0, so a naive coercion
462
+ // would turn a missing epoch into 1970 and a missing period count into 0.
463
+ describe('null and non-numeric values in the payload', () => {
464
+ const dateFilterPayload = (dateFilter) => ({
465
+ liveboardFilters: [
466
+ {
467
+ columnInfo: { name: 'date' },
468
+ filters: [{ dateFilterContent: [{ dateFilter: dateFilter }] }],
469
+ },
470
+ ],
471
+ });
472
+ test.each([null, '', 'not-a-date'])('skips an EXACT_DATE filter whose epoch is %p instead of emitting epoch 0', (epoch) => {
473
+ const payload = dateFilterPayload({ type: 'EXACT_DATE', op: 'EQ', epoch });
474
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
475
+ });
476
+ test('skips an EXACT_DATE_RANGE filter when either bound is null', () => {
477
+ const missingHigh = dateFilterPayload({
478
+ type: 'EXACT_DATE_RANGE', op: 'BW', dateRange: { lowEpoch: 1000, highEpoch: null },
479
+ });
480
+ const missingLow = dateFilterPayload({
481
+ type: 'EXACT_DATE_RANGE', op: 'BW', dateRange: { lowEpoch: null, highEpoch: 2000 },
482
+ });
483
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(missingHigh)).toEqual({ filters: [] });
484
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(missingLow)).toEqual({ filters: [] });
485
+ });
486
+ test.each(['LAST_N_PERIOD', 'NEXT_N_PERIOD'])('skips a %s filter whose number is null instead of emitting a 0-length period', (type) => {
487
+ const payload = dateFilterPayload({ type, op: 'EQ', number: null, datePeriod: 'MONTH' });
488
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
489
+ });
490
+ test('accepts an epoch of 0 as a real value', () => {
491
+ const payload = dateFilterPayload({ type: 'EXACT_DATE', op: 'EQ', epoch: 0 });
492
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
493
+ filters: [{
494
+ columnName: 'date', operator: 'EQ', values: [0], type: 'EXACT_DATE',
495
+ }],
496
+ });
497
+ });
498
+ test('accepts a numeric epoch sent as a string', () => {
499
+ const payload = dateFilterPayload({ type: 'EXACT_DATE', op: 'EQ', epoch: '1700000000' });
500
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
501
+ filters: [{
502
+ columnName: 'date', operator: 'EQ', values: [1700000000], type: 'EXACT_DATE',
503
+ }],
504
+ });
505
+ });
506
+ test('omits includeCurrentPeriod when it is null', () => {
507
+ const payload = dateFilterPayload({
508
+ type: 'LAST_N_PERIOD', op: 'EQ', number: 3, datePeriod: 'MONTH', includeCurrentPeriod: null,
509
+ });
510
+ const [filter] = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload).filters;
511
+ expect(filter).not.toHaveProperty('includeCurrentPeriod');
512
+ });
513
+ test('keeps includeCurrentPeriod when it is explicitly false', () => {
514
+ const payload = dateFilterPayload({
515
+ type: 'LAST_N_PERIOD', op: 'EQ', number: 3, datePeriod: 'MONTH', includeCurrentPeriod: false,
516
+ });
517
+ const [filter] = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload).filters;
518
+ expect(filter.includeCurrentPeriod).toBe(false);
519
+ });
520
+ test('drops null keys from an attribute filter but keeps the rest', () => {
521
+ const payload = {
522
+ liveboardFilters: [
523
+ {
524
+ columnInfo: { name: 'item type' },
525
+ filters: [
526
+ {
527
+ filterContent: [
528
+ {
529
+ filterType: 'IN',
530
+ value: [{ key: 'bags' }, { key: null }, { key: 'shirts' }],
531
+ },
532
+ ],
533
+ },
534
+ ],
535
+ },
536
+ ],
537
+ };
538
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
539
+ filters: [{ columnName: 'item type', operator: 'IN', values: ['bags', 'shirts'] }],
540
+ });
541
+ });
542
+ test('keeps a falsy-but-real key such as 0 or false', () => {
543
+ const payload = {
544
+ liveboardFilters: [
545
+ {
546
+ columnInfo: { name: 'quantity' },
547
+ filters: [
548
+ { filterContent: [{ filterType: 'IN', value: [{ key: 0 }, { key: false }] }] },
549
+ ],
550
+ },
551
+ ],
552
+ };
553
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
554
+ filters: [{ columnName: 'quantity', operator: 'IN', values: [0, false] }],
555
+ });
556
+ });
557
+ });
558
+ // A runtime filter needs no reshaping, but it still arrives as JSON. One
559
+ // malformed entry fails isValidUpdateFiltersPayload for the WHOLE filters
560
+ // array, which would take every other converted filter down with it.
561
+ describe('malformed runtime filters', () => {
562
+ const malformed = [
563
+ { columnName: null, operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
564
+ { columnName: '', operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
565
+ { operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
566
+ { columnName: 'region', operator: null, values: ['west'] },
567
+ { columnName: 'region', values: ['west'] },
568
+ { columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: null },
569
+ { columnName: 'region', operator: types_1.RuntimeFilterOp.EQ },
570
+ ];
571
+ test.each(malformed)('skips the malformed runtime filter %p', (runtimeFilter) => {
572
+ const payload = { runtimeFilters: [runtimeFilter] };
573
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({ filters: [] });
574
+ });
575
+ test('a bad runtime filter does not discard the good filters alongside it', () => {
576
+ const payload = {
577
+ liveboardFilters: [
578
+ {
579
+ columnInfo: { name: 'item type' },
580
+ filters: [{ filterContent: [{ filterType: 'IN', value: [{ key: 'bags' }] }] }],
581
+ },
582
+ ],
583
+ runtimeFilters: [
584
+ { columnName: null, operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
585
+ { columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
586
+ ],
587
+ };
588
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload);
589
+ expect(converted).toEqual({
590
+ filters: [
591
+ { columnName: 'item type', operator: 'IN', values: ['bags'] },
592
+ { columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: ['west'] },
593
+ ],
594
+ });
595
+ // The whole point: the surviving payload is still triggerable.
596
+ expect((0, utils_1.isValidUpdateFiltersPayload)(converted)).toBe(true);
597
+ });
598
+ test('keeps a runtime filter with an empty values array', () => {
599
+ const payload = {
600
+ runtimeFilters: [{ columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: [] }],
601
+ };
602
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload)).toEqual({
603
+ filters: [{ columnName: 'region', operator: types_1.RuntimeFilterOp.EQ, values: [] }],
604
+ });
605
+ });
606
+ });
607
+ // liveboardFilters entries carry an optional `applicability`
608
+ // ({level, targetId}) from SDK 1.53.0 / 26.10.0.cl, and UpdateFilters
609
+ // accepts it per filter. Dropping it would replay a tab-scoped filter
610
+ // across the whole Liveboard.
611
+ describe('applicability (filter scope)', () => {
612
+ const TAB_ID = 'e0836cad-4fdf-42d4-bd97-567a6b2a6058';
613
+ const groupWith = (applicability) => ({
614
+ liveboardFilters: [
615
+ {
616
+ columnInfo: { name: 'item type' },
617
+ applicability,
618
+ filters: [{ filterContent: [{ filterType: 'IN', value: [{ key: 'bags' }] }] }],
619
+ },
620
+ ],
621
+ });
622
+ test('carries TAB scope through to the converted filter', () => {
623
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(groupWith({ level: 'TAB', targetId: TAB_ID }));
624
+ expect(converted).toEqual({
625
+ filters: [{
626
+ columnName: 'item type',
627
+ operator: 'IN',
628
+ values: ['bags'],
629
+ applicability: { level: 'TAB', targetId: TAB_ID },
630
+ }],
631
+ });
632
+ expect((0, utils_1.isValidUpdateFiltersPayload)(converted)).toBe(true);
633
+ });
634
+ test('carries GROUP scope through to the converted filter', () => {
635
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(groupWith({ level: 'GROUP', targetId: TAB_ID }));
636
+ expect(converted.filters[0].applicability).toEqual({ level: 'GROUP', targetId: TAB_ID });
637
+ expect((0, utils_1.isValidUpdateFiltersPayload)(converted)).toBe(true);
638
+ });
639
+ test('carries LIVEBOARD scope, which needs no targetId', () => {
640
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(groupWith({ level: 'LIVEBOARD' }));
641
+ expect(converted.filters[0].applicability).toEqual({ level: 'LIVEBOARD' });
642
+ expect((0, utils_1.isValidUpdateFiltersPayload)(converted)).toBe(true);
643
+ });
644
+ test('omits applicability entirely when the payload has none', () => {
645
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(groupWith(undefined));
646
+ expect(converted.filters[0]).not.toHaveProperty('applicability');
647
+ expect((0, utils_1.isValidUpdateFiltersPayload)(converted)).toBe(true);
648
+ });
649
+ test('applies the group scope to every filter the group produces', () => {
650
+ const payload = {
651
+ liveboardFilters: [
652
+ {
653
+ columnInfo: { name: 'quantity' },
654
+ applicability: { level: 'TAB', targetId: TAB_ID },
655
+ filters: [
656
+ {
657
+ filterContent: [
658
+ { filterType: 'GE', value: [{ key: 5 }] },
659
+ { filterType: 'LE', value: [{ key: 10 }] },
660
+ ],
661
+ },
662
+ ],
663
+ },
664
+ ],
665
+ };
666
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload);
667
+ expect(converted.filters).toHaveLength(2);
668
+ converted.filters.forEach((filter) => {
669
+ expect(filter.applicability).toEqual({ level: 'TAB', targetId: TAB_ID });
670
+ });
671
+ });
672
+ test.each([
673
+ [{ level: 'TAB' }, 'TAB with no targetId'],
674
+ [{ level: 'GROUP', targetId: ' ' }, 'GROUP with a blank targetId'],
675
+ [{ level: 'SOMETHING_ELSE', targetId: TAB_ID }, 'an unknown level'],
676
+ [{ targetId: TAB_ID }, 'no level at all'],
677
+ ])('skips a filter scoped with %p (%s) rather than widening it', (applicability, _label) => {
678
+ expect((0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(groupWith(applicability)))
679
+ .toEqual({ filters: [] });
680
+ });
681
+ test('a malformed scope on one column does not invalidate the others', () => {
682
+ const payload = {
683
+ liveboardFilters: [
684
+ {
685
+ columnInfo: { name: 'item type' },
686
+ applicability: { level: 'TAB' },
687
+ filters: [{ filterContent: [{ filterType: 'IN', value: [{ key: 'bags' }] }] }],
688
+ },
689
+ {
690
+ columnInfo: { name: 'region' },
691
+ applicability: { level: 'TAB', targetId: TAB_ID },
692
+ filters: [{ filterContent: [{ filterType: 'IN', value: [{ key: 'west' }] }] }],
693
+ },
694
+ ],
695
+ };
696
+ const converted = (0, filterConverter_1.convertFilterChangedToUpdateFiltersPayload)(payload);
697
+ expect(converted).toEqual({
698
+ filters: [{
699
+ columnName: 'region',
700
+ operator: 'IN',
701
+ values: ['west'],
702
+ applicability: { level: 'TAB', targetId: TAB_ID },
703
+ }],
704
+ });
705
+ expect((0, utils_1.isValidUpdateFiltersPayload)(converted)).toBe(true);
706
+ });
707
+ });
708
+ });
709
+ //# sourceMappingURL=filterConverter.spec.js.map