Skip to content
Merged
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
32 changes: 18 additions & 14 deletions src/devtools/mobileharness/fe/v6/angular/app/app.ng.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@
}
</mat-toolbar>

<mat-sidenav-container autosize [class.collapsed]="!sideNavExpanded" class="app-sidenav-container">
<mat-sidenav-container autosize class="app-sidenav-container">
<!--Sidenav menu-->
<mat-sidenav mode="side" opened role="navigation">
<mat-sidenav mode="side" [opened]="sideNavExpanded" role="navigation">
<div class="sidenav-container">
<mat-nav-list>
<a
mat-list-item
routerLink="/dev/device-harness"
[class.active]="isNavActive('home')"
queryParamsHandling="preserve"
[queryParams]="getPreservedQueryParams()"
[matTooltip]="'Home'"
>
<mat-icon matListItemIcon class="material-symbols-outlined">home</mat-icon>
Expand All @@ -58,10 +58,9 @@

<a
mat-list-item
[routerLink]="isFakeData ? '/dev/device-harness' : '/devices'"
[fragment]="isFakeData ? 'device-scenarios' : undefined"
routerLink="/devices"
[class.active]="isNavActive('devices')"
queryParamsHandling="preserve"
[queryParams]="getPreservedQueryParams()"
[matTooltip]="'Devices'"
>
<mat-icon matListItemIcon class="material-symbols-outlined">devices</mat-icon>
Expand All @@ -73,7 +72,7 @@
[routerLink]="isFakeData ? '/dev/device-harness' : '/hosts'"
[fragment]="isFakeData ? 'host-scenarios' : undefined"
[class.active]="isNavActive('hosts')"
queryParamsHandling="preserve"
[queryParams]="getPreservedQueryParams()"
[matTooltip]="'Hosts'"
>
<mat-icon matListItemIcon class="material-symbols-outlined">dns</mat-icon>
Expand All @@ -84,10 +83,9 @@

<a
mat-list-item
[routerLink]="isFakeData ? '/dev/device-harness' : '/tests'"
[fragment]="isFakeData ? 'test-scenarios' : undefined"
routerLink="/tests"
[class.active]="isNavActive('tests')"
queryParamsHandling="preserve"
[queryParams]="getPreservedQueryParams()"
[matTooltip]="'Tests'"
>
<mat-icon matListItemIcon class="material-symbols-outlined">fact_check</mat-icon>
Expand All @@ -96,17 +94,23 @@

<a
mat-list-item
[routerLink]="isFakeData ? '/dev/device-harness' : '/jobs'"
[fragment]="isFakeData ? 'job-scenarios' : undefined"
routerLink="/jobs"
[class.active]="isNavActive('jobs')"
queryParamsHandling="preserve"
[queryParams]="getPreservedQueryParams()"
[matTooltip]="'Jobs'"
>
<mat-icon matListItemIcon class="material-symbols-outlined">task</mat-icon>
<span>Jobs</span>
</a>

<a mat-list-item routerLink="/sessions" routerLinkActive="active" queryParamsHandling="preserve" [matTooltip]="'Sessions'">
<a
mat-list-item
[routerLink]="isFakeData ? '/dev/device-harness' : '/sessions'"
[fragment]="isFakeData ? 'session-scenarios' : undefined"
[class.active]="isNavActive('sessions')"
[queryParams]="getPreservedQueryParams()"
[matTooltip]="'Sessions'"
>
<mat-icon matListItemIcon class="material-symbols-outlined">view_timeline</mat-icon>
<span>Sessions</span>
</a>
Expand Down
35 changes: 14 additions & 21 deletions src/devtools/mobileharness/fe/v6/angular/app/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ app-root {
height: 100vh;
background-color: $labconsole-bg;

$sidenav-collapsed-width: 62px;
$sidenav-expanded-width: 256px;
$nav-transition-duration: 250ms;

Expand Down Expand Up @@ -464,13 +463,26 @@ app-root {
flex-direction: column;
height: 100%;
background-color: $labconsole-bg;
overflow-x: hidden;
@include common.shared-scrollbar-style();

main {
flex: 1;
overflow: auto;
display: flex;
flex-direction: column;
min-height: 0;
overflow: hidden auto;
width: 100%;
max-width: 100%;
box-sizing: border-box;
background-color: $labconsole-bg;
@include common.shared-scrollbar-style();

> * {
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
}
}

Expand All @@ -481,25 +493,6 @@ app-root {
container-width: $sidenav-expanded-width,
)
);

&.collapsed {
@include mat.sidenav-overrides(
(
container-divider-color: $border-menu,
container-width: $sidenav-collapsed-width,
)
);

mat-divider {
margin: 16px 0;
border-color: transparent;
}

mat-nav-list > a[mat-list-item] {
border-radius: 0;
margin: 0;
}
}
}

