Skip to content

Commit 2a0f7e7

Browse files
OmniLab Teamcopybara-github
authored andcommitted
Internal change
PiperOrigin-RevId: 912880236
1 parent dd72ef3 commit 2a0f7e7

28 files changed

Lines changed: 967 additions & 350 deletions

src/devtools/mobileharness/fe/v6/angular/app/core/models/host_action.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,12 @@ export declare interface ReleaseReady {
8484
/**
8585
* Represents the status of a Lab Server release.
8686
*/
87-
export type ReleaseStatus = 'Latest' | 'Current' | 'Deprecated' | '';
87+
export type ReleaseStatus =
88+
| 'LATEST'
89+
| 'CURRENT'
90+
| 'LATEST_AND_CURRENT'
91+
| 'VERSION_STATUS_UNSPECIFIED'
92+
| '';
8893

8994
/**
9095
* Configuration for a specific Lab Server release.
@@ -174,7 +179,19 @@ export declare interface DecommissionHostResponse {}
174179
/**
175180
* Response for UpdatePassThroughFlags API.
176181
*/
177-
export declare interface UpdatePassThroughFlagsResponse {}
182+
export declare interface UpdatePassThroughFlagsResponse {
183+
readonly success: boolean;
184+
readonly error?: {
185+
readonly code:
186+
| 'CODE_UNSPECIFIED'
187+
| 'PERMISSION_DENIED'
188+
| 'INVALID_FLAGS'
189+
| 'HOST_NOT_FOUND'
190+
| 'WARPGATE_ERROR'
191+
| 'UNKNOWN';
192+
readonly message?: string;
193+
};
194+
}
178195

179196
/**
180197
* Response for those rollout action

src/devtools/mobileharness/fe/v6/angular/app/core/services/host/fake_host_service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ export class FakeHostService extends HostService {
165165
const scenario = MOCK_HOST_SCENARIOS.find((s) => s.hostName === hostName);
166166
if (scenario && scenario.overview) {
167167
scenario.overview.labServer.passThroughFlags = flags;
168-
return of({});
168+
return of({success: true});
169169
} else {
170170
return throwError(
171171
() =>

src/devtools/mobileharness/fe/v6/angular/app/core/services/mock_data/hosts/03_shared_mode.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @fileoverview Mock host scenario in SHARED device config mode. */
22

33
import {DeviceConfig} from '../../../models/device_config_models';
4+
import {PreflightLabServerReleaseResponse} from '../../../models/host_action';
45
import {HostConfig} from '../../../models/host_config_models';
56
import {MockHostScenario} from '../models';
67
import {
@@ -33,6 +34,25 @@ const HOST_CONFIG: HostConfig = {
3334
},
3435
};
3536

37+
const PREFLIGHT_RESPONSE: PreflightLabServerReleaseResponse = {
38+
ready: {
39+
versions: [
40+
{
41+
name: '[RELEASE] 4.358.0 mobileharness_lab_server',
42+
version: '4.358.0',
43+
status: 'LATEST_AND_CURRENT',
44+
buildTime: new Date(Date.now() - 3600000 * 24).toISOString(),
45+
},
46+
{
47+
name: '[RELEASE] 4.357.0 mobileharness_lab_server',
48+
version: '4.357.0',
49+
status: '',
50+
buildTime: new Date(Date.now() - 3600000 * 48).toISOString(),
51+
},
52+
],
53+
},
54+
};
55+
3656
export const SCENARIO_HOST_SHARED_MODE: MockHostScenario = {
3757
hostName: 'host-shared-mode.example.com',
3858
scenarioName: '3. Shared Mode',
@@ -44,4 +64,5 @@ export const SCENARIO_HOST_SHARED_MODE: MockHostScenario = {
4464
},
4565
defaultDeviceConfig: null, // No default in SHARED mode
4666
actions: createHostActions('RUNNING', true),
67+
releaseResponse: PREFLIGHT_RESPONSE,
4768
};

src/devtools/mobileharness/fe/v6/angular/app/core/services/mock_data/hosts/ui_status_utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export function createDefaultReleaseResponse(): PreflightLabServerReleaseRespons
9090
{
9191
name: 'mobileharness_lab_server',
9292
version: 'v4.349.0',
93-
status: 'Latest',
93+
status: 'LATEST',
9494
buildTime: '2024-03-15 21:30:00',
9595
ports: [{protocol: 'grpc', portNumber: 9994}],
9696
releaseDetails: {
@@ -270,7 +270,7 @@ export function createDefaultReleaseResponse(): PreflightLabServerReleaseRespons
270270
{
271271
name: 'release_configs',
272272
version: 'v4.357.0',
273-
status: 'Current',
273+
status: 'CURRENT',
274274
buildTime: '2025-03-13 12:00:00',
275275
ports: [
276276
{

src/devtools/mobileharness/fe/v6/angular/app/features/host_detail/components/host_overview/flags_dialog/flags_dialog.ng.html

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
type="host"
55
width="64rem"
66
height="80vh"
7-
maxHeight="90vh"
7+
maxHeight="80vh"
88
footerType="normal">
99
<div header-prefix class="header-icon-wrapper">
1010
<mat-icon>tune</mat-icon>
@@ -112,7 +112,8 @@
112112
</div>
113113

114114
<!-- Right Column: Presets -->
115-
<div class="flags-dialog-presets-col">
115+
<!-- TODO: qiupingf - remove hidden when the RPC is ready. -->
116+
<div class="flags-dialog-presets-col hidden">
116117
<div class="presets-header">
117118
<div class="header-title">
118119
<mat-icon>auto_awesome</mat-icon>
@@ -161,9 +162,6 @@ <h3>Quick Presets</h3>
161162

162163
<ng-template #actionsTemplate>
163164
<div class="footer-actions">
164-
@if (errorMessage()) {
165-
<span class="error-text">{{ errorMessage() }}</span>
166-
}
167165
<button class="secondary-button" (click)="discardChanges()" [disabled]="!isDirty() || isSaving()">Discard Changes</button>
168166
<button class="primary-button" (click)="save()" [disabled]="!isDirty() || isSaving()">
169167
@if (isSaving()) {

src/devtools/mobileharness/fe/v6/angular/app/features/host_detail/components/host_overview/flags_dialog/flags_dialog.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,10 @@
507507
}
508508
}
509509
}
510+
511+
&.hidden {
512+
display: none;
513+
}
510514
}
511515
}
512516

src/devtools/mobileharness/fe/v6/angular/app/features/host_detail/components/host_overview/flags_dialog/flags_dialog.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import {MatInputModule} from '@angular/material/input';
2121
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
2222
import {take} from 'rxjs/operators';
2323

24-
import {PopularFlag} from '../../../../../core/models/host_action';
24+
import {SnackBarService} from '@deviceinfra/app/shared/services/snackbar_service';
25+
import {
26+
PopularFlag,
27+
UpdatePassThroughFlagsResponse,
28+
} from '../../../../../core/models/host_action';
2529
import {HOST_SERVICE} from '../../../../../core/services/host/host_service';
2630
import {Dialog} from '../../../../../shared/components/config_common/dialog/dialog';
2731

@@ -58,14 +62,14 @@ export class FlagsDialog implements OnInit {
5862
readonly data = inject<FlagsDialogData>(MAT_DIALOG_DATA);
5963
private readonly dialogRef = inject(MatDialogRef<FlagsDialog>);
6064
private readonly hostService = inject(HOST_SERVICE);
65+
private readonly snackBarService = inject(SnackBarService);
6166

6267
readonly isListMode = signal(true);
6368
readonly currentFlagsArray = signal<string[]>([]);
6469
readonly initialFlagsArray = signal<string[]>([]);
6570
readonly presets = signal<PopularFlag[]>([]);
6671
readonly isLoadingPresets = signal(false);
6772
readonly isSaving = signal(false);
68-
readonly errorMessage = signal('');
6973
readonly addInput = signal('');
7074
readonly filterText = signal('');
7175
readonly rawTextFlags = signal('');
@@ -196,13 +200,23 @@ export class FlagsDialog implements OnInit {
196200
}
197201

198202
appendPreset(preset: PopularFlag) {
203+
const newFlags = this.splitFlags(preset.cmd);
199204
if (this.isListMode()) {
200-
const newFlags = this.splitFlags(preset.cmd);
201-
this.currentFlagsArray.update((flags) => [...flags, ...newFlags]);
205+
this.currentFlagsArray.update((flags) => {
206+
const currentSet = new Set(flags);
207+
const flagsToAppend = newFlags.filter((f) => !currentSet.has(f));
208+
return [...flags, ...flagsToAppend];
209+
});
202210
} else {
203211
this.rawTextFlags.update((text) => {
212+
const currentFlags = this.splitFlags(text);
213+
const currentSet = new Set(currentFlags);
214+
const flagsToAppend = newFlags.filter((f) => !currentSet.has(f));
215+
if (flagsToAppend.length === 0) return text;
204216
const trimmed = text.trim();
205-
return trimmed ? `${trimmed} ${preset.cmd}` : preset.cmd;
217+
return trimmed
218+
? `${trimmed} ${flagsToAppend.join(' ')}`
219+
: flagsToAppend.join(' ');
206220
});
207221
}
208222
}
@@ -228,19 +242,27 @@ export class FlagsDialog implements OnInit {
228242
}
229243

230244
this.isSaving.set(true);
231-
this.errorMessage.set('');
232245

233246
this.hostService
234247
.updatePassThroughFlags(this.data.hostName, finalString)
235248
.pipe(take(1))
236249
.subscribe({
237-
next: () => {
238-
this.isSaving.set(false);
239-
this.dialogRef.close(finalString);
250+
next: (response: UpdatePassThroughFlagsResponse) => {
251+
if (response.success) {
252+
this.isSaving.set(false);
253+
this.dialogRef.close(finalString);
254+
} else {
255+
this.isSaving.set(false);
256+
const msg =
257+
response.error?.message ||
258+
response.error?.code ||
259+
'Failed to save flags';
260+
this.snackBarService.showError(msg);
261+
}
240262
},
241-
error: (err: Error) => {
263+
error: () => {
242264
this.isSaving.set(false);
243-
this.errorMessage.set(err.message || 'Failed to save flags');
265+
this.snackBarService.showError('Failed to save flags');
244266
},
245267
});
246268
}

0 commit comments

Comments
 (0)