Skip to content

Commit 2d15eea

Browse files
muditgokhale2copybara-github
authored andcommitted
Add a submit button to the hosts sidenav for trace_viewer
PiperOrigin-RevId: 823535397
1 parent 56f6b21 commit 2d15eea

File tree

3 files changed

+114
-22
lines changed

3 files changed

+114
-22
lines changed

frontend/app/components/sidenav/sidenav.ng.html

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,37 @@
3030
</mat-form-field>
3131
</div>
3232

33-
<div class="item-container">
33+
<div class="item-container" *ngIf="!isMultiHostsEnabled">
3434
<div [ngClass]="{'mat-subheading-2': true, 'disabled': !hosts.length}">
35-
Hosts ({{ isMultiHostsEnabled ? selectedHostsInternal.length : hosts.length }})
35+
Hosts ({{hosts.length}})
3636
</div>
3737
<mat-form-field class="full-width" appearance="outline">
38-
<!-- Multi-host select -->
39-
<mat-select *ngIf="isMultiHostsEnabled" panelClass="panel-override" [value]="selectedHostsInternal" [disabled]="!hosts.length" (selectionChange)="onHostsSelectionChange($event.value)" multiple>
38+
<mat-select #singleSelectHost="matSelect" panelClass="panel-override" [value]="selectedHost" [disabled]="!hosts.length" (selectionChange)="onHostSelectionChange($event.value)">
4039
<mat-option *ngFor="let host of hosts" [value]="host">
4140
{{host}}
4241
</mat-option>
4342
</mat-select>
44-
<!-- Single-host select -->
45-
<mat-select *ngIf="!isMultiHostsEnabled" panelClass="panel-override" [value]="selectedHost" [disabled]="!hosts.length" (selectionChange)="onHostSelectionChange($event.value)">
46-
<mat-option *ngFor="let host of hosts" [value]="host">
47-
{{host}}
48-
</mat-option>
43+
</mat-form-field>
44+
</div>
45+
46+
<div class="item-container" *ngIf="isMultiHostsEnabled">
47+
<div [ngClass]="{'mat-subheading-2': true, 'disabled': !hosts.length}">
48+
Hosts ({{selectedHostsInternal.length}})
49+
</div>
50+
<mat-form-field class="full-width" appearance="outline">
51+
<mat-select #multiSelectHost="matSelect" panelClass="multi-host-select-panel" [value]="selectedHostsPending" [disabled]="!hosts.length" (selectionChange)="onHostsSelectionChange($event.value)" multiple>
52+
53+
<div class="select-panel-content">
54+
<mat-option *ngFor="let host of hosts" [value]="host">
55+
{{host}}
56+
</mat-option>
57+
58+
<div class="submit-button-container" (click)="$event.stopPropagation()">
59+
<button mat-flat-button color="primary" class="full-width" (click)="onSubmitHosts(); multiSelectHost.close()">
60+
Apply Host Selection
61+
</button>
62+
</div>
63+
</div>
4964
</mat-select>
5065
</mat-form-field>
5166
</div>
@@ -73,4 +88,3 @@
7388
</div>
7489

7590
<br>
76-

frontend/app/components/sidenav/sidenav.scss

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,36 @@
1313
.mat-subheading-2 {
1414
margin-bottom: 0;
1515
}
16+
17+
// Target the custom panel class defined in sidenav.ng.html
18+
.multi-host-select-panel {
19+
// Mat-select uses a standard mat-option list structure, but we need to ensure
20+
// the custom wrapper div inside the panel handles layout correctly.
21+
22+
// This selector targets the element that contains all the options and the button container.
23+
// It ensures vertical stacking of options and the button.
24+
.select-panel-content {
25+
display: flex;
26+
flex-direction: column;
27+
// Note: The Mat Select component internally sets overflow and max-height for scrolling.
28+
}
29+
30+
// Container for the submit button at the bottom of the dropdown
31+
.submit-button-container {
32+
position: sticky;
33+
bottom: 0;
34+
padding: 8px;
35+
36+
background: #fff;
37+
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
38+
39+
.full-width {
40+
width: 100%;
41+
}
42+
}
43+
44+
// Ensure options remain clickable and are not covered by the sticky button's padding.
45+
mat-option {
46+
flex-shrink: 0;
47+
}
48+
}

