Warning, /firebird/packages/firebird-ng/display/src/lib/services/painter-config.service.ts is written in an unsupported language. File is not indexed.
0001 import { Injectable, inject } from '@angular/core';
0002 import {
0003 EventPiece,
0004 PainterConfigView,
0005 PiecePainterConstructor,
0006 painterIdOf,
0007 painterMetaOf,
0008 } from '@dexvis/firebird-core';
0009 import { ConfigProperty, ConfigService } from '@dexvis/app-features';
0010
0011 /**
0012 * Binds painter metadata to the config system.
0013 *
0014 * Two kinds of keys, both under normal config precedence (defaults < server
0015 * < localStorage < URL < runtime), so a yaml file, a deep link, and the
0016 * painter panel all reach the same knobs:
0017 *
0018 * - `painters.byPiece.<pieceName>` — WHICH painter draws the piece, holding
0019 * a painter id from the registered candidates (default: first registered).
0020 * - `painters.byPiece.<pieceName>.<knob>` — the selected painter's knobs,
0021 * declared from the painter's `static meta.configs`.
0022 *
0023 * Painter instances read the knobs through a `PainterConfigView` — a plain
0024 * object over the declared properties, so painter code stays worker-safe
0025 * (`@dexvis/firebird-core` never sees DI).
0026 */
0027 @Injectable({
0028 providedIn: 'root',
0029 })
0030 export class PainterConfigService {
0031 private config = inject(ConfigService);
0032
0033 selectionKey(pieceName: string): string {
0034 return `painters.byPiece.${pieceName}`;
0035 }
0036
0037 knobKey(pieceName: string, knob: string): string {
0038 return `painters.byPiece.${pieceName}.${knob}`;
0039 }
0040
0041 visibilityKey(pieceName: string): string {
0042 return this.knobKey(pieceName, 'visible');
0043 }
0044
0045 /**
0046 * Declares (or returns) the piece visibility property. 'visible' is a
0047 * RESERVED knob name (`RESERVED_PAINTER_KNOB_KEYS` in
0048 * `@dexvis/firebird-core`; painter registration rejects a painter that
0049 * declares it): it lives under the painter knob namespace so the normal
0050 * config precedence applies (a pack ships a piece hidden via
0051 * `withConfigDefaults`, a deep link or the panel overrides), but it is
0052 * applied to the painter's root node by EventDisplayService, not read by
0053 * painter code.
0054 */
0055 visibilityProperty(pieceName: string): ConfigProperty<boolean> {
0056 return this.config.declare<boolean>({
0057 key: this.visibilityKey(pieceName),
0058 default: true,
0059 label: 'Visible',
0060 });
0061 }
0062
0063 /**
0064 * Declares (or returns) the painter-selection property of a piece.
0065 * The default is the first registered painter's id.
0066 */
0067 selectionProperty(pieceName: string, candidates: readonly PiecePainterConstructor[]): ConfigProperty<string> {
0068 return this.config.declare<string>({
0069 key: this.selectionKey(pieceName),
0070 default: candidates.length > 0 ? painterIdOf(candidates[0]) : '',
0071 label: `Painter`,
0072 options: candidates.map(painterIdOf),
0073 });
0074 }
0075
0076 /** Resolves a selection property value to one of the candidate classes. */
0077 resolveSelection(
0078 pieceName: string,
0079 candidates: readonly PiecePainterConstructor[],
0080 ): PiecePainterConstructor | undefined {
0081 if (candidates.length === 0) return undefined;
0082 const selectedId = this.selectionProperty(pieceName, candidates).value;
0083 return candidates.find(candidate => painterIdOf(candidate) === selectedId) ?? candidates[0];
0084 }
0085
0086 /** The declared knob properties of a painter applied to a piece. */
0087 knobProperties(piece: EventPiece, painterClass: PiecePainterConstructor): Map<string, ConfigProperty<unknown>> {
0088 const properties = new Map<string, ConfigProperty<unknown>>();
0089 const meta = painterMetaOf(painterClass);
0090 for (const descriptor of meta?.configs ?? []) {
0091 properties.set(descriptor.key, this.config.declare<unknown>({
0092 key: this.knobKey(piece.name, descriptor.key),
0093 default: descriptor.default,
0094 label: descriptor.label ?? descriptor.key,
0095 options: descriptor.options,
0096 min: descriptor.min,
0097 max: descriptor.max,
0098 }));
0099 }
0100 return properties;
0101 }
0102
0103 /**
0104 * The resolved config view a painter instance reads its knobs through.
0105 * Undefined when the painter declares no knobs (defaults view applies).
0106 */
0107 buildConfigView(piece: EventPiece, painterClass: PiecePainterConstructor): PainterConfigView | undefined {
0108 const properties = this.knobProperties(piece, painterClass);
0109 if (properties.size === 0) return undefined;
0110 return {
0111 value: <T>(key: string): T => properties.get(key)?.value as T,
0112 signal: <T>(key: string) => properties.get(key)!.valueSignal as import('@angular/core').Signal<T>,
0113 };
0114 }
0115 }