From a3f402562f1c8ddcb6908ad1635fd0d693e2bbf5 Mon Sep 17 00:00:00 2001 From: Dmitry Romanov Date: Wed, 3 Jul 2024 11:59:44 -0400 Subject: [PATCH] Introducing geometry URL change --- firebird-ng/package-lock.json | 20 ++++- firebird-ng/package.json | 9 +- .../input-config/input-config.component.html | 82 +++++++++-------- .../input-config/input-config.component.scss | 5 ++ .../input-config/input-config.component.ts | 87 ++++++++++++++++++- firebird-ng/src/app/user-config.service.ts | 7 ++ firebird-ng/src/app/utils/config-property.ts | 13 ++- firebird-ng/src/styles.scss | 2 +- pyrobird/src/pyrobird/cli/serve/__init__.py | 45 +++++++--- 9 files changed, 211 insertions(+), 59 deletions(-) diff --git a/firebird-ng/package-lock.json b/firebird-ng/package-lock.json index 7a243f8..b766cfd 100644 --- a/firebird-ng/package-lock.json +++ b/firebird-ng/package-lock.json @@ -1,23 +1,26 @@ { "name": "firebird", - "version": "0.0.3", + "version": "0.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "firebird", - "version": "0.0.3", + "version": "0.0.4", "dependencies": { "@angular/animations": "^17.3.0", + "@angular/cdk": "~17.3.7", "@angular/common": "^17.3.0", "@angular/compiler": "^17.3.0", "@angular/core": "^17.3.0", "@angular/forms": "^17.3.0", + "@angular/material": "~17.3.7", "@angular/platform-browser": "^17.3.0", "@angular/platform-browser-dynamic": "^17.3.0", "@angular/router": "^17.3.0", "@tweenjs/tween.js": "^23.1.2", "@types/picomatch": "^2.3.3", + "angular-split": "^17.2.0", "jsdom": "^24.0.0", "jsrootdi": "^7.6.101", "jszip": "^3.10.1", @@ -5148,6 +5151,19 @@ "ajv": "^8.8.2" } }, + "node_modules/angular-split": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/angular-split/-/angular-split-17.2.0.tgz", + "integrity": "sha512-Curv39t7f7ueFF6GvglTv6js7tjTyzW/S8HjU5FgYaodQUFXRE21+kU0sybydU8fnAdQrRbtD7ScIUha3CneLA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "rxjs": ">=7.0.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", diff --git a/firebird-ng/package.json b/firebird-ng/package.json index 11cfde5..1239c9f 100644 --- a/firebird-ng/package.json +++ b/firebird-ng/package.json @@ -1,9 +1,9 @@ { "name": "firebird", - "version": "0.0.3", + "version": "0.0.4", "scripts": { "ng": "ng", - "start": "ng serve", + "serve": "ng serve", "build": "ng build --configuration=production", "build:ghpages": "ng build --configuration=production --base-href='/firebird/'", "build:watch": "ng build", @@ -14,15 +14,18 @@ "private": true, "dependencies": { "@angular/animations": "^17.3.0", + "@angular/cdk": "~17.3.7", "@angular/common": "^17.3.0", "@angular/compiler": "^17.3.0", "@angular/core": "^17.3.0", "@angular/forms": "^17.3.0", + "@angular/material": "~17.3.7", "@angular/platform-browser": "^17.3.0", "@angular/platform-browser-dynamic": "^17.3.0", "@angular/router": "^17.3.0", "@tweenjs/tween.js": "^23.1.2", "@types/picomatch": "^2.3.3", + "angular-split": "^17.2.0", "jsdom": "^24.0.0", "jsrootdi": "^7.6.101", "jszip": "^3.10.1", @@ -59,4 +62,4 @@ "path": false, "vm": false } -} +} \ No newline at end of file diff --git a/firebird-ng/src/app/input-config/input-config.component.html b/firebird-ng/src/app/input-config/input-config.component.html index 147231b..5a592f6 100644 --- a/firebird-ng/src/app/input-config/input-config.component.html +++ b/firebird-ng/src/app/input-config/input-config.component.html @@ -5,44 +5,30 @@

Configure geometry pipeline

geometry-pipeline
+ + + + + +
Geometry Source
- Geometry file sources are taken from https://eic.github.io/epic/ - + Geometry file source: +
+
API Host
+ This field sets the host address for the API server. + + Geometry URL + + + {{option.name}} + + + +
+
Events Source
@@ -103,7 +89,33 @@
Merge geometries if possible
- + +
+
+
Server API Configuration
+
+ + +
+
+
+
API Host:
+
+
+ +
+
+
API Port:
+
+
+ +
+
+
+
+ + + diff --git a/firebird-ng/src/app/input-config/input-config.component.scss b/firebird-ng/src/app/input-config/input-config.component.scss index b42012e..c2d6db1 100644 --- a/firebird-ng/src/app/input-config/input-config.component.scss +++ b/firebird-ng/src/app/input-config/input-config.component.scss @@ -2,3 +2,8 @@ background-color: var(--phoenix-background-color-secondary); /* Using theme variables */ color: var(--phoenix-text-color); } + +.full-width-field { + display: block; + width: 100%; +} diff --git a/firebird-ng/src/app/input-config/input-config.component.ts b/firebird-ng/src/app/input-config/input-config.component.ts index 9871e1c..f94b23a 100644 --- a/firebird-ng/src/app/input-config/input-config.component.ts +++ b/firebird-ng/src/app/input-config/input-config.component.ts @@ -5,19 +5,78 @@ import { UserConfigService } from "../user-config.service"; import { ReactiveFormsModule } from '@angular/forms'; import {RouterLink} from '@angular/router'; import {ConfigProperty} from "../utils/config-property"; +import {MatCard, MatCardContent, MatCardTitle} from "@angular/material/card"; +import {MatSlideToggle} from "@angular/material/slide-toggle"; +import {MatFormField} from "@angular/material/form-field"; +import {MatInput, MatLabel} from "@angular/material/input"; +import {map, Observable, startWith} from "rxjs"; +import {MatAutocomplete, MatAutocompleteTrigger, MatOption} from "@angular/material/autocomplete"; +import {AsyncPipe, NgForOf} from "@angular/common"; +import {MatTooltip} from "@angular/material/tooltip"; + +export interface User { + name: string; + url: string; +} @Component({ selector: 'app-input-config', standalone: true, - imports: [ReactiveFormsModule, RouterLink], + imports: [ReactiveFormsModule, RouterLink, MatCard, MatCardContent, MatCardTitle, MatSlideToggle, MatFormField, MatInput, MatLabel, MatAutocompleteTrigger, MatAutocomplete, MatOption, AsyncPipe, MatTooltip, NgForOf], templateUrl: './input-config.component.html', styleUrl: './input-config.component.scss' }) export class InputConfigComponent implements OnInit { - selectedGeometry = new FormControl(''); + geometrySelectValue = new FormControl(''); + geometryUrl = new FormControl(''); selectedEventSource = new FormControl(''); onlyCentralDetector: FormControl = new FormControl(true); + serverUseApi: FormControl = new FormControl(false); + serverApiHost = new FormControl('localhost'); + serverApiPort: FormControl = new FormControl(5454); + filteredOptions: Observable = new Observable(); + + + myControl = new FormControl(''); + options: User[] = [ + {url: "builtin://epic-central-optimized", name: "EIC ePIC Central Detector optimized"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_bhcal.root", name: "epic_bhcal.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_calorimeters.root", name: "epic_calorimeters.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake.root", name: "epic_craterlake.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_10x100.root", name: "epic_craterlake_10x100.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_10x275.root", name: "epic_craterlake_10x275.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_18x110_Au.root", name: "epic_craterlake_18x110_Au.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_18x275.root", name: "epic_craterlake_18x275.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_5x41.root", name: "epic_craterlake_5x41.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_material_map.root", name: "epic_craterlake_material_map.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_no_bhcal.root", name: "epic_craterlake_no_bhcal.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_craterlake_tracking_only.root", name: "epic_craterlake_tracking_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_dirc_only.root", name: "epic_dirc_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_drich_only.root", name: "epic_drich_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_forward_detectors.root", name: "epic_forward_detectors.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_forward_detectors_with_inserts.root", name: "epic_forward_detectors_with_inserts.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_full.root", name: "epic_full.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_imaging_only.root", name: "epic_imaging_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_inner_detector.root", name: "epic_inner_detector.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_ip6.root", name: "epic_ip6.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_ip6_extended.root", name: "epic_ip6_extended.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_lfhcal_only.root", name: "epic_lfhcal_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_lfhcal_with_insert.root", name: "epic_lfhcal_with_insert.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_mrich_only.root", name: "epic_mrich_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_pfrich_only.root", name: "epic_pfrich_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_pid_only.root", name: "epic_pid_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_tof_endcap_only.root", name: "epic_tof_endcap_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_tof_only.root", name: "epic_tof_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_vertex_only.root", name: "epic_vertex_only.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_zdc_lyso_sipm.root", name: "epic_zdc_lyso_sipm.root"}, + {url: "https://eic.github.io/epic/artifacts/tgeo/epic_zdc_sipm_on_tile_only.root", name: "epic_zdc_sipm_on_tile_only.root"} +]; + + + + + constructor(private configService: UserConfigService) { } @@ -41,8 +100,30 @@ export class InputConfigComponent implements OnInit { ngOnInit(): void { //this.selectedGeometry.setValue(this.configService.selectedGeometry.value, { emitEvent: false }) - this.bindConfigToControl(this.selectedGeometry, this.configService.selectedGeometry); + this.bindConfigToControl(this.geometryUrl, this.configService.selectedGeometry); this.bindConfigToControl(this.selectedEventSource, this.configService.eventSource); this.bindConfigToControl(this.onlyCentralDetector, this.configService.onlyCentralDetector); + this.bindConfigToControl(this.serverUseApi, this.configService.localServerUseApi); + this.bindConfigToControl(this.serverApiHost, this.configService.localServerHost); + this.bindConfigToControl(this.serverApiPort, this.configService.localServerPort); + + // noinspection JSDeprecatedSymbols + this.filteredOptions = this.myControl.valueChanges.pipe( + startWith(''), + map(value => { + // Get string name + const name = typeof value === 'string' ? value : value?.name; + return name ? this._filter(name as string) : this.options.slice(); + }) + ); + } + + displayFn(user: User): string { + return user && user.name ? user.name : ''; + } + + private _filter(name: string): User[] { + const filterValue = name.toLowerCase(); + return this.options.filter(option => option.name.toLowerCase().includes(filterValue)); } } diff --git a/firebird-ng/src/app/user-config.service.ts b/firebird-ng/src/app/user-config.service.ts index 001433c..53f9033 100644 --- a/firebird-ng/src/app/user-config.service.ts +++ b/firebird-ng/src/app/user-config.service.ts @@ -9,10 +9,17 @@ export class UserConfigService { public selectedGeometry: ConfigProperty; public onlyCentralDetector: ConfigProperty; public eventSource: ConfigProperty; + public localServerUseApi: ConfigProperty; + public localServerHost: ConfigProperty; + public localServerPort: ConfigProperty; constructor() { this.selectedGeometry = new ConfigProperty("geometry.selectedGeometry", "epic-central-optimized"); this.onlyCentralDetector = new ConfigProperty("geometry.onlyCentralDetector", true); this.eventSource = new ConfigProperty("events.eventsSource", "recommended"); + this.localServerUseApi = new ConfigProperty("server.useApi", false); + this.localServerHost = new ConfigProperty("server.host", "localhost"); + this.localServerPort = new ConfigProperty("server.port", 5454); + } } diff --git a/firebird-ng/src/app/utils/config-property.ts b/firebird-ng/src/app/utils/config-property.ts index 20f49de..ebb5890 100644 --- a/firebird-ng/src/app/utils/config-property.ts +++ b/firebird-ng/src/app/utils/config-property.ts @@ -63,9 +63,11 @@ export class ConfigProperty { * @returns {T} The loaded or default value of the property. */ private loadValue(): T { + let storedValue: string|null = null; + let parsedValue: any = undefined; try { - let storedValue = this.storage.getItem(this.key); - let parsedValue: any; + storedValue = this.storage.getItem(this.key); + if (storedValue !== null) { parsedValue = (typeof this.defaultValue) !== 'string' ? JSON.parse(storedValue) : storedValue; } else { @@ -73,7 +75,12 @@ export class ConfigProperty { } return this.validator && !this.validator(parsedValue) ? this.defaultValue : parsedValue; } catch (error) { - console.error('Error loading value:', error); + console.error(`Error at ConfigProperty.loadValue, key='${this.key}'`); + console.log(' storedValue', storedValue); + console.log(' parsedValue', parsedValue); + console.log(' Default value will be used: ', this.defaultValue); + console.log(error); + return this.defaultValue; } } diff --git a/firebird-ng/src/styles.scss b/firebird-ng/src/styles.scss index 12842fe..2cd642b 100644 --- a/firebird-ng/src/styles.scss +++ b/firebird-ng/src/styles.scss @@ -1,2 +1,2 @@ /* You can add global styles to this file, and also import other style files */ -@import 'phoenix-ui-components/theming'; +// @import 'phoenix-ui-components/theming'; diff --git a/pyrobird/src/pyrobird/cli/serve/__init__.py b/pyrobird/src/pyrobird/cli/serve/__init__.py index f8a14fd..2e09854 100644 --- a/pyrobird/src/pyrobird/cli/serve/__init__.py +++ b/pyrobird/src/pyrobird/cli/serve/__init__.py @@ -21,9 +21,30 @@ logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) +from flask import Flask, send_file, request, abort app = Flask(__name__, static_folder='dist') + +@app.route('/download/') +def download_file(filename): + # Ensure the path is safe and only files within a certain directory can be accessed + # For example, let's say you store your files in a 'files' directory within the server root + safe_path = filename + base_path = '' + if base_path: + safe_path = os.path.join(base_path, filename) + safe_path = os.path.abspath(safe_path) # Resolve any path traversal attempts + + if not safe_path.startswith(base_path): + # Security check failed + abort(404) + + if os.path.exists(safe_path) and os.path.isfile(safe_path): + return send_file(safe_path, as_attachment=True) + else: + abort(404) + # Check for the filename argument if len(sys.argv) < 2: print("Usage: python app.py ") @@ -40,26 +61,26 @@ def static_file(path): return send_from_directory('dist', path) - -@click.group() +@click.command() @click.pass_context def serve(ctx): """ Operations with database (create tables, erase everything, etc) """ + app.run(debug=True) - # assert isinstance(ctx, click.Context) - # context = ctx.obj - # assert isinstance(context, CasdmAppContext) - # if not context.connection_str: - # ctx.fail("ERROR(!) Connection string is not set. Needs it to connect to BD") - # # click.echo(, err=True) - # # click.echo(ctx.get_help()) + # # assert isinstance(ctx, click.Context) + # # context = ctx.obj + # # assert isinstance(context, CasdmAppContext) + # # if not context.connection_str: + # # ctx.fail("ERROR(!) Connection string is not set. Needs it to connect to BD") + # # # click.echo(, err=True) + # # # click.echo(ctx.get_help()) + # + # if ctx.invoked_subcommand is None: + # print("No command was specified") - if ctx.invoked_subcommand is None: - print("No command was specified") - app.run(debug=True) if __name__ == '__main__': app.run(debug=True) \ No newline at end of file