Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 93 additions & 88 deletions src/app/components/chat-panel/chat-panel.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -284,104 +284,109 @@
}
</div>
} @if (appName != "" && isChatMode) {
<div class="chat-input">
<input type="file" multiple hidden (change)="fileSelect.emit($event)" #fileInput />
<mat-form-field class="input-field" appearance="outline">
@if ((selectedFiles.length && appName != "") || updatedSessionState) {
<div class="file-preview">
@for (file of selectedFiles; track file; let i = $index) {
<div>
@if (file.file.type.startsWith("image/")) {
<div class="image-container">
<img [src]="file.url" alt="preview" class="image-preview" />
<button mat-icon-button (click)="removeFile.emit(i)" class="delete-button">
<mat-icon color="warn">close</mat-icon>
</button>

<div class="chat-input">
<input type="file" multiple hidden (change)="fileSelect.emit($event)" #fileInput />
<mat-form-field class="input-field" appearance="outline">
@if ((selectedFiles.length && appName != "") || updatedSessionState) {
<div class="file-preview">
@for (file of selectedFiles; track file; let i = $index) {
<div>
@if (file.file.type.startsWith("image/")) {
<div class="image-container">
<img [src]="file.url" alt="preview" class="image-preview" />
<button mat-icon-button (click)="removeFile.emit(i)" class="delete-button">
<mat-icon color="warn">close</mat-icon>
</button>
</div>
} @else if (!file.file.type.startsWith("image/")) {
<div class="file-container">
<button mat-icon-button (click)="removeFile.emit(i)" class="delete-button">
<mat-icon color="warn">close</mat-icon>
</button>
<div class="file-info">
<mat-icon>insert_drive_file</mat-icon>
<span>{{ file.file.name }}</span>
</div>
</div>
}
</div>
} @else if (!file.file.type.startsWith("image/")) {
} @if (updatedSessionState) {
<div class="file-container">
<button mat-icon-button (click)="removeFile.emit(i)" class="delete-button">
<button mat-icon-button (click)="removeStateUpdate.emit()" class="delete-button">
<mat-icon color="warn">close</mat-icon>
</button>
<div class="file-info">
<mat-icon>insert_drive_file</mat-icon>
<span>{{ file.file.name }}</span>
<span>{{ i18n.updatedSessionStateChipLabel }}</span>
</div>
</div>
}
</div>
} @if (updatedSessionState) {
<div class="file-container">
<button mat-icon-button (click)="removeStateUpdate.emit()" class="delete-button">
<mat-icon color="warn">close</mat-icon>
</button>
<div class="file-info">
<span>{{ i18n.updatedSessionStateChipLabel }}</span>
</div>
</div>
}
</div>
}
<textarea
class="chat-input-box"
matInput
cdkTextareaAutosize
cdkAutosizeMinRows="1"
cdkAutosizeMaxRows="10"
[ngModel]="userInput"
(ngModelChange)="userInputChange.emit($event)"
(keydown.enter)="sendMessage.emit($event)"
[placeholder]="i18n.typeMessagePlaceholder"
></textarea>
<div class="chat-input-actions">
<div>
<button
mat-icon-button
(click)="fileInput.click()"
class="function-event-button"
[matTooltip]="i18n.uploadFileTooltip"
[disabled]="!(isMessageFileUploadEnabledObs | async)"
>
<mat-icon>attach_file</mat-icon>
</button>
<button
mat-icon-button
[matMenuTriggerFor]="moreMenu"
class="function-event-button"
[matTooltip]="i18n.moreOptionsTooltip"
[disabled]="!(isManualStateUpdateEnabledObs | async)"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #moreMenu="matMenu">
<span mat-menu-item (click)="updateState.emit()"> {{ i18n.updateStateMenuLabel }} </span>
</mat-menu>
</div>
<div>
<button
mat-icon-button
matSuffix
(click)="toggleAudioRecording.emit()"
class="audio-rec-btn"
[class.recording]="isAudioRecording"
[matTooltip]="isAudioRecording ? i18n.turnOffMicTooltip : i18n.useMicTooltip"
[disabled]="!(isBidiStreamingEnabledObs | async)"
>
<mat-icon>mic</mat-icon>
</button>
<button
mat-icon-button
matSuffix
(click)="toggleVideoRecording.emit()"
class="video-rec-btn"
[class.recording]="isVideoRecording"
[matTooltip]="isVideoRecording ? i18n.turnOffCamTooltip : i18n.useCamTooltip"
[disabled]="!(isBidiStreamingEnabledObs | async)"
>
<mat-icon>videocam</mat-icon>
</button>
<textarea
class="chat-input-box"
matInput
cdkTextareaAutosize
cdkAutosizeMinRows="1"
cdkAutosizeMaxRows="10"
[ngModel]="userInput"
(ngModelChange)="userInputChange.emit($event)"
(keydown.enter)="sendMessage.emit($event)"
[placeholder]="i18n.typeMessagePlaceholder"
></textarea>
<div class="chat-input-actions">
<div>
<button
mat-icon-button
(click)="fileInput.click()"
class="function-event-button"
[matTooltip]="i18n.uploadFileTooltip"
[disabled]="!(isMessageFileUploadEnabledObs | async)"
>
<mat-icon>attach_file</mat-icon>
</button>
<button
mat-icon-button
[matMenuTriggerFor]="moreMenu"
class="function-event-button"
[matTooltip]="i18n.moreOptionsTooltip"
[disabled]="!(isManualStateUpdateEnabledObs | async)"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #moreMenu="matMenu">
<span mat-menu-item
(click)="updateState.emit()"> {{ i18n.updateStateMenuLabel }}
</span>
</mat-menu>
</div>
<div>
<button
mat-icon-button
matSuffix
(click)="toggleAudioRecording.emit()"
class="audio-rec-btn"
[class.recording]="isAudioRecording"
[matTooltip]="isAudioRecording ? i18n.turnOffMicTooltip : i18n.useMicTooltip"
[disabled]="!(isBidiStreamingEnabledObs | async)"
>
<mat-icon>mic</mat-icon>
</button>
<button
mat-icon-button
matSuffix
(click)="toggleVideoRecording.emit()"
class="video-rec-btn"
[class.recording]="isVideoRecording"
[matTooltip]="isVideoRecording ? i18n.turnOffCamTooltip : i18n.useCamTooltip"
[disabled]="!(isBidiStreamingEnabledObs | async)"
>
<mat-icon>videocam</mat-icon>
</button>
</div>
</div>
</mat-form-field>
</div>
</mat-form-field>
</div>

}
8 changes: 5 additions & 3 deletions src/app/components/chat-panel/chat-panel.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,24 @@
* limitations under the License.
*/

import {MarkdownModule} from 'ngx-markdown';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {SimpleChange} from '@angular/core';
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {MatDialogModule} from '@angular/material/dialog';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {MarkdownModule} from 'ngx-markdown';
import {of} from 'rxjs';

import {FEATURE_FLAG_SERVICE} from '../../core/services/feature-flag.service';
import {STRING_TO_COLOR_SERVICE} from '../../core/services/interfaces/string-to-color';
import {StringToColorServiceImpl} from '../../core/services/string-to-color.service';
import {MockFeatureFlagService} from '../../core/services/testing/mock-feature-flag.service';
import {MockStringToColorService} from '../../core/services/testing/mock-string-to-color.service';
import {ChatPanelComponent} from './chat-panel.component';
import {MARKDOWN_COMPONENT} from '../markdown/markdown.component.interface';
import {MarkdownComponent} from '../markdown/markdown.component';
import {MARKDOWN_COMPONENT} from '../markdown/markdown.component.interface';

import {ChatPanelComponent} from './chat-panel.component';

const USER_ID = 'user';
const FUNC1_NAME = 'func1';
Expand Down Expand Up @@ -390,5 +391,6 @@ describe('ChatPanelComponent', () => {
'videocam');
expect(button!.nativeElement.disabled).toBeTrue();
});

});
});
26 changes: 19 additions & 7 deletions src/app/components/chat-panel/chat-panel.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import {TextFieldModule} from '@angular/cdk/text-field';
import {CommonModule, DOCUMENT, NgClass, NgStyle} from '@angular/common';
import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, inject, Inject, Input, OnChanges, Output, Renderer2, signal, SimpleChanges, ViewChild, Type} from '@angular/core';
import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, inject, Inject, Input, OnChanges, Output, Renderer2, signal, SimpleChanges, Type, ViewChild} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import {MatCardModule} from '@angular/material/card';
Expand Down Expand Up @@ -47,10 +47,21 @@ const ROOT_AGENT = 'root_agent';
styleUrl: './chat-panel.component.scss',
standalone: true,
imports: [
CommonModule, FormsModule, MatIconModule, MatCardModule,
MatProgressBarModule, MatButtonModule, MatInputModule, TextFieldModule,
MatFormFieldModule, MatMenuModule, NgxJsonViewerModule,
AudioPlayerComponent, MatTooltipModule, NgClass, NgStyle,
CommonModule,
FormsModule,
MatIconModule,
MatCardModule,
MatProgressBarModule,
MatButtonModule,
MatInputModule,
TextFieldModule,
MatFormFieldModule,
MatMenuModule,
NgxJsonViewerModule,
AudioPlayerComponent,
MatTooltipModule,
NgClass,
NgStyle,
],
})
export class ChatPanelComponent implements OnChanges, AfterViewInit {
Expand Down Expand Up @@ -103,7 +114,7 @@ export class ChatPanelComponent implements OnChanges, AfterViewInit {
protected readonly i18n = inject(ChatPanelMessagesInjectionToken);
private readonly stringToColorService = inject(STRING_TO_COLOR_SERVICE);
readonly markdownComponent: Type<MarkdownComponentInterface> = inject(
MARKDOWN_COMPONENT,
MARKDOWN_COMPONENT,
);
private readonly featureFlagService = inject(FEATURE_FLAG_SERVICE);
readonly MediaType = MediaType;
Expand Down Expand Up @@ -162,7 +173,8 @@ export class ChatPanelComponent implements OnChanges, AfterViewInit {
customIconColorClass(i: number) {
const agentName = this.getAgentNameFromEvent(i);
return agentName !== ROOT_AGENT ?
`custom-icon-color-${this.stringToColorService.stc(agentName).replace('#', '')}` :
`custom-icon-color-${
this.stringToColorService.stc(agentName).replace('#', '')}` :
'';
}

Expand Down
Loading