ngx-dynamic-entity 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/field-types/checkbox-field.component.mjs +73 -0
- package/esm2022/lib/field-types/date-field.component.mjs +82 -0
- package/esm2022/lib/field-types/dropdown-field.component.mjs +83 -0
- package/esm2022/lib/field-types/entity-ref-field.component.mjs +117 -0
- package/esm2022/lib/field-types/multi-select-field.component.mjs +91 -0
- package/esm2022/lib/field-types/number-field.component.mjs +73 -0
- package/esm2022/lib/field-types/text-field.component.mjs +74 -0
- package/esm2022/lib/field-types/textarea-field.component.mjs +73 -0
- package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +86 -0
- package/esm2022/lib/form/dynamic-form.component.mjs +167 -0
- package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +23 -0
- package/esm2022/lib/services/config.service.mjs +58 -0
- package/esm2022/lib/services/entity-ref-registry.service.mjs +31 -0
- package/esm2022/lib/services/field-registry.service.mjs +50 -0
- package/esm2022/lib/services/hook-registry.service.mjs +26 -0
- package/esm2022/lib/services/rbac.service.mjs +52 -0
- package/esm2022/lib/services/validator-registry.service.mjs +49 -0
- package/esm2022/lib/services/version.service.mjs +40 -0
- package/esm2022/lib/table/dynamic-table.component.mjs +160 -0
- package/esm2022/lib/tokens/injection-tokens.mjs +16 -0
- package/esm2022/ngx-dynamic-entity.mjs +5 -0
- package/esm2022/public-api.mjs +26 -0
- package/fesm2022/ngx-dynamic-entity.mjs +1352 -0
- package/fesm2022/ngx-dynamic-entity.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/field-types/checkbox-field.component.d.ts +12 -0
- package/lib/field-types/date-field.component.d.ts +14 -0
- package/lib/field-types/dropdown-field.component.d.ts +13 -0
- package/lib/field-types/entity-ref-field.component.d.ts +26 -0
- package/lib/field-types/multi-select-field.component.d.ts +13 -0
- package/lib/field-types/number-field.component.d.ts +12 -0
- package/lib/field-types/text-field.component.d.ts +13 -0
- package/lib/field-types/textarea-field.component.d.ts +12 -0
- package/lib/form/dynamic-field/dynamic-field.component.d.ts +30 -0
- package/lib/form/dynamic-form.component.d.ts +52 -0
- package/lib/providers/provide-ngx-dynamic-entity.d.ts +29 -0
- package/lib/services/config.service.d.ts +25 -0
- package/lib/services/entity-ref-registry.service.d.ts +20 -0
- package/lib/services/field-registry.service.d.ts +22 -0
- package/lib/services/hook-registry.service.d.ts +12 -0
- package/lib/services/rbac.service.d.ts +32 -0
- package/lib/services/validator-registry.service.d.ts +19 -0
- package/lib/services/version.service.d.ts +26 -0
- package/lib/table/dynamic-table.component.d.ts +56 -0
- package/lib/tokens/injection-tokens.d.ts +16 -0
- package/package.json +37 -0
- package/public-api.d.ts +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-dynamic-entity.mjs","sources":["../../src/lib/tokens/injection-tokens.ts","../../src/lib/providers/provide-ngx-dynamic-entity.ts","../../src/lib/services/config.service.ts","../../src/lib/field-types/text-field.component.ts","../../src/lib/field-types/textarea-field.component.ts","../../src/lib/field-types/number-field.component.ts","../../src/lib/field-types/checkbox-field.component.ts","../../src/lib/field-types/date-field.component.ts","../../src/lib/field-types/dropdown-field.component.ts","../../src/lib/field-types/multi-select-field.component.ts","../../src/lib/services/entity-ref-registry.service.ts","../../src/lib/field-types/entity-ref-field.component.ts","../../src/lib/services/field-registry.service.ts","../../src/lib/services/hook-registry.service.ts","../../src/lib/services/validator-registry.service.ts","../../src/lib/services/version.service.ts","../../src/lib/services/rbac.service.ts","../../src/lib/form/dynamic-field/dynamic-field.component.ts","../../src/lib/form/dynamic-form.component.ts","../../src/lib/form/dynamic-form.component.html","../../src/lib/table/dynamic-table.component.ts","../../src/lib/table/dynamic-table.component.html","../../src/public-api.ts","../../src/ngx-dynamic-entity.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport type { EntityConfig, FieldConfig, MigrationStrategy } from '@dynamic-entity/core';\nimport type { Type } from '@angular/core';\n\n/** Base URL for the dynamic-entity-server API */\nexport const DYNAMIC_ENTITY_API_URL = new InjectionToken<string>('DYNAMIC_ENTITY_API_URL');\n\n/** Roles that see XXXXXXXXX for masked fields (ADR-003) */\nexport const MASKED_ROLES = new InjectionToken<string[]>('MASKED_ROLES');\n\n/** Migration strategy for the frontend — 'strict' | 'graceful' only (ADR-005, never 'auto') */\nexport const MIGRATION_STRATEGY = new InjectionToken<'strict' | 'graceful'>('MIGRATION_STRATEGY');\n\n/** Registry: fieldType string → Angular component class */\nexport const FIELD_TYPE_REGISTRY = new InjectionToken<Map<string, Type<any>>>('FIELD_TYPE_REGISTRY');\n\n/** Registry: entity key → async () => options[] loader function */\nexport const ENTITY_REF_REGISTRY = new InjectionToken<Map<string, () => Promise<any[]>>>(\n 'ENTITY_REF_REGISTRY',\n);\n\n/** Registry: validator key → ValidatorFn */\nexport const VALIDATOR_REGISTRY = new InjectionToken<Map<string, any>>('VALIDATOR_REGISTRY');\n\n/** Registry: hook key → async (data, context) => data */\nexport const HOOK_REGISTRY = new InjectionToken<Map<string, Function>>('HOOK_REGISTRY');\n","import { EnvironmentProviders, makeEnvironmentProviders, Type } from '@angular/core';\nimport {\n DYNAMIC_ENTITY_API_URL,\n ENTITY_REF_REGISTRY,\n FIELD_TYPE_REGISTRY,\n HOOK_REGISTRY,\n MASKED_ROLES,\n MIGRATION_STRATEGY,\n VALIDATOR_REGISTRY,\n} from '../tokens/injection-tokens';\n\nexport interface NgxDynamicEntityConfig {\n /** Base URL of the dynamic-entity-server API. Example: 'http://localhost:3000/api/entities' */\n apiUrl?: string;\n /** Roles that see masked field values as XXXXXXXXX */\n maskedRoles?: string[];\n /** Migration strategy: 'strict' rejects stale records, 'graceful' flags them. Never 'auto' (ADR-005). */\n migrationStrategy?: 'strict' | 'graceful';\n /** Custom field type components keyed by type string */\n fieldTypes?: Record<string, Type<any>>;\n /** Entity-ref option loaders keyed by entity key (ADR-006) */\n entityRefs?: Record<string, () => Promise<any[]>>;\n /** Custom validator functions keyed by validator name */\n validators?: Record<string, any>;\n /** Hook functions keyed by hook name */\n hooks?: Record<string, Function>;\n}\n\n/**\n * Provider function for ngx-dynamic-entity.\n * All options are optional — consumers provide only what they use (ISP).\n *\n * Usage in app.config.ts:\n * provideNgxDynamicEntity({\n * apiUrl: 'http://localhost:3000/api/entities',\n * maskedRoles: ['IT_SUPPORT'],\n * entityRefs: { clients: () => clientService.getOptions() },\n * })\n */\nexport const provideNgxDynamicEntity = (config: NgxDynamicEntityConfig = {}): EnvironmentProviders =>\n makeEnvironmentProviders([\n { provide: DYNAMIC_ENTITY_API_URL, useValue: config.apiUrl ?? '' },\n { provide: MASKED_ROLES, useValue: config.maskedRoles ?? [] },\n { provide: MIGRATION_STRATEGY, useValue: config.migrationStrategy ?? 'graceful' },\n { provide: FIELD_TYPE_REGISTRY, useValue: new Map(Object.entries(config.fieldTypes ?? {})) },\n { provide: ENTITY_REF_REGISTRY, useValue: new Map(Object.entries(config.entityRefs ?? {})) },\n { provide: VALIDATOR_REGISTRY, useValue: new Map(Object.entries(config.validators ?? {})) },\n { provide: HOOK_REGISTRY, useValue: new Map(Object.entries(config.hooks ?? {})) },\n ]);\n","import { Injectable, inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Observable } from 'rxjs';\nimport { map, shareReplay } from 'rxjs/operators';\nimport type { EntityConfig } from '@dynamic-entity/core';\nimport { DYNAMIC_ENTITY_API_URL } from '../tokens/injection-tokens';\n\n/**\n * ConfigService — fetches entity configs from the dynamic-entity-server API.\n * Uses shareReplay(1) to cache per config key — avoids duplicate HTTP requests.\n * Following ONEHERMES smart service pattern: Observable$ + shareReplay.\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfigService {\n private readonly http = inject(HttpClient);\n private readonly apiUrl = inject(DYNAMIC_ENTITY_API_URL, { optional: true }) ?? '';\n private readonly cache = new Map<string, Observable<EntityConfig>>();\n\n /** Get a config by entity key. Cached via shareReplay(1). */\n getConfig(entity: string): Observable<EntityConfig> {\n if (!this.cache.has(entity)) {\n const config$ = this.http\n .get<{ success: boolean; data: EntityConfig }>(`${this.apiUrl}/config/${entity}`)\n .pipe(\n map(res => res.data!), // ADR-004: Success guarantees data\n shareReplay(1),\n );\n this.cache.set(entity, config$);\n }\n return this.cache.get(entity)!;\n }\n\n /** List all configs */\n listConfigs(): Observable<EntityConfig[]> {\n return this.http\n .get<{ success: boolean; data: EntityConfig[] }>(`${this.apiUrl}/config`)\n .pipe(map(res => res.data!)); // ADR-004: Success guarantees data\n }\n\n /** Create a new config */\n saveConfig(config: EntityConfig): Observable<EntityConfig> {\n return this.http\n .post<{ success: boolean; data: EntityConfig }>(`${this.apiUrl}/config`, config)\n .pipe(map(res => res.data!));\n }\n\n /** Update an existing config */\n updateConfig(entity: string, updates: Partial<EntityConfig>): Observable<EntityConfig> {\n return this.http\n .put<{ success: boolean; data: EntityConfig }>(`${this.apiUrl}/config/${entity}`, updates)\n .pipe(\n map(res => {\n this.invalidate(entity);\n return res.data!;\n })\n );\n }\n\n /** Invalidate cache for an entity (call after config update) */\n invalidate(entity: string): void {\n this.cache.delete(entity);\n }\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig } from '@dynamic-entity/core';\n\n/** ADR-008: Shared field component contract — all 8 built-in types implement this. */\n@Component({\n selector: 'ngx-text-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--text\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n @if (masked) {\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <span class=\"ngx-field__value\">{{ control.value }}</span>\n } @else {\n <input\n class=\"ngx-field__input\"\n type=\"text\"\n [formControl]=\"$any(control)\"\n [placeholder]=\"field.placeholder?.[language] || field.placeholder?.['en'] || ''\"\n [attr.disabled]=\"field.disabled ? true : null\"\n />\n @if (control.invalid && control.touched) {\n <span class=\"ngx-field__error\">This field has an error</span>\n }\n }\n </div>\n `,\n})\nexport class TextFieldComponent {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig } from '@dynamic-entity/core';\n\n@Component({\n selector: 'ngx-textarea-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--textarea\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n @if (masked) {\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <span class=\"ngx-field__value\">{{ control.value }}</span>\n } @else {\n <textarea\n class=\"ngx-field__input\"\n [formControl]=\"$any(control)\"\n [placeholder]=\"field.placeholder?.[language] || field.placeholder?.['en'] || ''\"\n [attr.disabled]=\"field.disabled ? true : null\"\n rows=\"3\"\n ></textarea>\n @if (control.invalid && control.touched) {\n <span class=\"ngx-field__error\">This field has an error</span>\n }\n }\n </div>\n `,\n})\nexport class TextareaFieldComponent {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig } from '@dynamic-entity/core';\n\n@Component({\n selector: 'ngx-number-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--number\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n @if (masked) {\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <span class=\"ngx-field__value\">{{ control.value }}</span>\n } @else {\n <input\n class=\"ngx-field__input\"\n type=\"number\"\n [formControl]=\"$any(control)\"\n [placeholder]=\"field.placeholder?.[language] || field.placeholder?.['en'] || ''\"\n [attr.disabled]=\"field.disabled ? true : null\"\n />\n @if (control.invalid && control.touched) {\n <span class=\"ngx-field__error\">This field has an error</span>\n }\n }\n </div>\n `,\n})\nexport class NumberFieldComponent {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig } from '@dynamic-entity/core';\n\n@Component({\n selector: 'ngx-checkbox-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--checkbox\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n @if (masked) {\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n <span class=\"ngx-field__value\">{{ control.value ? 'Yes' : 'No' }}</span>\n } @else {\n <label class=\"ngx-field__label\">\n <input\n class=\"ngx-field__input\"\n type=\"checkbox\"\n [formControl]=\"$any(control)\"\n [attr.disabled]=\"field.disabled ? true : null\"\n />\n {{ field.label[language] || field.label['en'] }}\n </label>\n }\n </div>\n `,\n})\nexport class CheckboxFieldComponent {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig } from '@dynamic-entity/core';\n\n@Component({\n selector: 'ngx-date-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--date\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n @if (masked) {\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <span class=\"ngx-field__value\">{{ formatDate(control.value) }}</span>\n } @else {\n <input\n class=\"ngx-field__input\"\n type=\"date\"\n [formControl]=\"$any(control)\"\n [attr.disabled]=\"field.disabled ? true : null\"\n />\n @if (control.invalid && control.touched) {\n <span class=\"ngx-field__error\">This field has an error</span>\n }\n }\n </div>\n `,\n})\nexport class DateFieldComponent {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n\n /** ISO 8601 date → locale display string (ONEHERMES convention: always UTC, display in user locale) */\n formatDate(value: string | null): string {\n if (!value) return '—';\n try {\n return new Date(value).toLocaleDateString();\n } catch {\n return value;\n }\n }\n}\n","import { Component, Input, OnInit, signal } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig, DropdownOption } from '@dynamic-entity/core';\n\n@Component({\n selector: 'ngx-dropdown-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--dropdown\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n @if (masked) {\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <span class=\"ngx-field__value\">{{ getLabel(control.value) }}</span>\n } @else {\n <select\n class=\"ngx-field__input\"\n [formControl]=\"$any(control)\"\n [attr.disabled]=\"field.disabled ? true : null\"\n >\n <option value=\"\">{{ field.placeholder?.[language] || field.placeholder?.['en'] || 'Select...' }}</option>\n @for (option of field.options || []; track option.value) {\n <option [value]=\"option.value\">{{ option.label[language] || option.label['en'] }}</option>\n }\n </select>\n @if (control.invalid && control.touched) {\n <span class=\"ngx-field__error\">This field has an error</span>\n }\n }\n </div>\n `,\n})\nexport class DropdownFieldComponent {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n\n getLabel(value: any): string {\n const option = (this.field.options || []).find(o => o.value === value);\n return option ? (option.label[this.language] || option.label['en'] || String(value)) : (value ?? '—');\n }\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig } from '@dynamic-entity/core';\n\n@Component({\n selector: 'ngx-multi-select-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--multiSelect\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n @if (masked) {\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <span class=\"ngx-field__value\">{{ getLabels(control.value) }}</span>\n } @else {\n <select\n class=\"ngx-field__input\"\n [formControl]=\"$any(control)\"\n [attr.disabled]=\"field.disabled ? true : null\"\n multiple\n size=\"4\"\n >\n @for (option of field.options || []; track option.value) {\n <option [value]=\"option.value\">{{ option.label[language] || option.label['en'] }}</option>\n }\n </select>\n @if (control.invalid && control.touched) {\n <span class=\"ngx-field__error\">This field has an error</span>\n }\n }\n </div>\n `,\n})\nexport class MultiSelectFieldComponent {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n\n getLabels(values: any[]): string {\n if (!Array.isArray(values) || !values.length) return '—';\n return values\n .map(v => {\n const opt = (this.field.options || []).find(o => o.value === v);\n return opt ? (opt.label[this.language] || opt.label['en']) : String(v);\n })\n .join(', ');\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { ENTITY_REF_REGISTRY } from '../tokens/injection-tokens';\n\n/**\n * EntityRefRegistryService — resolves entity-ref option loader functions.\n * ADR-006: Entity-ref options come ONLY from this registry.\n * Never pass loaders via @Input() on field components.\n *\n * Consumers register loaders via provideNgxDynamicEntity({ entityRefs: { clients: () => [...] } }).\n * EntityRefFieldComponent injects this service and calls resolve(field.component ?? field.id).\n */\n@Injectable({ providedIn: 'root' })\nexport class EntityRefRegistryService {\n private readonly registry = inject(ENTITY_REF_REGISTRY, { optional: true }) ?? new Map();\n\n /**\n * Get the option loader function for an entity key.\n * @returns Async function that returns options array, or null if not registered.\n */\n resolve(entityKey: string): (() => Promise<any[]>) | null {\n return this.registry.get(entityKey) ?? null;\n }\n\n has(entityKey: string): boolean {\n return this.registry.has(entityKey);\n }\n}\n","import { Component, Input, OnInit, signal } from '@angular/core';\nimport { AbstractControl, ReactiveFormsModule } from '@angular/forms';\nimport type { FieldConfig } from '@dynamic-entity/core';\nimport { EntityRefRegistryService } from '../services/entity-ref-registry.service';\nimport { inject } from '@angular/core';\n\n/**\n * EntityRefFieldComponent — renders a dropdown populated by a loader from EntityRefRegistryService.\n * ADR-006: Options come ONLY from the registry. Never via @Input() loader.\n * Uses field.component (if set) or field.id as the registry lookup key.\n */\n@Component({\n selector: 'ngx-entity-ref-field',\n standalone: true,\n imports: [ReactiveFormsModule],\n template: `\n <div class=\"ngx-field ngx-field--entity-ref\" [class.ngx-field--readonly]=\"readonly\" [class.ngx-field--masked]=\"masked\">\n <label class=\"ngx-field__label\">{{ field.label[language] || field.label['en'] }}</label>\n @if (masked) {\n <span class=\"ngx-field__value ngx-field__value--masked\">XXXXXXXXX</span>\n } @else if (readonly) {\n <span class=\"ngx-field__value\">{{ getLabel(control.value) }}</span>\n } @else {\n @if (loading()) {\n <span class=\"ngx-field__value\">Loading...</span>\n } @else {\n <select\n class=\"ngx-field__input\"\n [formControl]=\"$any(control)\"\n [attr.disabled]=\"field.disabled ? true : null\"\n >\n <option value=\"\">{{ field.placeholder?.[language] || 'Select...' }}</option>\n @for (option of options(); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @if (control.invalid && control.touched) {\n <span class=\"ngx-field__error\">This field has an error</span>\n }\n }\n </div>\n `,\n})\nexport class EntityRefFieldComponent implements OnInit {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() masked: boolean = false;\n\n private readonly entityRefRegistry = inject(EntityRefRegistryService);\n\n readonly options = signal<Array<{ value: any; label: string }>>([]);\n readonly loading = signal(false);\n\n async ngOnInit(): Promise<void> {\n if (this.masked) return; // No need to load options if masked\n const entityKey = this.field.component ?? this.field.id;\n const loader = this.entityRefRegistry.resolve(entityKey);\n if (!loader) return;\n\n this.loading.set(true);\n try {\n const raw = await loader();\n this.options.set(raw);\n } finally {\n this.loading.set(false);\n }\n }\n\n getLabel(value: any): string {\n const option = this.options().find(o => o.value === value);\n return option?.label ?? (value ?? '—');\n }\n}\n","import { Injectable, Type, inject } from '@angular/core';\nimport { FIELD_TYPE_REGISTRY } from '../tokens/injection-tokens';\n\n// Built-in field components — pre-registered in this service\nimport { TextFieldComponent } from '../field-types/text-field.component';\nimport { TextareaFieldComponent } from '../field-types/textarea-field.component';\nimport { NumberFieldComponent } from '../field-types/number-field.component';\nimport { CheckboxFieldComponent } from '../field-types/checkbox-field.component';\nimport { DateFieldComponent } from '../field-types/date-field.component';\nimport { DropdownFieldComponent } from '../field-types/dropdown-field.component';\nimport { MultiSelectFieldComponent } from '../field-types/multi-select-field.component';\nimport { EntityRefFieldComponent } from '../field-types/entity-ref-field.component';\n\n/**\n * FieldRegistryService — resolves field type strings to Angular component classes.\n * Open/Closed: open for extension via consumer fieldTypes config, closed for modification.\n * DynamicFieldComponent uses this to mount the right component via createComponent().\n */\n@Injectable({ providedIn: 'root' })\nexport class FieldRegistryService {\n private readonly consumerRegistry = inject(FIELD_TYPE_REGISTRY, { optional: true }) ?? new Map();\n\n /** Built-in field type → component map. Never remove an entry. */\n private readonly builtInRegistry = new Map<string, Type<any>>([\n ['text', TextFieldComponent],\n ['textarea', TextareaFieldComponent],\n ['number', NumberFieldComponent],\n ['checkbox', CheckboxFieldComponent],\n ['date', DateFieldComponent],\n ['dropdown', DropdownFieldComponent],\n ['multiSelect', MultiSelectFieldComponent],\n ['entity-ref', EntityRefFieldComponent],\n ]);\n\n /**\n * Resolve a field type string to a component class.\n * Consumer registry takes precedence over built-ins (open for extension).\n * Returns null if type is unknown — caller must handle gracefully.\n */\n resolve(fieldType: string): Type<any> | null {\n return this.consumerRegistry.get(fieldType) ?? this.builtInRegistry.get(fieldType) ?? null;\n }\n\n /** Check if a field type has a registered component */\n has(fieldType: string): boolean {\n return this.consumerRegistry.has(fieldType) || this.builtInRegistry.has(fieldType);\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { HOOK_REGISTRY } from '../tokens/injection-tokens';\n\n/**\n * HookRegistryService — stores and runs Angular-side pre/post hooks.\n * Consumers register hooks via provideNgxDynamicEntity({ hooks: { 'clients:beforeSave': fn } }).\n */\n@Injectable({ providedIn: 'root' })\nexport class HookRegistryService {\n private readonly registry = inject(HOOK_REGISTRY, { optional: true }) ?? new Map();\n\n has(key: string): boolean {\n return this.registry.has(key);\n }\n\n async run(key: string, data: any, context: any = {}): Promise<any> {\n const hook = this.registry.get(key);\n if (!hook) return data;\n return hook(data, context);\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { AbstractControl, ValidatorFn, Validators } from '@angular/forms';\nimport { VALIDATOR_REGISTRY } from '../tokens/injection-tokens';\n\n/**\n * ValidatorRegistryService — resolves validator key strings to Angular ValidatorFns.\n * Built-in validators: 'required', 'email', 'min:N', 'max:N', 'minLength:N', 'maxLength:N'.\n * Consumers can register custom validators via provideNgxDynamicEntity({ validators: {...} }).\n */\n@Injectable({ providedIn: 'root' })\nexport class ValidatorRegistryService {\n private readonly consumerRegistry = inject(VALIDATOR_REGISTRY, { optional: true }) ?? new Map();\n\n /**\n * Resolve a validator key to a ValidatorFn.\n * Supports parameterized built-ins like 'min:0', 'maxLength:255'.\n */\n resolve(validatorKey: string): ValidatorFn | null {\n // Consumer validators take precedence\n if (this.consumerRegistry.has(validatorKey)) {\n return this.consumerRegistry.get(validatorKey);\n }\n\n // Built-in validators\n if (validatorKey === 'required') return Validators.required;\n if (validatorKey === 'email') return Validators.email;\n\n const [name, param] = validatorKey.split(':');\n const value = parseFloat(param);\n\n if (name === 'min' && !isNaN(value)) return Validators.min(value);\n if (name === 'max' && !isNaN(value)) return Validators.max(value);\n if (name === 'minLength' && !isNaN(value)) return Validators.minLength(value);\n if (name === 'maxLength' && !isNaN(value)) return Validators.maxLength(value);\n\n return null;\n }\n\n /** Resolve multiple validator keys into a ValidatorFn[] */\n resolveAll(validatorKeys: string[] = []): ValidatorFn[] {\n return validatorKeys.map(k => this.resolve(k)).filter((v): v is ValidatorFn => v !== null);\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport type { VersionedRecord, EntityConfig, MigrationStrategy } from '@dynamic-entity/core';\nimport { MIGRATION_STRATEGY } from '../tokens/injection-tokens';\n\n/**\n * VersionService — checks config version staleness and migration strategy.\n * ADR-005: Frontend strategy is 'strict' | 'graceful' only. Never 'auto'.\n */\n@Injectable({ providedIn: 'root' })\nexport class VersionService {\n private readonly strategy = inject(MIGRATION_STRATEGY, { optional: true }) ?? 'graceful';\n\n /**\n * Check if a record is stale compared to the current config version.\n * Returns true if the record needs migration.\n */\n needsMigration(record: Partial<VersionedRecord>, config: EntityConfig): boolean {\n if (!record._configVersion) return false;\n return record._configVersion < config.version || !!record._needsMigration;\n }\n\n /**\n * Get the effective migration strategy for frontend use.\n * Only 'strict' or 'graceful' — never 'auto' (ADR-005).\n */\n getStrategy(): 'strict' | 'graceful' {\n return this.strategy === 'strict' ? 'strict' : 'graceful';\n }\n\n /**\n * Determine if form submission should be blocked for a stale record.\n * 'strict' → block; 'graceful' → allow with warning.\n */\n shouldBlockSubmit(record: Partial<VersionedRecord>, config: EntityConfig): boolean {\n return this.getStrategy() === 'strict' && this.needsMigration(record, config);\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport type { EntityConfig, FieldConfig, TabConfig } from '@dynamic-entity/core';\nimport { MASKED_ROLES } from '../tokens/injection-tokens';\n\n/**\n * RbacService — ALL permission checks and masking logic live here.\n * CRITICAL SYNC: resolveEffectiveMask() must be identical to rbac.utils.js in dynamic-entity-server.\n * Changing one without the other is a critical production bug (ADR-003).\n */\n@Injectable({ providedIn: 'root' })\nexport class RbacService {\n private readonly maskedRoles = inject(MASKED_ROLES, { optional: true }) ?? [];\n\n /**\n * Check if any of the user's roles satisfy the required roles.\n * hasPermission(roles, undefined) → true (no restriction).\n */\n hasPermission(userRoles: string[], requiredRoles?: string[]): boolean {\n if (!requiredRoles?.length) return true;\n return userRoles.some(r => requiredRoles.includes(r));\n }\n\n /**\n * ADR-003: 3-level OR resolution.\n * MUST match rbac.utils.js resolveEffectiveMask() exactly.\n */\n resolveEffectiveMask(formMask?: boolean, tabMask?: boolean, fieldMask?: boolean): boolean {\n return !!(formMask || tabMask || fieldMask);\n }\n\n /** Check if the user's roles include any masked role */\n isUserMaskedRole(userRoles: string[]): boolean {\n return this.maskedRoles.some(r => userRoles.includes(r));\n }\n\n /** Determine if a specific field should be masked for this user */\n shouldMaskField(field: FieldConfig, tab: TabConfig | undefined, config: EntityConfig, userRoles: string[]): boolean {\n if (!this.isUserMaskedRole(userRoles)) return false;\n return this.resolveEffectiveMask(config.maskData, tab?.maskData, field.maskData);\n }\n\n /** Get view/edit/delete permissions for a config */\n getPermissions(config: EntityConfig, userRoles: string[]) {\n return {\n canView: this.hasPermission(userRoles, config.permissions?.view),\n canEdit: this.hasPermission(userRoles, config.permissions?.edit),\n canDelete: this.hasPermission(userRoles, config.permissions?.delete),\n };\n }\n}\n","import {\n Component,\n Input,\n OnChanges,\n SimpleChanges,\n ViewChild,\n ViewContainerRef,\n inject,\n} from '@angular/core';\nimport { AbstractControl } from '@angular/forms';\nimport type { FieldConfig, EntityConfig, TabConfig } from '@dynamic-entity/core';\nimport { FieldRegistryService } from '../../services/field-registry.service';\nimport { RbacService } from '../../services/rbac.service';\n\n/**\n * DynamicFieldComponent — mounts the correct field component for a given FieldConfig.\n * Uses ViewContainerRef.createComponent() and passes inputs via setInput() (ADR-008).\n * Never add field-type-specific logic here — this component must remain generic.\n *\n * The 5 inputs (field, control, language, readonly, masked) are passed to every mounted\n * component uniformly — no special-casing per type.\n */\n@Component({\n selector: 'ngx-dynamic-field',\n standalone: true,\n template: `<ng-container #fieldHost></ng-container>`,\n})\nexport class DynamicFieldComponent implements OnChanges {\n @Input() field!: FieldConfig;\n @Input() control!: AbstractControl;\n @Input() config!: EntityConfig;\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() userRoles: string[] = [];\n\n @ViewChild('fieldHost', { read: ViewContainerRef, static: true })\n private readonly fieldHost!: ViewContainerRef;\n\n private readonly fieldRegistry = inject(FieldRegistryService);\n private readonly rbacService = inject(RbacService);\n\n private mountedComponent: any = null;\n\n ngOnChanges(_changes: SimpleChanges): void {\n this.mountField();\n }\n\n private mountField(): void {\n if (!this.field || !this.control) return;\n\n const ComponentClass = this.fieldRegistry.resolve(this.field.type);\n if (!ComponentClass) return; // Unknown field type — render nothing\n\n // Determine masking for this specific field\n const tab: TabConfig | undefined = (this.config?.tabs || []).find(t => t.id === this.field.tab);\n const masked = this.rbacService.shouldMaskField(this.field, tab, this.config, this.userRoles);\n\n // Re-use existing component if same type, otherwise recreate\n if (this.mountedComponent && this.mountedComponent instanceof ComponentClass) {\n this.setInputs(this.mountedComponent, masked);\n return;\n }\n\n this.fieldHost.clear();\n const ref = this.fieldHost.createComponent(ComponentClass);\n this.mountedComponent = ref.instance;\n this.setInputs(ref.instance, masked);\n ref.changeDetectorRef.markForCheck();\n }\n\n /** Pass all 5 contract inputs via setInput() — uniform for all types (ADR-008) */\n private setInputs(instance: any, masked: boolean): void {\n if ('field' in instance) instance.field = this.field;\n if ('control' in instance) instance.control = this.control;\n if ('language' in instance) instance.language = this.language;\n if ('readonly' in instance) instance.readonly = this.readonly || !!this.field.readonly;\n if ('masked' in instance) instance.masked = masked;\n }\n}\n","import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnChanges,\n SimpleChanges,\n signal,\n computed,\n inject,\n} from '@angular/core';\nimport { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';\nimport type { EntityConfig, VersionedRecord } from '@dynamic-entity/core';\nimport { DynamicFieldComponent } from './dynamic-field/dynamic-field.component';\nimport { ValidatorRegistryService } from '../services/validator-registry.service';\nimport { HookRegistryService } from '../services/hook-registry.service';\nimport { VersionService } from '../services/version.service';\nimport { RbacService } from '../services/rbac.service';\n\n/**\n * DynamicFormComponent — the main form component.\n * Renders a reactive form from EntityConfig with tab support, dependencies,\n * migration banner, and RBAC-gated submission.\n *\n * ONEHERMES pattern: isSaving state lock prevents subscription cyclones (ADR-002).\n * ONEHERMES bug fix: visibility rules re-evaluated after initialData loads (form-fixes doc).\n * ONEHERMES bug fix: use @for + @if separately, not both on same element (form-fixes doc).\n */\n@Component({\n selector: 'ngx-dynamic-form',\n standalone: true,\n imports: [ReactiveFormsModule, DynamicFieldComponent],\n templateUrl: './dynamic-form.component.html',\n})\nexport class DynamicFormComponent implements OnChanges {\n // ─── Inputs ───────────────────────────────────────────────────────────────\n @Input() config!: EntityConfig;\n @Input() initialData?: Record<string, any>;\n @Input() userRoles: string[] = [];\n @Input() language: string = 'en';\n @Input() readonly: boolean = false;\n @Input() loading: boolean = false;\n @Input() error: string | null = null;\n\n // ─── Outputs ──────────────────────────────────────────────────────────────\n @Output() formSubmit = new EventEmitter<Record<string, any>>();\n @Output() formChange = new EventEmitter<Record<string, any>>();\n @Output() formReset = new EventEmitter<void>();\n\n // ─── Services ─────────────────────────────────────────────────────────────\n private readonly fb = inject(FormBuilder);\n private readonly validatorRegistry = inject(ValidatorRegistryService);\n private readonly hookRegistry = inject(HookRegistryService);\n protected readonly versionService = inject(VersionService);\n private readonly rbacService = inject(RbacService);\n\n // ─── Signals (local reactive state) ───────────────────────────────────────\n readonly activeTab = signal<string>('');\n readonly isSaving = signal(false); // ADR-002: isSaving lock prevents API spam\n\n // ─── Form ─────────────────────────────────────────────────────────────────\n form!: FormGroup;\n\n // ─── Computed ─────────────────────────────────────────────────────────────\n get tabs() {\n return (this.config?.tabs || []).sort((a, b) => a.order - b.order);\n }\n\n get fieldsForActiveTab() {\n const tabId = this.activeTab();\n return (this.config?.fields || []).filter(f => {\n if (!this.tabs.length) return true; // No tabs — show all\n return f.tab === tabId || (!f.tab && tabId === this.tabs[0]?.id);\n });\n }\n\n get permissions() {\n return this.rbacService.getPermissions(this.config, this.userRoles);\n }\n\n get needsMigration(): boolean {\n return this.versionService.needsMigration(this.initialData || {}, this.config);\n }\n\n get canSubmit(): boolean {\n return (\n this.permissions.canEdit &&\n !this.readonly &&\n !this.isSaving() &&\n !this.versionService.shouldBlockSubmit(this.initialData || {}, this.config)\n );\n }\n\n // ─── Lifecycle ────────────────────────────────────────────────────────────\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['config'] && this.config) {\n this.buildForm();\n }\n // ONEHERMES fix: re-apply data after initialData loads (form-fixes doc)\n if (changes['initialData'] && this.form && this.initialData) {\n this.patchForm(this.initialData);\n }\n if (changes['config'] && this.tabs.length) {\n this.activeTab.set(this.tabs[0]?.id || '');\n }\n }\n\n private buildForm(): void {\n const controls: Record<string, any> = {};\n for (const field of this.config.fields || []) {\n if (field.isSystem) continue; // System fields not in form controls\n const validators = this.validatorRegistry.resolveAll(field.validators);\n controls[field.id] = [field.defaultValue ?? null, validators];\n }\n this.form = this.fb.group(controls);\n\n // Emit changes via formChange output\n this.form.valueChanges.subscribe(value => this.formChange.emit(value));\n\n // Apply initial data after form builds\n if (this.initialData) {\n this.patchForm(this.initialData);\n }\n\n if (this.tabs.length && !this.activeTab()) {\n this.activeTab.set(this.tabs[0].id);\n }\n }\n\n private patchForm(data: Record<string, any>): void {\n // Filter empty objects (ONEHERMES array field empty row bug fix)\n const cleanData = Object.fromEntries(\n Object.entries(data).filter(([, v]) => v !== undefined),\n );\n this.form.patchValue(cleanData, { emitEvent: false });\n }\n\n // ─── Actions ──────────────────────────────────────────────────────────────\n\n setActiveTab(tabId: string): void {\n this.activeTab.set(tabId);\n }\n\n async submit(): Promise<void> {\n if (!this.canSubmit || this.form.invalid) {\n this.form.markAllAsTouched();\n return;\n }\n\n // ADR-002: isSaving lock — prevents subscription cyclones / duplicate API calls\n if (this.isSaving()) return;\n this.isSaving.set(true);\n\n try {\n let data = { ...this.form.value };\n\n // Run pre-submit hook (Angular-side)\n data = await this.hookRegistry.run(`${this.config.entity}:beforeSave`, data, {\n config: this.config,\n userRoles: this.userRoles,\n });\n\n this.formSubmit.emit(data);\n } finally {\n // Reset saving lock in the consumer's success/error handler — here we just unblock\n this.isSaving.set(false);\n }\n }\n\n reset(): void {\n this.form.reset();\n if (this.initialData) this.patchForm(this.initialData);\n this.formReset.emit();\n }\n\n getControl(fieldId: string) {\n return this.form?.get(fieldId);\n }\n}\n","<form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"ngx-form\" novalidate>\n\n <!-- Migration banner — visible in graceful mode when record is stale -->\n @if (needsMigration) {\n <div class=\"ngx-form__migration-banner\" role=\"alert\">\n ⚠️ This record was created with an older configuration version.\n @if (versionService.shouldBlockSubmit(initialData || {}, config)) {\n Please run migration before editing.\n } @else {\n It will be updated to the latest version on save.\n }\n </div>\n }\n\n <!-- Error message -->\n @if (error) {\n <div class=\"ngx-form__error-banner\" role=\"alert\">{{ error }}</div>\n }\n\n <!-- Tab bar — only if tabs defined -->\n @if (tabs.length > 0) {\n <div class=\"ngx-form__tabs\" role=\"tablist\">\n <!-- ONEHERMES fix: @for and @if on separate elements, not same (form-fixes doc) -->\n @for (tab of tabs; track tab.id) {\n <button\n type=\"button\"\n class=\"ngx-form__tab\"\n [class.ngx-form__tab--active]=\"activeTab() === tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === tab.id\"\n >\n {{ tab.label[language] || tab.label['en'] }}\n </button>\n }\n </div>\n }\n\n <!-- Fields for active tab -->\n <div class=\"ngx-form__panel\">\n @for (field of fieldsForActiveTab; track field.id) {\n @if (field.visible !== false) {\n <ngx-dynamic-field\n [field]=\"field\"\n [control]=\"getControl(field.id)!\"\n [config]=\"config\"\n [language]=\"language\"\n [readonly]=\"readonly || !!field.readonly\"\n [userRoles]=\"userRoles\"\n />\n }\n }\n </div>\n\n <!-- Submit button — gated by RBAC and isSaving lock -->\n @if (!readonly && permissions.canEdit) {\n <div class=\"ngx-form__actions\">\n <button\n type=\"button\"\n class=\"ngx-form__reset\"\n (click)=\"reset()\"\n [disabled]=\"isSaving()\"\n >\n Reset\n </button>\n <button\n type=\"submit\"\n class=\"ngx-form__submit\"\n [disabled]=\"!canSubmit || form.invalid\"\n >\n @if (isSaving() || loading) {\n Saving…\n } @else {\n Save\n }\n </button>\n </div>\n }\n\n</form>\n","import { Component, Input, Output, EventEmitter, signal, computed, inject, OnChanges, SimpleChanges } from '@angular/core';\nimport type { EntityConfig, VersionedRecord } from '@dynamic-entity/core';\nimport { RbacService } from '../services/rbac.service';\nimport { VersionService } from '../services/version.service';\n\n/**\n * DynamicTableComponent — renders entity records as a searchable, sortable, paginated table.\n * Columns determined by FieldConfig.tableColumn === true.\n * Cell masking applied via RbacService (defense-in-depth).\n * Pagination, sort, and search emit events — parent controls data fetching (smart/dumb pattern).\n */\n@Component({\n selector: 'ngx-dynamic-table',\n standalone: true,\n imports: [],\n templateUrl: './dynamic-table.component.html',\n})\nexport class DynamicTableComponent implements OnChanges {\n // ─── Inputs ───────────────────────────────────────────────────────────────\n @Input() config!: EntityConfig;\n @Input() data: VersionedRecord[] = [];\n @Input() userRoles: string[] = [];\n @Input() language: string = 'en';\n @Input() loading: boolean = false;\n @Input() error: string | null = null;\n @Input() totalRecords: number = 0;\n @Input() pageSize: number = 20;\n @Input() currentPage: number = 1;\n\n // ─── Outputs ──────────────────────────────────────────────────────────────\n @Output() rowClick = new EventEmitter<VersionedRecord>();\n @Output() rowEdit = new EventEmitter<VersionedRecord>();\n @Output() rowDelete = new EventEmitter<VersionedRecord>();\n @Output() pageChange = new EventEmitter<number>();\n @Output() pageSizeChange = new EventEmitter<number>();\n @Output() sortChange = new EventEmitter<{ field: string; dir: 'asc' | 'desc' }>();\n @Output() searchChange = new EventEmitter<string>();\n\n // ─── Services ─────────────────────────────────────────────────────────────\n private readonly rbacService = inject(RbacService);\n private readonly versionService = inject(VersionService);\n\n // ─── Signals ──────────────────────────────────────────────────────────────\n readonly sortField = signal<string>('');\n readonly sortDir = signal<'asc' | 'desc'>('desc');\n readonly searchTerm = signal<string>('');\n\n // ─── Computed ─────────────────────────────────────────────────────────────\n readonly tableColumns = computed(() => \n (this.config?.fields || []).filter(f => f.tableColumn === true)\n );\n\n get permissions() {\n return this.rbacService.getPermissions(this.config, this.userRoles);\n }\n\n get totalPages(): number {\n return Math.ceil(this.totalRecords / this.pageSize) || 0;\n }\n\n ngOnChanges(_changes: SimpleChanges): void {\n // Pre-resolve masking per column once (ONEHERMES hardening: pre-resolved at extract time)\n this._resolveColumnMasks();\n }\n\n private columnMaskCache = new Map<string, boolean>();\n\n private _resolveColumnMasks(): void {\n if (!this.config) return;\n this.columnMaskCache.clear();\n for (const field of this.tableColumns()) {\n const tab = (this.config.tabs || []).find(t => t.id === field.tab);\n const masked = this.rbacService.shouldMaskField(field, tab, this.config, this.userRoles);\n this.columnMaskCache.set(field.id, masked);\n }\n }\n\n // ─── Helpers ──────────────────────────────────────────────────────────────\n\n isCellMasked(fieldId: string): boolean {\n return this.columnMaskCache.get(fieldId) ?? false;\n }\n\n getCellValue(record: VersionedRecord, fieldId: string): string {\n if (this.isCellMasked(fieldId)) return 'XXXXXXXXX';\n const value = record[fieldId];\n if (value === null || value === undefined) return '—';\n if (typeof value === 'boolean') return value ? 'Yes' : 'No';\n if (value instanceof Date || (typeof value === 'string' && value.match(/^\\d{4}-\\d{2}-\\d{2}/))) {\n try {\n return new Date(value).toLocaleDateString();\n } catch {\n return String(value);\n }\n }\n if (Array.isArray(value)) return value.join(', ');\n return String(value);\n }\n\n needsMigration(record: VersionedRecord): boolean {\n return this.versionService.needsMigration(record, this.config);\n }\n\n getColumnLabel(fieldId: string): string {\n const field = (this.config?.fields || []).find(f => f.id === fieldId);\n return field?.label?.[this.language] || field?.label?.['en'] || fieldId;\n }\n\n // ─── Sort / Search / Pagination ───────────────────────────────────────────\n\n onSort(fieldId: string): void {\n if (this.sortField() === fieldId) {\n const next = this.sortDir() === 'asc' ? 'desc' : 'asc';\n this.sortDir.set(next);\n } else {\n this.sortField.set(fieldId);\n this.sortDir.set('asc');\n }\n this.sortChange.emit({ field: this.sortField(), dir: this.sortDir() });\n }\n\n onSearch(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.searchTerm.set(value);\n this.searchChange.emit(value);\n }\n\n onPageChange(page: number): void {\n if (page < 1 || page > this.totalPages) return;\n this.pageChange.emit(page);\n }\n\n onEdit(event: Event, record: VersionedRecord): void {\n event.stopPropagation();\n this.rowEdit.emit(record);\n }\n\n onDelete(event: Event, record: VersionedRecord): void {\n event.stopPropagation();\n this.rowDelete.emit(record);\n }\n}\n","<div class=\"ngx-table\">\n\n <!-- Search bar -->\n <div class=\"ngx-table__toolbar\">\n <input\n class=\"ngx-table__search\"\n type=\"search\"\n placeholder=\"Search...\"\n [value]=\"searchTerm()\"\n (input)=\"onSearch($event)\"\n aria-label=\"Search records\"\n />\n </div>\n\n <!-- Error -->\n @if (error) {\n <div class=\"ngx-table__error\" role=\"alert\">{{ error }}</div>\n }\n\n <!-- Table -->\n <table class=\"ngx-table__table\">\n <thead>\n <tr>\n @for (col of tableColumns(); track col.id) {\n <th\n class=\"ngx-table__th\"\n [style.width]=\"col.columnWidth || 'auto'\"\n (click)=\"onSort(col.id)\"\n [attr.aria-sort]=\"sortField() === col.id ? sortDir() : 'none'\"\n role=\"columnheader\"\n >\n {{ getColumnLabel(col.id) }}\n @if (sortField() === col.id) {\n <span class=\"ngx-table__sort-icon\">{{ sortDir() === 'asc' ? '↑' : '↓' }}</span>\n }\n </th>\n }\n <!-- Actions column -->\n @if (permissions.canEdit || permissions.canDelete) {\n <th class=\"ngx-table__th ngx-table__th--actions\">Actions</th>\n }\n </tr>\n </thead>\n <tbody>\n @if (loading) {\n <tr>\n <td [attr.colspan]=\"tableColumns().length + 1\" class=\"ngx-table__loading\">Loading…</td>\n </tr>\n } @else if (!data || !data.length) {\n <tr>\n <td [attr.colspan]=\"tableColumns().length + 1\" class=\"ngx-table__empty\">No records found</td>\n </tr>\n } @else {\n @for (record of data; track record['_id']) {\n <tr class=\"ngx-table__row\" (click)=\"rowClick.emit(record)\">\n @for (col of tableColumns(); track col.id) {\n <td\n class=\"ngx-table__td\"\n [class.ngx-table__td--masked]=\"isCellMasked(col.id)\"\n >\n {{ getCellValue(record, col.id) }}\n <!-- Migration badge — shows when record is stale -->\n @if (tableColumns().length > 0 && col.id === tableColumns()[0].id && needsMigration(record)) {\n <span class=\"ngx-table__migration-badge\" title=\"Needs migration\">⚠</span>\n }\n </td>\n }\n <!-- Action buttons — gated by RBAC permissions -->\n @if (permissions.canEdit || permissions.canDelete) {\n <td class=\"ngx-table__td ngx-table__actions\">\n @if (permissions.canEdit) {\n <button\n type=\"button\"\n class=\"ngx-table__action ngx-table__action--edit\"\n (click)=\"onEdit($event, record)\"\n title=\"Edit\"\n >✏</button>\n }\n @if (permissions.canDelete) {\n <button\n type=\"button\"\n class=\"ngx-table__action ngx-table__action--delete\"\n (click)=\"onDelete($event, record)\"\n title=\"Delete\"\n >🗑</button>\n }\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n\n <!-- Pagination -->\n @if (totalPages > 1) {\n <div class=\"ngx-table__pagination\">\n <button\n type=\"button\"\n class=\"ngx-table__page-btn\"\n [disabled]=\"currentPage <= 1\"\n (click)=\"onPageChange(currentPage - 1)\"\n aria-label=\"Previous page\"\n >←</button>\n\n <span class=\"ngx-table__page-info\">\n Page {{ currentPage }} of {{ totalPages }} ({{ totalRecords }} records)\n </span>\n\n <button\n type=\"button\"\n class=\"ngx-table__page-btn\"\n [disabled]=\"currentPage >= totalPages\"\n (click)=\"onPageChange(currentPage + 1)\"\n aria-label=\"Next page\"\n >→</button>\n </div>\n }\n\n</div>\n","// Tokens\nexport * from './lib/tokens/injection-tokens';\n\n// Providers\nexport * from './lib/providers/provide-ngx-dynamic-entity';\n\n// Services\nexport * from './lib/services/config.service';\nexport * from './lib/services/field-registry.service';\nexport * from './lib/services/hook-registry.service';\nexport * from './lib/services/validator-registry.service';\nexport * from './lib/services/entity-ref-registry.service';\nexport * from './lib/services/version.service';\nexport * from './lib/services/rbac.service';\n\n// Components\nexport * from './lib/form/dynamic-form.component';\nexport * from './lib/form/dynamic-field/dynamic-field.component';\nexport * from './lib/table/dynamic-table.component';\n\n// Field type components (individually importable — reusability rule)\nexport * from './lib/field-types/text-field.component';\nexport * from './lib/field-types/textarea-field.component';\nexport * from './lib/field-types/number-field.component';\nexport * from './lib/field-types/checkbox-field.component';\nexport * from './lib/field-types/date-field.component';\nexport * from './lib/field-types/dropdown-field.component';\nexport * from './lib/field-types/multi-select-field.component';\nexport * from './lib/field-types/entity-ref-field.component';\n\n// Re-export core types so consumers need only one import\nexport type {\n EntityConfig,\n FieldConfig,\n TabConfig,\n DropdownOption,\n FieldDependency,\n EntityHooks,\n VersionedRecord,\n EntityPermissions,\n RbacContext,\n MigrationStrategy,\n QueryOptions,\n PaginatedResult,\n} from '@dynamic-entity/core';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractControl } from '@angular/forms';
|
|
2
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class CheckboxFieldComponent {
|
|
5
|
+
field: FieldConfig;
|
|
6
|
+
control: AbstractControl;
|
|
7
|
+
language: string;
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
masked: boolean;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CheckboxFieldComponent, never>;
|
|
11
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<CheckboxFieldComponent, "ngx-checkbox-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AbstractControl } from '@angular/forms';
|
|
2
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class DateFieldComponent {
|
|
5
|
+
field: FieldConfig;
|
|
6
|
+
control: AbstractControl;
|
|
7
|
+
language: string;
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
masked: boolean;
|
|
10
|
+
/** ISO 8601 date → locale display string (ONEHERMES convention: always UTC, display in user locale) */
|
|
11
|
+
formatDate(value: string | null): string;
|
|
12
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DateFieldComponent, never>;
|
|
13
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DateFieldComponent, "ngx-date-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AbstractControl } from '@angular/forms';
|
|
2
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class DropdownFieldComponent {
|
|
5
|
+
field: FieldConfig;
|
|
6
|
+
control: AbstractControl;
|
|
7
|
+
language: string;
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
masked: boolean;
|
|
10
|
+
getLabel(value: any): string;
|
|
11
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DropdownFieldComponent, never>;
|
|
12
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DropdownFieldComponent, "ngx-dropdown-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { OnInit } from '@angular/core';
|
|
2
|
+
import { AbstractControl } from '@angular/forms';
|
|
3
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* EntityRefFieldComponent — renders a dropdown populated by a loader from EntityRefRegistryService.
|
|
7
|
+
* ADR-006: Options come ONLY from the registry. Never via @Input() loader.
|
|
8
|
+
* Uses field.component (if set) or field.id as the registry lookup key.
|
|
9
|
+
*/
|
|
10
|
+
export declare class EntityRefFieldComponent implements OnInit {
|
|
11
|
+
field: FieldConfig;
|
|
12
|
+
control: AbstractControl;
|
|
13
|
+
language: string;
|
|
14
|
+
readonly: boolean;
|
|
15
|
+
masked: boolean;
|
|
16
|
+
private readonly entityRefRegistry;
|
|
17
|
+
readonly options: import("@angular/core").WritableSignal<{
|
|
18
|
+
value: any;
|
|
19
|
+
label: string;
|
|
20
|
+
}[]>;
|
|
21
|
+
readonly loading: import("@angular/core").WritableSignal<boolean>;
|
|
22
|
+
ngOnInit(): Promise<void>;
|
|
23
|
+
getLabel(value: any): string;
|
|
24
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<EntityRefFieldComponent, never>;
|
|
25
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<EntityRefFieldComponent, "ngx-entity-ref-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AbstractControl } from '@angular/forms';
|
|
2
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class MultiSelectFieldComponent {
|
|
5
|
+
field: FieldConfig;
|
|
6
|
+
control: AbstractControl;
|
|
7
|
+
language: string;
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
masked: boolean;
|
|
10
|
+
getLabels(values: any[]): string;
|
|
11
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MultiSelectFieldComponent, never>;
|
|
12
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MultiSelectFieldComponent, "ngx-multi-select-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractControl } from '@angular/forms';
|
|
2
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class NumberFieldComponent {
|
|
5
|
+
field: FieldConfig;
|
|
6
|
+
control: AbstractControl;
|
|
7
|
+
language: string;
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
masked: boolean;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NumberFieldComponent, never>;
|
|
11
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<NumberFieldComponent, "ngx-number-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AbstractControl } from '@angular/forms';
|
|
2
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/** ADR-008: Shared field component contract — all 8 built-in types implement this. */
|
|
5
|
+
export declare class TextFieldComponent {
|
|
6
|
+
field: FieldConfig;
|
|
7
|
+
control: AbstractControl;
|
|
8
|
+
language: string;
|
|
9
|
+
readonly: boolean;
|
|
10
|
+
masked: boolean;
|
|
11
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TextFieldComponent, never>;
|
|
12
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TextFieldComponent, "ngx-text-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractControl } from '@angular/forms';
|
|
2
|
+
import type { FieldConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class TextareaFieldComponent {
|
|
5
|
+
field: FieldConfig;
|
|
6
|
+
control: AbstractControl;
|
|
7
|
+
language: string;
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
masked: boolean;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TextareaFieldComponent, never>;
|
|
11
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TextareaFieldComponent, "ngx-textarea-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { OnChanges, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { AbstractControl } from '@angular/forms';
|
|
3
|
+
import type { FieldConfig, EntityConfig } from '@dynamic-entity/core';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* DynamicFieldComponent — mounts the correct field component for a given FieldConfig.
|
|
7
|
+
* Uses ViewContainerRef.createComponent() and passes inputs via setInput() (ADR-008).
|
|
8
|
+
* Never add field-type-specific logic here — this component must remain generic.
|
|
9
|
+
*
|
|
10
|
+
* The 5 inputs (field, control, language, readonly, masked) are passed to every mounted
|
|
11
|
+
* component uniformly — no special-casing per type.
|
|
12
|
+
*/
|
|
13
|
+
export declare class DynamicFieldComponent implements OnChanges {
|
|
14
|
+
field: FieldConfig;
|
|
15
|
+
control: AbstractControl;
|
|
16
|
+
config: EntityConfig;
|
|
17
|
+
language: string;
|
|
18
|
+
readonly: boolean;
|
|
19
|
+
userRoles: string[];
|
|
20
|
+
private readonly fieldHost;
|
|
21
|
+
private readonly fieldRegistry;
|
|
22
|
+
private readonly rbacService;
|
|
23
|
+
private mountedComponent;
|
|
24
|
+
ngOnChanges(_changes: SimpleChanges): void;
|
|
25
|
+
private mountField;
|
|
26
|
+
/** Pass all 5 contract inputs via setInput() — uniform for all types (ADR-008) */
|
|
27
|
+
private setInputs;
|
|
28
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DynamicFieldComponent, never>;
|
|
29
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DynamicFieldComponent, "ngx-dynamic-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "config": { "alias": "config"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "userRoles": { "alias": "userRoles"; "required": false; }; }, {}, never, never, true, never>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { FormGroup } from '@angular/forms';
|
|
3
|
+
import type { EntityConfig } from '@dynamic-entity/core';
|
|
4
|
+
import { VersionService } from '../services/version.service';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/**
|
|
7
|
+
* DynamicFormComponent — the main form component.
|
|
8
|
+
* Renders a reactive form from EntityConfig with tab support, dependencies,
|
|
9
|
+
* migration banner, and RBAC-gated submission.
|
|
10
|
+
*
|
|
11
|
+
* ONEHERMES pattern: isSaving state lock prevents subscription cyclones (ADR-002).
|
|
12
|
+
* ONEHERMES bug fix: visibility rules re-evaluated after initialData loads (form-fixes doc).
|
|
13
|
+
* ONEHERMES bug fix: use @for + @if separately, not both on same element (form-fixes doc).
|
|
14
|
+
*/
|
|
15
|
+
export declare class DynamicFormComponent implements OnChanges {
|
|
16
|
+
config: EntityConfig;
|
|
17
|
+
initialData?: Record<string, any>;
|
|
18
|
+
userRoles: string[];
|
|
19
|
+
language: string;
|
|
20
|
+
readonly: boolean;
|
|
21
|
+
loading: boolean;
|
|
22
|
+
error: string | null;
|
|
23
|
+
formSubmit: EventEmitter<Record<string, any>>;
|
|
24
|
+
formChange: EventEmitter<Record<string, any>>;
|
|
25
|
+
formReset: EventEmitter<void>;
|
|
26
|
+
private readonly fb;
|
|
27
|
+
private readonly validatorRegistry;
|
|
28
|
+
private readonly hookRegistry;
|
|
29
|
+
protected readonly versionService: VersionService;
|
|
30
|
+
private readonly rbacService;
|
|
31
|
+
readonly activeTab: import("@angular/core").WritableSignal<string>;
|
|
32
|
+
readonly isSaving: import("@angular/core").WritableSignal<boolean>;
|
|
33
|
+
form: FormGroup;
|
|
34
|
+
get tabs(): import("@dynamic-entity/core").TabConfig[];
|
|
35
|
+
get fieldsForActiveTab(): import("@dynamic-entity/core").FieldConfig[];
|
|
36
|
+
get permissions(): {
|
|
37
|
+
canView: boolean;
|
|
38
|
+
canEdit: boolean;
|
|
39
|
+
canDelete: boolean;
|
|
40
|
+
};
|
|
41
|
+
get needsMigration(): boolean;
|
|
42
|
+
get canSubmit(): boolean;
|
|
43
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
44
|
+
private buildForm;
|
|
45
|
+
private patchForm;
|
|
46
|
+
setActiveTab(tabId: string): void;
|
|
47
|
+
submit(): Promise<void>;
|
|
48
|
+
reset(): void;
|
|
49
|
+
getControl(fieldId: string): import("@angular/forms").AbstractControl<any, any>;
|
|
50
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DynamicFormComponent, never>;
|
|
51
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DynamicFormComponent, "ngx-dynamic-form", never, { "config": { "alias": "config"; "required": false; }; "initialData": { "alias": "initialData"; "required": false; }; "userRoles": { "alias": "userRoles"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, { "formSubmit": "formSubmit"; "formChange": "formChange"; "formReset": "formReset"; }, never, never, true, never>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { EnvironmentProviders, Type } from '@angular/core';
|
|
2
|
+
export interface NgxDynamicEntityConfig {
|
|
3
|
+
/** Base URL of the dynamic-entity-server API. Example: 'http://localhost:3000/api/entities' */
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
/** Roles that see masked field values as XXXXXXXXX */
|
|
6
|
+
maskedRoles?: string[];
|
|
7
|
+
/** Migration strategy: 'strict' rejects stale records, 'graceful' flags them. Never 'auto' (ADR-005). */
|
|
8
|
+
migrationStrategy?: 'strict' | 'graceful';
|
|
9
|
+
/** Custom field type components keyed by type string */
|
|
10
|
+
fieldTypes?: Record<string, Type<any>>;
|
|
11
|
+
/** Entity-ref option loaders keyed by entity key (ADR-006) */
|
|
12
|
+
entityRefs?: Record<string, () => Promise<any[]>>;
|
|
13
|
+
/** Custom validator functions keyed by validator name */
|
|
14
|
+
validators?: Record<string, any>;
|
|
15
|
+
/** Hook functions keyed by hook name */
|
|
16
|
+
hooks?: Record<string, Function>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Provider function for ngx-dynamic-entity.
|
|
20
|
+
* All options are optional — consumers provide only what they use (ISP).
|
|
21
|
+
*
|
|
22
|
+
* Usage in app.config.ts:
|
|
23
|
+
* provideNgxDynamicEntity({
|
|
24
|
+
* apiUrl: 'http://localhost:3000/api/entities',
|
|
25
|
+
* maskedRoles: ['IT_SUPPORT'],
|
|
26
|
+
* entityRefs: { clients: () => clientService.getOptions() },
|
|
27
|
+
* })
|
|
28
|
+
*/
|
|
29
|
+
export declare const provideNgxDynamicEntity: (config?: NgxDynamicEntityConfig) => EnvironmentProviders;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import type { EntityConfig } from '@dynamic-entity/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* ConfigService — fetches entity configs from the dynamic-entity-server API.
|
|
6
|
+
* Uses shareReplay(1) to cache per config key — avoids duplicate HTTP requests.
|
|
7
|
+
* Following ONEHERMES smart service pattern: Observable$ + shareReplay.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ConfigService {
|
|
10
|
+
private readonly http;
|
|
11
|
+
private readonly apiUrl;
|
|
12
|
+
private readonly cache;
|
|
13
|
+
/** Get a config by entity key. Cached via shareReplay(1). */
|
|
14
|
+
getConfig(entity: string): Observable<EntityConfig>;
|
|
15
|
+
/** List all configs */
|
|
16
|
+
listConfigs(): Observable<EntityConfig[]>;
|
|
17
|
+
/** Create a new config */
|
|
18
|
+
saveConfig(config: EntityConfig): Observable<EntityConfig>;
|
|
19
|
+
/** Update an existing config */
|
|
20
|
+
updateConfig(entity: string, updates: Partial<EntityConfig>): Observable<EntityConfig>;
|
|
21
|
+
/** Invalidate cache for an entity (call after config update) */
|
|
22
|
+
invalidate(entity: string): void;
|
|
23
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ConfigService, never>;
|
|
24
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ConfigService>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
/**
|
|
3
|
+
* EntityRefRegistryService — resolves entity-ref option loader functions.
|
|
4
|
+
* ADR-006: Entity-ref options come ONLY from this registry.
|
|
5
|
+
* Never pass loaders via @Input() on field components.
|
|
6
|
+
*
|
|
7
|
+
* Consumers register loaders via provideNgxDynamicEntity({ entityRefs: { clients: () => [...] } }).
|
|
8
|
+
* EntityRefFieldComponent injects this service and calls resolve(field.component ?? field.id).
|
|
9
|
+
*/
|
|
10
|
+
export declare class EntityRefRegistryService {
|
|
11
|
+
private readonly registry;
|
|
12
|
+
/**
|
|
13
|
+
* Get the option loader function for an entity key.
|
|
14
|
+
* @returns Async function that returns options array, or null if not registered.
|
|
15
|
+
*/
|
|
16
|
+
resolve(entityKey: string): (() => Promise<any[]>) | null;
|
|
17
|
+
has(entityKey: string): boolean;
|
|
18
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<EntityRefRegistryService, never>;
|
|
19
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<EntityRefRegistryService>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Type } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* FieldRegistryService — resolves field type strings to Angular component classes.
|
|
5
|
+
* Open/Closed: open for extension via consumer fieldTypes config, closed for modification.
|
|
6
|
+
* DynamicFieldComponent uses this to mount the right component via createComponent().
|
|
7
|
+
*/
|
|
8
|
+
export declare class FieldRegistryService {
|
|
9
|
+
private readonly consumerRegistry;
|
|
10
|
+
/** Built-in field type → component map. Never remove an entry. */
|
|
11
|
+
private readonly builtInRegistry;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a field type string to a component class.
|
|
14
|
+
* Consumer registry takes precedence over built-ins (open for extension).
|
|
15
|
+
* Returns null if type is unknown — caller must handle gracefully.
|
|
16
|
+
*/
|
|
17
|
+
resolve(fieldType: string): Type<any> | null;
|
|
18
|
+
/** Check if a field type has a registered component */
|
|
19
|
+
has(fieldType: string): boolean;
|
|
20
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FieldRegistryService, never>;
|
|
21
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<FieldRegistryService>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
/**
|
|
3
|
+
* HookRegistryService — stores and runs Angular-side pre/post hooks.
|
|
4
|
+
* Consumers register hooks via provideNgxDynamicEntity({ hooks: { 'clients:beforeSave': fn } }).
|
|
5
|
+
*/
|
|
6
|
+
export declare class HookRegistryService {
|
|
7
|
+
private readonly registry;
|
|
8
|
+
has(key: string): boolean;
|
|
9
|
+
run(key: string, data: any, context?: any): Promise<any>;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<HookRegistryService, never>;
|
|
11
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<HookRegistryService>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { EntityConfig, FieldConfig, TabConfig } from '@dynamic-entity/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* RbacService — ALL permission checks and masking logic live here.
|
|
5
|
+
* CRITICAL SYNC: resolveEffectiveMask() must be identical to rbac.utils.js in dynamic-entity-server.
|
|
6
|
+
* Changing one without the other is a critical production bug (ADR-003).
|
|
7
|
+
*/
|
|
8
|
+
export declare class RbacService {
|
|
9
|
+
private readonly maskedRoles;
|
|
10
|
+
/**
|
|
11
|
+
* Check if any of the user's roles satisfy the required roles.
|
|
12
|
+
* hasPermission(roles, undefined) → true (no restriction).
|
|
13
|
+
*/
|
|
14
|
+
hasPermission(userRoles: string[], requiredRoles?: string[]): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* ADR-003: 3-level OR resolution.
|
|
17
|
+
* MUST match rbac.utils.js resolveEffectiveMask() exactly.
|
|
18
|
+
*/
|
|
19
|
+
resolveEffectiveMask(formMask?: boolean, tabMask?: boolean, fieldMask?: boolean): boolean;
|
|
20
|
+
/** Check if the user's roles include any masked role */
|
|
21
|
+
isUserMaskedRole(userRoles: string[]): boolean;
|
|
22
|
+
/** Determine if a specific field should be masked for this user */
|
|
23
|
+
shouldMaskField(field: FieldConfig, tab: TabConfig | undefined, config: EntityConfig, userRoles: string[]): boolean;
|
|
24
|
+
/** Get view/edit/delete permissions for a config */
|
|
25
|
+
getPermissions(config: EntityConfig, userRoles: string[]): {
|
|
26
|
+
canView: boolean;
|
|
27
|
+
canEdit: boolean;
|
|
28
|
+
canDelete: boolean;
|
|
29
|
+
};
|
|
30
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RbacService, never>;
|
|
31
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RbacService>;
|
|
32
|
+
}
|