Skip to content

Commit

Permalink
Merge pull request #1978 from DSD-DBS/session-viewer-auto-connect
Browse files Browse the repository at this point in the history
feat: Handle unready sessions in session viewer
  • Loading branch information
MoritzWeber0 authored Nov 12, 2024
2 parents 164984d + 107fe1d commit c6d2508
Show file tree
Hide file tree
Showing 27 changed files with 586 additions and 415 deletions.
6 changes: 3 additions & 3 deletions frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ViewLogsDialogComponent } from 'src/app/projects/models/backup-settings
import { PipelineWrapperComponent } from 'src/app/projects/models/backup-settings/wrapper/pipeline-wrapper/pipeline-wrapper.component';
import { ModelRestrictionsComponent } from 'src/app/projects/models/model-restrictions/model-restrictions.component';
import { EditProjectMetadataComponent } from 'src/app/projects/project-detail/edit-project-metadata/edit-project-metadata.component';
import { SessionComponent } from 'src/app/sessions/session/session.component';
import { SessionViewerComponent } from 'src/app/sessions/session/session-viewer.component';
import { ConfigurationSettingsComponent } from 'src/app/settings/core/configuration-settings/configuration-settings.component';
import { PipelinesOverviewComponent } from 'src/app/settings/core/pipelines-overview/pipelines-overview.component';
import { CreateToolComponent } from 'src/app/settings/core/tools-settings/create-tool/create-tool.component';
Expand Down Expand Up @@ -61,8 +61,8 @@ export const routes: Routes = [
data: { breadcrumb: 'Sessions' },
},
{
path: 'session',
component: SessionComponent,
path: 'session-viewer',
component: SessionViewerComponent,
data: { breadcrumb: 'Session Viewer' },
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const authGuard: CanActivateFn = (
return true;
} else {
// Needs window.location, since Router.url isn't updated yet
authService.redirectURL = window.location.pathname;
authService.redirectURL = window.location.pathname + window.location.search;
authService.login();
return false;
}
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/app/general/header/header.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ class MockNavbarService implements Partial<NavBarService> {
name: 'Sessions',
requiredRole: 'user',
},
{
name: 'Session viewer',
requiredRole: 'user',
},
{
name: 'Session overview',
requiredRole: 'administrator',
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/app/general/nav-bar/nav-bar.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ export class NavBarService {
routerLink: '',
requiredRole: 'user',
},
{
name: 'Session viewer',
routerLink: ['/session'],
requiredRole: 'user',
},
{
name: 'Session overview',
routerLink: ['/sessions', 'overview'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,58 @@
~ SPDX-License-Identifier: Apache-2.0
-->

<ng-container *ngIf="sessionViewerService.sessions$ | async as viewerSessions">
@if (sessionViewerService.sessions$ | async; as viewerSessions) {
<div class="flex h-full gap-0.5">
<div
class="flex w-full flex-col active:z-30"
[ngClass]="{
'z-20': session.focused,
'z-10': !session.focused,
}"
(click)="sessionViewerService.focusSession(session)"
*ngFor="let session of viewerSessions; trackBy: trackBySessionId"
cdkDrag
(cdkDragStarted)="dragStart()"
(cdkDragEnded)="dragStop()"
>
@for (session of viewerSessions; track trackBySessionId) {
<div
class="flex cursor-grab items-center justify-between gap-2 rounded-t p-1 active:cursor-grabbing"
[ngClass]="session.focused ? 'bg-slate-100' : 'bg-slate-300'"
cdkDragHandle
class="flex w-full flex-col active:z-30"
[ngClass]="{
'z-20': session.focused,
'z-10': !session.focused,
}"
(click)="sessionViewerService.focusSession(session)"
cdkDrag
(cdkDragStarted)="dragStart()"
(cdkDragEnded)="dragStop()"
>
<div class="flex items-center gap-2">
<mat-icon>control_camera</mat-icon>
<span>
{{ session.version.tool.name }} {{ session.version.name }},
{{ session.type }}
</span>
</div>

<div>
<div *ngIf="session.focused" class="flex items-center gap-2">
<span>Focused</span><mat-icon>phonelink</mat-icon>
<div
class="flex cursor-grab items-center justify-between gap-2 rounded-t p-1 active:cursor-grabbing"
[ngClass]="session.focused ? 'bg-slate-100' : 'bg-slate-300'"
cdkDragHandle
>
<div class="flex items-center gap-2">
<mat-icon>control_camera</mat-icon>
<span>
{{ session.version.tool.name }} {{ session.version.name }},
{{ session.type }}
</span>
</div>
<div *ngIf="!session.focused" class="flex items-center gap-2">
<span>Not focused</span>
<mat-icon>phonelink_off</mat-icon>

<div class="flex items-center gap-2">
@if (session.focused) {
<span>Focused</span><mat-icon>phonelink</mat-icon>
} @else {
<span>Not focused</span>
<mat-icon>phonelink_off</mat-icon>
}
</div>

@if ((sessionViewerService.allSessions$ | async)!.length > 1) {
<button
class="m-0 flex items-center"
(click)="sessionViewerService.toggleFullscreen(session)"
>
@if (session.fullscreen) {
<mat-icon>fullscreen_exit</mat-icon>
} @else {
<mat-icon>fullscreen</mat-icon>
}
</button>
}
</div>

<button
class="m-0 flex items-center"
(click)="sessionViewerService.toggleFullscreen(session)"
>
<mat-icon *ngIf="!session.fullscreen">fullscreen</mat-icon>
<mat-icon *ngIf="session.fullscreen">fullscreen_exit</mat-icon>
</button>
<app-session-iframe class="flex h-full" [session]="session" />
</div>

<app-session-iframe class="flex h-full" [session]="session" />
</div>
}
</div>
</ng-container>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
import { NgIf, NgFor, NgClass, AsyncPipe } from '@angular/common';
import { NgClass, AsyncPipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { MatIcon } from '@angular/material/icon';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
Expand All @@ -16,8 +16,6 @@ import { SessionViewerService, ViewerSession } from '../session-viewer.service';
templateUrl: './floating-window-manager.component.html',
standalone: true,
imports: [
NgIf,
NgFor,
CdkDrag,
NgClass,
CdkDragHandle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,15 @@

z-index: 40;
}

.error {
@apply bg-error;
}

.warning {
@apply bg-warning;
}

.primary {
@apply bg-primary;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,57 @@
-->

<div class="relative grow">
<div
*ngIf="!session.focused"
class="iframe-overlay bg-black opacity-10"
></div>
@if (!session.focused) {
<div class="iframe-overlay bg-black opacity-10"></div>
}

@if (
!sessionService.beautifyState(session.preparation_state, session.state)
.success
) {
<div
class="iframe-overlay flex items-center justify-center bg-black text-white"
>
<div
class="m-2 rounded border p-5 text-center"
[ngClass]="
sessionService.beautifyState(session.preparation_state, session.state)
.css
"
>
The session will be loaded as soon as it is ready.
<div
class="mt-2 flex w-full items-center justify-center gap-5 text-center"
>
<div class="basis-1/3">
<div class="text-sm">Preparation</div>
<div class="text-xl font-bold">
{{ session.preparation_state }}
</div>
</div>
<mat-icon>{{
sessionService.beautifyState(
session.preparation_state,
session.state
).icon
}}</mat-icon>
<div class="basis-1/3">
<div class="text-sm">Session</div>
<div class="text-xl font-bold">{{ session.state }}</div>
</div>
</div>
@if (
sessionService.beautifyState(session.preparation_state, session.state)
.info;
as info
) {
<div class="mt-2 max-w-card text-sm">
{{ info }}
</div>
}
</div>
</div>
}
<iframe
[title]="
session.version.tool.name +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@
* SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { NgIf, NgClass } from '@angular/common';
import { NgClass } from '@angular/common';
import { Component, Input } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { SessionService } from 'src/app/sessions/service/session.service';
import { ViewerSession } from '../session-viewer.service';

@Component({
selector: 'app-session-iframe',
templateUrl: './session-iframe.component.html',
styleUrls: ['./session-iframe.component.css'],
standalone: true,
imports: [NgIf, NgClass],
imports: [NgClass, MatIconModule],
})
export class SessionIFrameComponent {
@Input({ required: true }) session!: ViewerSession;

constructor(public sessionService: SessionService) {}
}
43 changes: 43 additions & 0 deletions frontend/src/app/sessions/session/session-viewer.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!--
~ SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors
~ SPDX-License-Identifier: Apache-2.0
-->

@if ((sessionViewerService.sessions$ | async) === undefined) {
<div class="flex h-screen">
<mat-spinner class="m-auto"></mat-spinner>
</div>
}

@if (sessionViewerService.sessions$ | async; as viewerSessions) {
@if (viewerSessions.length) {
<div
class="select-none"
[ngClass]="{
'h-[calc(100vh-2vh-65px-110px)]':
(fullscreenService.isFullscreen$ | async) === false,
'h-screen': fullscreenService.isFullscreen$ | async,
}"
>
@if (this.selectedWindowType === "floating") {
<app-floating-window-manager />
} @else {
<app-tiling-window-manager />
}
</div>
}
}

<div class="fixed bottom-4 right-4 z-50">
<button
mat-fab
color="primary"
(click)="fullscreenService.toggleFullscreen()"
>
@if (fullscreenService.isFullscreen$ | async) {
<mat-icon>fullscreen_exit</mat-icon>
} @else {
<mat-icon>fullscreen</mat-icon>
}
</button>
</div>
72 changes: 72 additions & 0 deletions frontend/src/app/sessions/session/session-viewer.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { NgClass, AsyncPipe } from '@angular/common';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule, MatFabButton } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { ActivatedRoute } from '@angular/router';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { FullscreenService } from 'src/app/sessions/service/fullscreen.service';
import { SessionService } from 'src/app/sessions/service/session.service';
import { UserSessionService } from 'src/app/sessions/service/user-session.service';
import { FloatingWindowManagerComponent } from './floating-window-manager/floating-window-manager.component';
import { SessionViewerService } from './session-viewer.service';
import { TilingWindowManagerComponent } from './tiling-window-manager/tiling-window-manager.component';

@Component({
selector: 'app-session-viewer',
templateUrl: './session-viewer.component.html',
standalone: true,
imports: [
NgxSkeletonLoaderModule,
FormsModule,
MatButtonModule,
MatIconModule,
NgClass,
FloatingWindowManagerComponent,
TilingWindowManagerComponent,
MatFabButton,
AsyncPipe,
MatProgressSpinnerModule,
],
})
@UntilDestroy()
export class SessionViewerComponent implements OnInit, OnDestroy {
selectedWindowType?: string = undefined;

constructor(
public userSessionService: UserSessionService,
public sessionService: SessionService,
public sessionViewerService: SessionViewerService,
public fullscreenService: FullscreenService,
private route: ActivatedRoute,
) {
this.fullscreenService.toggleFullscreen();
this.fullscreenService.isFullscreen$
.pipe(untilDestroyed(this))
.subscribe(() => this.sessionViewerService.resizeSessions());
}

ngOnInit(): void {
this.route.queryParams.subscribe((params) => {
this.selectedWindowType = params['window-manager'] || 'tiling';
const sessionIDs = params['session-id'];
if (typeof sessionIDs === 'string') {
this.sessionViewerService.pushSession(sessionIDs);
} else {
for (const sessionID of sessionIDs) {
this.sessionViewerService.pushSession(sessionID);
}
}
});
}

ngOnDestroy(): void {
this.sessionViewerService.clearSessions();
}
}
Loading

0 comments on commit c6d2508

Please sign in to comment.