Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/packages/firebird-ng/display/src/lib/pages/input-config/input-config.component.ts is written in an unsupported language. File is not indexed.

0001 import { Component, OnInit, ChangeDetectionStrategy, DestroyRef, inject, signal } from '@angular/core';
0002 import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
0003 import { FormControl, ReactiveFormsModule } from '@angular/forms';
0004 import { Router, RouterLink } from '@angular/router';
0005 import { NgIf } from '@angular/common';
0006 import { MatCard, MatCardContent, MatCardTitle } from '@angular/material/card';
0007 import { MatSlideToggle } from '@angular/material/slide-toggle';
0008 import { MatFormField } from '@angular/material/form-field';
0009 import { MatInput, MatLabel } from '@angular/material/input';
0010 import { MatAccordion, MatExpansionPanel, MatExpansionPanelTitle, MatExpansionPanelHeader } from '@angular/material/expansion';
0011 import { MatButton } from "@angular/material/button";
0012 import { MatSelect } from '@angular/material/select';
0013 import { MatOption } from '@angular/material/autocomplete';
0014 import { ConfigProperty, ConfigSchema, ConfigService, ServerConfigService, resolveRegistry } from '@dexvis/app-features';
0015 import {
0016   BACKEND_URL_CONFIG,
0017   BACKEND_USE_API_CONFIG,
0018   GEOMETRY_CUT_LIST_CONFIG,
0019   GEOMETRY_FAST_MATERIAL_CONFIG,
0020   GEOMETRY_ROOT_FILTER_CONFIG,
0021   GEOMETRY_THEME_CONFIG,
0022   GEOMETRY_THEMES,
0023   resolveRootGeometryRules,
0024   ROOT_GEOMETRY_RULES,
0025   ServerConfig,
0026   UrlService,
0027   USE_CONTROLLER_CONFIG,
0028 } from '@dexvis/firebird-ng/api';
0029 import { DataSelectorComponent } from '../../components/data-selector/data-selector.component';
0030 import { FirebirdShellComponent } from '../../components/firebird-shell/firebird-shell.component';
0031 import { GEOMETRY_PIPELINE_DIAGRAM_URL } from './geometry-pipeline-diagram';
0032 
0033 /** One choice of a geometry pipeline select. */
0034 interface PipelineOption {
0035   value: string;
0036   label: string;
0037 }
0038 
0039 /**
0040  * The configuration page: what to load (the data selector, shared with the
0041  * display's toolbar panel), the geometry pipeline options, controls and the
0042  * backend connection. Every control is bound to a config key, so the same
0043  * values are reachable from deep links, config.jsonc and yaml.
0044  */
0045 @Component({
0046   selector: 'app-input-config',
0047   standalone: true,
0048   imports: [
0049     ReactiveFormsModule,
0050     RouterLink,
0051     MatCard,
0052     MatCardContent,
0053     MatCardTitle,
0054     MatSlideToggle,
0055     MatFormField,
0056     MatInput,
0057     MatLabel,
0058     DataSelectorComponent,
0059     MatAccordion,
0060     MatExpansionPanel,
0061     MatExpansionPanelTitle,
0062     MatExpansionPanelHeader,
0063     FirebirdShellComponent,
0064     MatButton,
0065     MatSelect,
0066     MatOption,
0067     NgIf,
0068   ],
0069   templateUrl: './input-config.component.html',
0070   changeDetection: ChangeDetectionStrategy.OnPush,
0071   styleUrls: ['./input-config.component.scss']
0072 })
0073 export class InputConfigComponent implements OnInit {
0074   private readonly router = inject(Router);
0075   private readonly destroyRef = inject(DestroyRef);
0076   /** The backend the app talks to right now (shown under Backend Details). */
0077   protected readonly urlService = inject(UrlService);
0078   protected readonly pipelineDiagramUrl = GEOMETRY_PIPELINE_DIAGRAM_URL;
0079 
0080   serverUseApi = new FormControl<boolean>(false);
0081   serverApiUrl = new FormControl<string>('http://localhost:5454');
0082 
0083   geometryThemeName = new FormControl<string>('off');
0084   geometryCutListName = new FormControl<string>('off');
0085   geometryRootFilterName = new FormControl<string>('off');
0086 
0087   /** The registered themes (withGeometryTheme); the template adds 'off'. */
0088   readonly themeOptions: PipelineOption[] = resolveRegistry(inject(GEOMETRY_THEMES, { optional: true }) ?? [], theme => theme.id)
0089     .map(theme => ({ value: theme.id, label: theme.label ?? theme.id }));
0090   /** Cut lists and edit rule sets (withRootGeometryRules), filled once the rule data loads; the template adds 'off'. */
0091   readonly cutListOptions = signal<PipelineOption[]>([]);
0092   readonly rootFilterOptions = signal<PipelineOption[]>([]);
0093   private readonly rootRuleSources = inject(ROOT_GEOMETRY_RULES, { optional: true }) ?? [];
0094   geometryFastAndUgly = new FormControl<boolean>(false);
0095   useController = new FormControl<boolean>(false);
0096 
0097   /**
0098    * Server config for the template, bound through the service SIGNAL:
0099    * ServerConfigService replaces its config object when the async load
0100    * completes, so a by-reference snapshot taken in ngOnInit goes stale.
0101    */
0102   get firebirdConfig(): ServerConfig {
0103     return this.firebirdConfigService.configSignal();
0104   }
0105 
0106   constructor(
0107     private userConfigService: ConfigService,
0108     private firebirdConfigService: ServerConfigService<ServerConfig>
0109   ) {}
0110 
0111   /** The selector wrote the config keys; the display page loads from them on init. */
0112   onDataApplied(): void {
0113     void this.router.navigate(['/display']);
0114   }
0115 
0116   /**
0117    * Two-way binds a form control to a config key. The key is declared from
0118    * the same schema its consumer declares (UrlService, GameControllerService,
0119    * GeometryService), so the control writes exactly what the app reads.
0120    * Both subscriptions end with the page.
0121    */
0122   private bind<T>(control: FormControl<T | null>, schema: ConfigSchema<T>): ConfigProperty<T> {
0123     const property = this.userConfigService.declare(schema);
0124     control.setValue(property.value, { emitEvent: false });
0125     property.changes$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {
0126       control.setValue(value, { emitEvent: false });
0127     });
0128     control.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {
0129       if (value !== null) {
0130         property.value = value;
0131       }
0132     });
0133     return property;
0134   }
0135 
0136   ngOnInit(): void {
0137     this.bind(this.serverUseApi, BACKEND_USE_API_CONFIG);
0138     this.bind(this.serverApiUrl, BACKEND_URL_CONFIG);
0139     this.bind(this.geometryThemeName, GEOMETRY_THEME_CONFIG);
0140     this.bind(this.geometryCutListName, GEOMETRY_CUT_LIST_CONFIG);
0141     this.bind(this.geometryRootFilterName, GEOMETRY_ROOT_FILTER_CONFIG);
0142     this.bind(this.geometryFastAndUgly, GEOMETRY_FAST_MATERIAL_CONFIG);
0143     this.bind(this.useController, USE_CONTROLLER_CONFIG);
0144 
0145     resolveRootGeometryRules(this.rootRuleSources).then(rules => {
0146       this.cutListOptions.set(Object.entries(rules.cutLists ?? {})
0147         .map(([name, cutList]) => ({ value: name, label: cutList.label ?? name })));
0148       this.rootFilterOptions.set(Object.entries(rules.editRules ?? {})
0149         .map(([name, ruleSet]) => ({ value: name, label: ruleSet.label ?? name })));
0150     }, error => console.error('[Config] Geometry rules failed to load:', error));
0151   }
0152 
0153   /** Drops the saved pipeline choices: each falls back to the server value or its default. */
0154   resetGeometryToDefaults() {
0155     for (const schema of [GEOMETRY_THEME_CONFIG, GEOMETRY_CUT_LIST_CONFIG, GEOMETRY_ROOT_FILTER_CONFIG]) {
0156       this.userConfigService.declare<string>(schema).setDefault();
0157     }
0158   }
0159 }