@servicetitan/titan-chatbot-api 5.3.0 → 6.0.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/models/chatbot-customizations.d.ts +12 -0
- package/dist/models/chatbot-customizations.d.ts.map +1 -1
- package/dist/stores/__tests__/filter.store.test.js +70 -0
- package/dist/stores/__tests__/filter.store.test.js.map +1 -1
- package/dist/stores/chatbot-ui-backend.store.d.ts.map +1 -1
- package/dist/stores/chatbot-ui-backend.store.js +4 -1
- package/dist/stores/chatbot-ui-backend.store.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 +3 -3
- package/dist/stores/chatbot-ui.store.js.map +1 -1
- package/dist/stores/filter.store.d.ts +15 -2
- package/dist/stores/filter.store.d.ts.map +1 -1
- package/dist/stores/filter.store.js +27 -2
- package/dist/stores/filter.store.js.map +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js.map +1 -1
- package/package.json +3 -3
- package/src/models/chatbot-customizations.ts +13 -0
- package/src/stores/__tests__/filter.store.test.ts +82 -0
- package/src/stores/chatbot-ui-backend.store.ts +3 -1
- package/src/stores/chatbot-ui.store.ts +4 -4
- package/src/stores/filter.store.ts +31 -2
- package/src/stores/index.ts +5 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -401,4 +401,86 @@ describe('[FilterStore]', () => {
|
|
|
401
401
|
store.selectOption('Sources', 'Jarvis');
|
|
402
402
|
checkDisabled([false, false, false, false, false]);
|
|
403
403
|
});
|
|
404
|
+
|
|
405
|
+
describe('isDefaultSelected customization', () => {
|
|
406
|
+
test('should not select any options by default when isDefaultSelected is not provided', () => {
|
|
407
|
+
store.initFilters(ModelsMocks.mockFrontendModel());
|
|
408
|
+
|
|
409
|
+
expect(store.selected.get('Sources')).toBeUndefined();
|
|
410
|
+
expect(store.selected.get('ContentTypes')).toBeUndefined();
|
|
411
|
+
expect(store.selected.get('ProductAreas')).toBeUndefined();
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
test('should select options where isDefaultSelected returns true', () => {
|
|
415
|
+
store.initFilters(ModelsMocks.mockFrontendModel(), {
|
|
416
|
+
isDefaultSelected: (filterKey, optionKey) => {
|
|
417
|
+
return filterKey === 'Sources' && optionKey === 'KnowledgeBase';
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
expect(store.selected.get('Sources')).toEqual(['KnowledgeBase']);
|
|
422
|
+
expect(store.selected.get('ContentTypes')).toBeUndefined();
|
|
423
|
+
expect(store.selected.get('ProductAreas')).toBeUndefined();
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
test('should select multiple options across filters when isDefaultSelected returns true', () => {
|
|
427
|
+
store.initFilters(ModelsMocks.mockFrontendModel(), {
|
|
428
|
+
isDefaultSelected: (filterKey, optionKey) => {
|
|
429
|
+
if (filterKey === 'Sources') {
|
|
430
|
+
return true; // Select all sources
|
|
431
|
+
}
|
|
432
|
+
if (filterKey === 'ProductAreas' && optionKey === 'Marketing') {
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
return false;
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
expect(store.selected.get('Sources')).toEqual(['KnowledgeBase', 'Jarvis']);
|
|
440
|
+
expect(store.selected.get('ContentTypes')).toBeUndefined();
|
|
441
|
+
expect(store.selected.get('ProductAreas')).toEqual(['Marketing']);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
test('should not select any options when isDefaultSelected always returns false', () => {
|
|
445
|
+
store.initFilters(ModelsMocks.mockFrontendModel(), {
|
|
446
|
+
isDefaultSelected: () => false,
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
expect(store.selected.get('Sources')).toBeUndefined();
|
|
450
|
+
expect(store.selected.get('ContentTypes')).toBeUndefined();
|
|
451
|
+
expect(store.selected.get('ProductAreas')).toBeUndefined();
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
test('should select all options when isDefaultSelected always returns true', () => {
|
|
455
|
+
store.initFilters(ModelsMocks.mockFrontendModel(), {
|
|
456
|
+
isDefaultSelected: () => true,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
expect(store.selected.get('Sources')).toEqual(['KnowledgeBase', 'Jarvis']);
|
|
460
|
+
expect(store.selected.get('ContentTypes')).toEqual([
|
|
461
|
+
'kbReleaseNotes',
|
|
462
|
+
'kbFaq',
|
|
463
|
+
'kbHowTo',
|
|
464
|
+
'xxx',
|
|
465
|
+
'yyy',
|
|
466
|
+
]);
|
|
467
|
+
expect(store.selected.get('ProductAreas')).toEqual([
|
|
468
|
+
'Call Booking',
|
|
469
|
+
'Marketing',
|
|
470
|
+
'Marketing Pro',
|
|
471
|
+
]);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test('should work with flat filter structure', () => {
|
|
475
|
+
store.initFilters(ModelsMocks.mockFrontendModelFlat(), {
|
|
476
|
+
isDefaultSelected: (filterKey, optionKey) => {
|
|
477
|
+
return filterKey === 'ContentTypes' && optionKey === 'kbFaq';
|
|
478
|
+
},
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
expect(store.selected.get('Sources')).toBeUndefined();
|
|
482
|
+
expect(store.selected.get('ContentTypes')).toEqual(['kbFaq']);
|
|
483
|
+
expect(store.selected.get('ProductAreas')).toBeUndefined();
|
|
484
|
+
});
|
|
485
|
+
});
|
|
404
486
|
});
|
|
@@ -253,7 +253,9 @@ export class ChatbotUiBackendStore extends InitializeStore implements IChatbotUi
|
|
|
253
253
|
await super.initializeInternal();
|
|
254
254
|
const options = await this.chatbotApiClient.getOptions();
|
|
255
255
|
runInAction(() => {
|
|
256
|
-
this.chatUiStore.filterStore.initFilters(options
|
|
256
|
+
this.chatUiStore.filterStore.initFilters(options, {
|
|
257
|
+
isDefaultSelected: this.customizations?.filters?.isDefaultSelected,
|
|
258
|
+
});
|
|
257
259
|
});
|
|
258
260
|
}
|
|
259
261
|
|
|
@@ -3,7 +3,7 @@ import { ChatUiEvent, ChatUiStore, IChatUiStore } from '@servicetitan/titan-chat
|
|
|
3
3
|
import { action, makeObservable } from 'mobx';
|
|
4
4
|
import { Models } from '../api-client';
|
|
5
5
|
import { ChatbotCustomizations } from '../models';
|
|
6
|
-
import { FilterStore, IFilterStore } from './filter.store';
|
|
6
|
+
import { FilterStore, IFilterStore, IFilterStoreInitOptions } from './filter.store';
|
|
7
7
|
|
|
8
8
|
export const CHATBOT_UI_STORE_TOKEN = symbolToken<IChatbotUiStore>('CHATBOT_UI_STORE_TOKEN');
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ export enum ChatbotUiEvent {
|
|
|
16
16
|
export interface IChatbotUiStore extends IChatUiStore<ChatbotCustomizations> {
|
|
17
17
|
filterStore: IFilterStore;
|
|
18
18
|
settings?: Models.IFrontendModel;
|
|
19
|
-
setFilters: (filterOptions: Models.IFrontendModel) => void;
|
|
19
|
+
setFilters: (filterOptions: Models.IFrontendModel, options?: IFilterStoreInitOptions) => void;
|
|
20
20
|
startSession: (
|
|
21
21
|
sessionData?: Models.ISession['data'],
|
|
22
22
|
forceRecreate?: boolean
|
|
@@ -59,8 +59,8 @@ export class ChatbotUiStore extends ChatUiStore<ChatbotCustomizations> implement
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
@action
|
|
62
|
-
setFilters(filterOptions: Models.IFrontendModel) {
|
|
63
|
-
this.filterStore.initFilters(filterOptions);
|
|
62
|
+
setFilters(filterOptions: Models.IFrontendModel, options?: IFilterStoreInitOptions) {
|
|
63
|
+
this.filterStore.initFilters(filterOptions, options);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
@action
|
|
@@ -2,6 +2,7 @@ import cloneDeep from 'lodash/cloneDeep';
|
|
|
2
2
|
import { action, makeObservable, observable } from 'mobx';
|
|
3
3
|
import { nanoid } from 'nanoid';
|
|
4
4
|
import { Models, ModelsUtils } from '../api-client';
|
|
5
|
+
import { FilterDefaultSelectionFn } from '../models/chatbot-customizations';
|
|
5
6
|
|
|
6
7
|
export interface IUiFilterOption {
|
|
7
8
|
uid: string;
|
|
@@ -12,10 +13,17 @@ export interface IUiFilterOption {
|
|
|
12
13
|
subOptions?: IUiFilterOption[] | undefined;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
export interface IFilterStoreInitOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Function to determine if a filter option should be selected by default.
|
|
19
|
+
*/
|
|
20
|
+
isDefaultSelected?: FilterDefaultSelectionFn;
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
export interface IFilterStore {
|
|
16
24
|
selected: Map<string, string[]>;
|
|
17
25
|
filters: IUiFilterOption[];
|
|
18
|
-
initFilters(model: Models.IFrontendModel): void;
|
|
26
|
+
initFilters(model: Models.IFrontendModel, options?: IFilterStoreInitOptions): void;
|
|
19
27
|
isOptionChecked(filterKey: string, optionKey: string): boolean;
|
|
20
28
|
isOptionDisabled(filterKey: string, optionKey: string): boolean;
|
|
21
29
|
getFilterOptions(filterKey: string): IUiFilterOption[];
|
|
@@ -46,11 +54,12 @@ export class FilterStore implements IFilterStore {
|
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
@action
|
|
49
|
-
initFilters(model: Models.IFrontendModel) {
|
|
57
|
+
initFilters(model: Models.IFrontendModel, options?: IFilterStoreInitOptions) {
|
|
50
58
|
this.originalFilters = cloneDeep(
|
|
51
59
|
model?.options.subOptions?.filter(x => x.type === Models.OptionType.Group) ?? []
|
|
52
60
|
);
|
|
53
61
|
this.initLocalFilters(this.originalFilters as IUiFilterOption[]);
|
|
62
|
+
this.applyDefaultSelections(options?.isDefaultSelected);
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
isOptionChecked = (filterKey: string, optionKey: string): boolean => {
|
|
@@ -164,6 +173,26 @@ export class FilterStore implements IFilterStore {
|
|
|
164
173
|
return ModelsUtils.createSelectionsModel(this.originalFilters, this.selected);
|
|
165
174
|
}
|
|
166
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Applies default selections based on the provided customization function.
|
|
178
|
+
* Iterates through all filters and their options, selecting those where
|
|
179
|
+
* isDefaultSelected returns true.
|
|
180
|
+
*/
|
|
181
|
+
@action
|
|
182
|
+
private applyDefaultSelections(isDefaultSelected?: FilterDefaultSelectionFn) {
|
|
183
|
+
if (!isDefaultSelected) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
for (const filter of this.filters) {
|
|
187
|
+
const filterOptions = this.getFilterOptions(filter.key);
|
|
188
|
+
for (const option of filterOptions) {
|
|
189
|
+
if (isDefaultSelected(filter.key, option.key)) {
|
|
190
|
+
this.selectOption(filter.key, option.key);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
167
196
|
private assertFilterKeyExists = (filterKey: string) => {
|
|
168
197
|
const filter = this.getFilterByKey(filterKey);
|
|
169
198
|
if (!filter) {
|
package/src/stores/index.ts
CHANGED
|
@@ -9,7 +9,11 @@ export {
|
|
|
9
9
|
ChatbotUiStore,
|
|
10
10
|
ChatbotUiEvent,
|
|
11
11
|
} from './chatbot-ui.store';
|
|
12
|
-
export {
|
|
12
|
+
export {
|
|
13
|
+
type IUiFilterOption,
|
|
14
|
+
type IFilterStore,
|
|
15
|
+
type IFilterStoreInitOptions,
|
|
16
|
+
} from './filter.store';
|
|
13
17
|
export { InitializeStore, InitializeStoreStatus } from './initialize.store';
|
|
14
18
|
export { MessageFeedbackStore } from './message-feedback.store';
|
|
15
19
|
export { MessageFeedbackGuardrailStore } from './message-feedback-guardrail.store';
|