@cdc/dashboard 4.25.10 → 4.25.11
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/dist/{cdcdashboard-fce76882.es.js → cdcdashboard-BnB1QM5d.es.js} +6 -13
- package/dist/{cdcdashboard-c55ac1ea.es.js → cdcdashboard-D6CG2-Hb.es.js} +5 -12
- package/dist/{cdcdashboard-31a33da1.es.js → cdcdashboard-MXgURbdZ.es.js} +6 -13
- package/dist/{cdcdashboard-1a1724a1.es.js → cdcdashboard-dgT_1dIT.es.js} +136 -151
- package/dist/cdcdashboard.js +48574 -46414
- package/examples/api-test/categories.json +18 -0
- package/examples/api-test/chart-data.json +602 -0
- package/examples/api-test/topics.json +47 -0
- package/examples/api-test/years.json +22 -0
- package/examples/markup-axis-label.json +4167 -0
- package/examples/private/DEV-10538.json +407 -0
- package/examples/private/DEV-11405.json +39112 -0
- package/examples/private/big-dashboard.json +39095 -39077
- package/examples/private/clade-2.json +430 -0
- package/examples/private/delete.json +32919 -0
- package/examples/private/diabetes.json +546 -196
- package/examples/private/markup-footer/mortality-deaths-footnotes-age.csv +3 -0
- package/examples/private/mpox.json +38128 -0
- package/examples/private/reset.json +32920 -0
- package/examples/test-api-filter-reset.json +132 -0
- package/index.html +2 -2
- package/package.json +9 -10
- package/src/CdcDashboardComponent.tsx +17 -8
- package/src/DashboardContext.tsx +3 -1
- package/src/_stories/Dashboard.stories.tsx +17 -0
- package/src/_stories/_mock/custom-order-new-values.json +116 -0
- package/src/components/DashboardFilters/DashboardFilters.tsx +34 -20
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +29 -12
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +77 -111
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +51 -51
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +120 -24
- package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +62 -3
- package/src/components/DataDesignerModal.tsx +12 -5
- package/src/components/Header/Header.tsx +10 -9
- package/src/components/Toggle/Toggle.tsx +48 -48
- package/src/components/VisualizationRow.tsx +4 -3
- package/src/helpers/addValuesToDashboardFilters.ts +29 -4
- package/src/helpers/apiFilterHelpers.ts +26 -2
- package/src/helpers/filterData.ts +52 -7
- package/src/helpers/filterResetHelpers.ts +102 -0
- package/src/helpers/getVizConfig.ts +2 -2
- package/src/helpers/loadAPIFilters.ts +109 -99
- package/src/helpers/tests/filterResetHelpers.test.ts +532 -0
- package/src/index.tsx +1 -0
- package/src/scss/editor-panel.scss +3 -431
- package/src/scss/main.scss +1 -24
- package/src/store/errorMessage/errorMessage.reducer.ts +1 -1
- package/src/types/DashboardFilters.ts +9 -8
- package/examples/private/burden_toolkit_mortality_diabetes_attributable_deaths_data.csv +0 -14041
- package/examples/private/burden_toolkit_mortality_diabetes_attributable_deaths_per_100000_data.csv +0 -14041
- package/examples/private/burden_toolkit_mortality_qaly_data.csv +0 -18721
- package/examples/private/burden_toolkit_mortality_yll_data.csv +0 -18721
- package/src/helpers/getAutoLoadVisualization.ts +0 -11
- package/src/scss/mixins.scss +0 -47
- package/src/scss/variables.scss +0 -5
- /package/dist/{cdcdashboard-548642e6.es.js → cdcdashboard-Ct2SB0vL.es.js} +0 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { getFilterResetValue, resetFilterToValue, clearChildFilterDropdowns } from '../filterResetHelpers'
|
|
3
|
+
import { SharedFilter } from '../../types/SharedFilter'
|
|
4
|
+
import { APIFilterDropdowns } from '../../components/DashboardFilters'
|
|
5
|
+
import { FILTER_STYLE } from '../../types/FilterStyles'
|
|
6
|
+
import _ from 'lodash'
|
|
7
|
+
|
|
8
|
+
describe('getFilterResetValue', () => {
|
|
9
|
+
const mockAPIFilterDropdowns: APIFilterDropdowns = {
|
|
10
|
+
'api.example.com/filter1': [
|
|
11
|
+
{ value: 'option1', text: 'Option 1' },
|
|
12
|
+
{ value: 'option2', text: 'Option 2' }
|
|
13
|
+
],
|
|
14
|
+
'api.example.com/filter2': []
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('when forceEmpty is true', () => {
|
|
18
|
+
it('should return empty string for API filters without resetLabel', () => {
|
|
19
|
+
const filter: SharedFilter = {
|
|
20
|
+
key: 'testFilter',
|
|
21
|
+
apiFilter: {
|
|
22
|
+
apiEndpoint: 'api.example.com/filter1',
|
|
23
|
+
valueSelector: 'value',
|
|
24
|
+
textSelector: 'text'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, true)
|
|
29
|
+
expect(result).toBe('')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should return empty string for API filters with resetLabel', () => {
|
|
33
|
+
const filter: SharedFilter = {
|
|
34
|
+
key: 'testFilter',
|
|
35
|
+
resetLabel: 'Select One',
|
|
36
|
+
apiFilter: {
|
|
37
|
+
apiEndpoint: 'api.example.com/filter1',
|
|
38
|
+
valueSelector: 'value',
|
|
39
|
+
textSelector: 'text'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, true)
|
|
44
|
+
expect(result).toBe('')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should return empty string for data filters with resetLabel', () => {
|
|
48
|
+
const filter: SharedFilter = {
|
|
49
|
+
key: 'testFilter',
|
|
50
|
+
resetLabel: 'Select One',
|
|
51
|
+
values: ['value1', 'value2']
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, true)
|
|
55
|
+
expect(result).toBe('')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should return undefined for data filters without resetLabel', () => {
|
|
59
|
+
const filter: SharedFilter = {
|
|
60
|
+
key: 'testFilter',
|
|
61
|
+
values: ['value1', 'value2']
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, true)
|
|
65
|
+
expect(result).toBe('')
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
describe('when forceEmpty is false', () => {
|
|
70
|
+
it('should return defaultValue if it exists', () => {
|
|
71
|
+
const filter: SharedFilter = {
|
|
72
|
+
key: 'testFilter',
|
|
73
|
+
defaultValue: 'defaultVal',
|
|
74
|
+
resetLabel: 'Select One',
|
|
75
|
+
apiFilter: {
|
|
76
|
+
apiEndpoint: 'api.example.com/filter1',
|
|
77
|
+
valueSelector: 'value',
|
|
78
|
+
textSelector: 'text'
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, false)
|
|
83
|
+
expect(result).toBe('defaultVal')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should return empty string if resetLabel exists (no defaultValue)', () => {
|
|
87
|
+
const filter: SharedFilter = {
|
|
88
|
+
key: 'testFilter',
|
|
89
|
+
resetLabel: 'Select One',
|
|
90
|
+
apiFilter: {
|
|
91
|
+
apiEndpoint: 'api.example.com/filter1',
|
|
92
|
+
valueSelector: 'value',
|
|
93
|
+
textSelector: 'text'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, false)
|
|
98
|
+
expect(result).toBe('')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('should return first API option if no defaultValue or resetLabel', () => {
|
|
102
|
+
const filter: SharedFilter = {
|
|
103
|
+
key: 'testFilter',
|
|
104
|
+
apiFilter: {
|
|
105
|
+
apiEndpoint: 'api.example.com/filter1',
|
|
106
|
+
valueSelector: 'value',
|
|
107
|
+
textSelector: 'text'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, false)
|
|
112
|
+
expect(result).toBe('option1')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('should return undefined if API filter has no options', () => {
|
|
116
|
+
const filter: SharedFilter = {
|
|
117
|
+
key: 'testFilter',
|
|
118
|
+
apiFilter: {
|
|
119
|
+
apiEndpoint: 'api.example.com/filter2',
|
|
120
|
+
valueSelector: 'value',
|
|
121
|
+
textSelector: 'text'
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, false)
|
|
126
|
+
expect(result).toBeUndefined()
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('should return undefined if no API filter, defaultValue, or resetLabel', () => {
|
|
130
|
+
const filter: SharedFilter = {
|
|
131
|
+
key: 'testFilter',
|
|
132
|
+
values: ['value1', 'value2']
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const result = getFilterResetValue(filter, mockAPIFilterDropdowns, false)
|
|
136
|
+
expect(result).toBeUndefined()
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
describe('resetFilterToValue', () => {
|
|
142
|
+
const mockAPIFilterDropdowns: APIFilterDropdowns = {
|
|
143
|
+
'api.example.com/nested': [
|
|
144
|
+
{
|
|
145
|
+
value: 'group1',
|
|
146
|
+
text: 'Group 1',
|
|
147
|
+
subOptions: [
|
|
148
|
+
{ value: 'sub1', text: 'Sub 1' },
|
|
149
|
+
{ value: 'sub2', text: 'Sub 2' }
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
value: 'group2',
|
|
154
|
+
text: 'Group 2',
|
|
155
|
+
subOptions: [{ value: 'sub3', text: 'Sub 3' }]
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
describe('multi-select filters', () => {
|
|
161
|
+
it('should reset to array with single value when resetValue is provided', () => {
|
|
162
|
+
const filter: SharedFilter = {
|
|
163
|
+
key: 'multiFilter',
|
|
164
|
+
filterStyle: FILTER_STYLE.multiSelect,
|
|
165
|
+
active: ['value1', 'value2'],
|
|
166
|
+
queuedActive: ['value3']
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
resetFilterToValue(filter, 'value1', mockAPIFilterDropdowns)
|
|
170
|
+
|
|
171
|
+
expect(filter.active).toEqual(['value1'])
|
|
172
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('should reset to empty array when resetValue is undefined', () => {
|
|
176
|
+
const filter: SharedFilter = {
|
|
177
|
+
key: 'multiFilter',
|
|
178
|
+
filterStyle: FILTER_STYLE.multiSelect,
|
|
179
|
+
active: ['value1', 'value2']
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
resetFilterToValue(filter, undefined, mockAPIFilterDropdowns)
|
|
183
|
+
|
|
184
|
+
expect(filter.active).toEqual([])
|
|
185
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('should reset to empty array when resetValue is empty string', () => {
|
|
189
|
+
const filter: SharedFilter = {
|
|
190
|
+
key: 'multiFilter',
|
|
191
|
+
filterStyle: FILTER_STYLE.multiSelect,
|
|
192
|
+
active: ['value1', 'value2']
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
resetFilterToValue(filter, '', mockAPIFilterDropdowns)
|
|
196
|
+
|
|
197
|
+
expect(filter.active).toEqual([])
|
|
198
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
describe('nested dropdown filters', () => {
|
|
203
|
+
it('should clear both group and subgroup when resetValue is empty string', () => {
|
|
204
|
+
const filter: SharedFilter = {
|
|
205
|
+
key: 'nestedFilter',
|
|
206
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
207
|
+
active: 'group1',
|
|
208
|
+
subGrouping: {
|
|
209
|
+
active: 'sub1'
|
|
210
|
+
},
|
|
211
|
+
apiFilter: {
|
|
212
|
+
apiEndpoint: 'api.example.com/nested',
|
|
213
|
+
valueSelector: 'value',
|
|
214
|
+
textSelector: 'text'
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
resetFilterToValue(filter, '', mockAPIFilterDropdowns)
|
|
219
|
+
|
|
220
|
+
expect(filter.active).toBe('')
|
|
221
|
+
expect(filter.subGrouping.active).toBe('')
|
|
222
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('should clear both group and subgroup when resetValue is undefined', () => {
|
|
226
|
+
const filter: SharedFilter = {
|
|
227
|
+
key: 'nestedFilter',
|
|
228
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
229
|
+
active: 'group1',
|
|
230
|
+
subGrouping: {
|
|
231
|
+
active: 'sub1'
|
|
232
|
+
},
|
|
233
|
+
apiFilter: {
|
|
234
|
+
apiEndpoint: 'api.example.com/nested',
|
|
235
|
+
valueSelector: 'value',
|
|
236
|
+
textSelector: 'text'
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
resetFilterToValue(filter, undefined, mockAPIFilterDropdowns)
|
|
241
|
+
|
|
242
|
+
expect(filter.active).toBe('')
|
|
243
|
+
expect(filter.subGrouping.active).toBe('')
|
|
244
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('should set to resetValue and first suboption when resetValue is provided', () => {
|
|
248
|
+
const filter: SharedFilter = {
|
|
249
|
+
key: 'nestedFilter',
|
|
250
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
251
|
+
active: 'oldValue',
|
|
252
|
+
subGrouping: {
|
|
253
|
+
active: 'oldSub'
|
|
254
|
+
},
|
|
255
|
+
apiFilter: {
|
|
256
|
+
apiEndpoint: 'api.example.com/nested',
|
|
257
|
+
valueSelector: 'value',
|
|
258
|
+
textSelector: 'text'
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
resetFilterToValue(filter, 'group2', mockAPIFilterDropdowns)
|
|
263
|
+
|
|
264
|
+
expect(filter.active).toBe('group2')
|
|
265
|
+
expect(filter.subGrouping.active).toBe('sub3')
|
|
266
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('should fallback to first option when no resetValue and options exist', () => {
|
|
270
|
+
const filter: SharedFilter = {
|
|
271
|
+
key: 'nestedFilter',
|
|
272
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
273
|
+
active: 'oldValue',
|
|
274
|
+
subGrouping: {
|
|
275
|
+
active: 'oldSub'
|
|
276
|
+
},
|
|
277
|
+
apiFilter: {
|
|
278
|
+
apiEndpoint: 'api.example.com/nested',
|
|
279
|
+
valueSelector: 'value',
|
|
280
|
+
textSelector: 'text'
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
resetFilterToValue(filter, undefined, mockAPIFilterDropdowns)
|
|
285
|
+
|
|
286
|
+
expect(filter.active).toBe('')
|
|
287
|
+
expect(filter.subGrouping.active).toBe('')
|
|
288
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
describe('standard dropdown filters', () => {
|
|
293
|
+
it('should reset to provided resetValue', () => {
|
|
294
|
+
const filter: SharedFilter = {
|
|
295
|
+
key: 'standardFilter',
|
|
296
|
+
active: 'oldValue',
|
|
297
|
+
queuedActive: 'queuedValue'
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
resetFilterToValue(filter, 'newValue', mockAPIFilterDropdowns)
|
|
301
|
+
|
|
302
|
+
expect(filter.active).toBe('newValue')
|
|
303
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('should reset to empty string when resetValue is empty string', () => {
|
|
307
|
+
const filter: SharedFilter = {
|
|
308
|
+
key: 'standardFilter',
|
|
309
|
+
active: 'oldValue'
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
resetFilterToValue(filter, '', mockAPIFilterDropdowns)
|
|
313
|
+
|
|
314
|
+
expect(filter.active).toBe('')
|
|
315
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it('should reset to undefined when resetValue is undefined', () => {
|
|
319
|
+
const filter: SharedFilter = {
|
|
320
|
+
key: 'standardFilter',
|
|
321
|
+
active: 'oldValue'
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
resetFilterToValue(filter, undefined, mockAPIFilterDropdowns)
|
|
325
|
+
|
|
326
|
+
expect(filter.active).toBeUndefined()
|
|
327
|
+
expect(filter.queuedActive).toBeUndefined()
|
|
328
|
+
})
|
|
329
|
+
})
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
describe('clearChildFilterDropdowns', () => {
|
|
333
|
+
it('should clear dropdowns for filters with parents', () => {
|
|
334
|
+
const sharedFilters: SharedFilter[] = [
|
|
335
|
+
{
|
|
336
|
+
key: 'parentFilter',
|
|
337
|
+
apiFilter: {
|
|
338
|
+
apiEndpoint: 'api.example.com/parent',
|
|
339
|
+
valueSelector: 'value',
|
|
340
|
+
textSelector: 'text'
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
key: 'childFilter',
|
|
345
|
+
parents: ['parentFilter'],
|
|
346
|
+
apiFilter: {
|
|
347
|
+
apiEndpoint: 'api.example.com/child',
|
|
348
|
+
valueSelector: 'value',
|
|
349
|
+
textSelector: 'text'
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
355
|
+
'api.example.com/parent': [
|
|
356
|
+
{ value: 'parent1', text: 'Parent 1' },
|
|
357
|
+
{ value: 'parent2', text: 'Parent 2' }
|
|
358
|
+
],
|
|
359
|
+
'api.example.com/child': [
|
|
360
|
+
{ value: 'child1', text: 'Child 1' },
|
|
361
|
+
{ value: 'child2', text: 'Child 2' }
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const result = clearChildFilterDropdowns(sharedFilters, apiFilterDropdowns)
|
|
366
|
+
|
|
367
|
+
// Parent filter dropdown should remain unchanged
|
|
368
|
+
expect(result['api.example.com/parent']).toEqual([
|
|
369
|
+
{ value: 'parent1', text: 'Parent 1' },
|
|
370
|
+
{ value: 'parent2', text: 'Parent 2' }
|
|
371
|
+
])
|
|
372
|
+
|
|
373
|
+
// Child filter dropdown should be cleared to empty array
|
|
374
|
+
expect(result['api.example.com/child']).toEqual([])
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('should not clear dropdowns for filters without parents', () => {
|
|
378
|
+
const sharedFilters: SharedFilter[] = [
|
|
379
|
+
{
|
|
380
|
+
key: 'filter1',
|
|
381
|
+
apiFilter: {
|
|
382
|
+
apiEndpoint: 'api.example.com/filter1',
|
|
383
|
+
valueSelector: 'value',
|
|
384
|
+
textSelector: 'text'
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
key: 'filter2',
|
|
389
|
+
apiFilter: {
|
|
390
|
+
apiEndpoint: 'api.example.com/filter2',
|
|
391
|
+
valueSelector: 'value',
|
|
392
|
+
textSelector: 'text'
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
]
|
|
396
|
+
|
|
397
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
398
|
+
'api.example.com/filter1': [{ value: 'val1', text: 'Value 1' }],
|
|
399
|
+
'api.example.com/filter2': [{ value: 'val2', text: 'Value 2' }]
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const result = clearChildFilterDropdowns(sharedFilters, apiFilterDropdowns)
|
|
403
|
+
|
|
404
|
+
// Both should remain unchanged since neither has parents
|
|
405
|
+
expect(result['api.example.com/filter1']).toEqual([{ value: 'val1', text: 'Value 1' }])
|
|
406
|
+
expect(result['api.example.com/filter2']).toEqual([{ value: 'val2', text: 'Value 2' }])
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
it('should handle filters with empty parents array', () => {
|
|
410
|
+
const sharedFilters: SharedFilter[] = [
|
|
411
|
+
{
|
|
412
|
+
key: 'filter1',
|
|
413
|
+
parents: [],
|
|
414
|
+
apiFilter: {
|
|
415
|
+
apiEndpoint: 'api.example.com/filter1',
|
|
416
|
+
valueSelector: 'value',
|
|
417
|
+
textSelector: 'text'
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
]
|
|
421
|
+
|
|
422
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
423
|
+
'api.example.com/filter1': [{ value: 'val1', text: 'Value 1' }]
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const result = clearChildFilterDropdowns(sharedFilters, apiFilterDropdowns)
|
|
427
|
+
|
|
428
|
+
// Should remain unchanged since parents array is empty
|
|
429
|
+
expect(result['api.example.com/filter1']).toEqual([{ value: 'val1', text: 'Value 1' }])
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
it('should handle mixed filters with and without parents', () => {
|
|
433
|
+
const sharedFilters: SharedFilter[] = [
|
|
434
|
+
{
|
|
435
|
+
key: 'parent',
|
|
436
|
+
apiFilter: {
|
|
437
|
+
apiEndpoint: 'api.example.com/parent',
|
|
438
|
+
valueSelector: 'value',
|
|
439
|
+
textSelector: 'text'
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
key: 'child1',
|
|
444
|
+
parents: ['parent'],
|
|
445
|
+
apiFilter: {
|
|
446
|
+
apiEndpoint: 'api.example.com/child1',
|
|
447
|
+
valueSelector: 'value',
|
|
448
|
+
textSelector: 'text'
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
key: 'independent',
|
|
453
|
+
apiFilter: {
|
|
454
|
+
apiEndpoint: 'api.example.com/independent',
|
|
455
|
+
valueSelector: 'value',
|
|
456
|
+
textSelector: 'text'
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
key: 'child2',
|
|
461
|
+
parents: ['child1'],
|
|
462
|
+
apiFilter: {
|
|
463
|
+
apiEndpoint: 'api.example.com/child2',
|
|
464
|
+
valueSelector: 'value',
|
|
465
|
+
textSelector: 'text'
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
|
|
470
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
471
|
+
'api.example.com/parent': [{ value: 'p1', text: 'Parent 1' }],
|
|
472
|
+
'api.example.com/child1': [{ value: 'c1', text: 'Child 1' }],
|
|
473
|
+
'api.example.com/independent': [{ value: 'i1', text: 'Independent 1' }],
|
|
474
|
+
'api.example.com/child2': [{ value: 'c2', text: 'Child 2' }]
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const result = clearChildFilterDropdowns(sharedFilters, apiFilterDropdowns)
|
|
478
|
+
|
|
479
|
+
// Parent and independent should remain unchanged
|
|
480
|
+
expect(result['api.example.com/parent']).toEqual([{ value: 'p1', text: 'Parent 1' }])
|
|
481
|
+
expect(result['api.example.com/independent']).toEqual([{ value: 'i1', text: 'Independent 1' }])
|
|
482
|
+
|
|
483
|
+
// Children should be cleared
|
|
484
|
+
expect(result['api.example.com/child1']).toEqual([])
|
|
485
|
+
expect(result['api.example.com/child2']).toEqual([])
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
it('should not mutate original apiFilterDropdowns', () => {
|
|
489
|
+
const sharedFilters: SharedFilter[] = [
|
|
490
|
+
{
|
|
491
|
+
key: 'child',
|
|
492
|
+
parents: ['parent'],
|
|
493
|
+
apiFilter: {
|
|
494
|
+
apiEndpoint: 'api.example.com/child',
|
|
495
|
+
valueSelector: 'value',
|
|
496
|
+
textSelector: 'text'
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
]
|
|
500
|
+
|
|
501
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
502
|
+
'api.example.com/child': [{ value: 'child1', text: 'Child 1' }]
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const originalDropdowns = _.cloneDeep(apiFilterDropdowns)
|
|
506
|
+
const result = clearChildFilterDropdowns(sharedFilters, apiFilterDropdowns)
|
|
507
|
+
|
|
508
|
+
// Original should remain unchanged
|
|
509
|
+
expect(apiFilterDropdowns).toEqual(originalDropdowns)
|
|
510
|
+
// Result should have cleared child
|
|
511
|
+
expect(result['api.example.com/child']).toEqual([])
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
it('should handle filters without apiFilter', () => {
|
|
515
|
+
const sharedFilters: SharedFilter[] = [
|
|
516
|
+
{
|
|
517
|
+
key: 'dataFilter',
|
|
518
|
+
parents: ['parent'],
|
|
519
|
+
values: ['value1', 'value2']
|
|
520
|
+
}
|
|
521
|
+
]
|
|
522
|
+
|
|
523
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
524
|
+
'api.example.com/other': [{ value: 'val1', text: 'Value 1' }]
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const result = clearChildFilterDropdowns(sharedFilters, apiFilterDropdowns)
|
|
528
|
+
|
|
529
|
+
// Should remain unchanged since dataFilter doesn't have apiFilter
|
|
530
|
+
expect(result).toEqual(apiFilterDropdowns)
|
|
531
|
+
})
|
|
532
|
+
})
|