@servicetitan/titan-chat-ui 1.1.1 → 2.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 +24 -0
- package/dist/components/chat/__tests-cy__/chat-messages.test.js +69 -1
- package/dist/components/chat/__tests-cy__/chat-messages.test.js.map +1 -1
- package/dist/components/chat/chat-input.js +2 -2
- package/dist/components/chat/chat-input.js.map +1 -1
- package/dist/components/chat/chat-log.d.ts +8 -0
- package/dist/components/chat/chat-log.d.ts.map +1 -0
- package/dist/components/chat/chat-log.js +15 -0
- package/dist/components/chat/chat-log.js.map +1 -0
- package/dist/components/chat/chat-message-template-agent.d.ts.map +1 -1
- package/dist/components/chat/chat-message-template-agent.js +2 -2
- package/dist/components/chat/chat-message-template-agent.js.map +1 -1
- package/dist/components/chat/chat-message-template-user.js +2 -2
- package/dist/components/chat/chat-message-template-user.js.map +1 -1
- package/dist/components/chat/chat-message.d.ts +1 -5
- package/dist/components/chat/chat-message.d.ts.map +1 -1
- package/dist/components/chat/chat-message.js +4 -4
- package/dist/components/chat/chat-message.js.map +1 -1
- package/dist/components/chat/chat-messages.d.ts +3 -0
- package/dist/components/chat/chat-messages.d.ts.map +1 -1
- package/dist/components/chat/chat-messages.js +35 -7
- package/dist/components/chat/chat-messages.js.map +1 -1
- package/dist/components/chat/chat.d.ts.map +1 -1
- package/dist/components/chat/chat.js +3 -1
- package/dist/components/chat/chat.js.map +1 -1
- package/dist/components/messages/__tests-cy__/message-agent.test.js +1 -1
- package/dist/components/messages/__tests-cy__/message-agent.test.js.map +1 -1
- package/dist/components/messages/message-agent.d.ts +1 -0
- package/dist/components/messages/message-agent.d.ts.map +1 -1
- package/dist/components/messages/message-agent.js +2 -4
- package/dist/components/messages/message-agent.js.map +1 -1
- package/dist/components/messages/message-agent.module.less +29 -37
- package/dist/components/messages/message-footer.d.ts +1 -1
- package/dist/components/messages/message-footer.d.ts.map +1 -1
- package/dist/components/messages/message-footer.js +1 -1
- package/dist/components/messages/message-footer.js.map +1 -1
- package/dist/components/messages/message-user.js +2 -2
- package/dist/components/messages/message-user.js.map +1 -1
- package/dist/components/messages/message-user.module.less +3 -6
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/models/__mocks__/support-chat.mock.d.ts +9 -0
- package/dist/models/__mocks__/support-chat.mock.d.ts.map +1 -0
- package/dist/models/__mocks__/support-chat.mock.js +82 -0
- package/dist/models/__mocks__/support-chat.mock.js.map +1 -0
- package/dist/models/chat-customizations.d.ts +14 -6
- package/dist/models/chat-customizations.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +1 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/support-chat.d.ts +4 -4
- package/dist/models/support-chat.d.ts.map +1 -1
- package/dist/models/support-chat.js +18 -0
- package/dist/models/support-chat.js.map +1 -1
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts +6 -1
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts.map +1 -1
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.js +30 -0
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.js.map +1 -1
- package/dist/stores/__tests__/chat-input.store.test.d.ts +2 -0
- package/dist/stores/__tests__/chat-input.store.test.d.ts.map +1 -0
- package/dist/stores/__tests__/chat-input.store.test.js +32 -0
- package/dist/stores/__tests__/chat-input.store.test.js.map +1 -0
- package/dist/stores/chat-ui.store.d.ts +19 -10
- package/dist/stores/chat-ui.store.d.ts.map +1 -1
- package/dist/stores/chat-ui.store.js +47 -48
- package/dist/stores/chat-ui.store.js.map +1 -1
- package/dist/utils/test-utils.d.ts +5 -0
- package/dist/utils/test-utils.d.ts.map +1 -0
- package/dist/utils/test-utils.js +17 -0
- package/dist/utils/test-utils.js.map +1 -0
- package/package.json +2 -2
- package/src/components/chat/__tests-cy__/chat-messages.test.tsx +78 -1
- package/src/components/chat/chat-input.tsx +4 -4
- package/src/components/chat/chat-log.tsx +29 -0
- package/src/components/chat/chat-message-template-agent.tsx +7 -3
- package/src/components/chat/chat-message-template-user.tsx +3 -3
- package/src/components/chat/chat-message.tsx +58 -52
- package/src/components/chat/chat-messages.tsx +55 -11
- package/src/components/chat/chat.tsx +14 -8
- package/src/components/messages/__tests-cy__/message-agent.test.tsx +1 -1
- package/src/components/messages/message-agent.module.less +29 -37
- package/src/components/messages/message-agent.module.less.d.ts +0 -1
- package/src/components/messages/message-agent.tsx +4 -4
- package/src/components/messages/message-footer.tsx +4 -3
- package/src/components/messages/message-user.module.less +3 -6
- package/src/components/messages/message-user.tsx +5 -5
- package/src/index.ts +3 -0
- package/src/models/__mocks__/support-chat.mock.ts +105 -0
- package/src/models/chat-customizations.ts +17 -6
- package/src/models/index.ts +1 -0
- package/src/models/support-chat.ts +22 -10
- package/src/stores/__mocks-cy__/chat-ui.store.mock.ts +6 -0
- package/src/stores/__tests__/chat-input.store.test.ts +39 -0
- package/src/stores/chat-ui.store.ts +54 -55
- package/src/utils/test-utils.ts +22 -0
- package/tsconfig.json +1 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -28,14 +28,6 @@ export interface ChatParticipantModel {
|
|
|
28
28
|
icon: ChatParticipantIcon;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export type ChatMessageModelType =
|
|
32
|
-
| 'welcome'
|
|
33
|
-
| 'message'
|
|
34
|
-
| 'timeout'
|
|
35
|
-
| 'file'
|
|
36
|
-
| 'askSupport'
|
|
37
|
-
| 'askSupportButtons';
|
|
38
|
-
|
|
39
31
|
export interface ChatConfiguration {
|
|
40
32
|
agentName?: string;
|
|
41
33
|
agentIcon?: ChatParticipantIcon;
|
|
@@ -44,7 +36,7 @@ export interface ChatConfiguration {
|
|
|
44
36
|
export interface ChatMessageModelBase {
|
|
45
37
|
id: string;
|
|
46
38
|
timestamp: Date;
|
|
47
|
-
type:
|
|
39
|
+
type: string;
|
|
48
40
|
participant: ChatParticipantModel;
|
|
49
41
|
state: ChatMessageState;
|
|
50
42
|
data?: any;
|
|
@@ -69,7 +61,7 @@ export interface ChatMessageModelFile extends ChatMessageModelBase {
|
|
|
69
61
|
fileName: string;
|
|
70
62
|
}
|
|
71
63
|
|
|
72
|
-
type ChatErrorRecoverStrategy =
|
|
64
|
+
export type ChatErrorRecoverStrategy =
|
|
73
65
|
| {
|
|
74
66
|
recoverButtonTitle: string;
|
|
75
67
|
}
|
|
@@ -94,6 +86,26 @@ export class ChatError<T = any> extends Error {
|
|
|
94
86
|
this.data = options?.data;
|
|
95
87
|
Object.setPrototypeOf(this, ChatError.prototype);
|
|
96
88
|
}
|
|
89
|
+
|
|
90
|
+
toJSON(): Record<string, any> {
|
|
91
|
+
return {
|
|
92
|
+
name: this.name,
|
|
93
|
+
message: this.message,
|
|
94
|
+
title: this.title,
|
|
95
|
+
recoverStrategy: this.recoverStrategy,
|
|
96
|
+
data: this.data,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fromJSON(json: Record<string, any>): ChatError<T> {
|
|
101
|
+
const error = new ChatError<T>(json.message, {
|
|
102
|
+
title: json.title,
|
|
103
|
+
recoverStrategy: json.recoverStrategy,
|
|
104
|
+
data: json.data,
|
|
105
|
+
});
|
|
106
|
+
error.name = json.name;
|
|
107
|
+
return error;
|
|
108
|
+
}
|
|
97
109
|
}
|
|
98
110
|
|
|
99
111
|
export enum ChatRunState {
|
|
@@ -2,6 +2,7 @@ import { FileDescriptor } from '@servicetitan/form';
|
|
|
2
2
|
import {
|
|
3
3
|
ChatConfiguration,
|
|
4
4
|
ChatCustomizations,
|
|
5
|
+
ChatEndReason,
|
|
5
6
|
ChatError,
|
|
6
7
|
ChatErrorOptions,
|
|
7
8
|
ChatMessageModelBase,
|
|
@@ -84,6 +85,8 @@ export class ChatUiStoreMock implements IChatUiStore {
|
|
|
84
85
|
off: <T>(event: string, listener: ChatUiEventListener<T>) => void = cy.stub();
|
|
85
86
|
on: <T>(event: string, listener: ChatUiEventListener<T>) => void = cy.stub();
|
|
86
87
|
resetError: (runState: ChatRunState) => void = cy.stub();
|
|
88
|
+
reset: (resetState?: boolean) => void = cy.stub();
|
|
89
|
+
resetFile: () => void = cy.stub();
|
|
87
90
|
setAgentTyping: (typing: boolean) => void = cy.stub();
|
|
88
91
|
setChatError: (chatError: ChatError) => void = cy.stub();
|
|
89
92
|
setError: <T = any>(message: string, options?: ChatErrorOptions<T>) => void = cy.stub();
|
|
@@ -104,4 +107,7 @@ export class ChatUiStoreMock implements IChatUiStore {
|
|
|
104
107
|
setStatus: (status: ChatRunState) => void = cy.stub();
|
|
105
108
|
setTimer: (timer?: ChatTimer) => void = cy.stub();
|
|
106
109
|
restartTimers: () => Promise<void> = cy.stub();
|
|
110
|
+
restart: () => Promise<void> = cy.stub();
|
|
111
|
+
cancelChat: () => Promise<void> = cy.stub();
|
|
112
|
+
endChat: (endReason?: ChatEndReason) => Promise<void> = cy.stub();
|
|
107
113
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { expect } from '@jest/globals';
|
|
2
|
+
import { Container } from '@servicetitan/react-ioc';
|
|
3
|
+
import { initTestContainer } from '../../utils/test-utils';
|
|
4
|
+
import { ChatInputStore } from '../chat-input.store';
|
|
5
|
+
|
|
6
|
+
const initContainer = initTestContainer(ChatInputStore, () => {});
|
|
7
|
+
|
|
8
|
+
describe('[ChatInputStore]', () => {
|
|
9
|
+
let container: Container;
|
|
10
|
+
let store: ChatInputStore;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
container = initContainer();
|
|
14
|
+
store = container.get(ChatInputStore);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should have proper form state', async () => {
|
|
18
|
+
expect(store.formState.$.message).toBeDefined();
|
|
19
|
+
expect(store.formState.$.message.value).toBe('');
|
|
20
|
+
const validateResult = await store.formState.validate();
|
|
21
|
+
expect(validateResult.hasError).toBe(false);
|
|
22
|
+
|
|
23
|
+
store.formState.$.message.onChange('test');
|
|
24
|
+
expect(store.formState.$.message.value).toBe('test');
|
|
25
|
+
const validateResult2 = await store.formState.validate();
|
|
26
|
+
expect(validateResult2.hasError).toBe(false);
|
|
27
|
+
|
|
28
|
+
store.formState.$.message.onChange('a'.repeat(6000));
|
|
29
|
+
expect(store.formState.$.message.value).toBe('a'.repeat(6000));
|
|
30
|
+
const validateResult3 = await store.formState.validate();
|
|
31
|
+
expect(validateResult3.hasError).toBe(false);
|
|
32
|
+
|
|
33
|
+
store.formState.$.message.onChange('a'.repeat(6001));
|
|
34
|
+
expect(store.formState.$.message.value).toBe('a'.repeat(6001));
|
|
35
|
+
const validateResult4 = await store.formState.validate();
|
|
36
|
+
expect(validateResult4.hasError).toBe(true);
|
|
37
|
+
expect(store.formState.$.message.error).toBe('Message character max is 6000.');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
ChatMessageModelFile,
|
|
14
14
|
ChatMessageModelText,
|
|
15
15
|
ChatMessageModelTimeout,
|
|
16
|
-
ChatMessageModelType,
|
|
17
16
|
ChatMessageModelWelcome,
|
|
18
17
|
ChatMessageState,
|
|
19
18
|
ChatParticipantIcon,
|
|
@@ -29,12 +28,15 @@ export enum ChatUiEvent {
|
|
|
29
28
|
eventRun = 'eventRun',
|
|
30
29
|
eventDestroy = 'eventDestroy',
|
|
31
30
|
eventRestart = 'eventRestart',
|
|
31
|
+
eventCancel = 'eventCancel',
|
|
32
|
+
eventEndChat = 'eventEndChat',
|
|
32
33
|
eventRecover = 'eventRecover',
|
|
33
34
|
eventChasitorTyping = 'eventChasitorTyping',
|
|
34
35
|
eventTimerRestart = 'eventTimerRestart',
|
|
35
36
|
eventMessageSend = 'eventMessageSend',
|
|
36
|
-
eventMessageSendFile = 'eventMessageSendFile',
|
|
37
37
|
eventMessageSendRetry = 'eventMessageSendRetry',
|
|
38
|
+
eventMessageSendFile = 'eventMessageSendFile',
|
|
39
|
+
eventMessageSendFileRetry = 'eventMessageSendFileRetry',
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export type ChatUiEventListener<T = void> = (
|
|
@@ -82,6 +84,8 @@ export interface IChatUiStore<T extends ChatCustomizations = ChatCustomizations>
|
|
|
82
84
|
setError<T = any>(message: string, options?: ChatErrorOptions<T>): void;
|
|
83
85
|
setStatus(status: ChatRunState): void;
|
|
84
86
|
resetError(runState: ChatRunState): void;
|
|
87
|
+
reset(resetStatus?: boolean): void;
|
|
88
|
+
resetFile(): void;
|
|
85
89
|
|
|
86
90
|
triggerScroll(): void;
|
|
87
91
|
configure(configuration?: ChatConfiguration): void;
|
|
@@ -90,6 +94,9 @@ export interface IChatUiStore<T extends ChatCustomizations = ChatCustomizations>
|
|
|
90
94
|
destroy(): Promise<void>;
|
|
91
95
|
chasitorTyping(isTyping: boolean): Promise<void>;
|
|
92
96
|
restartTimers(): Promise<void>;
|
|
97
|
+
restart(): Promise<void>;
|
|
98
|
+
cancelChat(): Promise<void>;
|
|
99
|
+
endChat(endReason?: ChatEndReason): Promise<void>;
|
|
93
100
|
sendMessageText(messageText: string): Promise<void>;
|
|
94
101
|
sendMessageRetry(message: ChatMessageModelBase): Promise<void>;
|
|
95
102
|
addMessage(isAgent: boolean, message: string, data?: any): void;
|
|
@@ -306,24 +313,21 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
|
|
|
306
313
|
await this.emitAsync(ChatUiEvent.eventDestroy);
|
|
307
314
|
}
|
|
308
315
|
|
|
309
|
-
restart() {
|
|
316
|
+
async restart() {
|
|
310
317
|
this.reset();
|
|
311
|
-
this.
|
|
318
|
+
await this.emitAsync(ChatUiEvent.eventRestart);
|
|
312
319
|
}
|
|
313
320
|
|
|
314
|
-
cancelChat() {
|
|
315
|
-
this.
|
|
321
|
+
async cancelChat() {
|
|
322
|
+
await this.emitAsync(ChatUiEvent.eventCancel);
|
|
316
323
|
}
|
|
317
324
|
|
|
318
|
-
endChat() {
|
|
319
|
-
this.
|
|
325
|
+
async endChat(endReason?: ChatEndReason) {
|
|
326
|
+
await this.emitAsync(ChatUiEvent.eventEndChat, endReason);
|
|
320
327
|
}
|
|
321
328
|
|
|
322
329
|
async chasitorTyping(isTyping: boolean) {
|
|
323
|
-
await this.emitAsync(
|
|
324
|
-
ChatUiEvent.eventChasitorTyping,
|
|
325
|
-
isTyping ? 'chasitorTyping' : 'chasitorNotTyping'
|
|
326
|
-
);
|
|
330
|
+
await this.emitAsync(ChatUiEvent.eventChasitorTyping, isTyping);
|
|
327
331
|
}
|
|
328
332
|
|
|
329
333
|
@action
|
|
@@ -358,10 +362,10 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
|
|
|
358
362
|
}
|
|
359
363
|
|
|
360
364
|
@action
|
|
361
|
-
sendMessageFileRetry(messageModel: ChatMessageModelFile) {
|
|
365
|
+
async sendMessageFileRetry(messageModel: ChatMessageModelFile) {
|
|
362
366
|
this.resetError(ChatRunState.Started);
|
|
363
367
|
this.setMessageState(messageModel, ChatMessageState.Delivering);
|
|
364
|
-
this.
|
|
368
|
+
await this.emitAsync(ChatUiEvent.eventMessageSendFileRetry, messageModel);
|
|
365
369
|
}
|
|
366
370
|
|
|
367
371
|
getParticipant(participantKey: symbol): ChatParticipantModel {
|
|
@@ -431,6 +435,26 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
|
|
|
431
435
|
}
|
|
432
436
|
}
|
|
433
437
|
|
|
438
|
+
@action
|
|
439
|
+
resetFile() {
|
|
440
|
+
this.currentFileMessage = undefined;
|
|
441
|
+
this.file = undefined;
|
|
442
|
+
this.isFilePickerEnabled = false;
|
|
443
|
+
this.triggerScroll();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
@action
|
|
447
|
+
reset(resetStatus = true) {
|
|
448
|
+
this.setMessages([]);
|
|
449
|
+
if (resetStatus) {
|
|
450
|
+
this.status = ChatRunState.Offline;
|
|
451
|
+
}
|
|
452
|
+
this.error = undefined;
|
|
453
|
+
this.isAgentTyping = false;
|
|
454
|
+
this.endReason = undefined;
|
|
455
|
+
this.resetFile();
|
|
456
|
+
}
|
|
457
|
+
|
|
434
458
|
getLastFailedMessages() {
|
|
435
459
|
const result: ChatMessageModelText[] = [];
|
|
436
460
|
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
@@ -453,26 +477,6 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
|
|
|
453
477
|
}, 0);
|
|
454
478
|
}
|
|
455
479
|
|
|
456
|
-
@action
|
|
457
|
-
protected reset(resetStatus = true) {
|
|
458
|
-
this.setMessages([]);
|
|
459
|
-
if (resetStatus) {
|
|
460
|
-
this.status = ChatRunState.Offline;
|
|
461
|
-
}
|
|
462
|
-
this.error = undefined;
|
|
463
|
-
this.isAgentTyping = false;
|
|
464
|
-
this.endReason = undefined;
|
|
465
|
-
this.resetFile();
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
@action
|
|
469
|
-
protected resetFile() {
|
|
470
|
-
this.currentFileMessage = undefined;
|
|
471
|
-
this.file = undefined;
|
|
472
|
-
this.isFilePickerEnabled = false;
|
|
473
|
-
this.triggerScroll();
|
|
474
|
-
}
|
|
475
|
-
|
|
476
480
|
protected async emitAsync<T>(event: string, ...args: unknown[]) {
|
|
477
481
|
if (!this.eventEmitter.listenerCount(event)) {
|
|
478
482
|
return Promise.resolve();
|
|
@@ -482,23 +486,14 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
|
|
|
482
486
|
});
|
|
483
487
|
}
|
|
484
488
|
|
|
485
|
-
|
|
486
|
-
if (message.trim() === '') {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
const messageModel = this.addMessage(false, message);
|
|
490
|
-
await this.emitAsync(ChatUiEvent.eventMessageSend, messageModel);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
private addMessageInternal<T extends ChatMessageModelBase>(
|
|
489
|
+
protected addMessageInternal<T extends ChatMessageModelBase>(
|
|
494
490
|
message: Omit<T, 'id' | 'timestamp'>
|
|
495
491
|
): T {
|
|
496
492
|
if (message.type === 'timeout') {
|
|
497
493
|
this.removeMessageByType('timeout'); // Remove previous timeout messages
|
|
498
494
|
} else {
|
|
499
|
-
this.restartTimers();
|
|
495
|
+
this.restartTimers().then(() => {});
|
|
500
496
|
}
|
|
501
|
-
this.removeAskSupportButtons();
|
|
502
497
|
const newMessage = this.createMessage<T>(message);
|
|
503
498
|
this.setMessages([...this.messages, newMessage]);
|
|
504
499
|
if (message.participant.isAgent) {
|
|
@@ -507,6 +502,20 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
|
|
|
507
502
|
return newMessage;
|
|
508
503
|
}
|
|
509
504
|
|
|
505
|
+
protected removeMessageByType(type: string) {
|
|
506
|
+
if (this.messages.some(m => m.type === type)) {
|
|
507
|
+
this.setMessages(this.messages.filter(m => m.type !== type));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
private async sendMessageTextInternal(message: string) {
|
|
512
|
+
if (message.trim() === '') {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
const messageModel = this.addMessage(false, message);
|
|
516
|
+
await this.emitAsync(ChatUiEvent.eventMessageSend, messageModel);
|
|
517
|
+
}
|
|
518
|
+
|
|
510
519
|
private createMessage<T extends ChatMessageModelBase>(rest: Omit<T, 'id' | 'timestamp'>) {
|
|
511
520
|
return {
|
|
512
521
|
id: nanoid(),
|
|
@@ -528,14 +537,4 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
|
|
|
528
537
|
this.incomingMessageSoundPromise = undefined;
|
|
529
538
|
}
|
|
530
539
|
}
|
|
531
|
-
|
|
532
|
-
private removeMessageByType(type: ChatMessageModelType) {
|
|
533
|
-
if (this.messages.some(m => m.type === type)) {
|
|
534
|
-
this.setMessages(this.messages.filter(m => m.type !== type));
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
private removeAskSupportButtons() {
|
|
539
|
-
this.removeMessageByType('askSupportButtons');
|
|
540
|
-
}
|
|
541
540
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Container } from '@servicetitan/react-ioc';
|
|
2
|
+
|
|
3
|
+
type Newable<T> = new (...args: never[]) => T;
|
|
4
|
+
|
|
5
|
+
export const initTestContainer = (
|
|
6
|
+
serviceIdentifier: Newable<unknown> | Newable<unknown>[],
|
|
7
|
+
initDependenciesFn: (container: Container) => void
|
|
8
|
+
) => {
|
|
9
|
+
const rootContainer = new Container();
|
|
10
|
+
if (Array.isArray(serviceIdentifier)) {
|
|
11
|
+
serviceIdentifier.forEach(identifier => rootContainer.bind(identifier).toSelf());
|
|
12
|
+
} else {
|
|
13
|
+
rootContainer.bind(serviceIdentifier).toSelf();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return () => {
|
|
17
|
+
const container = new Container();
|
|
18
|
+
container.parent = rootContainer;
|
|
19
|
+
initDependenciesFn(container);
|
|
20
|
+
return container;
|
|
21
|
+
};
|
|
22
|
+
};
|