@servicetitan/titan-chatbot-api 4.3.3 → 4.4.0
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 +12 -0
- package/dist/api-client/models/__mocks__/models.mock.d.ts.map +1 -1
- package/dist/api-client/models/__mocks__/models.mock.js +9 -7
- package/dist/api-client/models/__mocks__/models.mock.js.map +1 -1
- package/dist/api-client/utils/model-utils.d.ts +1 -1
- package/dist/api-client/utils/model-utils.d.ts.map +1 -1
- package/dist/api-client/utils/model-utils.js +2 -2
- package/dist/api-client/utils/model-utils.js.map +1 -1
- package/dist/stores/__tests__/chatbot-ui.store.test.js +1 -1
- package/dist/stores/__tests__/filter.store.test.js +49 -40
- package/dist/stores/__tests__/filter.store.test.js.map +1 -1
- package/dist/stores/chatbot-ui.store.d.ts +3 -3
- package/dist/stores/chatbot-ui.store.d.ts.map +1 -1
- package/dist/stores/chatbot-ui.store.js.map +1 -1
- package/dist/stores/filter.store.d.ts +50 -17
- package/dist/stores/filter.store.d.ts.map +1 -1
- package/dist/stores/filter.store.js +255 -179
- package/dist/stores/filter.store.js.map +1 -1
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js.map +1 -1
- package/package.json +3 -3
- package/src/api-client/models/__mocks__/models.mock.ts +10 -6
- package/src/api-client/utils/model-utils.ts +3 -3
- package/src/stores/__tests__/chatbot-ui.store.test.ts +1 -1
- package/src/stores/__tests__/filter.store.test.ts +63 -45
- package/src/stores/chatbot-ui.store.ts +3 -3
- package/src/stores/filter.store.ts +250 -187
- package/src/stores/index.ts +1 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,17 +3,43 @@ import { action, makeObservable, observable } from 'mobx';
|
|
|
3
3
|
import { nanoid } from 'nanoid';
|
|
4
4
|
import { Models, ModelsUtils } from '../api-client';
|
|
5
5
|
|
|
6
|
-
interface
|
|
7
|
-
uid
|
|
8
|
-
|
|
6
|
+
export interface IUiFilterOption {
|
|
7
|
+
uid: string;
|
|
8
|
+
parentUids: string[];
|
|
9
|
+
key: string;
|
|
10
|
+
displayName?: string | undefined;
|
|
11
|
+
type: Models.OptionType;
|
|
12
|
+
subOptions?: IUiFilterOption[] | undefined;
|
|
9
13
|
}
|
|
10
14
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
export interface IFilterStore {
|
|
16
|
+
selected: Map<string, string[]>;
|
|
17
|
+
filters: IUiFilterOption[];
|
|
18
|
+
initFilters(model: Models.IFrontendModel): void;
|
|
19
|
+
isOptionChecked(filterKey: string, optionKey: string): boolean;
|
|
20
|
+
isOptionDisabled(filterKey: string, optionKey: string): boolean;
|
|
21
|
+
getFilterOptions(filterKey: string): IUiFilterOption[];
|
|
22
|
+
selectOption(filterKey: string, optionKey: string): void;
|
|
23
|
+
selectAll(filterKey: string): void;
|
|
24
|
+
deselectOption(filterKey: string, optionKey: string): void;
|
|
25
|
+
deselectAll(filterKey: string): void;
|
|
26
|
+
getFilterLabel(key: string): string;
|
|
27
|
+
export(): Models.Selections | undefined;
|
|
28
|
+
}
|
|
14
29
|
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
export class FilterStore implements IFilterStore {
|
|
31
|
+
/**
|
|
32
|
+
* Selected items map: filter key -> selectable keys
|
|
33
|
+
*/
|
|
34
|
+
@observable selected = new Map<string, string[]>();
|
|
35
|
+
/**
|
|
36
|
+
* Available filters with their selectable options (flattened and merged)
|
|
37
|
+
*/
|
|
38
|
+
@observable filters: IUiFilterOption[] = [];
|
|
39
|
+
private localFilters: IUiFilterOption[] = [];
|
|
40
|
+
private originalFilters: Models.IOption[] = [];
|
|
41
|
+
private mapUidToOption = new Map<string, IUiFilterOption>();
|
|
42
|
+
private mapUidToParentUid = new Map<string, string | undefined>();
|
|
17
43
|
|
|
18
44
|
constructor() {
|
|
19
45
|
makeObservable(this);
|
|
@@ -21,56 +47,108 @@ export class FilterStore {
|
|
|
21
47
|
|
|
22
48
|
@action
|
|
23
49
|
initFilters(model: Models.IFrontendModel) {
|
|
24
|
-
const setUids = (o?: IOption[]) => {
|
|
25
|
-
o?.forEach(x => {
|
|
26
|
-
x.uid = nanoid();
|
|
27
|
-
setUids(x.subOptions as IOption[]);
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
this.model = model;
|
|
32
50
|
this.originalFilters = cloneDeep(
|
|
33
|
-
model
|
|
51
|
+
model?.options.subOptions?.filter(x => x.type === Models.OptionType.Group) ?? []
|
|
34
52
|
);
|
|
35
|
-
|
|
36
|
-
this.filters = this.originalFilters;
|
|
53
|
+
this.initLocalFilters(this.originalFilters as IUiFilterOption[]);
|
|
37
54
|
}
|
|
38
55
|
|
|
56
|
+
isOptionChecked = (filterKey: string, optionKey: string): boolean => {
|
|
57
|
+
const selectedOptions = this.selected.get(filterKey);
|
|
58
|
+
if (!selectedOptions) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return selectedOptions.includes(optionKey);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
isOptionDisabled = (filterKey: string, optionKey: string): boolean => {
|
|
65
|
+
const filter = this.getFilterByKey(filterKey);
|
|
66
|
+
const option = filter?.subOptions?.find(o => o.key === optionKey);
|
|
67
|
+
if (!option) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
// check any parent selectable is selected
|
|
71
|
+
for (const optionFilter of option.parentUids
|
|
72
|
+
.map(uid => this.mapUidToOption.get(uid))
|
|
73
|
+
.filter(Boolean)) {
|
|
74
|
+
if (!optionFilter?.parentUids?.length) {
|
|
75
|
+
// no parent -> root filter -> so not disabled
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// Check all parent filters
|
|
79
|
+
for (const parentUid of optionFilter.parentUids) {
|
|
80
|
+
const parentOption = this.mapUidToOption.get(parentUid);
|
|
81
|
+
if (!parentOption) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const parentFilter = this.getOptionFilter(parentOption);
|
|
85
|
+
if (!parentFilter) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const isParentSelected = this.isOptionChecked(parentFilter.key, parentOption.key);
|
|
89
|
+
if (isParentSelected) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
getFilterOptions = (filterKey: string): IUiFilterOption[] => {
|
|
98
|
+
const filter = this.getFilterByKey(filterKey);
|
|
99
|
+
if (!filter?.subOptions) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
return filter.subOptions.filter(x => x.type === Models.OptionType.Selectable);
|
|
103
|
+
};
|
|
104
|
+
|
|
39
105
|
@action
|
|
40
106
|
selectOption = (filterKey: string, optionKey: string) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (!
|
|
44
|
-
|
|
107
|
+
this.assertFilterKeyExists(filterKey);
|
|
108
|
+
this.assertOptionKeyExists(filterKey, optionKey);
|
|
109
|
+
if (!this.selected.has(filterKey)) {
|
|
110
|
+
this.selected.set(filterKey, []);
|
|
45
111
|
}
|
|
46
|
-
|
|
47
|
-
|
|
112
|
+
const selectedOptions = this.selected.get(filterKey)!;
|
|
113
|
+
if (selectedOptions.includes(optionKey)) {
|
|
114
|
+
return;
|
|
48
115
|
}
|
|
49
|
-
this.
|
|
50
|
-
this.addSubSequentFilters(filterKey);
|
|
116
|
+
this.selected.set(filterKey, [...selectedOptions, optionKey]);
|
|
51
117
|
};
|
|
52
118
|
|
|
53
119
|
@action
|
|
54
120
|
selectAll = (filterKey: string) => {
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
121
|
+
this.assertFilterKeyExists(filterKey);
|
|
122
|
+
const filter = this.getFilterByKey(filterKey);
|
|
123
|
+
if (!filter?.subOptions) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const selectableOptions = filter.subOptions.filter(
|
|
127
|
+
x => x.type === Models.OptionType.Selectable
|
|
128
|
+
);
|
|
129
|
+
this.selected.set(
|
|
130
|
+
filterKey,
|
|
131
|
+
selectableOptions.map(o => o.key)
|
|
132
|
+
);
|
|
57
133
|
};
|
|
58
134
|
|
|
59
135
|
@action
|
|
60
136
|
deselectOption = (filterKey: string, optionKey: string) => {
|
|
61
|
-
this.
|
|
62
|
-
|
|
137
|
+
this.assertFilterKeyExists(filterKey);
|
|
138
|
+
this.assertOptionKeyExists(filterKey, optionKey);
|
|
139
|
+
const selectedOptions = this.selected.get(filterKey) ?? [];
|
|
140
|
+
this.selected.set(
|
|
141
|
+
filterKey,
|
|
142
|
+
selectedOptions.filter(o => o !== optionKey)
|
|
63
143
|
);
|
|
64
|
-
this.
|
|
65
|
-
this.removeSubSequentFilters(filterKey);
|
|
66
|
-
this.addSubSequentFilters(filterKey);
|
|
144
|
+
this.uncheckDisabledOptions();
|
|
67
145
|
};
|
|
68
146
|
|
|
69
147
|
@action
|
|
70
148
|
deselectAll = (filterKey: string) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
149
|
+
this.assertFilterKeyExists(filterKey);
|
|
150
|
+
this.selected.set(filterKey, []);
|
|
151
|
+
this.uncheckDisabledOptions();
|
|
74
152
|
};
|
|
75
153
|
|
|
76
154
|
getFilterLabel = (key: string) => {
|
|
@@ -83,180 +161,165 @@ export class FilterStore {
|
|
|
83
161
|
};
|
|
84
162
|
|
|
85
163
|
export(): Models.Selections | undefined {
|
|
86
|
-
return ModelsUtils.createSelectionsModel(this.originalFilters, this.
|
|
164
|
+
return ModelsUtils.createSelectionsModel(this.originalFilters, this.selected);
|
|
87
165
|
}
|
|
88
166
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.filters = this.filters.filter(x => !subFilters.some(f => f.key === x.key));
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
@action
|
|
97
|
-
private addSubSequentFilters = (filterKey: string) => {
|
|
98
|
-
const filter = this.getExistingFilterByKey(filterKey);
|
|
99
|
-
if (!filter.subOptions) {
|
|
100
|
-
return;
|
|
167
|
+
private assertFilterKeyExists = (filterKey: string) => {
|
|
168
|
+
const filter = this.getFilterByKey(filterKey);
|
|
169
|
+
if (!filter) {
|
|
170
|
+
throw new Error(`Filter with key "${filterKey}" does not exist.`);
|
|
101
171
|
}
|
|
172
|
+
};
|
|
102
173
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const allSubFilters: IOption[] =
|
|
111
|
-
filterSelectedOptions.flatMap<IOption>(selectedOption => {
|
|
112
|
-
// For each selected option, collect its sub-filters
|
|
113
|
-
const subFilters: IOption[] = [];
|
|
114
|
-
for (const subFilter of selectedOption.subOptions ?? []) {
|
|
115
|
-
const originalFilter = cloneDeep(
|
|
116
|
-
this.getOriginalFilter((subFilter as IOption).uid)
|
|
117
|
-
);
|
|
118
|
-
originalFilter.parentKeys = [selectedOption.uid!];
|
|
119
|
-
subFilters.push(originalFilter);
|
|
120
|
-
}
|
|
121
|
-
return subFilters;
|
|
122
|
-
}) ?? [];
|
|
123
|
-
|
|
124
|
-
// Merge sub-filters with the same key and their options (with parent keys merging)
|
|
125
|
-
const mergedSubFilters = allSubFilters.reduce<IOption[]>((acc, subFilter) => {
|
|
126
|
-
if (!subFilter.subOptions) {
|
|
127
|
-
return acc;
|
|
128
|
-
}
|
|
129
|
-
const subfilterOptions = (subFilter.subOptions ?? []) as IOption[];
|
|
130
|
-
const subfilterParentKeys = subFilter.parentKeys;
|
|
131
|
-
|
|
132
|
-
// Merge filters with the same key and their options if they already exist
|
|
133
|
-
subfilterOptions.forEach(subfilterOption => {
|
|
134
|
-
subfilterOption.parentKeys = this.mergeParentKeys(
|
|
135
|
-
subfilterOption.parentKeys,
|
|
136
|
-
subfilterParentKeys
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Check if the filter already exists in the accumulator
|
|
141
|
-
const existingFilter = acc.find(x => x.key === subFilter.key);
|
|
142
|
-
if (!existingFilter) {
|
|
143
|
-
return [...acc, subFilter];
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Merge parent keys for the filter
|
|
147
|
-
existingFilter.parentKeys = this.mergeParentKeys(
|
|
148
|
-
existingFilter.parentKeys,
|
|
149
|
-
subfilterParentKeys
|
|
174
|
+
private assertOptionKeyExists = (filterKey: string, optionKey: string) => {
|
|
175
|
+
this.assertFilterKeyExists(filterKey);
|
|
176
|
+
const filter = this.getFilterByKey(filterKey)!;
|
|
177
|
+
const option = filter.subOptions?.find(o => o.key === optionKey);
|
|
178
|
+
if (!option) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Option with key "${optionKey}" does not exist in filter "${filterKey}".`
|
|
150
181
|
);
|
|
151
|
-
|
|
152
|
-
// Merge options for subfilters by key
|
|
153
|
-
existingFilter.subOptions = subfilterOptions.reduce(
|
|
154
|
-
(acc2, subfilterOption) => {
|
|
155
|
-
const existing = acc2.find(o => o.key === subfilterOption.key) as
|
|
156
|
-
| IOption
|
|
157
|
-
| undefined;
|
|
158
|
-
if (!existing) {
|
|
159
|
-
return [...acc2, subfilterOption];
|
|
160
|
-
}
|
|
161
|
-
existing.parentKeys = this.mergeParentKeys(
|
|
162
|
-
existing.parentKeys,
|
|
163
|
-
subfilterOption.parentKeys
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
return acc2;
|
|
167
|
-
},
|
|
168
|
-
[...(existingFilter.subOptions ?? [])]
|
|
169
|
-
) as Models.Option[];
|
|
170
|
-
return acc;
|
|
171
|
-
}, []);
|
|
172
|
-
|
|
173
|
-
// Update the filters with the merged sub-filters
|
|
174
|
-
for (const newFilter of mergedSubFilters) {
|
|
175
|
-
const existingFilterIdx = this.filters.findIndex(f => f.key === newFilter.key);
|
|
176
|
-
if (existingFilterIdx < 0) {
|
|
177
|
-
this.filters.push(newFilter);
|
|
178
|
-
} else {
|
|
179
|
-
this.filters[existingFilterIdx] = newFilter;
|
|
180
|
-
}
|
|
181
|
-
this.addSubSequentFilters(newFilter.key);
|
|
182
182
|
}
|
|
183
183
|
};
|
|
184
184
|
|
|
185
|
-
private
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return keys1;
|
|
185
|
+
private getFilterByKey = (filterKey: string): IUiFilterOption | undefined => {
|
|
186
|
+
return this.filters.find(f => f.key === filterKey);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
private getOptionFilter = (option: IUiFilterOption): IUiFilterOption | undefined => {
|
|
190
|
+
const parentUid = this.mapUidToParentUid.get(option.uid);
|
|
191
|
+
if (!parentUid) {
|
|
192
|
+
return undefined;
|
|
194
193
|
}
|
|
195
|
-
|
|
196
|
-
return Array.from(mergedKeys);
|
|
194
|
+
return this.mapUidToOption.get(parentUid);
|
|
197
195
|
};
|
|
198
196
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
for (let i = filterIdx + 1; i < this.filters.length; i++) {
|
|
205
|
-
const subFilter = this.filters[i];
|
|
206
|
-
if (!subFilter.parentKeys?.some(k => k === filterSubOptionToRemoveUid)) {
|
|
207
|
-
// If the sub-filter does not depend on the removed option, skip it
|
|
197
|
+
@action
|
|
198
|
+
private uncheckDisabledOptions = () => {
|
|
199
|
+
for (const [filterKey, selectedOptions] of this.selected.entries()) {
|
|
200
|
+
const filter = this.getFilterByKey(filterKey);
|
|
201
|
+
if (!filter) {
|
|
208
202
|
continue;
|
|
209
203
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
this.selectedOptions[subFilter.key] = this.selectedOptions[
|
|
215
|
-
subFilter.key
|
|
216
|
-
]?.filter(x => x !== o.key);
|
|
204
|
+
const validSelectedOptions = selectedOptions.filter(optionKey => {
|
|
205
|
+
const option = filter.subOptions?.find(o => o.key === optionKey);
|
|
206
|
+
if (!option) {
|
|
207
|
+
return false;
|
|
217
208
|
}
|
|
209
|
+
return !this.isOptionDisabled(filterKey, optionKey);
|
|
218
210
|
});
|
|
219
|
-
|
|
220
|
-
Boolean(o.parentKeys?.length)
|
|
221
|
-
);
|
|
211
|
+
this.selected.set(filterKey, validSelectedOptions);
|
|
222
212
|
}
|
|
223
213
|
};
|
|
224
214
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Sets unique IDs (uids) for each option and builds a parent options map that tracks parent-child relationships.
|
|
217
|
+
* @param options The list of options to process (recursive).
|
|
218
|
+
*/
|
|
219
|
+
private initLocalFilters = (options: IUiFilterOption[]) => {
|
|
220
|
+
// Set up local filters uids
|
|
221
|
+
this.localFilters = cloneDeep(options);
|
|
222
|
+
const setUids = (o?: IUiFilterOption[], parentUid?: string) => {
|
|
223
|
+
if (!o) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
o.forEach(x => {
|
|
227
|
+
x.uid = nanoid();
|
|
228
|
+
x.parentUids = parentUid ? [parentUid] : [];
|
|
229
|
+
setUids(x.subOptions, x.uid);
|
|
230
230
|
});
|
|
231
|
-
}
|
|
232
|
-
|
|
231
|
+
};
|
|
232
|
+
setUids(this.localFilters);
|
|
233
|
+
this.initLocalUiFilters(this.localFilters);
|
|
233
234
|
};
|
|
234
235
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Go through local filters and set up UI objects that will be rendered: filters and filter selectables
|
|
238
|
+
*/
|
|
239
|
+
@action
|
|
240
|
+
private initLocalUiFilters = (options: IUiFilterOption[]) => {
|
|
241
|
+
this.mapUidToOption = new Map<string, IUiFilterOption>();
|
|
242
|
+
this.mapUidToParentUid = new Map<string, string | undefined>();
|
|
243
|
+
const filtersKeyToFilter = new Map<string, IUiFilterOption>();
|
|
240
244
|
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
// Function to merge duplicate selectable options by key
|
|
246
|
+
const mergeDuplicates = (options: IUiFilterOption[]) => {
|
|
247
|
+
// Merge selectables with the same keys. Original uids will be stored in "parentUids"
|
|
248
|
+
const keyToOption = new Map<string, IUiFilterOption>();
|
|
249
|
+
for (const option of options) {
|
|
250
|
+
if (option.type !== Models.OptionType.Selectable) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (!keyToOption.has(option.key)) {
|
|
254
|
+
keyToOption.set(option.key, {
|
|
255
|
+
uid: option.uid,
|
|
256
|
+
parentUids: [],
|
|
257
|
+
key: option.key,
|
|
258
|
+
displayName: option.displayName,
|
|
259
|
+
type: option.type,
|
|
260
|
+
subOptions: [],
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
const existingOption = keyToOption.get(option.key)!;
|
|
264
|
+
existingOption.parentUids = [...existingOption.parentUids, ...option.parentUids];
|
|
265
|
+
}
|
|
266
|
+
return Array.from(keyToOption.values());
|
|
267
|
+
};
|
|
249
268
|
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
269
|
+
// Recursive flattening function
|
|
270
|
+
const flatten = (curr: IUiFilterOption, parent?: IUiFilterOption) => {
|
|
271
|
+
// Skip empty objects and none types
|
|
272
|
+
if (!curr || curr.type === Models.OptionType.None) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
// Map uid to parent uid
|
|
276
|
+
if (parent) {
|
|
277
|
+
this.mapUidToParentUid.set(curr.uid, parent.uid);
|
|
278
|
+
}
|
|
254
279
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
280
|
+
// Process selectable
|
|
281
|
+
if (curr.type === Models.OptionType.Selectable) {
|
|
282
|
+
const newOption: IUiFilterOption = {
|
|
283
|
+
uid: curr.uid,
|
|
284
|
+
parentUids: parent ? [parent.uid] : [],
|
|
285
|
+
key: curr.key,
|
|
286
|
+
displayName: curr.displayName,
|
|
287
|
+
type: curr.type,
|
|
288
|
+
};
|
|
289
|
+
this.mapUidToOption.set(newOption.uid, newOption);
|
|
290
|
+
const optionFilter = filtersKeyToFilter.get(parent!.key)!;
|
|
291
|
+
optionFilter.subOptions = [...(optionFilter.subOptions ?? []), newOption];
|
|
292
|
+
// Go into subfilters
|
|
293
|
+
for (const subOption of curr.subOptions ?? []) {
|
|
294
|
+
flatten(subOption, newOption);
|
|
295
|
+
}
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Process filter
|
|
300
|
+
if (!filtersKeyToFilter.has(curr.key)) {
|
|
301
|
+
const newFilter: IUiFilterOption = {
|
|
302
|
+
uid: curr.uid,
|
|
303
|
+
parentUids: parent ? [parent.uid] : [],
|
|
304
|
+
key: curr.key,
|
|
305
|
+
type: curr.type,
|
|
306
|
+
displayName: curr.displayName,
|
|
307
|
+
subOptions: [],
|
|
308
|
+
};
|
|
309
|
+
filtersKeyToFilter.set(curr.key, newFilter);
|
|
310
|
+
}
|
|
311
|
+
const filter = filtersKeyToFilter.get(curr.key)!;
|
|
312
|
+
this.mapUidToOption.set(curr.uid, curr);
|
|
313
|
+
for (const subOption of curr.subOptions ?? []) {
|
|
314
|
+
flatten(subOption, curr);
|
|
315
|
+
}
|
|
316
|
+
if (filter.subOptions?.length) {
|
|
317
|
+
filter.subOptions = mergeDuplicates(filter.subOptions);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
for (const option of options) {
|
|
321
|
+
flatten(option);
|
|
259
322
|
}
|
|
260
|
-
|
|
323
|
+
this.filters = Array.from(filtersKeyToFilter.values());
|
|
261
324
|
};
|
|
262
325
|
}
|
package/src/stores/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export {
|
|
|
9
9
|
ChatbotUiStore,
|
|
10
10
|
ChatbotUiEvent,
|
|
11
11
|
} from './chatbot-ui.store';
|
|
12
|
+
export { type IUiFilterOption, type IFilterStore } from './filter.store';
|
|
12
13
|
export { InitializeStore, InitializeStoreStatus } from './initialize.store';
|
|
13
14
|
export { MessageFeedbackStore } from './message-feedback.store';
|
|
14
15
|
export { MessageFeedbackGuardrailStore } from './message-feedback-guardrail.store';
|