.embedded-content {
Expand Down
55 changes: 55 additions & 0 deletions src/devtools/mobileharness/fe/v6/angular/app/app.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,59 @@ describe('App Component', () => {
expect(component).toBeTruthy();
});

it('should have sideNavExpanded true by default', () => {
expect(component.sideNavExpanded).toBeTrue();
});

describe('Standalone mode', () => {
let standaloneComponent: App;
let standaloneFixture: ComponentFixture<App>;

beforeEach(async () => {
const standaloneMockActivatedRoute = {
snapshot: {
queryParams: {},
queryParamMap: convertToParamMap({'is_embedded_mode': 'false'}),
} as unknown as ActivatedRoute['snapshot'],
queryParamMap: of(convertToParamMap({'is_embedded_mode': 'false'})),
};

await TestBed.resetTestingModule();
await TestBed.configureTestingModule({
imports: [NoopAnimationsModule, App],
providers: [
provideRouter([]),
{provide: APP_DATA, useValue: appData},
{provide: UrlService, useValue: mockUrlService},
{provide: ActivatedRoute, useValue: standaloneMockActivatedRoute},
],
}).compileComponents();

standaloneFixture = TestBed.createComponent(App);
standaloneComponent = standaloneFixture.componentInstance;
standaloneFixture.detectChanges();
});

it('should be in standalone mode with expanded sideNav by default', () => {
expect(standaloneComponent.isStandaloneMode).toBeTrue();
expect(standaloneComponent.sideNavExpanded).toBeTrue();
const sidenav =
standaloneFixture.nativeElement.querySelector('mat-sidenav');
expect(sidenav).toBeTruthy();
});

it('should toggle sideNavExpanded when menu button is clicked', () => {
const toggleButton: HTMLButtonElement =
standaloneFixture.nativeElement.querySelector('.toggleSidenavButton');
expect(toggleButton).toBeTruthy();

toggleButton.click();
standaloneFixture.detectChanges();
expect(standaloneComponent.sideNavExpanded).toBeFalse();

toggleButton.click();
standaloneFixture.detectChanges();
expect(standaloneComponent.sideNavExpanded).toBeTrue();
});
});
});
31 changes: 28 additions & 3 deletions src/devtools/mobileharness/fe/v6/angular/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ import {filter, takeUntil} from 'rxjs/operators';
],
})
export class App implements OnDestroy {
sideNavExpanded = false;
sideNavExpanded = true;
private readonly destroy = new ReplaySubject<void>();
private readonly route: ActivatedRoute = inject(ActivatedRoute);
private readonly cdr: ChangeDetectorRef = inject(ChangeDetectorRef);
Expand All @@ -91,7 +91,7 @@ export class App implements OnDestroy {
}

isNavActive(
section: 'home' | 'devices' | 'hosts' | 'tests' | 'jobs',
section: 'home' | 'devices' | 'hosts' | 'tests' | 'jobs' | 'sessions',
): boolean {
const path = this.getCurrentRoutePath();
const fragment = this.router.parseUrl(this.router.url).fragment;
Expand All @@ -110,11 +110,28 @@ export class App implements OnDestroy {
(path.startsWith('jobs') && !path.includes('tests')) ||
fragment === 'job-scenarios'
);
case 'sessions':
return path.startsWith('sessions') || fragment === 'session-scenarios';
default:
return false;
}
}

getPreservedQueryParams() {
const qParams: Record<string, string> = {};
if (this.isFakeData) {
qParams['fake_data'] = 'true';
}
if (this.isEmbeddedMode) {
qParams['is_embedded_mode'] = 'true';
}
const universe = this.route.snapshot.queryParams['universe'];
if (universe) {
qParams['universe'] = universe;
}
return qParams;
}