frontend/app/components/sidenav/sidenav.ts

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export class SideNav implements OnInit, OnDestroy {
3333
selectedTagInternal = '';
3434
selectedHostInternal = '';
3535
selectedHostsInternal: string[] = [];
36+
selectedHostsPending: string[] = [];
3637
selectedModuleInternal = '';
3738
navigationParams: {[key: string]: string|boolean} = {};
3839
multiHostEnabledTools: string[] = ['trace_viewer', 'trace_viewer@'];
@@ -141,10 +142,14 @@ export class SideNav implements OnInit, OnDestroy {
141142
this.selectedTagInternal = tag;
142143
this.selectedModuleInternal = moduleName;
143144

144-
if (hostsParam) {
145-
this.selectedHostsInternal = hostsParam.split(',');
145+
if (this.isMultiHostsEnabled) {
146+
if (hostsParam) {
147+
this.selectedHostsInternal = hostsParam.split(',');
148+
}
149+
this.selectedHostsPending = [...this.selectedHostsInternal];
150+
} else {
151+
this.selectedHostInternal = host;
146152
}
147-
this.selectedHostInternal = host;
148153
this.update();
149154
}
150155

@@ -168,7 +173,7 @@ export class SideNav implements OnInit, OnDestroy {
168173
...this.navigationParams,
169174
};
170175
if (this.isMultiHostsEnabled) {
171-
navigationEvent.hosts = this.selectedHosts;
176+
navigationEvent.hosts = this.selectedHostsInternal;
172177
} else {
173178
navigationEvent.host = this.selectedHost;
174179
}
@@ -258,9 +263,35 @@ export class SideNav implements OnInit, OnDestroy {
258263
this.afterUpdateTag();
259264
}
260265

261-
onTagSelectionChange(tag: string) {
266+
async onTagSelectionChange(tag: string) {
267+
const previousSelectedTag = this.selectedTagInternal;
262268
this.selectedTagInternal = tag;
263-
this.afterUpdateTag();
269+
270+
const isChangingToMultiHost = !previousSelectedTag ||
271+
(this.isMultiHostsEnabled && previousSelectedTag !== this.selectedTag);
272+
273+
this.selectedHostsInternal = [];
274+
this.selectedHostsPending = [];
275+
this.selectedHostInternal = '';
276+
277+
if (isChangingToMultiHost) {
278+
this.hosts = await this.getHostsForSelectedTag();
279+
if (this.hosts.length > 0) {
280+
this.selectedHostsInternal = [this.hosts[0]];
281+
} else {
282+
this.selectedHostsInternal = [];
283+
}
284+
this.selectedHostsPending = [...this.selectedHostsInternal];
285+
286+
if (this.is_hlo_tool) {
287+
this.moduleList = await this.getModuleListForSelectedTag();
288+
}
289+
290+
this.navigateTools();
291+
292+
} else {
293+
this.afterUpdateTag();
294+
}
264295
}
265296

266297
afterUpdateTag() {
@@ -271,8 +302,17 @@ export class SideNav implements OnInit, OnDestroy {
271302
// Keep them under the same update function as initial step of the separation.
272303
async updateHosts() {
273304
this.hosts = await this.getHostsForSelectedTag();
274-
this.selectedHostsInternal = [this.hosts[0]];
275-
this.selectedHostInternal = this.hosts[0];
305+
306+
if (this.isMultiHostsEnabled) {
307+
if (this.selectedHostsInternal.length === 0 && this.hosts.length > 0) {
308+
this.selectedHostsInternal = [this.hosts[0]];
309+
}
310+
this.selectedHostsPending = [...this.selectedHostsInternal];
311+
} else {
312+
if (!this.selectedHostInternal && this.hosts.length > 0) {
313+
this.selectedHostInternal = this.hosts[0];
314+
}
315+
}
276316
if (this.is_hlo_tool) {
277317
this.moduleList = await this.getModuleListForSelectedTag();
278318
}
@@ -282,13 +322,16 @@ export class SideNav implements OnInit, OnDestroy {
282322

283323
onHostSelectionChange(selection: string) {
284324
this.selectedHostInternal = selection;
285-
this.selectedHostsInternal = [];
286325
this.navigateTools();
287326
}
288327

289328
onHostsSelectionChange(selection: string[]) {
290-
this.selectedHostsInternal = selection;
291-
this.selectedHostInternal = ''; // Ensure single-host is empty
329+
this.selectedHostsPending =
330+
Array.isArray(selection) ? selection : [selection];
331+
}
332+
333+
onSubmitHosts() {
334+
this.selectedHostsInternal = [...this.selectedHostsPending];
292335
this.navigateTools();
293336
}
294337

@@ -298,7 +341,9 @@ export class SideNav implements OnInit, OnDestroy {
298341
}
299342

300343
afterUpdateHost() {
301-
this.navigateTools();
344+
if (!this.isMultiHostsEnabled) {
345+
this.navigateTools();
346+
}
302347
}
303348

304349
// Helper function to serialize query parameters

0 commit comments

Comments
 (0)