From 46025835973ab0fa3870e6807081ce2de50b268b Mon Sep 17 00:00:00 2001 From: appel_c Date: Tue, 11 Feb 2025 10:56:49 +0100 Subject: [PATCH] feat: add control side-panel --- .../bec_atlas/src/app/core/model/session.ts | 7 + .../src/app/core/remote-data.service.ts | 24 +++ .../app/dashboard/dashboard.component.html | 35 +++-- .../app/scan-table/scan-table.component.html | 139 +++++++++--------- .../app/scan-table/scan-table.component.scss | 24 +-- .../app/scan-table/scan-table.component.ts | 72 +++++---- .../side-panel/side-panel.component.html | 11 ++ .../side-panel/side-panel.component.scss | 0 .../side-panel/side-panel.component.spec.ts | 23 +++ .../side-panel/side-panel.component.ts | 34 +++++ 10 files changed, 251 insertions(+), 118 deletions(-) create mode 100644 frontend/bec_atlas/src/app/core/model/session.ts create mode 100644 frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.html create mode 100644 frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.scss create mode 100644 frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.spec.ts create mode 100644 frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.ts diff --git a/frontend/bec_atlas/src/app/core/model/session.ts b/frontend/bec_atlas/src/app/core/model/session.ts new file mode 100644 index 0000000..adce990 --- /dev/null +++ b/frontend/bec_atlas/src/app/core/model/session.ts @@ -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 +} diff --git a/frontend/bec_atlas/src/app/core/remote-data.service.ts b/frontend/bec_atlas/src/app/core/remote-data.service.ts index bd03dfe..087b072 100644 --- a/frontend/bec_atlas/src/app/core/remote-data.service.ts +++ b/frontend/bec_atlas/src/app/core/remote-data.service.ts @@ -1,5 +1,6 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { Session } from './model/session'; import { ServerSettingsService } from '../server-settings.service'; import { ScanDataResponse } from './model/scan-data'; 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( + 'sessions', + { offset: offset.toString(), limit: limit.toString() }, + headers + ); + } +} diff --git a/frontend/bec_atlas/src/app/dashboard/dashboard.component.html b/frontend/bec_atlas/src/app/dashboard/dashboard.component.html index 5d6c72a..97b59a4 100644 --- a/frontend/bec_atlas/src/app/dashboard/dashboard.component.html +++ b/frontend/bec_atlas/src/app/dashboard/dashboard.component.html @@ -25,15 +25,32 @@ - - + + + + table_chart + Data Browser + + + + + + + + -
- - - - Table with Scan Data - - - - - - - - @for (column of displayedColumns(); track column) { - - - - - -
{{ column | titlecase }} - @if (column === 'timestamp') { - {{ element[column] * 1000 | date :'HH:mm:ss'}} -
- {{ element[column] * 1000 | date :'dd/MM/yyyy'}} - } - @else if (column === 'user_rating') { - - - } - @else if (column === 'user_comments') { - - - +
+ - } - @else{ -

{{ element[column] }}

- } - - } - -
-
-
- -
- - + +
+ + + + Scan Data for {{session()?.name}} + + + + + + + + @for (column of displayedColumns(); track column) { + + + + + +
{{ column | titlecase }} + @if (column === 'timestamp') { + {{ element[column] * 1000 | date :'HH:mm:ss'}} +
+ {{ element[column] * 1000 | date :'dd/MM/yyyy'}} + } + @else if (column === 'user_rating') { + + + } + @else{ +

{{ element[column] }}

+ } + + } + +
+
+
+ +
+ + +
+
+ + + + + +
\ No newline at end of file diff --git a/frontend/bec_atlas/src/app/scan-table/scan-table.component.scss b/frontend/bec_atlas/src/app/scan-table/scan-table.component.scss index d4a5d63..be69843 100644 --- a/frontend/bec_atlas/src/app/scan-table/scan-table.component.scss +++ b/frontend/bec_atlas/src/app/scan-table/scan-table.component.scss @@ -5,8 +5,10 @@ padding-left: 16px; padding-bottom: 16px; } + .table-container{ width: auto; + padding-right: 16px; } .mat-mdc-row:hover { background-color: var(--mat-sys-secondary-container); @@ -21,19 +23,9 @@ max-height: 200px } -textarea { - resize: none; - min-height: 32px; /* Initial height */ - max-height: 200px; /* Maximum height */ - overflow-y: auto; /* Enable scroll when max height is reached */ - width: 100%; - padding:0px; - border: none; - } - - mat-form-field { - font-size: 12px; - line-height: 1.2; - padding-top: 16px; - max-height: var(max-height); - } \ No newline at end of file +.main-container { + // display: flex; + // flex-direction: column; + height: 100%; + width:100%; +} \ No newline at end of file diff --git a/frontend/bec_atlas/src/app/scan-table/scan-table.component.ts b/frontend/bec_atlas/src/app/scan-table/scan-table.component.ts index feb1a5a..ca35fcd 100644 --- a/frontend/bec_atlas/src/app/scan-table/scan-table.component.ts +++ b/frontend/bec_atlas/src/app/scan-table/scan-table.component.ts @@ -6,6 +6,7 @@ import { resource, Signal, inject, + WritableSignal, } from '@angular/core'; import { ScanDataService } from '../core/remote-data.service'; 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 { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; - -export interface ResourceStatus { - status: any; -} -export interface ResourceLoaderParams { - request: any; - abortSignal: AbortSignal; - previous: ResourceStatus; -} +import { SidePanelComponent } from './side-panel/side-panel.component'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { Session } from '../core/model/session'; @Component({ selector: 'app-scan-table', @@ -59,20 +54,21 @@ export interface ResourceLoaderParams { MatCheckboxModule, MatFormFieldModule, MatInputModule, + SidePanelComponent, + MatSidenavModule, ], templateUrl: './scan-table.component.html', styleUrl: './scan-table.component.scss', }) export class ScanTableComponent { + // -------------------------------- + // -------------Signals------------- + // -------------------------------- tableData: Signal; totalScanCount: Signal; limit = signal(10); offset = signal(0); - sessionId = signal(''); - dialog = inject(MatDialog); - pageEvent: PageEvent = new PageEvent(); - isEditingUserComments: boolean = false; - sorting: number = -1; + session: WritableSignal = signal(null); displayedColumns = signal([ 'scan_number', 'status', @@ -82,8 +78,15 @@ export class ScanTableComponent { 'dataset_number', 'timestamp', 'user_rating', - 'user_comments', ]); + + // ----------------------------------- + // -------------Variables------------- + // ----------------------------------- + dialog = inject(MatDialog); + pageEvent: PageEvent = new PageEvent(); + isEditingUserComments: boolean = false; + sorting: number = -1; allColumns: string[] = [ 'scan_id', 'scan_number', @@ -116,17 +119,28 @@ export class ScanTableComponent { 'info', ]; + // ---------------------------------------- + // -------------Compute Signals------------- + // ---------------------------------------- + + // Available columns are all columns that are not ignored availableColumns = computed(() => this.allColumns.filter((element) => !this.ignoredEntries.includes(element)) ); + // Reload criteria is the criteria used to reload the scan data reloadCriteria = computed(() => ({ - sessionId: this.sessionId(), + session: this.session(), offset: this.offset(), limit: this.limit(), column: this.displayedColumns(), })); + // ----------------------------------- + // -------------Resources------------- + // ----------------------------------- + + // Load scan data resource loadScanDataResource = resource({ request: () => this.reloadCriteria(), loader: ({ request, abortSignal }): Promise => { @@ -142,10 +156,11 @@ export class ScanTableComponent { : element ); columns.push('scan_id'); // always include scan_id + let sessionId = request.session ? request.session._id : ''; console.log('Columns', columns); return firstValueFrom( this.scanData.getScanData( - request.sessionId, + sessionId, request.offset, request.limit, columns, @@ -156,13 +171,18 @@ export class ScanTableComponent { }, }); + // Load scan count resource loadScanCountResource = resource({ request: () => this.reloadCriteria(), loader: ({ request, abortSignal }): Promise => { - return firstValueFrom(this.scanData.getScanCount(request.sessionId)); + let sessionId = request.session ? request.session._id : ''; + return firstValueFrom(this.scanData.getScanCount(sessionId)); }, }); + // ----------------------------------- + // -------------Functions------------- + // ----------------------------------- handleScanData(data: ScanDataResponse[] | []) { for (const entry of data) { if (entry?.user_data !== undefined) { @@ -201,11 +221,9 @@ export class ScanTableComponent { @ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatSort) sort!: MatSort; - ngOnInit(): void { - this.sessionId.set('6793628df62026a414d9338e'); - // this.updateUI(); - } - + // ---------------------------------------- + // -------------Event Handlers------------- + // ---------------------------------------- handlePageEvent(event: PageEvent) { this.pageEvent = event; this.offset.set(event.pageIndex * event.pageSize); @@ -228,14 +246,14 @@ export class ScanTableComponent { dialogRef.afterClosed().subscribe((result: string[] | null) => { if (result !== null) { this.displayedColumns.set(result); - // this.handleRefresh(); } }); } - handleColumnSelection(event: any) {} - - toggleAllEdit() {} + onSessionChange(session: Session | null): void { + console.log('Session changed', session); + this.session.set(session); + } async handleOnRatingChanged(event: any, element: ScanDataResponse) { console.log('Event', event, 'Element', element); diff --git a/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.html b/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.html new file mode 100644 index 0000000..1d403c9 --- /dev/null +++ b/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.html @@ -0,0 +1,11 @@ +

Control Panel

+ + Select Session + + -- + @for (session of sessions; track session) { + {{session.name}} + } + + +

Add Filters

diff --git a/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.scss b/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.spec.ts b/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.spec.ts new file mode 100644 index 0000000..26c22d1 --- /dev/null +++ b/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.spec.ts @@ -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; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SidePanelComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SidePanelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.ts b/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.ts new file mode 100644 index 0000000..3dd69e2 --- /dev/null +++ b/frontend/bec_atlas/src/app/scan-table/side-panel/side-panel.component.ts @@ -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(); + + 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); + } +}