mirror of
https://github.com/bec-project/bec_atlas.git
synced 2025-07-13 22:51:49 +02:00
feat: add control side-panel
This commit is contained in:
7
frontend/bec_atlas/src/app/core/model/session.ts
Normal file
7
frontend/bec_atlas/src/app/core/model/session.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export interface Session {
|
||||||
|
name: string;
|
||||||
|
deployment_id: string;
|
||||||
|
_id: string;
|
||||||
|
owner_groups: string[];
|
||||||
|
access_groups: []; // This should probably be string[] as well
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Session } from './model/session';
|
||||||
import { ServerSettingsService } from '../server-settings.service';
|
import { ServerSettingsService } from '../server-settings.service';
|
||||||
import { ScanDataResponse } from './model/scan-data';
|
import { ScanDataResponse } from './model/scan-data';
|
||||||
import { Realm } from './model/realm';
|
import { Realm } from './model/realm';
|
||||||
@ -229,3 +230,26 @@ export class ScanDataService extends RemoteDataService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class SessionDataService extends RemoteDataService {
|
||||||
|
/**
|
||||||
|
* Method for getting the available sessions
|
||||||
|
* @param offset Pagination offset (default = 0)
|
||||||
|
* @param limit Number of records to retrieve (default = 100)
|
||||||
|
* @returns response from the server with the scan data
|
||||||
|
* @throws HttpErrorResponse if the request fails
|
||||||
|
* @throws TimeoutError if the request takes too long
|
||||||
|
*/
|
||||||
|
getSessions(offset: number = 0, limit: number = 100) {
|
||||||
|
let headers = new HttpHeaders();
|
||||||
|
headers = headers.set('Content-Type', 'application/json; charset=utf-8');
|
||||||
|
return this.get<Session[]>(
|
||||||
|
'sessions',
|
||||||
|
{ offset: offset.toString(), limit: limit.toString() },
|
||||||
|
headers
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -25,15 +25,32 @@
|
|||||||
|
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
<!-- Scan Table -->
|
<!-- Data Browser -->
|
||||||
<button
|
<mat-expansion-panel>
|
||||||
mat-button
|
<mat-expansion-panel-header>
|
||||||
class="menu-item"
|
<mat-icon>table_chart</mat-icon>
|
||||||
[routerLink]="['/dashboard/scan-table']"
|
<span class="menu-text">Data Browser</span>
|
||||||
>
|
</mat-expansion-panel-header>
|
||||||
<mat-icon>home</mat-icon>
|
|
||||||
<span class="menu-text">Data Browser</span>
|
<button
|
||||||
</button>
|
mat-button
|
||||||
|
class="menu-item"
|
||||||
|
[routerLink]="['/dashboard/scan-table']"
|
||||||
|
> Session Data
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
class="menu-item"
|
||||||
|
> Scan Data
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
class="menu-item"
|
||||||
|
> Device Data
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
</mat-expansion-panel>
|
||||||
|
|
||||||
<!-- Experiment Control Expansion -->
|
<!-- Experiment Control Expansion -->
|
||||||
<mat-expansion-panel
|
<mat-expansion-panel
|
||||||
|
@ -1,69 +1,76 @@
|
|||||||
<!-- Table -->
|
<!-- Table -->
|
||||||
<div class="table-container">
|
<div class="main-container">
|
||||||
<mat-card>
|
<mat-sidenav-container class="sidenav-container">
|
||||||
<!-- Toolbar -->
|
|
||||||
<mat-toolbar color="primary">
|
|
||||||
Table with Scan Data
|
|
||||||
<span class="spacer"></span>
|
|
||||||
<button mat-icon-button (click)="ngOnInit()">
|
|
||||||
<mat-icon>search</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button (click)="handleRefresh()">
|
|
||||||
<mat-icon>refresh</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button (click)="openDialog()">
|
|
||||||
<mat-icon>settings</mat-icon>
|
|
||||||
</button>
|
|
||||||
</mat-toolbar>
|
|
||||||
<!-- Table -->
|
|
||||||
<table mat-table *ngIf="tableData() as data" [dataSource]="data" class="mat-elevation-z8">
|
|
||||||
@for (column of displayedColumns(); track column) {
|
|
||||||
<ng-container [matColumnDef]="column">
|
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ column | titlecase }}</th>
|
|
||||||
<td mat-cell class="table-cell" *matCellDef="let element">
|
|
||||||
@if (column === 'timestamp') {
|
|
||||||
{{ element[column] * 1000 | date :'HH:mm:ss'}}
|
|
||||||
<br>
|
|
||||||
{{ element[column] * 1000 | date :'dd/MM/yyyy'}}
|
|
||||||
}
|
|
||||||
@else if (column === 'user_rating') {
|
|
||||||
<star-rating
|
|
||||||
[starType]="'svg'"
|
|
||||||
[hoverEnabled]="true"
|
|
||||||
(ratingChange)="handleOnRatingChanged($event, element)"
|
|
||||||
[rating]="element[column]">
|
|
||||||
</star-rating>
|
|
||||||
}
|
|
||||||
@else if (column === 'user_comments') {
|
|
||||||
<mat-form-field appearance="outline">
|
|
||||||
<textarea matInput ></textarea>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
}
|
<mat-sidenav-content>
|
||||||
@else{
|
<div class="table-container">
|
||||||
<p> {{ element[column] }}</p>
|
<mat-card>
|
||||||
}
|
<!-- Toolbar -->
|
||||||
</ng-container>
|
<mat-toolbar color="primary">
|
||||||
}
|
Scan Data for {{session()?.name}}
|
||||||
<!-- Header Row -->
|
<span class="spacer"></span>
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns(); sticky: true"></tr>
|
<button mat-icon-button>
|
||||||
<!-- Data Rows -->
|
<!-- Search is not working yet and not hooked up-->
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns()"></tr>
|
<mat-icon>search</mat-icon>
|
||||||
</table>
|
</button>
|
||||||
</mat-card>
|
<button mat-icon-button (click)="handleRefresh()">
|
||||||
</div>
|
<mat-icon>refresh</mat-icon>
|
||||||
<!-- Paginator -->
|
</button>
|
||||||
<div class="table-paginator">
|
<button mat-icon-button (click)="openDialog()">
|
||||||
<mat-paginator
|
<mat-icon>settings</mat-icon>
|
||||||
#paginator
|
</button>
|
||||||
class="table-paginator"
|
</mat-toolbar>
|
||||||
(page) = "handlePageEvent($event)"
|
<!-- Table -->
|
||||||
[length]="totalScanCount()"
|
<table mat-table *ngIf="tableData() as data" [dataSource]="data" class="mat-elevation-z8">
|
||||||
[pageSize]= "limit()"
|
@for (column of displayedColumns(); track column) {
|
||||||
[showFirstLastButtons]="true"
|
<ng-container [matColumnDef]="column">
|
||||||
[pageSizeOptions]="[5, 10, 25, 100]"
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ column | titlecase }}</th>
|
||||||
[pageIndex]="offset()/limit()"
|
<td mat-cell class="table-cell" *matCellDef="let element">
|
||||||
aria-label="Select page"
|
@if (column === 'timestamp') {
|
||||||
sticky= true>
|
{{ element[column] * 1000 | date :'HH:mm:ss'}}
|
||||||
</mat-paginator>
|
<br>
|
||||||
|
{{ element[column] * 1000 | date :'dd/MM/yyyy'}}
|
||||||
|
}
|
||||||
|
@else if (column === 'user_rating') {
|
||||||
|
<star-rating
|
||||||
|
[starType]="'svg'"
|
||||||
|
[hoverEnabled]="true"
|
||||||
|
(ratingChange)="handleOnRatingChanged($event, element)"
|
||||||
|
[rating]="element[column]">
|
||||||
|
</star-rating>
|
||||||
|
}
|
||||||
|
@else{
|
||||||
|
<p> {{ element[column] }}</p>
|
||||||
|
}
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
<!-- Header Row -->
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns(); sticky: true"></tr>
|
||||||
|
<!-- Data Rows -->
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns()"></tr>
|
||||||
|
</table>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
<!-- Paginator -->
|
||||||
|
<div class="table-paginator">
|
||||||
|
<mat-paginator
|
||||||
|
#paginator
|
||||||
|
class="table-paginator"
|
||||||
|
(page) = "handlePageEvent($event)"
|
||||||
|
[length]="totalScanCount()"
|
||||||
|
[pageSize]= "limit()"
|
||||||
|
[showFirstLastButtons]="true"
|
||||||
|
[pageSizeOptions]="[5, 10, 25, 100]"
|
||||||
|
[pageIndex]="offset()/limit()"
|
||||||
|
aria-label="Select page"
|
||||||
|
sticky= true>
|
||||||
|
</mat-paginator>
|
||||||
|
</div>
|
||||||
|
</mat-sidenav-content>
|
||||||
|
<!-- Right side panel -->
|
||||||
|
<mat-sidenav #rightSidenav mode="side" opened="true" position="end" class="sidenav">
|
||||||
|
<!-- Embed the side-panel component here -->
|
||||||
|
<app-side-panel (sessionChanged)="onSessionChange($event)"></app-side-panel>
|
||||||
|
</mat-sidenav>
|
||||||
|
</mat-sidenav-container>
|
||||||
</div>
|
</div>
|
@ -5,8 +5,10 @@
|
|||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-container{
|
.table-container{
|
||||||
width: auto;
|
width: auto;
|
||||||
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
.mat-mdc-row:hover {
|
.mat-mdc-row:hover {
|
||||||
background-color: var(--mat-sys-secondary-container);
|
background-color: var(--mat-sys-secondary-container);
|
||||||
@ -21,19 +23,9 @@
|
|||||||
max-height: 200px
|
max-height: 200px
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
.main-container {
|
||||||
resize: none;
|
// display: flex;
|
||||||
min-height: 32px; /* Initial height */
|
// flex-direction: column;
|
||||||
max-height: 200px; /* Maximum height */
|
height: 100%;
|
||||||
overflow-y: auto; /* Enable scroll when max height is reached */
|
width:100%;
|
||||||
width: 100%;
|
}
|
||||||
padding:0px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-form-field {
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.2;
|
|
||||||
padding-top: 16px;
|
|
||||||
max-height: var(max-height);
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import {
|
|||||||
resource,
|
resource,
|
||||||
Signal,
|
Signal,
|
||||||
inject,
|
inject,
|
||||||
|
WritableSignal,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ScanDataService } from '../core/remote-data.service';
|
import { ScanDataService } from '../core/remote-data.service';
|
||||||
import { ScanDataResponse } from '../core/model/scan-data';
|
import { ScanDataResponse } from '../core/model/scan-data';
|
||||||
@ -31,15 +32,9 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { ColumnSelectionDialogComponent } from './column-selection-dialog/column-selection-dialog.component';
|
import { ColumnSelectionDialogComponent } from './column-selection-dialog/column-selection-dialog.component';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { SidePanelComponent } from './side-panel/side-panel.component';
|
||||||
export interface ResourceStatus {
|
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||||
status: any;
|
import { Session } from '../core/model/session';
|
||||||
}
|
|
||||||
export interface ResourceLoaderParams {
|
|
||||||
request: any;
|
|
||||||
abortSignal: AbortSignal;
|
|
||||||
previous: ResourceStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-scan-table',
|
selector: 'app-scan-table',
|
||||||
@ -59,20 +54,21 @@ export interface ResourceLoaderParams {
|
|||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
|
SidePanelComponent,
|
||||||
|
MatSidenavModule,
|
||||||
],
|
],
|
||||||
templateUrl: './scan-table.component.html',
|
templateUrl: './scan-table.component.html',
|
||||||
styleUrl: './scan-table.component.scss',
|
styleUrl: './scan-table.component.scss',
|
||||||
})
|
})
|
||||||
export class ScanTableComponent {
|
export class ScanTableComponent {
|
||||||
|
// --------------------------------
|
||||||
|
// -------------Signals-------------
|
||||||
|
// --------------------------------
|
||||||
tableData: Signal<ScanDataResponse[]>;
|
tableData: Signal<ScanDataResponse[]>;
|
||||||
totalScanCount: Signal<number>;
|
totalScanCount: Signal<number>;
|
||||||
limit = signal<number>(10);
|
limit = signal<number>(10);
|
||||||
offset = signal<number>(0);
|
offset = signal<number>(0);
|
||||||
sessionId = signal<string>('');
|
session: WritableSignal<Session | null> = signal(null);
|
||||||
dialog = inject(MatDialog);
|
|
||||||
pageEvent: PageEvent = new PageEvent();
|
|
||||||
isEditingUserComments: boolean = false;
|
|
||||||
sorting: number = -1;
|
|
||||||
displayedColumns = signal<string[]>([
|
displayedColumns = signal<string[]>([
|
||||||
'scan_number',
|
'scan_number',
|
||||||
'status',
|
'status',
|
||||||
@ -82,8 +78,15 @@ export class ScanTableComponent {
|
|||||||
'dataset_number',
|
'dataset_number',
|
||||||
'timestamp',
|
'timestamp',
|
||||||
'user_rating',
|
'user_rating',
|
||||||
'user_comments',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// -------------Variables-------------
|
||||||
|
// -----------------------------------
|
||||||
|
dialog = inject(MatDialog);
|
||||||
|
pageEvent: PageEvent = new PageEvent();
|
||||||
|
isEditingUserComments: boolean = false;
|
||||||
|
sorting: number = -1;
|
||||||
allColumns: string[] = [
|
allColumns: string[] = [
|
||||||
'scan_id',
|
'scan_id',
|
||||||
'scan_number',
|
'scan_number',
|
||||||
@ -116,17 +119,28 @@ export class ScanTableComponent {
|
|||||||
'info',
|
'info',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// -------------Compute Signals-------------
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
// Available columns are all columns that are not ignored
|
||||||
availableColumns = computed(() =>
|
availableColumns = computed(() =>
|
||||||
this.allColumns.filter((element) => !this.ignoredEntries.includes(element))
|
this.allColumns.filter((element) => !this.ignoredEntries.includes(element))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Reload criteria is the criteria used to reload the scan data
|
||||||
reloadCriteria = computed(() => ({
|
reloadCriteria = computed(() => ({
|
||||||
sessionId: this.sessionId(),
|
session: this.session(),
|
||||||
offset: this.offset(),
|
offset: this.offset(),
|
||||||
limit: this.limit(),
|
limit: this.limit(),
|
||||||
column: this.displayedColumns(),
|
column: this.displayedColumns(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// -------------Resources-------------
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Load scan data resource
|
||||||
loadScanDataResource = resource({
|
loadScanDataResource = resource({
|
||||||
request: () => this.reloadCriteria(),
|
request: () => this.reloadCriteria(),
|
||||||
loader: ({ request, abortSignal }): Promise<ScanDataResponse[]> => {
|
loader: ({ request, abortSignal }): Promise<ScanDataResponse[]> => {
|
||||||
@ -142,10 +156,11 @@ export class ScanTableComponent {
|
|||||||
: element
|
: element
|
||||||
);
|
);
|
||||||
columns.push('scan_id'); // always include scan_id
|
columns.push('scan_id'); // always include scan_id
|
||||||
|
let sessionId = request.session ? request.session._id : '';
|
||||||
console.log('Columns', columns);
|
console.log('Columns', columns);
|
||||||
return firstValueFrom(
|
return firstValueFrom(
|
||||||
this.scanData.getScanData(
|
this.scanData.getScanData(
|
||||||
request.sessionId,
|
sessionId,
|
||||||
request.offset,
|
request.offset,
|
||||||
request.limit,
|
request.limit,
|
||||||
columns,
|
columns,
|
||||||
@ -156,13 +171,18 @@ export class ScanTableComponent {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load scan count resource
|
||||||
loadScanCountResource = resource({
|
loadScanCountResource = resource({
|
||||||
request: () => this.reloadCriteria(),
|
request: () => this.reloadCriteria(),
|
||||||
loader: ({ request, abortSignal }): Promise<ScanCountResponse> => {
|
loader: ({ request, abortSignal }): Promise<ScanCountResponse> => {
|
||||||
return firstValueFrom(this.scanData.getScanCount(request.sessionId));
|
let sessionId = request.session ? request.session._id : '';
|
||||||
|
return firstValueFrom(this.scanData.getScanCount(sessionId));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// -------------Functions-------------
|
||||||
|
// -----------------------------------
|
||||||
handleScanData(data: ScanDataResponse[] | []) {
|
handleScanData(data: ScanDataResponse[] | []) {
|
||||||
for (const entry of data) {
|
for (const entry of data) {
|
||||||
if (entry?.user_data !== undefined) {
|
if (entry?.user_data !== undefined) {
|
||||||
@ -201,11 +221,9 @@ export class ScanTableComponent {
|
|||||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
@ViewChild(MatSort) sort!: MatSort;
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
|
||||||
ngOnInit(): void {
|
// ----------------------------------------
|
||||||
this.sessionId.set('6793628df62026a414d9338e');
|
// -------------Event Handlers-------------
|
||||||
// this.updateUI();
|
// ----------------------------------------
|
||||||
}
|
|
||||||
|
|
||||||
handlePageEvent(event: PageEvent) {
|
handlePageEvent(event: PageEvent) {
|
||||||
this.pageEvent = event;
|
this.pageEvent = event;
|
||||||
this.offset.set(event.pageIndex * event.pageSize);
|
this.offset.set(event.pageIndex * event.pageSize);
|
||||||
@ -228,14 +246,14 @@ export class ScanTableComponent {
|
|||||||
dialogRef.afterClosed().subscribe((result: string[] | null) => {
|
dialogRef.afterClosed().subscribe((result: string[] | null) => {
|
||||||
if (result !== null) {
|
if (result !== null) {
|
||||||
this.displayedColumns.set(result);
|
this.displayedColumns.set(result);
|
||||||
// this.handleRefresh();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleColumnSelection(event: any) {}
|
onSessionChange(session: Session | null): void {
|
||||||
|
console.log('Session changed', session);
|
||||||
toggleAllEdit() {}
|
this.session.set(session);
|
||||||
|
}
|
||||||
|
|
||||||
async handleOnRatingChanged(event: any, element: ScanDataResponse) {
|
async handleOnRatingChanged(event: any, element: ScanDataResponse) {
|
||||||
console.log('Event', event, 'Element', element);
|
console.log('Event', event, 'Element', element);
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
<h2>Control Panel</h2>
|
||||||
|
<mat-form-field appearance="outline" class="side-panel-item">
|
||||||
|
<mat-label>Select Session</mat-label>
|
||||||
|
<mat-select [value]="selectedSession" (selectionChange)="onSessionChange($event.value)">
|
||||||
|
<mat-option>--</mat-option>
|
||||||
|
@for (session of sessions; track session) {
|
||||||
|
<mat-option [value]="session">{{session.name}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<h2>Add Filters</h2>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SidePanelComponent } from './side-panel.component';
|
||||||
|
|
||||||
|
describe('SidePanelComponent', () => {
|
||||||
|
let component: SidePanelComponent;
|
||||||
|
let fixture: ComponentFixture<SidePanelComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [SidePanelComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(SidePanelComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,34 @@
|
|||||||
|
import { Component, output, Signal, signal } from '@angular/core';
|
||||||
|
import { MatSelect } from '@angular/material/select';
|
||||||
|
import { MatFormField } from '@angular/material/select';
|
||||||
|
import { MatLabel } from '@angular/material/select';
|
||||||
|
import { MatOption } from '@angular/material/select';
|
||||||
|
|
||||||
|
import { Session } from '../../core/model/session';
|
||||||
|
import { SessionDataService } from '../../core/remote-data.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-side-panel',
|
||||||
|
imports: [MatSelect, MatFormField, MatLabel, MatOption],
|
||||||
|
templateUrl: './side-panel.component.html',
|
||||||
|
styleUrl: './side-panel.component.scss',
|
||||||
|
})
|
||||||
|
export class SidePanelComponent {
|
||||||
|
selectedSession: Session | null = null;
|
||||||
|
sessions: Session[] = [];
|
||||||
|
|
||||||
|
readonly sessionChanged = output<Session | null>();
|
||||||
|
|
||||||
|
constructor(private sessionDataService: SessionDataService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.sessionDataService.getSessions().subscribe((sessions) => {
|
||||||
|
this.sessions = sessions;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSessionChange(session: Session | null): void {
|
||||||
|
this.selectedSession = session;
|
||||||
|
this.sessionChanged.emit(session);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user