@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
|
@@ -127,14 +127,18 @@ export const mockFeedback = (overrides?: Partial<Models.IFeedback>): Models.Feed
|
|
|
127
127
|
...overrides,
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
export const mockSelections = (overrides?: Models.Selections): Models.Selections | undefined =>
|
|
131
|
-
new Models.Selections({
|
|
132
|
-
...ModelsUtils.createSelectionsModel(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
export const mockSelections = (overrides?: Models.Selections): Models.Selections | undefined => {
|
|
131
|
+
return new Models.Selections({
|
|
132
|
+
...ModelsUtils.createSelectionsModel(
|
|
133
|
+
[mockFrontendModel().options],
|
|
134
|
+
new Map<string, string[]>([
|
|
135
|
+
['Sources', ['KnowledgeBase', 'Jarvis']],
|
|
136
|
+
['ContentTypes', ['kbReleaseNotes', 'kbFaq', 'xxx']],
|
|
137
|
+
])
|
|
138
|
+
),
|
|
136
139
|
...overrides,
|
|
137
140
|
});
|
|
141
|
+
};
|
|
138
142
|
|
|
139
143
|
export const mockUserMessage = (overrides?: Partial<Models.IUserMessage>): Models.UserMessage =>
|
|
140
144
|
new Models.UserMessage({
|
|
@@ -6,7 +6,7 @@ export function createNewSessionModel(data?: Models.ISession): Models.Session {
|
|
|
6
6
|
|
|
7
7
|
export function createSelectionsModel(
|
|
8
8
|
filters: Models.IOption[],
|
|
9
|
-
selected:
|
|
9
|
+
selected: Map<string, string[]>
|
|
10
10
|
): Models.Selections | undefined {
|
|
11
11
|
const process = (filters: Models.IOption[]): Models.Selections | undefined => {
|
|
12
12
|
let result: Models.Selections | undefined;
|
|
@@ -29,7 +29,7 @@ export function createSelectionsModel(
|
|
|
29
29
|
// Leaf filter: just collect selected values
|
|
30
30
|
const values = filter.subOptions
|
|
31
31
|
?.map(o => o.key)
|
|
32
|
-
.filter(o => selected
|
|
32
|
+
.filter(o => selected.get(filter.key)?.includes(o));
|
|
33
33
|
if (values?.length) {
|
|
34
34
|
ensureResult();
|
|
35
35
|
result!.subOptions![filter.key] = new Models.Selections({ values });
|
|
@@ -40,7 +40,7 @@ export function createSelectionsModel(
|
|
|
40
40
|
x =>
|
|
41
41
|
x.type === Models.OptionType.Selectable &&
|
|
42
42
|
Boolean(x.subOptions?.length) &&
|
|
43
|
-
selected
|
|
43
|
+
selected.get(filter.key)?.includes(x.key!)
|
|
44
44
|
);
|
|
45
45
|
if (!filterSelectables.length) {
|
|
46
46
|
continue;
|
|
@@ -52,7 +52,7 @@ describe('[ChatbotUiStore]', () => {
|
|
|
52
52
|
const frontendModel = ModelsMocks.mockFrontendModel();
|
|
53
53
|
store.setFilters(frontendModel);
|
|
54
54
|
|
|
55
|
-
expect(store.filterStore.filters.length).toEqual(
|
|
55
|
+
expect(store.filterStore.filters.length).toEqual(3);
|
|
56
56
|
expect(store.filterStore.filters[0].key).toEqual('Sources');
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { expect } from '@jest/globals';
|
|
2
2
|
import { Models, ModelsMocks } from '../../api-client';
|
|
3
|
-
import { FilterStore } from '../filter.store';
|
|
3
|
+
import { FilterStore, IFilterStore } from '../filter.store';
|
|
4
4
|
|
|
5
5
|
describe('[FilterStore]', () => {
|
|
6
|
-
let store:
|
|
6
|
+
let store: IFilterStore;
|
|
7
7
|
|
|
8
8
|
const validateFilters = (key: string, subOptionsLength: number) => {
|
|
9
9
|
const filter = store.filters.find(f => f.key === key);
|
|
@@ -12,9 +12,9 @@ describe('[FilterStore]', () => {
|
|
|
12
12
|
|
|
13
13
|
const validateSelected = (key: string, expected?: string[]) => {
|
|
14
14
|
if (!expected) {
|
|
15
|
-
expect(store.
|
|
15
|
+
expect(store.selected.get(key)).toBeUndefined();
|
|
16
16
|
}
|
|
17
|
-
expect(store.
|
|
17
|
+
expect(store.selected.get(key)).toEqual(expected);
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
beforeEach(() => {
|
|
@@ -27,35 +27,35 @@ describe('[FilterStore]', () => {
|
|
|
27
27
|
|
|
28
28
|
test('should validate defaults', () => {
|
|
29
29
|
expect(Object.keys(store.filters).length).toEqual(0);
|
|
30
|
-
expect(
|
|
30
|
+
expect(store.selected.size).toEqual(0);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
test('Should initialize properly', () => {
|
|
34
34
|
store.initFilters(ModelsMocks.mockFrontendModel());
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
expect(
|
|
56
|
-
expect(
|
|
57
|
-
expect(
|
|
58
|
-
expect(
|
|
35
|
+
expect(store.filters.length).toEqual(3);
|
|
36
|
+
|
|
37
|
+
const checkFilter = (
|
|
38
|
+
idx: number,
|
|
39
|
+
key: string,
|
|
40
|
+
type: Models.OptionType,
|
|
41
|
+
subOptionsLength: number
|
|
42
|
+
) => {
|
|
43
|
+
expect(store.filters[idx].key).toEqual(key);
|
|
44
|
+
expect(store.filters[idx].type).toEqual(type);
|
|
45
|
+
expect(store.filters[idx].subOptions!.length).toEqual(subOptionsLength);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Check filters flattened
|
|
49
|
+
checkFilter(0, 'Sources', Models.OptionType.Group, 2);
|
|
50
|
+
checkFilter(1, 'ContentTypes', Models.OptionType.Group, 5);
|
|
51
|
+
checkFilter(2, 'ProductAreas', Models.OptionType.Group, 3);
|
|
52
|
+
|
|
53
|
+
// Check options and that they don't have sub-options (because of flattening)
|
|
54
|
+
const optionKnowledgeBase = store.filters[0].subOptions![0];
|
|
55
|
+
expect(optionKnowledgeBase.key).toEqual('KnowledgeBase');
|
|
56
|
+
expect(optionKnowledgeBase.displayName).toEqual('Knowledge Base');
|
|
57
|
+
expect(optionKnowledgeBase.type).toEqual(Models.OptionType.Selectable);
|
|
58
|
+
expect(optionKnowledgeBase.subOptions!.length).toEqual(0);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
test('Should fail when selecting option from non-existing filter', () => {
|
|
@@ -68,22 +68,22 @@ describe('[FilterStore]', () => {
|
|
|
68
68
|
test('Should fail when selecting non-existing option from existing filter', () => {
|
|
69
69
|
store.initFilters(ModelsMocks.mockFrontendModel());
|
|
70
70
|
expect(() => store.selectOption('Sources', 'non-existing-option')).toThrow(
|
|
71
|
-
'Option "non-existing-option" does not exist in
|
|
71
|
+
'Option with key \"non-existing-option\" does not exist in filter \"Sources\".'
|
|
72
72
|
);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
test('Should select value', () => {
|
|
76
76
|
store.initFilters(ModelsMocks.mockFrontendModel());
|
|
77
77
|
|
|
78
|
-
expect(store.filters.length).toEqual(
|
|
78
|
+
expect(store.filters.length).toEqual(3);
|
|
79
79
|
|
|
80
80
|
// Source filter: select Jarvis option: 1 filter + 1 subfilter
|
|
81
81
|
store.selectOption('Sources', 'Jarvis');
|
|
82
82
|
validateSelected('Sources', ['Jarvis']);
|
|
83
|
-
expect(store.filters.length).toEqual(
|
|
83
|
+
expect(store.filters.length).toEqual(3);
|
|
84
84
|
expect(store.filters[0].key).toEqual('Sources');
|
|
85
85
|
expect(store.filters[1].key).toEqual('ContentTypes');
|
|
86
|
-
expect(store.filters[
|
|
86
|
+
expect(store.filters[2].key).toEqual('ProductAreas');
|
|
87
87
|
|
|
88
88
|
// Source filter: select knowledgeBase option (options with the same key are merged)
|
|
89
89
|
store.selectOption('Sources', 'KnowledgeBase');
|
|
@@ -134,7 +134,7 @@ describe('[FilterStore]', () => {
|
|
|
134
134
|
store.deselectOption('Sources', 'Jarvis');
|
|
135
135
|
expect(store.filters.length).toEqual(3);
|
|
136
136
|
validateFilters('Sources', 2);
|
|
137
|
-
validateFilters('ContentTypes',
|
|
137
|
+
validateFilters('ContentTypes', 5);
|
|
138
138
|
validateFilters('ProductAreas', 3);
|
|
139
139
|
validateSelected('Sources', ['KnowledgeBase']);
|
|
140
140
|
validateSelected('ContentTypes', ['kbReleaseNotes', 'kbHowTo']);
|
|
@@ -143,7 +143,7 @@ describe('[FilterStore]', () => {
|
|
|
143
143
|
store.deselectOption('ContentTypes', 'kbHowTo');
|
|
144
144
|
expect(store.filters.length).toEqual(3);
|
|
145
145
|
validateFilters('Sources', 2);
|
|
146
|
-
validateFilters('ContentTypes',
|
|
146
|
+
validateFilters('ContentTypes', 5);
|
|
147
147
|
validateFilters('ProductAreas', 3);
|
|
148
148
|
validateSelected('Sources', ['KnowledgeBase']);
|
|
149
149
|
validateSelected('ContentTypes', ['kbReleaseNotes']);
|
|
@@ -152,7 +152,7 @@ describe('[FilterStore]', () => {
|
|
|
152
152
|
store.deselectOption('ContentTypes', 'kbReleaseNotes');
|
|
153
153
|
expect(store.filters.length).toEqual(3);
|
|
154
154
|
validateFilters('Sources', 2);
|
|
155
|
-
validateFilters('ContentTypes',
|
|
155
|
+
validateFilters('ContentTypes', 5);
|
|
156
156
|
validateFilters('ProductAreas', 3);
|
|
157
157
|
validateSelected('Sources', ['KnowledgeBase']);
|
|
158
158
|
validateSelected('ContentTypes', []);
|
|
@@ -161,17 +161,17 @@ describe('[FilterStore]', () => {
|
|
|
161
161
|
store.deselectOption('ProductAreas', 'Marketing Pro');
|
|
162
162
|
expect(store.filters.length).toEqual(3);
|
|
163
163
|
validateFilters('Sources', 2);
|
|
164
|
-
validateFilters('ContentTypes',
|
|
164
|
+
validateFilters('ContentTypes', 5);
|
|
165
165
|
validateFilters('ProductAreas', 3);
|
|
166
166
|
validateSelected('Sources', ['KnowledgeBase']);
|
|
167
167
|
validateSelected('ContentTypes', []);
|
|
168
168
|
validateSelected('ProductAreas', ['Marketing']);
|
|
169
169
|
|
|
170
170
|
store.deselectOption('Sources', 'KnowledgeBase');
|
|
171
|
-
expect(store.filters.length).toEqual(
|
|
171
|
+
expect(store.filters.length).toEqual(3);
|
|
172
172
|
validateFilters('Sources', 2);
|
|
173
|
-
validateFilters('ContentTypes',
|
|
174
|
-
validateFilters('ProductAreas',
|
|
173
|
+
validateFilters('ContentTypes', 5);
|
|
174
|
+
validateFilters('ProductAreas', 3);
|
|
175
175
|
validateSelected('Sources', []);
|
|
176
176
|
validateSelected('ContentTypes', []);
|
|
177
177
|
validateSelected('ProductAreas', []);
|
|
@@ -182,7 +182,7 @@ describe('[FilterStore]', () => {
|
|
|
182
182
|
|
|
183
183
|
store.selectOption('Sources', 'KnowledgeBase');
|
|
184
184
|
validateFilters('Sources', 2);
|
|
185
|
-
validateFilters('ContentTypes',
|
|
185
|
+
validateFilters('ContentTypes', 5);
|
|
186
186
|
validateFilters('ProductAreas', 3);
|
|
187
187
|
|
|
188
188
|
store.selectOption('Sources', 'Jarvis');
|
|
@@ -193,8 +193,8 @@ describe('[FilterStore]', () => {
|
|
|
193
193
|
|
|
194
194
|
store.deselectOption('Sources', 'KnowledgeBase');
|
|
195
195
|
validateFilters('Sources', 2);
|
|
196
|
-
validateFilters('ContentTypes',
|
|
197
|
-
validateFilters('ProductAreas',
|
|
196
|
+
validateFilters('ContentTypes', 5);
|
|
197
|
+
validateFilters('ProductAreas', 3);
|
|
198
198
|
|
|
199
199
|
store.selectOption('Sources', 'KnowledgeBase');
|
|
200
200
|
validateFilters('Sources', 2);
|
|
@@ -251,8 +251,8 @@ describe('[FilterStore]', () => {
|
|
|
251
251
|
validateSelected('ContentTypes', []);
|
|
252
252
|
validateSelected('ProductAreas', []);
|
|
253
253
|
validateFilters('Sources', 2);
|
|
254
|
-
validateFilters('ContentTypes',
|
|
255
|
-
validateFilters('ProductAreas',
|
|
254
|
+
validateFilters('ContentTypes', 5);
|
|
255
|
+
validateFilters('ProductAreas', 3);
|
|
256
256
|
});
|
|
257
257
|
|
|
258
258
|
test('should getFilterLabel', () => {
|
|
@@ -384,4 +384,22 @@ describe('[FilterStore]', () => {
|
|
|
384
384
|
const exported = store.export();
|
|
385
385
|
expect(exported).toBeUndefined();
|
|
386
386
|
});
|
|
387
|
+
|
|
388
|
+
test('should detect disabled options', () => {
|
|
389
|
+
const checkDisabled = (disabledArray: boolean[]) => {
|
|
390
|
+
const keys = ['kbFaq', 'kbReleaseNotes', 'kbHowTo', 'xxx', 'yyy'];
|
|
391
|
+
keys.forEach((key, index) => {
|
|
392
|
+
expect(store.isOptionDisabled('ContentTypes', key)).toBe(disabledArray[index]);
|
|
393
|
+
});
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
store.initFilters(ModelsMocks.mockFrontendModel());
|
|
397
|
+
checkDisabled([true, true, true, true, true]);
|
|
398
|
+
|
|
399
|
+
store.selectOption('Sources', 'KnowledgeBase');
|
|
400
|
+
checkDisabled([false, false, false, true, true]);
|
|
401
|
+
|
|
402
|
+
store.selectOption('Sources', 'Jarvis');
|
|
403
|
+
checkDisabled([false, false, false, false, false]);
|
|
404
|
+
});
|
|
387
405
|
});
|
|
@@ -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 } from './filter.store';
|
|
6
|
+
import { FilterStore, IFilterStore } from './filter.store';
|
|
7
7
|
|
|
8
8
|
export const CHATBOT_UI_STORE_TOKEN = symbolToken<IChatbotUiStore>('CHATBOT_UI_STORE_TOKEN');
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ export enum ChatbotUiEvent {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface IChatbotUiStore extends IChatUiStore<ChatbotCustomizations> {
|
|
17
|
-
filterStore:
|
|
17
|
+
filterStore: IFilterStore;
|
|
18
18
|
settings?: Models.IFrontendModel;
|
|
19
19
|
setFilters: (filterOptions: Models.IFrontendModel) => void;
|
|
20
20
|
startSession: (
|
|
@@ -32,7 +32,7 @@ export interface IChatbotUiStore extends IChatUiStore<ChatbotCustomizations> {
|
|
|
32
32
|
|
|
33
33
|
@injectable()
|
|
34
34
|
export class ChatbotUiStore extends ChatUiStore<ChatbotCustomizations> implements IChatbotUiStore {
|
|
35
|
-
filterStore = new FilterStore();
|
|
35
|
+
filterStore: IFilterStore = new FilterStore();
|
|
36
36
|
|
|
37
37
|
constructor() {
|
|
38
38
|
super();
|