@servicetitan/titan-chatbot-api 4.4.0 → 4.4.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.
- package/CHANGELOG.md +24 -0
- package/dist/api-client/models/__mocks__/models.mock.d.ts +1 -0
- package/dist/api-client/models/__mocks__/models.mock.d.ts.map +1 -1
- package/dist/api-client/models/__mocks__/models.mock.js +22 -0
- package/dist/api-client/models/__mocks__/models.mock.js.map +1 -1
- package/dist/api-client/utils/__tests__/model-utils.test.d.ts +2 -0
- package/dist/api-client/utils/__tests__/model-utils.test.d.ts.map +1 -0
- package/dist/api-client/utils/__tests__/model-utils.test.js +421 -0
- package/dist/api-client/utils/__tests__/model-utils.test.js.map +1 -0
- package/dist/api-client/utils/model-utils.d.ts.map +1 -1
- package/dist/api-client/utils/model-utils.js +45 -28
- package/dist/api-client/utils/model-utils.js.map +1 -1
- package/dist/stores/__tests__/filter.store.test.js +4 -5
- package/dist/stores/__tests__/filter.store.test.js.map +1 -1
- package/package.json +3 -3
- package/src/api-client/models/__mocks__/models.mock.ts +23 -0
- package/src/api-client/utils/__tests__/model-utils.test.ts +453 -0
- package/src/api-client/utils/model-utils.ts +48 -29
- package/src/stores/__tests__/filter.store.test.ts +4 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { expect } from '@jest/globals';
|
|
2
|
+
import { Models, ModelsMocks } from '../..';
|
|
3
|
+
import { createSelectionsModel } from '../model-utils';
|
|
4
|
+
|
|
5
|
+
describe('[model-utils] createSelectionsModel', () => {
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
jest.clearAllMocks();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe('with no selections', () => {
|
|
11
|
+
test('should return undefined when no selections are made', () => {
|
|
12
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
13
|
+
const filters = [frontendModel.options];
|
|
14
|
+
const selected = new Map<string, string[]>();
|
|
15
|
+
|
|
16
|
+
const result = createSelectionsModel(filters, selected);
|
|
17
|
+
|
|
18
|
+
expect(result).toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('should return undefined when selected map is empty', () => {
|
|
22
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
23
|
+
const filters = [frontendModel.options];
|
|
24
|
+
const selected = new Map<string, string[]>();
|
|
25
|
+
|
|
26
|
+
const result = createSelectionsModel(filters, selected);
|
|
27
|
+
|
|
28
|
+
expect(result).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should handle empty selection arrays', () => {
|
|
32
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
33
|
+
const filters = [frontendModel.options];
|
|
34
|
+
const selected = new Map<string, string[]>([
|
|
35
|
+
['Sources', []],
|
|
36
|
+
['ContentTypes', []],
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
const result = createSelectionsModel(filters, selected);
|
|
40
|
+
|
|
41
|
+
expect(result).toBeUndefined();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('with flat filter structure (leaf filters only)', () => {
|
|
46
|
+
test('top level, single filter, single value', () => {
|
|
47
|
+
const flatModel = ModelsMocks.mockFrontendModelFlat();
|
|
48
|
+
const flatFilters = flatModel.options.subOptions ?? [];
|
|
49
|
+
const selected = new Map<string, string[]>([['ContentTypes', ['kbReleaseNotes']]]);
|
|
50
|
+
|
|
51
|
+
const result = createSelectionsModel(flatFilters, selected);
|
|
52
|
+
expect(result).toEqual({
|
|
53
|
+
subOptions: {
|
|
54
|
+
ContentTypes: {
|
|
55
|
+
values: ['kbReleaseNotes'],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('top level, single filter, multiple values', () => {
|
|
62
|
+
const flatModel = ModelsMocks.mockFrontendModelFlat();
|
|
63
|
+
const flatFilters = flatModel.options.subOptions ?? [];
|
|
64
|
+
const selected = new Map<string, string[]>([
|
|
65
|
+
['ContentTypes', ['kbReleaseNotes', 'kbFaq', 'kbHowTo']],
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
const result = createSelectionsModel(flatFilters, selected);
|
|
69
|
+
expect(result).toEqual({
|
|
70
|
+
subOptions: {
|
|
71
|
+
ContentTypes: {
|
|
72
|
+
values: ['kbReleaseNotes', 'kbFaq', 'kbHowTo'],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('top level, multiple filter, multiple values', () => {
|
|
79
|
+
const flatModel = ModelsMocks.mockFrontendModelFlat();
|
|
80
|
+
const flatFilters = flatModel.options.subOptions ?? [];
|
|
81
|
+
const selected = new Map<string, string[]>([
|
|
82
|
+
['ContentTypes', ['kbReleaseNotes', 'kbFaq']],
|
|
83
|
+
['ProductAreas', ['Marketing']],
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
const result = createSelectionsModel(flatFilters, selected);
|
|
87
|
+
expect(result).toEqual({
|
|
88
|
+
subOptions: {
|
|
89
|
+
ContentTypes: {
|
|
90
|
+
values: ['kbReleaseNotes', 'kbFaq'],
|
|
91
|
+
},
|
|
92
|
+
ProductAreas: {
|
|
93
|
+
values: ['Marketing'],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('non-existing filter', () => {
|
|
100
|
+
const flatModel = ModelsMocks.mockFrontendModelFlat();
|
|
101
|
+
const flatFilters = flatModel.options.subOptions ?? [];
|
|
102
|
+
const selected = new Map<string, string[]>([
|
|
103
|
+
['ContentTypes', ['kbReleaseNotes', 'nonExistentOption']],
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
const result = createSelectionsModel(flatFilters, selected);
|
|
107
|
+
expect(result).toEqual({
|
|
108
|
+
subOptions: {
|
|
109
|
+
ContentTypes: {
|
|
110
|
+
values: ['kbReleaseNotes'],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('no valid filters', () => {
|
|
117
|
+
const flatModel = ModelsMocks.mockFrontendModelFlat();
|
|
118
|
+
const flatFilters = flatModel.options.subOptions ?? [];
|
|
119
|
+
const selected = new Map<string, string[]>([
|
|
120
|
+
['ContentTypes', ['nonExistent1', 'nonExistent2']],
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
const result = createSelectionsModel(flatFilters, selected);
|
|
124
|
+
expect(result).toBeUndefined();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('with mixed filter structure', () => {
|
|
129
|
+
test('top level, single filter, single value', () => {
|
|
130
|
+
const frontendModel = ModelsMocks.mockFrontendModelMixed();
|
|
131
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
132
|
+
const selected = new Map<string, string[]>([['Sources', ['Jarvis']]]);
|
|
133
|
+
|
|
134
|
+
const result = createSelectionsModel(filters, selected);
|
|
135
|
+
expect(result).toEqual({
|
|
136
|
+
subOptions: {
|
|
137
|
+
Sources: {
|
|
138
|
+
values: ['Jarvis'],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('top level, multiple filters, single value', () => {
|
|
145
|
+
const frontendModel = ModelsMocks.mockFrontendModelMixed();
|
|
146
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
147
|
+
const selected = new Map<string, string[]>([['Sources', ['KnowledgeBase', 'Jarvis']]]);
|
|
148
|
+
|
|
149
|
+
const result = createSelectionsModel(filters, selected);
|
|
150
|
+
expect(result).toEqual({
|
|
151
|
+
subOptions: {
|
|
152
|
+
Sources: {
|
|
153
|
+
values: ['KnowledgeBase', 'Jarvis'],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('all levels, multiple filters, multiple values', () => {
|
|
160
|
+
const frontendModel = ModelsMocks.mockFrontendModelMixed();
|
|
161
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
162
|
+
const selected = new Map<string, string[]>([
|
|
163
|
+
['Sources', ['KnowledgeBase', 'Jarvis']],
|
|
164
|
+
['ContentTypes', ['kbReleaseNotes']],
|
|
165
|
+
['ProductAreas', ['Marketing']],
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
const result = createSelectionsModel(filters, selected);
|
|
169
|
+
expect(result).toEqual({
|
|
170
|
+
subOptions: {
|
|
171
|
+
Sources: {
|
|
172
|
+
values: ['KnowledgeBase', 'Jarvis'],
|
|
173
|
+
subOptions: {
|
|
174
|
+
KnowledgeBase: {
|
|
175
|
+
subOptions: {
|
|
176
|
+
ContentTypes: {
|
|
177
|
+
values: ['kbReleaseNotes'],
|
|
178
|
+
},
|
|
179
|
+
ProductAreas: {
|
|
180
|
+
values: ['Marketing'],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('with nested filter structure', () => {
|
|
192
|
+
test('top level, single filter, single value', () => {
|
|
193
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
194
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
195
|
+
const selected = new Map<string, string[]>([['Sources', ['KnowledgeBase']]]);
|
|
196
|
+
|
|
197
|
+
const result = createSelectionsModel(filters, selected);
|
|
198
|
+
expect(result).toEqual({
|
|
199
|
+
subOptions: {
|
|
200
|
+
Sources: {
|
|
201
|
+
values: ['KnowledgeBase'],
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('all levels, multiple filters, single value', () => {
|
|
208
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
209
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
210
|
+
const selected = new Map<string, string[]>([
|
|
211
|
+
['Sources', ['KnowledgeBase']],
|
|
212
|
+
['ContentTypes', ['kbReleaseNotes']],
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
const result = createSelectionsModel(filters, selected);
|
|
216
|
+
expect(result).toEqual({
|
|
217
|
+
subOptions: {
|
|
218
|
+
Sources: {
|
|
219
|
+
values: ['KnowledgeBase'],
|
|
220
|
+
subOptions: {
|
|
221
|
+
KnowledgeBase: {
|
|
222
|
+
subOptions: {
|
|
223
|
+
ContentTypes: {
|
|
224
|
+
values: ['kbReleaseNotes'],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('all levels, multiple filters, multiple values (with shared sub option)', () => {
|
|
235
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
236
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
237
|
+
const selected = new Map<string, string[]>([
|
|
238
|
+
['Sources', ['KnowledgeBase', 'Jarvis']],
|
|
239
|
+
['ContentTypes', ['kbReleaseNotes']],
|
|
240
|
+
]);
|
|
241
|
+
|
|
242
|
+
const result = createSelectionsModel(filters, selected);
|
|
243
|
+
expect(result).toEqual({
|
|
244
|
+
subOptions: {
|
|
245
|
+
Sources: {
|
|
246
|
+
values: ['KnowledgeBase', 'Jarvis'],
|
|
247
|
+
subOptions: {
|
|
248
|
+
KnowledgeBase: {
|
|
249
|
+
subOptions: {
|
|
250
|
+
ContentTypes: {
|
|
251
|
+
values: ['kbReleaseNotes'],
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
Jarvis: {
|
|
256
|
+
subOptions: {
|
|
257
|
+
ContentTypes: {
|
|
258
|
+
values: ['kbReleaseNotes'],
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test('all levels, multiple filters, multiple values (with mixed sub options)', () => {
|
|
269
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
270
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
271
|
+
const selected = new Map<string, string[]>([
|
|
272
|
+
['Sources', ['KnowledgeBase', 'Jarvis']],
|
|
273
|
+
['ContentTypes', ['kbReleaseNotes', 'kbFaq', 'xxx']],
|
|
274
|
+
]);
|
|
275
|
+
|
|
276
|
+
const result = createSelectionsModel(filters, selected);
|
|
277
|
+
expect(result).toEqual({
|
|
278
|
+
subOptions: {
|
|
279
|
+
Sources: {
|
|
280
|
+
values: ['KnowledgeBase', 'Jarvis'],
|
|
281
|
+
subOptions: {
|
|
282
|
+
KnowledgeBase: {
|
|
283
|
+
subOptions: {
|
|
284
|
+
ContentTypes: {
|
|
285
|
+
values: ['kbReleaseNotes', 'kbFaq'],
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
Jarvis: {
|
|
290
|
+
subOptions: {
|
|
291
|
+
ContentTypes: {
|
|
292
|
+
values: ['kbReleaseNotes', 'xxx'],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test('all levels, multiple filters, multiple values', () => {
|
|
303
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
304
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
305
|
+
const selected = new Map<string, string[]>([
|
|
306
|
+
['Sources', ['KnowledgeBase']],
|
|
307
|
+
['ProductAreas', ['Marketing', 'Marketing Pro']],
|
|
308
|
+
]);
|
|
309
|
+
|
|
310
|
+
const result = createSelectionsModel(filters, selected);
|
|
311
|
+
expect(result).toEqual({
|
|
312
|
+
subOptions: {
|
|
313
|
+
Sources: {
|
|
314
|
+
values: ['KnowledgeBase'],
|
|
315
|
+
subOptions: {
|
|
316
|
+
KnowledgeBase: {
|
|
317
|
+
subOptions: {
|
|
318
|
+
ProductAreas: {
|
|
319
|
+
values: ['Marketing', 'Marketing Pro'],
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test('all levels, multiple filters, multiple values (more values)', () => {
|
|
330
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
331
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
332
|
+
const selected = new Map<string, string[]>([
|
|
333
|
+
['Sources', ['KnowledgeBase']],
|
|
334
|
+
['ContentTypes', ['kbReleaseNotes', 'kbHowTo']],
|
|
335
|
+
['ProductAreas', ['Marketing']],
|
|
336
|
+
]);
|
|
337
|
+
|
|
338
|
+
const result = createSelectionsModel(filters, selected);
|
|
339
|
+
expect(result).toEqual({
|
|
340
|
+
subOptions: {
|
|
341
|
+
Sources: {
|
|
342
|
+
values: ['KnowledgeBase'],
|
|
343
|
+
subOptions: {
|
|
344
|
+
KnowledgeBase: {
|
|
345
|
+
subOptions: {
|
|
346
|
+
ContentTypes: {
|
|
347
|
+
values: ['kbReleaseNotes', 'kbHowTo'],
|
|
348
|
+
},
|
|
349
|
+
ProductAreas: {
|
|
350
|
+
values: ['Marketing'],
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
test('all levels, multiple filters, multiple values (more values2)', () => {
|
|
361
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
362
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
363
|
+
const selected = new Map<string, string[]>([
|
|
364
|
+
['Sources', ['KnowledgeBase', 'Jarvis']],
|
|
365
|
+
['ContentTypes', ['kbReleaseNotes', 'yyy', 'kbHowTo']],
|
|
366
|
+
['ProductAreas', ['Marketing', 'Marketing Pro']],
|
|
367
|
+
]);
|
|
368
|
+
|
|
369
|
+
const result = createSelectionsModel(filters, selected);
|
|
370
|
+
expect(result).toEqual({
|
|
371
|
+
subOptions: {
|
|
372
|
+
Sources: {
|
|
373
|
+
values: ['KnowledgeBase', 'Jarvis'],
|
|
374
|
+
subOptions: {
|
|
375
|
+
KnowledgeBase: {
|
|
376
|
+
subOptions: {
|
|
377
|
+
ContentTypes: {
|
|
378
|
+
values: ['kbReleaseNotes', 'kbHowTo'],
|
|
379
|
+
},
|
|
380
|
+
ProductAreas: {
|
|
381
|
+
values: ['Marketing', 'Marketing Pro'],
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
Jarvis: {
|
|
386
|
+
subOptions: {
|
|
387
|
+
ContentTypes: {
|
|
388
|
+
values: ['kbReleaseNotes', 'yyy'],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
describe('edge cases', () => {
|
|
400
|
+
test('should ignore non-Group type filters', () => {
|
|
401
|
+
const customFilters: Models.IOption[] = [
|
|
402
|
+
new Models.Option({
|
|
403
|
+
key: 'NotAGroup',
|
|
404
|
+
displayName: 'Not A Group',
|
|
405
|
+
type: Models.OptionType.Selectable,
|
|
406
|
+
subOptions: [
|
|
407
|
+
new Models.Option({
|
|
408
|
+
key: 'option1',
|
|
409
|
+
displayName: 'Option 1',
|
|
410
|
+
type: Models.OptionType.Selectable,
|
|
411
|
+
}),
|
|
412
|
+
],
|
|
413
|
+
}),
|
|
414
|
+
];
|
|
415
|
+
const selected = new Map<string, string[]>([['NotAGroup', ['option1']]]);
|
|
416
|
+
|
|
417
|
+
const result = createSelectionsModel(customFilters, selected);
|
|
418
|
+
|
|
419
|
+
expect(result).toBeUndefined();
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test('should handle filters with no subOptions', () => {
|
|
423
|
+
const customFilters: Models.IOption[] = [
|
|
424
|
+
new Models.Option({
|
|
425
|
+
key: 'EmptyFilter',
|
|
426
|
+
displayName: 'Empty Filter',
|
|
427
|
+
type: Models.OptionType.Group,
|
|
428
|
+
subOptions: [],
|
|
429
|
+
}),
|
|
430
|
+
];
|
|
431
|
+
const selected = new Map<string, string[]>([['EmptyFilter', ['anything']]]);
|
|
432
|
+
|
|
433
|
+
const result = createSelectionsModel(customFilters, selected);
|
|
434
|
+
|
|
435
|
+
expect(result).toBeUndefined();
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test('should create proper Selections model structure', () => {
|
|
439
|
+
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
440
|
+
const filters = frontendModel.options.subOptions ?? [];
|
|
441
|
+
const selected = new Map<string, string[]>([
|
|
442
|
+
['Sources', ['KnowledgeBase']],
|
|
443
|
+
['ContentTypes', ['kbReleaseNotes']],
|
|
444
|
+
]);
|
|
445
|
+
|
|
446
|
+
const result = createSelectionsModel(filters, selected);
|
|
447
|
+
|
|
448
|
+
expect(result).toBeInstanceOf(Models.Selections);
|
|
449
|
+
expect(result!.subOptions).toBeDefined();
|
|
450
|
+
expect(typeof result?.subOptions).toBe('object');
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
});
|
|
@@ -16,49 +16,68 @@ export function createSelectionsModel(
|
|
|
16
16
|
subOptions: {},
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
+
return result.subOptions!;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const filterList = filters.filter(
|
|
22
23
|
x => x.type === Models.OptionType.Group && Boolean(x.subOptions?.length)
|
|
23
24
|
);
|
|
24
25
|
for (const filter of filterList) {
|
|
25
|
-
const
|
|
26
|
-
|
|
26
|
+
const selectedLeafOptions = filter.subOptions!.filter(
|
|
27
|
+
x =>
|
|
28
|
+
x.type === Models.OptionType.Selectable &&
|
|
29
|
+
selected.get(filter.key)?.includes(x.key!)
|
|
27
30
|
);
|
|
28
|
-
|
|
31
|
+
let values: string[] | undefined;
|
|
32
|
+
if (selectedLeafOptions.length) {
|
|
29
33
|
// Leaf filter: just collect selected values
|
|
30
|
-
|
|
34
|
+
values = selectedLeafOptions
|
|
31
35
|
?.map(o => o.key)
|
|
32
36
|
.filter(o => selected.get(filter.key)?.includes(o));
|
|
33
37
|
if (values?.length) {
|
|
34
|
-
ensureResult();
|
|
35
|
-
|
|
38
|
+
const subOptions = ensureResult();
|
|
39
|
+
subOptions[filter.key] = new Models.Selections({ values });
|
|
36
40
|
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
}
|
|
42
|
+
if (!selectedLeafOptions.length) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Non-leaf filter: add selected options as selectables and process sub-filters
|
|
47
|
+
const selectedNonLeafOptions = filter.subOptions!.filter(
|
|
48
|
+
x =>
|
|
49
|
+
x.type === Models.OptionType.Selectable &&
|
|
50
|
+
selected.get(filter.key)?.includes(x.key!) &&
|
|
51
|
+
Boolean(x.subOptions?.length)
|
|
52
|
+
);
|
|
53
|
+
if (!selectedNonLeafOptions.length) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// We have some sub-filters to process: collect their results
|
|
58
|
+
const subFilterResults = new Map<string, Models.Selections>();
|
|
59
|
+
for (const nonLeafOption of selectedNonLeafOptions) {
|
|
60
|
+
const subFilters = nonLeafOption.subOptions!;
|
|
61
|
+
const resultSubFilters = process(subFilters);
|
|
62
|
+
if (!resultSubFilters) {
|
|
46
63
|
continue;
|
|
47
64
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
65
|
+
subFilterResults.set(nonLeafOption.key!, resultSubFilters);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// If any sub-filters selected, ensure result and add them to the current subOptions
|
|
69
|
+
if (subFilterResults.size) {
|
|
70
|
+
const subOptions = ensureResult();
|
|
71
|
+
for (const [key, value] of subFilterResults) {
|
|
72
|
+
let subFilterSelection = subOptions[filter.key];
|
|
73
|
+
if (!subFilterSelection) {
|
|
74
|
+
subFilterSelection = new Models.Selections({});
|
|
75
|
+
subOptions[filter.key] = subFilterSelection;
|
|
76
|
+
}
|
|
77
|
+
if (!subFilterSelection.subOptions) {
|
|
78
|
+
subFilterSelection.subOptions = {};
|
|
79
|
+
}
|
|
80
|
+
subFilterSelection.subOptions![key] = value;
|
|
62
81
|
}
|
|
63
82
|
}
|
|
64
83
|
}
|
|
@@ -277,6 +277,7 @@ describe('[FilterStore]', () => {
|
|
|
277
277
|
expect(exported).toEqual({
|
|
278
278
|
subOptions: {
|
|
279
279
|
Sources: {
|
|
280
|
+
values: ['KnowledgeBase', 'Jarvis'],
|
|
280
281
|
subOptions: {
|
|
281
282
|
KnowledgeBase: {
|
|
282
283
|
subOptions: {
|
|
@@ -314,11 +315,7 @@ describe('[FilterStore]', () => {
|
|
|
314
315
|
expect(exported).toEqual({
|
|
315
316
|
subOptions: {
|
|
316
317
|
Sources: {
|
|
317
|
-
|
|
318
|
-
KnowledgeBase: {
|
|
319
|
-
subOptions: {},
|
|
320
|
-
},
|
|
321
|
-
},
|
|
318
|
+
values: ['KnowledgeBase'],
|
|
322
319
|
},
|
|
323
320
|
},
|
|
324
321
|
});
|
|
@@ -335,6 +332,7 @@ describe('[FilterStore]', () => {
|
|
|
335
332
|
expect(exported).toEqual({
|
|
336
333
|
subOptions: {
|
|
337
334
|
Sources: {
|
|
335
|
+
values: ['KnowledgeBase'],
|
|
338
336
|
subOptions: {
|
|
339
337
|
KnowledgeBase: {
|
|
340
338
|
subOptions: {
|
|
@@ -359,6 +357,7 @@ describe('[FilterStore]', () => {
|
|
|
359
357
|
expect(exported).toEqual({
|
|
360
358
|
subOptions: {
|
|
361
359
|
Sources: {
|
|
360
|
+
values: ['KnowledgeBase', 'Jarvis'],
|
|
362
361
|
subOptions: {
|
|
363
362
|
KnowledgeBase: {
|
|
364
363
|
subOptions: {
|