From 5918401f774609033bd05142bd1a4f759a432a55 Mon Sep 17 00:00:00 2001 From: appel_c Date: Thu, 30 Jan 2025 15:52:31 +0100 Subject: [PATCH] feat: add column settings dialog, no changing column order --- .../bec_atlas/src/app/core/model/scan-data.ts | 62 ++++++++----- .../src/app/core/model/scan-user-data.ts | 7 ++ .../src/app/core/remote-data.service.ts | 7 +- .../column-selection-dialog.component.html | 17 ++++ .../column-selection-dialog.component.scss | 0 .../column-selection-dialog.component.spec.ts | 23 +++++ .../column-selection-dialog.component.ts | 41 +++++++++ .../app/scan-table/scan-table.component.html | 18 ++-- .../app/scan-table/scan-table.component.ts | 92 +++++++++++++++++-- 9 files changed, 228 insertions(+), 39 deletions(-) create mode 100644 frontend/bec_atlas/src/app/core/model/scan-user-data.ts create mode 100644 frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.html create mode 100644 frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.scss create mode 100644 frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.spec.ts create mode 100644 frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.ts diff --git a/frontend/bec_atlas/src/app/core/model/scan-data.ts b/frontend/bec_atlas/src/app/core/model/scan-data.ts index 90871f2..264f124 100644 --- a/frontend/bec_atlas/src/app/core/model/scan-data.ts +++ b/frontend/bec_atlas/src/app/core/model/scan-data.ts @@ -1,24 +1,42 @@ export interface ScanDataResponse { - scan_id?: string; - scan_number?: number; - status?: "open" | "paused" | "aborted" | "halted" | "closed"; - session_id?: string; - num_points?: number; - scan_name?: string; - scan_type?: "step" | "fly"; - dataset_number?: number; - scan_report_devices?: string[]; - user_metadata?: { [key: string]: any }; - readout_priority?: { [key: "monitored" | "baseline" | "async" | "continuous" | "on_request" | string]: string[] }; - scan_parameters?: { [key: "exp_time" | "frames_per_trigger" | "settling_time" | "readout_time" | string]: any }; - request_inputs?: { [key: "arg_bundle" | "inputs" | "kwargs" | string]: any }; - info?: { [key: string]: any }; - timestamp?: number; - user_data?: { [key: string]: any }; - name?: string; - user_rating?: number; - system_rating?: number; - user_comments?: string; - system_comments?: string; + scan_id?: string; + scan_number?: number; + status?: 'open' | 'paused' | 'aborted' | 'halted' | 'closed'; + session_id?: string; + num_points?: number; + scan_name?: string; + scan_type?: 'step' | 'fly'; + dataset_number?: number; + scan_report_devices?: string[]; + user_metadata?: { [key: string]: any }; + readout_priority?: { + [ + key: + | 'monitored' + | 'baseline' + | 'async' + | 'continuous' + | 'on_request' + | string + ]: string[]; + }; + scan_parameters?: { + [ + key: + | 'exp_time' + | 'frames_per_trigger' + | 'settling_time' + | 'readout_time' + | string + ]: any; + }; + request_inputs?: { [key: 'arg_bundle' | 'inputs' | 'kwargs' | string]: any }; + info?: { [key: string]: any }; + timestamp?: number; + user_data?: { [key: string]: any }; + name?: string; + user_rating?: number; + system_rating?: number; + user_comments?: string; + system_comments?: string; } - \ No newline at end of file diff --git a/frontend/bec_atlas/src/app/core/model/scan-user-data.ts b/frontend/bec_atlas/src/app/core/model/scan-user-data.ts new file mode 100644 index 0000000..273eec1 --- /dev/null +++ b/frontend/bec_atlas/src/app/core/model/scan-user-data.ts @@ -0,0 +1,7 @@ +export interface ScanUserData { + name: string; + user_rating: number; + system_rating: number; + user_comments: string; + system_comments: string; +} 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 6fb71f3..8ea45ae 100644 --- a/frontend/bec_atlas/src/app/core/remote-data.service.ts +++ b/frontend/bec_atlas/src/app/core/remote-data.service.ts @@ -1,10 +1,11 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { Inject, inject, Injectable } from '@angular/core'; +import { Injectable } from '@angular/core'; import { ServerSettingsService } from '../server-settings.service'; import { ScanDataResponse } from './model/scan-data'; import { Realm } from './model/realm'; import { Deployment } from './model/deployment'; import { ScanCountResponse } from './model/scan-count'; +import { ScanUserData } from './model/scan-user-data'; @Injectable({ providedIn: 'root', @@ -42,7 +43,7 @@ export class RemoteDataService { */ protected get( path: string, - params: { [key: string]: string | number }, + params: { [key: string]: string | number | Array }, headers: HttpHeaders ) { return this.httpClient.get( @@ -110,7 +111,7 @@ export class ScanDataService extends RemoteDataService { session_id: sessionId, offset: offset.toString(), limit: limit.toString(), - fields: fields ? fields.join(',') : '', + fields: fields ? fields : '', sort: sort ? JSON.stringify(sort) : '', includeUserData: includeUserData.toString(), }, diff --git a/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.html b/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.html new file mode 100644 index 0000000..eeb66a8 --- /dev/null +++ b/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.html @@ -0,0 +1,17 @@ +

Select Columns

+ + + @for (column of columns; track column; let i = $index) { + {{ column.name }}
+ } +
+ + + + + + \ No newline at end of file diff --git a/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.scss b/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.spec.ts b/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.spec.ts new file mode 100644 index 0000000..fa5392c --- /dev/null +++ b/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ColumnSelectionDialogComponent } from './column-selection-dialog.component'; + +describe('ColumnSelectionDialogComponent', () => { + let component: ColumnSelectionDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ColumnSelectionDialogComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ColumnSelectionDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.ts b/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.ts new file mode 100644 index 0000000..16c1c00 --- /dev/null +++ b/frontend/bec_atlas/src/app/scan-table/column-selection-dialog/column-selection-dialog.component.ts @@ -0,0 +1,41 @@ +import { Component, inject } from '@angular/core'; +import { MatCheckbox, MatCheckboxChange } from '@angular/material/checkbox'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { + MatDialogModule, + MatDialogRef, + MAT_DIALOG_DATA, +} from '@angular/material/dialog'; + +// Models +export interface ColumnModel { + name: string; + selected: boolean; +} +@Component({ + selector: 'app-column-selection-dialog', + imports: [MatCheckbox, MatDialogModule, MatIconModule, MatButtonModule], + templateUrl: './column-selection-dialog.component.html', + styleUrl: './column-selection-dialog.component.scss', +}) +export class ColumnSelectionDialogComponent { + columns = inject(MAT_DIALOG_DATA); + initialSelection: string[] = []; + readonly dialogRef = inject(MatDialogRef); + + handleCheckboxChecked(event: MatCheckboxChange, index: number): void { + this.columns[index].selected = event.checked; + } + + onCancelClick(): void { + this.dialogRef.close(null); + } + + onApplyClick(): void { + let data = this.columns + .filter((column) => column.selected) + .map((column) => column.name); + this.dialogRef.close(data); + } +} diff --git a/frontend/bec_atlas/src/app/scan-table/scan-table.component.html b/frontend/bec_atlas/src/app/scan-table/scan-table.component.html index 9f627dd..09d3747 100644 --- a/frontend/bec_atlas/src/app/scan-table/scan-table.component.html +++ b/frontend/bec_atlas/src/app/scan-table/scan-table.component.html @@ -6,18 +6,24 @@ - - + - - + + + - +
{{ column | titlecase }} {{ column | titlecase }} @if (column === 'timestamp') { {{ element[column] * 1000 | date :'HH:mm:ss'}} @@ -33,9 +39,9 @@ -
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 cb51739..25571bf 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 @@ -1,12 +1,11 @@ import { - ChangeDetectionStrategy, Component, - WritableSignal, signal, ViewChild, computed, resource, Signal, + inject, } from '@angular/core'; import { ScanCountService, ScanDataService } from '../core/remote-data.service'; import { ScanDataResponse } from '../core/model/scan-data'; @@ -26,6 +25,10 @@ import { StarRatingModule } from 'angular-star-rating'; import { MatSort } from '@angular/material/sort'; import { firstValueFrom, Observable } from 'rxjs'; import { ScanCountResponse } from '../core/model/scan-count'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialog } from '@angular/material/dialog'; +import { ColumnSelectionDialogComponent } from './column-selection-dialog/column-selection-dialog.component'; export interface ResourceStatus { status: any; @@ -50,10 +53,11 @@ export interface ResourceLoaderParams { MatPaginatorModule, StarRatingModule, MatProgressSpinnerModule, + MatMenuModule, + MatCheckboxModule, ], templateUrl: './scan-table.component.html', styleUrl: './scan-table.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush, }) export class ScanTableComponent { tableData: Signal; @@ -61,11 +65,10 @@ export class ScanTableComponent { limit = signal(10); offset = signal(0); sessionId = signal(''); - - // page: number = this.offset / this.limit; + dialog = inject(MatDialog); pageEvent: PageEvent = new PageEvent(); sorting: number = -1; - displayedColumns: string[] = [ + displayedColumns = signal([ 'scan_number', 'status', 'num_points', @@ -74,6 +77,29 @@ export class ScanTableComponent { 'dataset_number', 'timestamp', 'user_rating', + ]); + allColumns: string[] = [ + 'scan_id', + 'scan_number', + 'status', + 'session_id', + 'num_points', + 'scan_name', + 'scan_type', + 'dataset_number', + 'scan_report_devices', + 'user_metadata', + 'readout_priority', + 'scan_parameters', + 'request_inputs', + 'info', + 'timestamp', + 'user_data', + 'name', + 'user_rating', + 'system_rating', + 'user_comments', + 'system_comments', ]; ignoredEntries: string[] = [ 'scan_report_devices', @@ -84,21 +110,38 @@ export class ScanTableComponent { 'info', ]; + availableColumns = computed(() => + this.allColumns.filter((element) => !this.ignoredEntries.includes(element)) + ); + reloadCriteria = computed(() => ({ sessionId: this.sessionId(), offset: this.offset(), limit: this.limit(), + column: this.displayedColumns(), })); loadScanDataResource = resource({ request: () => this.reloadCriteria(), loader: ({ request, abortSignal }): Promise => { + let columns = request.column.map((element) => + [ + 'name', + 'user_rating', + 'system_rating', + 'user_comments', + 'system_comments', + ].includes(element) + ? 'user_data' + : element + ); + console.log('Columns', columns); return firstValueFrom( this.scanData.getScanData( request.sessionId, request.offset, request.limit, - this.displayedColumns, + columns, false, { scan_number: this.sorting } ) @@ -115,8 +158,18 @@ export class ScanTableComponent { handleScanData(data: ScanDataResponse[] | []) { for (const entry of data) { - if (entry.user_data && entry.user_data['user_rating']) { + if (entry?.user_data !== undefined) { + entry.name = entry.user_data['name']; + entry.system_rating = entry.user_data['system_rating']; entry.user_rating = entry.user_data['user_rating']; + entry.user_comments = entry.user_data['user_comments']; + entry.system_comments = entry.user_data['system_comments']; + } else { + entry.name = ''; + entry.system_rating = 0; + entry.user_rating = 0; + entry.user_comments = ''; + entry.system_comments = ''; } } return data; @@ -154,4 +207,27 @@ export class ScanTableComponent { this.offset.set(event.pageIndex * event.pageSize); this.limit.set(event.pageSize); } + + handleRefresh() { + this.loadScanCountResource.reload(); + this.loadScanDataResource.reload(); + } + + openDialog(): void { + const dialogRef = this.dialog.open(ColumnSelectionDialogComponent, { + data: this.availableColumns().map((element) => ({ + name: element, + selected: this.displayedColumns().includes(element), + })), + disableClose: true, + }); + dialogRef.afterClosed().subscribe((result: string[] | null) => { + if (result !== null) { + this.displayedColumns.set(result); + // this.handleRefresh(); + } + }); + } + + handleColumnSelection(event: any) {} }