valtech-components 2.0.1016 → 2.0.1017

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, NgZone, ViewChild, ChangeDetectorRef, output, ContentChild, ElementRef, viewChild, untracked, Injector, isSignal, ViewEncapsulation } from '@angular/core';
2
+ import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, NgZone, ViewChild, ChangeDetectorRef, output, ContentChild, model, ElementRef, viewChild, untracked, Injector, isSignal, ViewEncapsulation } from '@angular/core';
3
3
  import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, forkJoin, race, timer, shareReplay } from 'rxjs';
4
4
  import { catchError, switchMap, finalize, filter, take, map as map$1, tap, distinctUntilChanged as distinctUntilChanged$1, retry, timeout, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
5
5
  import * as i1$3 from '@angular/common/http';
@@ -54,7 +54,7 @@ import 'prismjs/components/prism-json';
54
54
  * Current version of valtech-components.
55
55
  * This is automatically updated during the publish process.
56
56
  */
57
- const VERSION = '2.0.1016';
57
+ const VERSION = '2.0.1017';
58
58
 
59
59
  // Control de estado de refresco (singleton a nivel de módulo)
60
60
  let isRefreshing = false;
@@ -18915,13 +18915,7 @@ class SelectSearchComponent {
18915
18915
 
18916
18916
  <ion-input style="position: absolute;" [formControl]="props.control" type="hidden"></ion-input>
18917
18917
 
18918
- <ion-modal
18919
- #modal
18920
- trigger="open-modal"
18921
- [initialBreakpoint]="1"
18922
- [breakpoints]="[0, 0.5, 0.75, 1]"
18923
- (didDismiss)="resetState()"
18924
- >
18918
+ <ion-modal #modal [initialBreakpoint]="1" [breakpoints]="[0, 0.5, 0.75, 1]" (didDismiss)="resetState()">
18925
18919
  <ng-template>
18926
18920
  <ion-header>
18927
18921
  <ion-toolbar>
@@ -18962,13 +18956,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
18962
18956
 
18963
18957
  <ion-input style="position: absolute;" [formControl]="props.control" type="hidden"></ion-input>
18964
18958
 
18965
- <ion-modal
18966
- #modal
18967
- trigger="open-modal"
18968
- [initialBreakpoint]="1"
18969
- [breakpoints]="[0, 0.5, 0.75, 1]"
18970
- (didDismiss)="resetState()"
18971
- >
18959
+ <ion-modal #modal [initialBreakpoint]="1" [breakpoints]="[0, 0.5, 0.75, 1]" (didDismiss)="resetState()">
18972
18960
  <ng-template>
18973
18961
  <ion-header>
18974
18962
  <ion-toolbar>
@@ -22052,8 +22040,13 @@ class MultiSelectSearchComponent {
22052
22040
  }
22053
22041
  // Parse comma-separated values for multi-select
22054
22042
  const values = typeof controlValue === 'string'
22055
- ? controlValue.split(',').map(v => v.trim()).filter(v => v !== '')
22056
- : Array.isArray(controlValue) ? controlValue : [controlValue];
22043
+ ? controlValue
22044
+ .split(',')
22045
+ .map(v => v.trim())
22046
+ .filter(v => v !== '')
22047
+ : Array.isArray(controlValue)
22048
+ ? controlValue
22049
+ : [controlValue];
22057
22050
  if (this.props.options && this.props.options.length > 0) {
22058
22051
  const map = new Map(this.props.options.map(opt => [String(opt[this.valueProperty]), opt]));
22059
22052
  this.selectedItems = values.map(val => map.get(String(val))).filter(Boolean);
@@ -22215,13 +22208,7 @@ class MultiSelectSearchComponent {
22215
22208
 
22216
22209
  <ion-input style="position: absolute;" [formControl]="props.control" type="hidden"></ion-input>
22217
22210
 
22218
- <ion-modal
22219
- #modal
22220
- trigger="open-modal"
22221
- [initialBreakpoint]="1"
22222
- [breakpoints]="[0, 0.5, 0.75, 1]"
22223
- (didDismiss)="resetState()"
22224
- >
22211
+ <ion-modal #modal [initialBreakpoint]="1" [breakpoints]="[0, 0.5, 0.75, 1]" (didDismiss)="resetState()">
22225
22212
  <ng-template>
22226
22213
  <ion-header>
22227
22214
  <ion-toolbar>
@@ -22237,12 +22224,7 @@ class MultiSelectSearchComponent {
22237
22224
  <ion-content>
22238
22225
  <!-- Action buttons for multi-select -->
22239
22226
  <div class="actions-container" style="padding: 16px; border-bottom: 1px solid var(--ion-color-light-shade);">
22240
- <ion-button
22241
- fill="clear"
22242
- size="small"
22243
- (click)="selectAll()"
22244
- [disabled]="filteredItems.length === 0"
22245
- >
22227
+ <ion-button fill="clear" size="small" (click)="selectAll()" [disabled]="filteredItems.length === 0">
22246
22228
  {{ getSelectAllText() }}
22247
22229
  </ion-button>
22248
22230
  <ion-button
@@ -22258,10 +22240,7 @@ class MultiSelectSearchComponent {
22258
22240
 
22259
22241
  <ion-list>
22260
22242
  <ion-item *ngFor="let item of filteredItems" button (click)="selectItem(item)" detail="false">
22261
- <ion-checkbox
22262
- slot="start"
22263
- [checked]="isItemSelected(item)"
22264
- ></ion-checkbox>
22243
+ <ion-checkbox slot="start" [checked]="isItemSelected(item)"></ion-checkbox>
22265
22244
  <ion-label>{{ item[labelProperty] }}</ion-label>
22266
22245
  </ion-item>
22267
22246
  <ion-item *ngIf="filteredItems.length === 0" lines="none">
@@ -22293,13 +22272,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22293
22272
 
22294
22273
  <ion-input style="position: absolute;" [formControl]="props.control" type="hidden"></ion-input>
22295
22274
 
22296
- <ion-modal
22297
- #modal
22298
- trigger="open-modal"
22299
- [initialBreakpoint]="1"
22300
- [breakpoints]="[0, 0.5, 0.75, 1]"
22301
- (didDismiss)="resetState()"
22302
- >
22275
+ <ion-modal #modal [initialBreakpoint]="1" [breakpoints]="[0, 0.5, 0.75, 1]" (didDismiss)="resetState()">
22303
22276
  <ng-template>
22304
22277
  <ion-header>
22305
22278
  <ion-toolbar>
@@ -22315,12 +22288,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22315
22288
  <ion-content>
22316
22289
  <!-- Action buttons for multi-select -->
22317
22290
  <div class="actions-container" style="padding: 16px; border-bottom: 1px solid var(--ion-color-light-shade);">
22318
- <ion-button
22319
- fill="clear"
22320
- size="small"
22321
- (click)="selectAll()"
22322
- [disabled]="filteredItems.length === 0"
22323
- >
22291
+ <ion-button fill="clear" size="small" (click)="selectAll()" [disabled]="filteredItems.length === 0">
22324
22292
  {{ getSelectAllText() }}
22325
22293
  </ion-button>
22326
22294
  <ion-button
@@ -22336,10 +22304,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22336
22304
 
22337
22305
  <ion-list>
22338
22306
  <ion-item *ngFor="let item of filteredItems" button (click)="selectItem(item)" detail="false">
22339
- <ion-checkbox
22340
- slot="start"
22341
- [checked]="isItemSelected(item)"
22342
- ></ion-checkbox>
22307
+ <ion-checkbox slot="start" [checked]="isItemSelected(item)"></ion-checkbox>
22343
22308
  <ion-label>{{ item[labelProperty] }}</ion-label>
22344
22309
  </ion-item>
22345
22310
  <ion-item *ngIf="filteredItems.length === 0" lines="none">
@@ -28205,6 +28170,158 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
28205
28170
  type: Output
28206
28171
  }] } });
28207
28172
 
28173
+ const DEFAULT_NAMESPACE$j = 'PermissionSelector';
28174
+ const PERMISSION_SELECTOR_I18N = {
28175
+ es: {
28176
+ selectAll: 'Todos',
28177
+ empty: 'No hay permisos disponibles para asignar.',
28178
+ },
28179
+ en: {
28180
+ selectAll: 'All',
28181
+ empty: 'No permissions available to assign.',
28182
+ },
28183
+ };
28184
+ /**
28185
+ * `val-permission-selector` — selector de permisos agrupado por recurso.
28186
+ *
28187
+ * Presentacional: recibe el catálogo (YA filtrado por el consumer — sin `internal`,
28188
+ * sin otras apps) y emite los códigos `resource:action` seleccionados. Agrupa por
28189
+ * recurso con su label legible (del backend), una fila por recurso con checkbox
28190
+ * "Todos" (tri-estado) y un chip por acción. Bilingüe vía `locale` + los labels del
28191
+ * catálogo; las pocas etiquetas propias (Todos / vacío) se auto-registran (es/en).
28192
+ *
28193
+ * Pensado para el modal de creación de API Key (asignar permisos a la key) y
28194
+ * reusable en cualquier UI que asigne permisos (roles custom, etc.).
28195
+ */
28196
+ class PermissionSelectorComponent {
28197
+ constructor() {
28198
+ this.i18n = inject(I18nService);
28199
+ /** Catálogo YA filtrado (sin internal, sin otras apps). */
28200
+ this.permissions = input([]);
28201
+ /** Labels de acción (es/en) por código de acción — del catálogo del backend. */
28202
+ this.actionLabels = input({});
28203
+ /** Idioma activo (es/en). Si no se pasa, usa el de `I18nService`. */
28204
+ this.locale = input('');
28205
+ /** Permisos seleccionados (`resource:action`). Two-way (`model`). */
28206
+ this.selected = model([]);
28207
+ this.activeLocale = computed(() => this.locale() || this.i18n.lang());
28208
+ this.groups = computed(() => {
28209
+ const sel = new Set(this.selected());
28210
+ const loc = this.activeLocale();
28211
+ const actionLabels = this.actionLabels();
28212
+ return this.permissions().map(r => {
28213
+ const actions = r.actions.map(a => {
28214
+ const code = `${r.resource}:${a}`;
28215
+ return { action: a, code, label: actionLabels[a]?.[loc] ?? a, checked: sel.has(code) };
28216
+ });
28217
+ const checkedCount = actions.filter(a => a.checked).length;
28218
+ return {
28219
+ resource: r.resource,
28220
+ label: r.label?.[loc] ?? r.resource,
28221
+ actions,
28222
+ checkedCount,
28223
+ all: actions.length > 0 && checkedCount === actions.length,
28224
+ some: checkedCount > 0 && checkedCount < actions.length,
28225
+ };
28226
+ });
28227
+ });
28228
+ if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$j)) {
28229
+ this.i18n.registerContent(DEFAULT_NAMESPACE$j, PERMISSION_SELECTOR_I18N);
28230
+ }
28231
+ }
28232
+ toggleAction(code) {
28233
+ const sel = new Set(this.selected());
28234
+ if (sel.has(code))
28235
+ sel.delete(code);
28236
+ else
28237
+ sel.add(code);
28238
+ this.selected.set([...sel]);
28239
+ }
28240
+ toggleGroup(resource) {
28241
+ const group = this.groups().find(g => g.resource === resource);
28242
+ if (!group)
28243
+ return;
28244
+ const sel = new Set(this.selected());
28245
+ if (group.all)
28246
+ group.actions.forEach(a => sel.delete(a.code));
28247
+ else
28248
+ group.actions.forEach(a => sel.add(a.code));
28249
+ this.selected.set([...sel]);
28250
+ }
28251
+ tt(key) {
28252
+ this.i18n.lang();
28253
+ return this.i18n.t(key, DEFAULT_NAMESPACE$j);
28254
+ }
28255
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28256
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PermissionSelectorComponent, isStandalone: true, selector: "val-permission-selector", inputs: { permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: false, transformFunction: null }, actionLabels: { classPropertyName: "actionLabels", publicName: "actionLabels", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange" }, ngImport: i0, template: `
28257
+ @if (groups().length === 0) {
28258
+ <val-text [props]="{ content: tt('empty'), size: 'medium', color: 'medium', bold: false }" />
28259
+ } @else {
28260
+ <div class="perm-selector">
28261
+ @for (g of groups(); track g.resource) {
28262
+ <div class="perm-group" [class.perm-group--active]="g.checkedCount > 0">
28263
+ <div class="perm-group__head">
28264
+ <label class="perm-group__all">
28265
+ <input type="checkbox" [checked]="g.all" [indeterminate]="g.some" (change)="toggleGroup(g.resource)" />
28266
+ <span class="perm-group__title">{{ g.label }}</span>
28267
+ </label>
28268
+ <span class="perm-group__count">{{ g.checkedCount }}/{{ g.actions.length }}</span>
28269
+ </div>
28270
+ <div class="perm-group__actions">
28271
+ @for (a of g.actions; track a.code) {
28272
+ <button
28273
+ type="button"
28274
+ class="perm-chip"
28275
+ [class.perm-chip--on]="a.checked"
28276
+ [attr.aria-pressed]="a.checked"
28277
+ (click)="toggleAction(a.code)"
28278
+ >
28279
+ {{ a.label }}
28280
+ </button>
28281
+ }
28282
+ </div>
28283
+ </div>
28284
+ }
28285
+ </div>
28286
+ }
28287
+ `, isInline: true, styles: [":host{display:block}.perm-selector{display:flex;flex-direction:column;gap:10px}.perm-group{border:1.5px solid var(--ion-color-light, #e7e4ea);border-radius:12px;padding:12px 14px;transition:border-color .15s ease}.perm-group--active{border-color:var(--ion-color-primary, #7026df)}.perm-group__head{display:flex;align-items:center;justify-content:space-between;gap:8px}.perm-group__all{display:flex;align-items:center;gap:10px;cursor:pointer;font-weight:600;color:var(--ion-color-dark)}.perm-group__all input{width:18px;height:18px;accent-color:var(--ion-color-primary, #7026df);cursor:pointer}.perm-group__title{font-size:.95rem}.perm-group__count{font-size:.75rem;color:var(--ion-color-medium, #6b6675);flex-shrink:0}.perm-group__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}.perm-chip{appearance:none;border:1.5px solid var(--ion-color-medium, #6b6675);background:transparent;color:var(--ion-color-dark);border-radius:999px;padding:5px 14px;font-size:.8125rem;cursor:pointer;transition:background .15s ease,border-color .15s ease,color .15s ease}.perm-chip:hover{border-color:var(--ion-color-primary, #7026df)}.perm-chip--on{background:var(--ion-color-primary, #7026df);border-color:var(--ion-color-primary, #7026df);color:var(--ion-color-primary-contrast, #fff)}:host-context(body.dark) .perm-group,:host-context(html.ion-palette-dark) .perm-group{border-color:#ffffff1f}\n"], dependencies: [{ kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
28288
+ }
28289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionSelectorComponent, decorators: [{
28290
+ type: Component,
28291
+ args: [{ selector: 'val-permission-selector', standalone: true, imports: [TextComponent], template: `
28292
+ @if (groups().length === 0) {
28293
+ <val-text [props]="{ content: tt('empty'), size: 'medium', color: 'medium', bold: false }" />
28294
+ } @else {
28295
+ <div class="perm-selector">
28296
+ @for (g of groups(); track g.resource) {
28297
+ <div class="perm-group" [class.perm-group--active]="g.checkedCount > 0">
28298
+ <div class="perm-group__head">
28299
+ <label class="perm-group__all">
28300
+ <input type="checkbox" [checked]="g.all" [indeterminate]="g.some" (change)="toggleGroup(g.resource)" />
28301
+ <span class="perm-group__title">{{ g.label }}</span>
28302
+ </label>
28303
+ <span class="perm-group__count">{{ g.checkedCount }}/{{ g.actions.length }}</span>
28304
+ </div>
28305
+ <div class="perm-group__actions">
28306
+ @for (a of g.actions; track a.code) {
28307
+ <button
28308
+ type="button"
28309
+ class="perm-chip"
28310
+ [class.perm-chip--on]="a.checked"
28311
+ [attr.aria-pressed]="a.checked"
28312
+ (click)="toggleAction(a.code)"
28313
+ >
28314
+ {{ a.label }}
28315
+ </button>
28316
+ }
28317
+ </div>
28318
+ </div>
28319
+ }
28320
+ </div>
28321
+ }
28322
+ `, styles: [":host{display:block}.perm-selector{display:flex;flex-direction:column;gap:10px}.perm-group{border:1.5px solid var(--ion-color-light, #e7e4ea);border-radius:12px;padding:12px 14px;transition:border-color .15s ease}.perm-group--active{border-color:var(--ion-color-primary, #7026df)}.perm-group__head{display:flex;align-items:center;justify-content:space-between;gap:8px}.perm-group__all{display:flex;align-items:center;gap:10px;cursor:pointer;font-weight:600;color:var(--ion-color-dark)}.perm-group__all input{width:18px;height:18px;accent-color:var(--ion-color-primary, #7026df);cursor:pointer}.perm-group__title{font-size:.95rem}.perm-group__count{font-size:.75rem;color:var(--ion-color-medium, #6b6675);flex-shrink:0}.perm-group__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}.perm-chip{appearance:none;border:1.5px solid var(--ion-color-medium, #6b6675);background:transparent;color:var(--ion-color-dark);border-radius:999px;padding:5px 14px;font-size:.8125rem;cursor:pointer;transition:background .15s ease,border-color .15s ease,color .15s ease}.perm-chip:hover{border-color:var(--ion-color-primary, #7026df)}.perm-chip--on{background:var(--ion-color-primary, #7026df);border-color:var(--ion-color-primary, #7026df);color:var(--ion-color-primary-contrast, #fff)}:host-context(body.dark) .perm-group,:host-context(html.ion-palette-dark) .perm-group{border-color:#ffffff1f}\n"] }]
28323
+ }], ctorParameters: () => [] });
28324
+
28208
28325
  addIcons({ checkmarkCircle, closeCircle, alertCircle });
28209
28326
  /**
28210
28327
  * Username Input Component
@@ -47824,7 +47941,11 @@ class InviteMemberModalComponent {
47824
47941
  return [];
47825
47942
  }
47826
47943
  const cleanQ = (q.startsWith('@') ? q.slice(1) : q).toLowerCase();
47827
- const q$ = query$1(collection(this.firestore, 'profiles'), orderBy('handle'), startAt(cleanQ), endAt(cleanQ + ''), limit(8));
47944
+ // Prefijo: el sentinel alto `` cierra el rango (antes `cleanQ + ''`
47945
+ // era exact-match → solo encontraba el handle idéntico). NOTA: solo busca
47946
+ // por `handle`; la búsqueda por nombre requiere un campo normalizado en
47947
+ // /profiles (pendiente, ver TODO de búsqueda por nombre).
47948
+ const q$ = query$1(collection(this.firestore, 'profiles'), orderBy('handle'), startAt(cleanQ), endAt(cleanQ + '\uf8ff'), limit(8));
47828
47949
  return from(getDocs(q$)).pipe(map$1(snap => ({
47829
47950
  users: snap.docs.map(d => ({
47830
47951
  userId: d.id,
@@ -47837,10 +47958,7 @@ class InviteMemberModalComponent {
47837
47958
  next: res => {
47838
47959
  if (res && 'users' in res) {
47839
47960
  const currentUserId = this.auth.user()?.userId;
47840
- const excluded = new Set([
47841
- ...(currentUserId ? [currentUserId] : []),
47842
- ...this.existingMemberIds,
47843
- ]);
47961
+ const excluded = new Set([...(currentUserId ? [currentUserId] : []), ...this.existingMemberIds]);
47844
47962
  this.searchResults.set(res.users.filter(u => !excluded.has(u.userId)));
47845
47963
  }
47846
47964
  this.searching.set(false);
@@ -49340,6 +49458,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
49340
49458
  args: [VALTECH_AUTH_CONFIG]
49341
49459
  }] }, { type: i1$3.HttpClient }] });
49342
49460
 
49461
+ /**
49462
+ * Consume el catálogo de permisos del backend (`GET /org/{orgId}/permissions-catalog`).
49463
+ * El backend es la fuente de verdad de qué permisos existen y de su alcance
49464
+ * (globales de plataforma vs. propios de una app). La respuesta incluye el
49465
+ * `appId` del request para que la vista distinga la app actual.
49466
+ *
49467
+ * Promovido desde `showcase` a la lib bajo el proceso de ADR-021. Usa
49468
+ * `VALTECH_AUTH_CONFIG.apiUrl` (como `OrgService`) en vez del `environment` de la
49469
+ * app — la lib no importa el environment del consumer.
49470
+ */
49471
+ class PermissionCatalogService {
49472
+ constructor(config, http) {
49473
+ this.config = config;
49474
+ this.http = http;
49475
+ }
49476
+ getCatalog(orgId) {
49477
+ return this.http.get(`${this.config.apiUrl}/org/${orgId}/permissions-catalog`);
49478
+ }
49479
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1$3.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
49480
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, providedIn: 'root' }); }
49481
+ }
49482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, decorators: [{
49483
+ type: Injectable,
49484
+ args: [{ providedIn: 'root' }]
49485
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
49486
+ type: Inject,
49487
+ args: [VALTECH_AUTH_CONFIG]
49488
+ }] }, { type: i1$3.HttpClient }] });
49489
+
49343
49490
  /**
49344
49491
  * Defaults i18n (es/en) embebidos en `val-api-keys-modal` (ADR-023).
49345
49492
  * Auto-registrados si el consumer no proveyó el namespace `Settings.ApiKeysModal`.
@@ -49415,10 +49562,17 @@ class ApiKeysModalComponent {
49415
49562
  constructor() {
49416
49563
  this.i18n = inject(I18nService);
49417
49564
  this.apiKeys = inject(ApiKeyService);
49565
+ this.catalog = inject(PermissionCatalogService);
49566
+ this.auth = inject(AuthService);
49418
49567
  /** Namespace i18n. */
49419
49568
  this.i18nNamespace = DEFAULT_NAMESPACE$5;
49569
+ /** Permisos del catálogo YA filtrados (sin internal, sin otras apps). */
49570
+ this.catalogPermissions = signal([]);
49571
+ /** Labels de acción (es/en) del backend, para el selector. */
49572
+ this.actionLabels = signal({});
49573
+ /** Permisos seleccionados para la nueva key (`resource:action`). */
49574
+ this.selectedPerms = signal([]);
49420
49575
  this.keys = signal([]);
49421
- this.availablePermissions = signal([]);
49422
49576
  this.loading = signal(true);
49423
49577
  this.showCreate = signal(false);
49424
49578
  this.submitting = signal(false);
@@ -49446,24 +49600,6 @@ class ApiKeysModalComponent {
49446
49600
  value: '',
49447
49601
  state: ComponentStates.ENABLED,
49448
49602
  };
49449
- const permsField = {
49450
- token: 'apikey-perms',
49451
- name: 'permissions',
49452
- label: this.t('permissionsLabel'),
49453
- hint: '',
49454
- placeholder: '',
49455
- type: InputType.MULTI_SELECT,
49456
- order: 2,
49457
- validators: [Validators.required],
49458
- errors: { required: this.t('noPerms') },
49459
- value: '',
49460
- options: this.availablePermissions().map((p, i) => ({
49461
- id: p,
49462
- name: p,
49463
- order: i + 1,
49464
- })),
49465
- state: ComponentStates.ENABLED,
49466
- };
49467
49603
  const expiresField = {
49468
49604
  token: 'apikey-expires',
49469
49605
  name: 'expiresInDays',
@@ -49491,7 +49627,7 @@ class ApiKeysModalComponent {
49491
49627
  return {
49492
49628
  name: '',
49493
49629
  state: working ? ComponentStates.WORKING : ComponentStates.ENABLED,
49494
- sections: [{ name: '', order: 1, fields: [nameField, permsField, expiresField] }],
49630
+ sections: [{ name: '', order: 1, fields: [nameField, expiresField] }],
49495
49631
  actions: submitButton,
49496
49632
  };
49497
49633
  });
@@ -49504,11 +49640,34 @@ class ApiKeysModalComponent {
49504
49640
  this.i18n.registerContent(this.i18nNamespace, API_KEYS_MODAL_I18N);
49505
49641
  }
49506
49642
  this.refresh();
49507
- this.apiKeys.availablePermissions().subscribe({
49508
- next: perms => this.availablePermissions.set(perms),
49509
- error: () => { },
49643
+ this.loadCatalog();
49644
+ }
49645
+ /**
49646
+ * Carga el catálogo de permisos y lo filtra a lo asignable a una API Key de la
49647
+ * org: descarta `scope:internal` (el backend ya los omite para no-staff) y los
49648
+ * permisos de OTRAS apps (`appId !== appId del catálogo`). Quedan los permisos de
49649
+ * org (users/roles/rbac) + los de la app actual.
49650
+ */
49651
+ loadCatalog() {
49652
+ const orgId = this.activeOrgId();
49653
+ if (!orgId)
49654
+ return;
49655
+ this.catalog.getCatalog(orgId).subscribe({
49656
+ next: res => {
49657
+ const appId = res.appId;
49658
+ const filtered = (res.permissions ?? []).filter(p => p.scope !== 'internal' && (p.scope !== 'app' || p.appId === appId));
49659
+ this.catalogPermissions.set(filtered);
49660
+ this.actionLabels.set(res.actionLabels ?? {});
49661
+ },
49662
+ error: () => {
49663
+ // Sin catálogo: el selector queda vacío (el form valida ≥1 permiso).
49664
+ },
49510
49665
  });
49511
49666
  }
49667
+ activeOrgId() {
49668
+ const u = this.auth.user();
49669
+ return u?.activeOrgId ?? u?.activeOrg ?? '';
49670
+ }
49512
49671
  refresh() {
49513
49672
  this.loading.set(true);
49514
49673
  this.apiKeys.list().subscribe({
@@ -49521,6 +49680,7 @@ class ApiKeysModalComponent {
49521
49680
  }
49522
49681
  openCreate() {
49523
49682
  this.errorMsg.set('');
49683
+ this.selectedPerms.set([]);
49524
49684
  this.showCreate.set(true);
49525
49685
  }
49526
49686
  onCreateSubmit(event) {
@@ -49528,14 +49688,7 @@ class ApiKeysModalComponent {
49528
49688
  return;
49529
49689
  this.errorMsg.set('');
49530
49690
  const name = String(event.fields['name'] ?? '').trim();
49531
- // MULTI_SELECT puede devolver array o csv según el render — normalizamos.
49532
- const rawPerms = event.fields['permissions'];
49533
- const permissions = Array.isArray(rawPerms)
49534
- ? rawPerms
49535
- : String(rawPerms ?? '')
49536
- .split(',')
49537
- .map(s => s.trim())
49538
- .filter(Boolean);
49691
+ const permissions = this.selectedPerms();
49539
49692
  const expiresRaw = Number(event.fields['expiresInDays']);
49540
49693
  if (!name) {
49541
49694
  this.errorMsg.set(this.t('noName'));
@@ -49655,9 +49808,16 @@ class ApiKeysModalComponent {
49655
49808
  <p class="apikey-error">{{ errorMsg() }}</p>
49656
49809
  }
49657
49810
 
49658
- <!-- Crear — val-form (consistencia con el resto de modales del factory). -->
49811
+ <!-- Crear — val-form (nombre + expiración) + selector de permisos. -->
49659
49812
  @if (showCreate()) {
49660
49813
  <div class="apikey-create">
49814
+ <p class="apikey-create__label">{{ t('permissionsLabel') }} ({{ selectedPerms().length }})</p>
49815
+ <val-permission-selector
49816
+ [permissions]="catalogPermissions()"
49817
+ [actionLabels]="actionLabels()"
49818
+ [selected]="selectedPerms()"
49819
+ (selectedChange)="selectedPerms.set($event)"
49820
+ />
49661
49821
  <val-form [props]="createForm()" (onSubmit)="onCreateSubmit($event)" />
49662
49822
  <ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
49663
49823
  {{ t('cancel') }}
@@ -49673,7 +49833,7 @@ class ApiKeysModalComponent {
49673
49833
  }
49674
49834
  }
49675
49835
  </ion-content>
49676
- `, isInline: true, styles: ["val-display{display:block;margin-bottom:4px}val-title{display:block;margin-bottom:12px}.apikey-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}.apikey-row{display:flex;align-items:center;justify-content:space-between;padding:12px;border-radius:10px;border:1.5px solid var(--ion-color-light)}.apikey-row__main{display:flex;flex-direction:column}.apikey-row__name{font-weight:600;color:var(--ion-color-dark)}.apikey-row__meta{font-size:12px;color:var(--ion-color-medium-shade, #6b6e76)}.apikey-create{margin-top:8px;padding:16px;border-radius:12px;background:var(--ion-color-light)}.apikey-create__label{margin:12px 0 4px;font-size:13px;font-weight:600;color:var(--ion-color-dark)}.apikey-perms{display:flex;flex-direction:column;gap:6px;margin-bottom:12px;font-size:13px}.apikey-actions{margin-top:16px;display:flex;flex-direction:column;gap:8px}.apikey-error{margin:8px 0;font-size:.875rem;color:var(--ion-color-danger, #c0392b)}.apikey-secret__warn{font-size:.875rem;color:var(--ion-color-warning-shade, #b88600);margin:0 0 12px}.apikey-secret__box{padding:12px;border-radius:8px;background:var(--ion-color-dark);color:#fff;word-break:break-all;font-family:monospace;font-size:13px}\n"], dependencies: [{ kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
49836
+ `, isInline: true, styles: ["val-display{display:block;margin-bottom:4px}val-title{display:block;margin-bottom:12px}.apikey-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}.apikey-row{display:flex;align-items:center;justify-content:space-between;padding:12px;border-radius:10px;border:1.5px solid var(--ion-color-light)}.apikey-row__main{display:flex;flex-direction:column}.apikey-row__name{font-weight:600;color:var(--ion-color-dark)}.apikey-row__meta{font-size:12px;color:var(--ion-color-medium-shade, #6b6e76)}.apikey-create{margin-top:8px;padding:16px;border-radius:12px;background:var(--ion-color-light)}.apikey-create__label{margin:12px 0 4px;font-size:13px;font-weight:600;color:var(--ion-color-dark)}.apikey-perms{display:flex;flex-direction:column;gap:6px;margin-bottom:12px;font-size:13px}.apikey-actions{margin-top:16px;display:flex;flex-direction:column;gap:8px}.apikey-error{margin:8px 0;font-size:.875rem;color:var(--ion-color-danger, #c0392b)}.apikey-secret__warn{font-size:.875rem;color:var(--ion-color-warning-shade, #b88600);margin:0 0 12px}.apikey-secret__box{padding:12px;border-radius:8px;background:var(--ion-color-dark);color:#fff;word-break:break-all;font-family:monospace;font-size:13px}\n"], dependencies: [{ kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: PermissionSelectorComponent, selector: "val-permission-selector", inputs: ["permissions", "actionLabels", "locale", "selected"], outputs: ["selectedChange"] }] }); }
49677
49837
  }
49678
49838
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeysModalComponent, decorators: [{
49679
49839
  type: Component,
@@ -49688,6 +49848,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
49688
49848
  DisplayComponent,
49689
49849
  TextComponent,
49690
49850
  TitleComponent,
49851
+ PermissionSelectorComponent,
49691
49852
  ], template: `
49692
49853
  <ion-header>
49693
49854
  <ion-toolbar>
@@ -49750,9 +49911,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
49750
49911
  <p class="apikey-error">{{ errorMsg() }}</p>
49751
49912
  }
49752
49913
 
49753
- <!-- Crear — val-form (consistencia con el resto de modales del factory). -->
49914
+ <!-- Crear — val-form (nombre + expiración) + selector de permisos. -->
49754
49915
  @if (showCreate()) {
49755
49916
  <div class="apikey-create">
49917
+ <p class="apikey-create__label">{{ t('permissionsLabel') }} ({{ selectedPerms().length }})</p>
49918
+ <val-permission-selector
49919
+ [permissions]="catalogPermissions()"
49920
+ [actionLabels]="actionLabels()"
49921
+ [selected]="selectedPerms()"
49922
+ (selectedChange)="selectedPerms.set($event)"
49923
+ />
49756
49924
  <val-form [props]="createForm()" (onSubmit)="onCreateSubmit($event)" />
49757
49925
  <ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
49758
49926
  {{ t('cancel') }}
@@ -50499,9 +50667,22 @@ class OrganizationViewComponent {
50499
50667
  admin: 'roleAdmin',
50500
50668
  super_admin: 'roleSuperAdmin',
50501
50669
  };
50502
- const key = keyMap[name] ?? name;
50503
- const label = this.tt(key);
50504
- return label && !label.startsWith('[') ? label : name;
50670
+ // 1) Rol genérico conocido → label i18n. 2) displayName/descripción del backend.
50671
+ // 3) Fallback: humanizar el nombre crudo (ej. "bingo_admin" → "Bingo Admin")
50672
+ // para no mostrar el código técnico a app-specific roles.
50673
+ const mapped = keyMap[name];
50674
+ if (mapped) {
50675
+ const label = this.tt(mapped);
50676
+ if (label && !label.startsWith('['))
50677
+ return label;
50678
+ }
50679
+ if (found?.description)
50680
+ return found.description;
50681
+ return name
50682
+ .split(/[_-]/)
50683
+ .filter(Boolean)
50684
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
50685
+ .join(' ');
50505
50686
  }
50506
50687
  permissionLabel(perm) {
50507
50688
  if (perm === '*:*')
@@ -51920,35 +52101,6 @@ function provideValtechNotificationPreferencesRoutes(opts) {
51920
52101
  ];
51921
52102
  }
51922
52103
 
51923
- /**
51924
- * Consume el catálogo de permisos del backend (`GET /org/{orgId}/permissions-catalog`).
51925
- * El backend es la fuente de verdad de qué permisos existen y de su alcance
51926
- * (globales de plataforma vs. propios de una app). La respuesta incluye el
51927
- * `appId` del request para que la vista distinga la app actual.
51928
- *
51929
- * Promovido desde `showcase` a la lib bajo el proceso de ADR-021. Usa
51930
- * `VALTECH_AUTH_CONFIG.apiUrl` (como `OrgService`) en vez del `environment` de la
51931
- * app — la lib no importa el environment del consumer.
51932
- */
51933
- class PermissionCatalogService {
51934
- constructor(config, http) {
51935
- this.config = config;
51936
- this.http = http;
51937
- }
51938
- getCatalog(orgId) {
51939
- return this.http.get(`${this.config.apiUrl}/org/${orgId}/permissions-catalog`);
51940
- }
51941
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1$3.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
51942
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, providedIn: 'root' }); }
51943
- }
51944
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, decorators: [{
51945
- type: Injectable,
51946
- args: [{ providedIn: 'root' }]
51947
- }], ctorParameters: () => [{ type: undefined, decorators: [{
51948
- type: Inject,
51949
- args: [VALTECH_AUTH_CONFIG]
51950
- }] }, { type: i1$3.HttpClient }] });
51951
-
51952
52104
  /**
51953
52105
  * Defaults i18n (es/en) embebidos en `val-permissions-view`. Auto-registrados en
51954
52106
  * el constructor del componente si el consumer no proveyó el namespace
@@ -64421,5 +64573,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
64421
64573
  * Generated bundle index. Do not edit.
64422
64574
  */
64423
64575
 
64424
- export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyService, ApiKeysModalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CONTENT_CARD_DEFAULTS, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentCardComponent, ContentLoaderComponent, ContentReactionComponent, ContentService, ContentTransformer, CookieBannerComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
64576
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyService, ApiKeysModalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CONTENT_CARD_DEFAULTS, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentCardComponent, ContentLoaderComponent, ContentReactionComponent, ContentService, ContentTransformer, CookieBannerComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionSelectorComponent, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
64425
64577
  //# sourceMappingURL=valtech-components.mjs.map