Skip to content

Commit d6447c6

Browse files
Shibani Basavashibbas
authored andcommitted
chore: update all DI to be reactive controllers
1 parent 175f299 commit d6447c6

File tree

10 files changed

+242
-103
lines changed

10 files changed

+242
-103
lines changed

packages/chat-component/src/components/chat-component.ts

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ import { ChatController } from './chat-controller.js';
2323
import { ChatHistoryController } from './chat-history-controller.js';
2424
import {
2525
lazyMultiInject,
26-
ComponentType,
27-
type ChatInputComponent,
28-
type ChatInputFooterComponent,
29-
type CitationActionComponent,
26+
ControllerType,
27+
type ChatInputController,
28+
type ChatInputFooterController,
29+
type CitationController,
30+
type ChatSectionController,
3031
} from './composable.js';
32+
import { ChatContextController } from './chat-context.js';
3133

3234
/**
3335
* A chat component that allows the user to ask questions and get answers from an API.
@@ -50,10 +52,22 @@ export class ChatComponent extends LitElement {
5052
inputPosition = 'sticky';
5153

5254
@property({ type: String, attribute: 'data-interaction-model' })
53-
interactionModel: 'ask' | 'chat' = 'chat';
55+
set interactionModel(value: 'ask' | 'chat') {
56+
this.chatContext.interactionModel = value || 'chat';
57+
}
58+
59+
get interactionModel(): 'ask' | 'chat' {
60+
return this.chatContext.interactionModel;
61+
}
5462

5563
@property({ type: String, attribute: 'data-api-url' })
56-
apiUrl = chatHttpOptions.url;
64+
set apiUrl(value: string = chatHttpOptions.url) {
65+
this.chatContext.apiUrl = value;
66+
}
67+
68+
get apiUrl(): string {
69+
return this.chatContext.apiUrl;
70+
}
5771

5872
@property({ type: String, attribute: 'data-custom-branding', converter: (value) => value?.toLowerCase() === 'true' })
5973
isCustomBranding: boolean = globalConfig.IS_CUSTOM_BRANDING;
@@ -78,14 +92,20 @@ export class ChatComponent extends LitElement {
7892
@state()
7993
isDisabled = false;
8094

81-
@state()
82-
isChatStarted = false;
95+
set isChatStarted(value: boolean) {
96+
this.chatContext.isChatStarted = value;
97+
}
98+
99+
get isChatStarted(): boolean {
100+
return this.chatContext.isChatStarted;
101+
}
83102

84103
@state()
85104
isResetInput = false;
86105

87106
private chatController = new ChatController(this);
88107
private chatHistoryController = new ChatHistoryController(this);
108+
private chatContext = new ChatContextController(this);
89109

90110
// Is showing thought process panel
91111
@state()
@@ -104,14 +124,42 @@ export class ChatComponent extends LitElement {
104124

105125
static override styles = [chatStyle];
106126

107-
@lazyMultiInject(ComponentType.ChatInputComponent)
108-
chatInputComponents: ChatInputComponent[] | undefined;
127+
@lazyMultiInject(ControllerType.ChatInput)
128+
chatInputComponents: ChatInputController[] | undefined;
129+
130+
@lazyMultiInject(ControllerType.ChatInputFooter)
131+
chatInputFooterComponets: ChatInputFooterController[] | undefined;
109132

110-
@lazyMultiInject(ComponentType.ChatInputFooterComponent)
111-
chatInputFooterComponets: ChatInputFooterComponent[] | undefined;
133+
@lazyMultiInject(ControllerType.Citation)
134+
citationControllers: CitationController[] | undefined;
112135

113-
@lazyMultiInject(ComponentType.CitationActionComponent)
114-
citationActionComponents: CitationActionComponent[] | undefined;
136+
@lazyMultiInject(ControllerType.ChatSection)
137+
chatFooterComponents: ChatSectionController[] | undefined;
138+
139+
// Lifecycle method that runs when the component is first connected to the DOM
140+
override connectedCallback(): void {
141+
super.connectedCallback();
142+
if (this.chatInputComponents) {
143+
for (const component of this.chatInputComponents) {
144+
component.attach(this, this.chatContext);
145+
}
146+
}
147+
if (this.chatInputFooterComponets) {
148+
for (const component of this.chatInputFooterComponets) {
149+
component.attach(this, this.chatContext);
150+
}
151+
}
152+
if (this.citationControllers) {
153+
for (const component of this.citationControllers) {
154+
component.attach(this, this.chatContext);
155+
}
156+
}
157+
if (this.chatFooterComponents) {
158+
for (const component of this.chatFooterComponents) {
159+
component.attach(this, this.chatContext);
160+
}
161+
}
162+
}
115163

116164
override updated(changedProperties: Map<string | number | symbol, unknown>) {
117165
super.updated(changedProperties);
@@ -326,7 +374,7 @@ export class ChatComponent extends LitElement {
326374
@on-citation-click="${this.handleCitationClick}"
327375
></citation-list>
328376
${this.selectedCitation
329-
? this.citationActionComponents?.map((component) =>
377+
? this.citationControllers?.map((component) =>
330378
component.render(this.selectedCitation, `${this.apiUrl}/content/${this.selectedCitation.text}`),
331379
)
332380
: ''}
@@ -373,6 +421,7 @@ export class ChatComponent extends LitElement {
373421
.selectedCitation="${this.selectedCitation}"
374422
.isCustomBranding="${this.isCustomBranding}"
375423
.svgIcon="${iconLogo}"
424+
.context="${this.chatContext}"
376425
@on-action-button-click="${this.handleChatEntryActionButtonClick}"
377426
@on-citation-click="${this.handleCitationClick}"
378427
@on-followup-click="${this.handleInput}"
@@ -385,7 +434,7 @@ export class ChatComponent extends LitElement {
385434
? ''
386435
: this.chatInputComponents
387436
.filter((component) => component.position === position)
388-
.map((component) => component.render(this.handleInput, this.isChatStarted, this.interactionModel));
437+
.map((component) => component.render(this.handleInput));
389438
}
390439

391440
// Render the chat component as a web component
@@ -479,7 +528,7 @@ export class ChatComponent extends LitElement {
479528
)}
480529
</form>
481530
</section>
482-
${this.isShowingThoughtProcess
531+
<!-- ${this.isShowingThoughtProcess
483532
? html`
484533
<aside class="aside" data-testid="aside-thought-process">
485534
<div class="aside__header">
@@ -494,7 +543,8 @@ export class ChatComponent extends LitElement {
494543
${this.renderChatEntryTabContent(this.selectedChatEntry as ChatThreadEntry)}
495544
</aside>
496545
`
497-
: ''}
546+
: ''} -->
547+
${this.chatFooterComponents?.map((component) => component.render())}
498548
</section>
499549
`;
500550
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { type ReactiveController, type ReactiveControllerHost } from 'lit';
2+
3+
export class ChatContextController implements ReactiveController {
4+
host: ReactiveControllerHost;
5+
6+
constructor(host: ReactiveControllerHost) {
7+
(this.host = host).addController(this);
8+
}
9+
10+
hostConnected() {
11+
// no-op
12+
}
13+
14+
hostDisconnected() {
15+
// no-op
16+
}
17+
18+
private _state: Record<string, any> = {};
19+
20+
private _selectedChatEntry: ChatThreadEntry | undefined = undefined;
21+
22+
private _apiUrl: string = '';
23+
24+
private _interactionModel: 'ask' | 'chat' = 'chat';
25+
26+
private _isChatStarted: boolean = false;
27+
28+
public set isChatStarted(value: boolean) {
29+
this._isChatStarted = value;
30+
this.host.requestUpdate();
31+
}
32+
33+
public get isChatStarted() {
34+
return this._isChatStarted;
35+
}
36+
37+
public setState(key: string, value: any) {
38+
this._state[key] = value;
39+
this.host.requestUpdate();
40+
}
41+
42+
public getState(key: string) {
43+
return this._state[key];
44+
}
45+
46+
public set selectedChatEntry(entry: ChatThreadEntry | undefined) {
47+
this._selectedChatEntry = entry;
48+
this.host.requestUpdate();
49+
}
50+
51+
public get selectedChatEntry() {
52+
return this._selectedChatEntry;
53+
}
54+
55+
public set apiUrl(url: string) {
56+
this._apiUrl = url;
57+
this.host.requestUpdate();
58+
}
59+
60+
public get apiUrl() {
61+
return this._apiUrl;
62+
}
63+
64+
public set interactionModel(model: 'ask' | 'chat') {
65+
this._interactionModel = model;
66+
this.host.requestUpdate();
67+
}
68+
69+
public get interactionModel() {
70+
return this._interactionModel;
71+
}
72+
}

packages/chat-component/src/components/chat-thread-component.ts

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
1010
import iconQuestion from '../../public/svg/bubblequestion-icon.svg?raw';
1111

1212
import { type ChatActionButton } from './chat-action-button.js';
13-
import { type ChatEntryActionButtonComponent, ComponentType, lazyMultiInject } from './composable.js';
13+
import { type ChatEntryActionController, ControllerType, lazyMultiInject } from './composable.js';
14+
import { type ChatContextController } from './chat-context.js';
1415

1516
@customElement('chat-thread-component')
1617
export class ChatThreadComponent extends LitElement {
@@ -19,9 +20,6 @@ export class ChatThreadComponent extends LitElement {
1920
@property({ type: Array })
2021
chatThread: ChatThreadEntry[] = [];
2122

22-
@property({ type: Array })
23-
actionButtons: ChatActionButton[] = [];
24-
2523
@property({ type: Boolean })
2624
isDisabled = false;
2725

@@ -37,14 +35,17 @@ export class ChatThreadComponent extends LitElement {
3735
@property({ type: Object })
3836
selectedCitation: Citation | undefined = undefined;
3937

40-
@lazyMultiInject(ComponentType.ChatEntryActionButtonComponent)
41-
actionCompontents: ChatEntryActionButtonComponent[] | undefined;
38+
@property({ type: Object })
39+
context: ChatContextController | undefined = undefined;
4240

43-
constructor() {
44-
super();
41+
@lazyMultiInject(ControllerType.ChatEntryAction)
42+
actionCompontents: ChatEntryActionController[] | undefined;
43+
44+
connectedCallback() {
45+
super.connectedCallback();
4546
if (this.actionCompontents) {
4647
for (const component of this.actionCompontents) {
47-
component.attach(this);
48+
component.attach(this, this.context);
4849
}
4950
}
5051
}
@@ -105,18 +106,7 @@ export class ChatThreadComponent extends LitElement {
105106
return html`
106107
<header class="chat__header">
107108
<div class="chat__header--button">
108-
${this.actionButtons.map(
109-
(actionButton) => html`
110-
<chat-action-button
111-
.label="${actionButton.label}"
112-
.svgIcon="${actionButton.svgIcon}"
113-
.isDisabled="${actionButton.isDisabled}"
114-
.actionId="${actionButton.id}"
115-
@click="${(event) => this.actionButtonClicked(actionButton, entry, event)}"
116-
></chat-action-button>
117-
`,
118-
)}
119-
${this.actionCompontents?.map((component) => component.render(entry, this.isDisabled, () => {}))}
109+
${this.actionCompontents?.map((component) => component.render(entry, this.isDisabled))}
120110
</div>
121111
</header>
122112
`;
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { injectable } from 'inversify';
2-
import { container, type CitationActionComponent, ComponentType } from './composable.js';
2+
import { container, type CitationController, ControllerType, ComposableReactiveControllerBase } from './composable.js';
33
import { html } from 'lit';
44

55
@injectable()
6-
export class CitationPreviewer implements CitationActionComponent {
6+
export class CitationPreviewer extends ComposableReactiveControllerBase implements CitationController {
77
render(citation: Citation, url: string) {
88
return html`<document-previewer url="${url}"></document-previewer>`;
99
}
1010
}
1111

12-
container.bind<CitationActionComponent>(ComponentType.CitationActionComponent).to(CitationPreviewer);
12+
container.bind<CitationController>(ControllerType.Citation).to(CitationPreviewer);

0 commit comments

Comments
 (0)