private getCurrentRoutePath(): string {
let route = this.router.routerState.snapshot.root;
while (route.firstChild) {
Expand Down Expand Up @@ -162,7 +179,15 @@ export class App implements OnDestroy {
const path = route.routeConfig?.path;
const params = route.params;

if (path === 'dev/device-harness' || path === 'devices' || !path) {
if (
!path ||
path === 'dev/device-harness' ||
path === 'devices' ||
path === 'hosts' ||
path === 'tests' ||
path === 'jobs' ||
path === 'sessions'
) {
this.showContent = true;
} else if (path === 'devices/:id' && params['id']) {
this.showContent = true;
Expand Down
15 changes: 13 additions & 2 deletions src/devtools/mobileharness/fe/v6/angular/app/app_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '@angular/core';
import {MatSnackBarModule} from '@angular/material/snack-bar';
import {provideAnimations} from '@angular/platform-browser/animations';
import {ActivatedRoute, provideRouter} from '@angular/router';
import {ActivatedRoute, provideRouter, withRouterConfig} from '@angular/router';

import {routes} from './app_routes';
import {authInterceptor} from './core/interceptors/auth_interceptor';
Expand All @@ -26,6 +26,9 @@ import {InterceptedFakeHostService} from './core/services/host/intercepted_fake_
import {FakeJobService} from './core/services/job/fake_job_service';
import {HttpJobService} from './core/services/job/http_job_service';
import {JOB_SERVICE} from './core/services/job/job_service';
import {FakeSearchService} from './core/services/search/fake_search_service';
import {HttpSearchService} from './core/services/search/http_search_service';
import {SEARCH_SERVICE} from './core/services/search/search_service';
import {FakeSessionService} from './core/services/session/fake_session_service';
import {HttpSessionService} from './core/services/session/http_session_service';
import {SESSION_SERVICE} from './core/services/session/session_service';
Expand All @@ -40,7 +43,7 @@ export const appConfig: ApplicationConfig = {
providers: [
provideZonelessChangeDetection(),
importProvidersFrom(MatSnackBarModule),
provideRouter(routes),
provideRouter(routes, withRouterConfig({onSameUrlNavigation: 'reload'})),
provideHttpClient(
withInterceptors([
authInterceptor,
Expand Down Expand Up @@ -103,6 +106,14 @@ export const appConfig: ApplicationConfig = {
},
deps: [ActivatedRoute],
},
{
provide: SEARCH_SERVICE,
useFactory: (route: ActivatedRoute) => {
const useFakeData = route.snapshot.queryParams['fake_data'] === 'true';
return useFakeData ? new FakeSearchService() : new HttpSearchService();
},
deps: [ActivatedRoute],
},
provideAnimations(),
{
provide: APP_DATA,
Expand Down
51 changes: 50 additions & 1 deletion src/devtools/mobileharness/fe/v6/angular/app/app_routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import {DevHarnessPage} from './features/dev_harness/dev_harness_page';
import {DeviceDetailPage} from './features/device_detail/device_detail_page';
import {HostDetail} from './features/host_detail/host_detail';
import {JobDetail} from './features/job_detail/job_detail';
import {SearchPage} from './features/search_page/search_page';
import {FleetSearchStore} from './features/search_page/services/fleet_search_store';
import {SearchPageStore} from './features/search_page/services/search_page_store';
import {TjsSearchStore} from './features/search_page/services/tjs_search_store';
import {SessionDetailPage} from './features/session_detail/session_detail';
import {TestDetail} from './features/test_detail/test_detail';

Expand Down Expand Up @@ -33,9 +37,54 @@ export const routes: Routes = [
path: 'dev/device-harness',
component: DevHarnessPage,
},
{
path: 'devices',
component: SearchPage,
data: {'entity': 'devices'},
providers: [
FleetSearchStore,
{provide: SearchPageStore, useExisting: FleetSearchStore},
],
},
{
path: 'hosts',
component: SearchPage,
data: {'entity': 'hosts'},
providers: [
FleetSearchStore,
{provide: SearchPageStore, useExisting: FleetSearchStore},
],
},
{
path: 'tests',
component: SearchPage,
data: {'entity': 'tests'},
providers: [
TjsSearchStore,
{provide: SearchPageStore, useExisting: TjsSearchStore},
],
},
{
path: 'jobs',
component: SearchPage,
data: {'entity': 'jobs'},
providers: [
TjsSearchStore,
{provide: SearchPageStore, useExisting: TjsSearchStore},
],
},
{
path: 'sessions',
component: SearchPage,
data: {'entity': 'sessions'},
providers: [
TjsSearchStore,
{provide: SearchPageStore, useExisting: TjsSearchStore},
],
},
{
path: 'devices/:id',
component: DeviceDetailPage, // Changed from loadComponent
component: DeviceDetailPage,
},
{
path: 'hosts/:hostName',
Expand Down
Loading
Loading