valtech-components 2.0.1016 → 2.0.1018

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.1018';
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,203 @@ 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: 'Todo',
28177
+ clearAll: 'Ninguno',
28178
+ empty: 'No hay permisos disponibles para asignar.',
28179
+ },
28180
+ en: {
28181
+ selectAll: 'All',
28182
+ clearAll: 'None',
28183
+ empty: 'No permissions available to assign.',
28184
+ },
28185
+ };
28186
+ /**
28187
+ * `val-permission-selector` — selector de permisos agrupado por recurso.
28188
+ *
28189
+ * Presentacional: recibe el catálogo (YA filtrado por el consumer — sin `internal`,
28190
+ * sin otras apps) y emite los códigos `resource:action` seleccionados. Agrupa por
28191
+ * recurso con su label legible (del backend), una fila por recurso con checkbox
28192
+ * "Todos" (tri-estado) y un chip por acción. Bilingüe vía `locale` + los labels del
28193
+ * catálogo; las pocas etiquetas propias (Todos / vacío) se auto-registran (es/en).
28194
+ *
28195
+ * Pensado para el modal de creación de API Key (asignar permisos a la key) y
28196
+ * reusable en cualquier UI que asigne permisos (roles custom, etc.).
28197
+ */
28198
+ class PermissionSelectorComponent {
28199
+ constructor() {
28200
+ this.i18n = inject(I18nService);
28201
+ /** Catálogo YA filtrado (sin internal, sin otras apps). */
28202
+ this.permissions = input([]);
28203
+ /** Labels de acción (es/en) por código de acción — del catálogo del backend. */
28204
+ this.actionLabels = input({});
28205
+ /** Idioma activo (es/en). Si no se pasa, usa el de `I18nService`. */
28206
+ this.locale = input('');
28207
+ /** Título opcional de la barra superior (con contador + toggle "Todo"). */
28208
+ this.header = input('');
28209
+ /** Permisos seleccionados (`resource:action`). Two-way (`model`). */
28210
+ this.selected = model([]);
28211
+ /** Todos los códigos seleccionables (`resource:action`) del catálogo actual. */
28212
+ this.allCodes = computed(() => this.permissions().flatMap(r => r.actions.map(a => `${r.resource}:${a}`)));
28213
+ this.selectedCount = computed(() => this.selected().length);
28214
+ this.allSelected = computed(() => {
28215
+ const all = this.allCodes();
28216
+ if (all.length === 0)
28217
+ return false;
28218
+ const sel = new Set(this.selected());
28219
+ return all.every(c => sel.has(c));
28220
+ });
28221
+ this.activeLocale = computed(() => this.locale() || this.i18n.lang());
28222
+ this.groups = computed(() => {
28223
+ const sel = new Set(this.selected());
28224
+ const loc = this.activeLocale();
28225
+ const actionLabels = this.actionLabels();
28226
+ return this.permissions().map(r => {
28227
+ const actions = r.actions.map(a => {
28228
+ const code = `${r.resource}:${a}`;
28229
+ return { action: a, code, label: actionLabels[a]?.[loc] ?? a, checked: sel.has(code) };
28230
+ });
28231
+ const checkedCount = actions.filter(a => a.checked).length;
28232
+ return {
28233
+ resource: r.resource,
28234
+ label: r.label?.[loc] ?? r.resource,
28235
+ actions,
28236
+ checkedCount,
28237
+ all: actions.length > 0 && checkedCount === actions.length,
28238
+ some: checkedCount > 0 && checkedCount < actions.length,
28239
+ };
28240
+ });
28241
+ });
28242
+ if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$j)) {
28243
+ this.i18n.registerContent(DEFAULT_NAMESPACE$j, PERMISSION_SELECTOR_I18N);
28244
+ }
28245
+ }
28246
+ toggleAction(code) {
28247
+ const sel = new Set(this.selected());
28248
+ if (sel.has(code))
28249
+ sel.delete(code);
28250
+ else
28251
+ sel.add(code);
28252
+ this.selected.set([...sel]);
28253
+ }
28254
+ toggleAll() {
28255
+ this.selected.set(this.allSelected() ? [] : [...this.allCodes()]);
28256
+ }
28257
+ toggleGroup(resource) {
28258
+ const group = this.groups().find(g => g.resource === resource);
28259
+ if (!group)
28260
+ return;
28261
+ const sel = new Set(this.selected());
28262
+ if (group.all)
28263
+ group.actions.forEach(a => sel.delete(a.code));
28264
+ else
28265
+ group.actions.forEach(a => sel.add(a.code));
28266
+ this.selected.set([...sel]);
28267
+ }
28268
+ tt(key) {
28269
+ this.i18n.lang();
28270
+ return this.i18n.t(key, DEFAULT_NAMESPACE$j);
28271
+ }
28272
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28273
+ 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 }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange" }, ngImport: i0, template: `
28274
+ @if (header() || allCodes().length > 0) {
28275
+ <div class="perm-selector__bar">
28276
+ @if (header()) {
28277
+ <span class="perm-selector__title">{{ header() }} ({{ selectedCount() }})</span>
28278
+ } @else {
28279
+ <span></span>
28280
+ }
28281
+ @if (allCodes().length > 0) {
28282
+ <button type="button" class="perm-selector__toggle" (click)="toggleAll()">
28283
+ {{ allSelected() ? tt('clearAll') : tt('selectAll') }}
28284
+ </button>
28285
+ }
28286
+ </div>
28287
+ }
28288
+ @if (groups().length === 0) {
28289
+ <val-text [props]="{ content: tt('empty'), size: 'medium', color: 'medium', bold: false }" />
28290
+ } @else {
28291
+ <div class="perm-selector">
28292
+ @for (g of groups(); track g.resource) {
28293
+ <div class="perm-group" [class.perm-group--active]="g.checkedCount > 0">
28294
+ <div class="perm-group__head">
28295
+ <label class="perm-group__all">
28296
+ <input type="checkbox" [checked]="g.all" [indeterminate]="g.some" (change)="toggleGroup(g.resource)" />
28297
+ <span class="perm-group__title">{{ g.label }}</span>
28298
+ </label>
28299
+ <span class="perm-group__count">{{ g.checkedCount }}/{{ g.actions.length }}</span>
28300
+ </div>
28301
+ <div class="perm-group__actions">
28302
+ @for (a of g.actions; track a.code) {
28303
+ <button
28304
+ type="button"
28305
+ class="perm-chip"
28306
+ [class.perm-chip--on]="a.checked"
28307
+ [attr.aria-pressed]="a.checked"
28308
+ (click)="toggleAction(a.code)"
28309
+ >
28310
+ {{ a.label }}
28311
+ </button>
28312
+ }
28313
+ </div>
28314
+ </div>
28315
+ }
28316
+ </div>
28317
+ }
28318
+ `, isInline: true, styles: [":host{display:block}.perm-selector__bar{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}.perm-selector__title{font-size:.8125rem;font-weight:600;color:var(--ion-color-dark)}.perm-selector__toggle{appearance:none;background:transparent;border:none;padding:4px 2px;font-size:.8125rem;font-weight:600;color:var(--ion-color-secondary-shade, var(--ion-color-secondary));cursor:pointer}.perm-selector__toggle:hover{text-decoration:underline}.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-secondary, #c090ff)}.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-secondary, #c090ff);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-secondary, #c090ff)}.perm-chip--on{background:var(--ion-color-secondary, #c090ff);border-color:var(--ion-color-secondary, #c090ff);color:var(--ion-color-secondary-contrast, #2f2a36)}: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"] }] }); }
28319
+ }
28320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionSelectorComponent, decorators: [{
28321
+ type: Component,
28322
+ args: [{ selector: 'val-permission-selector', standalone: true, imports: [TextComponent], template: `
28323
+ @if (header() || allCodes().length > 0) {
28324
+ <div class="perm-selector__bar">
28325
+ @if (header()) {
28326
+ <span class="perm-selector__title">{{ header() }} ({{ selectedCount() }})</span>
28327
+ } @else {
28328
+ <span></span>
28329
+ }
28330
+ @if (allCodes().length > 0) {
28331
+ <button type="button" class="perm-selector__toggle" (click)="toggleAll()">
28332
+ {{ allSelected() ? tt('clearAll') : tt('selectAll') }}
28333
+ </button>
28334
+ }
28335
+ </div>
28336
+ }
28337
+ @if (groups().length === 0) {
28338
+ <val-text [props]="{ content: tt('empty'), size: 'medium', color: 'medium', bold: false }" />
28339
+ } @else {
28340
+ <div class="perm-selector">
28341
+ @for (g of groups(); track g.resource) {
28342
+ <div class="perm-group" [class.perm-group--active]="g.checkedCount > 0">
28343
+ <div class="perm-group__head">
28344
+ <label class="perm-group__all">
28345
+ <input type="checkbox" [checked]="g.all" [indeterminate]="g.some" (change)="toggleGroup(g.resource)" />
28346
+ <span class="perm-group__title">{{ g.label }}</span>
28347
+ </label>
28348
+ <span class="perm-group__count">{{ g.checkedCount }}/{{ g.actions.length }}</span>
28349
+ </div>
28350
+ <div class="perm-group__actions">
28351
+ @for (a of g.actions; track a.code) {
28352
+ <button
28353
+ type="button"
28354
+ class="perm-chip"
28355
+ [class.perm-chip--on]="a.checked"
28356
+ [attr.aria-pressed]="a.checked"
28357
+ (click)="toggleAction(a.code)"
28358
+ >
28359
+ {{ a.label }}
28360
+ </button>
28361
+ }
28362
+ </div>
28363
+ </div>
28364
+ }
28365
+ </div>
28366
+ }
28367
+ `, styles: [":host{display:block}.perm-selector__bar{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}.perm-selector__title{font-size:.8125rem;font-weight:600;color:var(--ion-color-dark)}.perm-selector__toggle{appearance:none;background:transparent;border:none;padding:4px 2px;font-size:.8125rem;font-weight:600;color:var(--ion-color-secondary-shade, var(--ion-color-secondary));cursor:pointer}.perm-selector__toggle:hover{text-decoration:underline}.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-secondary, #c090ff)}.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-secondary, #c090ff);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-secondary, #c090ff)}.perm-chip--on{background:var(--ion-color-secondary, #c090ff);border-color:var(--ion-color-secondary, #c090ff);color:var(--ion-color-secondary-contrast, #2f2a36)}:host-context(body.dark) .perm-group,:host-context(html.ion-palette-dark) .perm-group{border-color:#ffffff1f}\n"] }]
28368
+ }], ctorParameters: () => [] });
28369
+
28208
28370
  addIcons({ checkmarkCircle, closeCircle, alertCircle });
28209
28371
  /**
28210
28372
  * Username Input Component
@@ -46220,7 +46382,7 @@ class OrgInfoSheetComponent {
46220
46382
  <val-button [props]="resolvedCloseProps()" (click)="dismiss()" />
46221
46383
  </div>
46222
46384
  </ion-content>
46223
- `, isInline: true, styles: ["ion-content{--padding-bottom: 32px}val-display{margin-bottom:4px;display:block}val-title{margin-bottom:8px;display:block}.info-features{display:flex;flex-direction:column;gap:12px;margin:16px 0}.info-feature{display:flex;align-items:flex-start;gap:14px;padding:12px 14px;border-radius:10px;background:var(--ion-color-light, #f4f5f8)}:host-context(body.dark) .info-feature,:host-context(html.ion-palette-dark) .info-feature,:host-context([data-theme=\"dark\"]) .info-feature{background:#ffffff0d}.info-feature__icon{font-size:22px;color:var(--ion-color-primary);flex-shrink:0;margin-top:2px}.info-feature__title{font-weight:600;font-size:.9rem;color:var(--ion-color-dark)}.info-feature__desc{font-size:.82rem;color:var(--ion-color-medium);margin-top:2px}.sheet-footer{margin-top:20px}\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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { 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"] }] }); }
46385
+ `, isInline: true, styles: ["ion-content{--padding-bottom: 64px}val-display{margin-bottom:4px;display:block}val-title{margin-bottom:8px;display:block}.info-features{display:flex;flex-direction:column;gap:12px;margin:16px 0}.info-feature{display:flex;align-items:flex-start;gap:14px;padding:12px 14px;border-radius:10px;background:var(--ion-color-light, #f4f5f8)}:host-context(body.dark) .info-feature,:host-context(html.ion-palette-dark) .info-feature,:host-context([data-theme=\"dark\"]) .info-feature{background:#ffffff0d}.info-feature__icon{font-size:22px;color:var(--ion-color-primary);flex-shrink:0;margin-top:2px}.info-feature__title{font-weight:600;font-size:.9rem;color:var(--ion-color-dark)}.info-feature__desc{font-size:.82rem;color:var(--ion-color-medium);margin-top:2px}.sheet-footer{margin-top:20px}\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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { 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"] }] }); }
46224
46386
  }
46225
46387
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgInfoSheetComponent, decorators: [{
46226
46388
  type: Component,
@@ -46291,7 +46453,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
46291
46453
  <val-button [props]="resolvedCloseProps()" (click)="dismiss()" />
46292
46454
  </div>
46293
46455
  </ion-content>
46294
- `, styles: ["ion-content{--padding-bottom: 32px}val-display{margin-bottom:4px;display:block}val-title{margin-bottom:8px;display:block}.info-features{display:flex;flex-direction:column;gap:12px;margin:16px 0}.info-feature{display:flex;align-items:flex-start;gap:14px;padding:12px 14px;border-radius:10px;background:var(--ion-color-light, #f4f5f8)}:host-context(body.dark) .info-feature,:host-context(html.ion-palette-dark) .info-feature,:host-context([data-theme=\"dark\"]) .info-feature{background:#ffffff0d}.info-feature__icon{font-size:22px;color:var(--ion-color-primary);flex-shrink:0;margin-top:2px}.info-feature__title{font-weight:600;font-size:.9rem;color:var(--ion-color-dark)}.info-feature__desc{font-size:.82rem;color:var(--ion-color-medium);margin-top:2px}.sheet-footer{margin-top:20px}\n"] }]
46456
+ `, styles: ["ion-content{--padding-bottom: 64px}val-display{margin-bottom:4px;display:block}val-title{margin-bottom:8px;display:block}.info-features{display:flex;flex-direction:column;gap:12px;margin:16px 0}.info-feature{display:flex;align-items:flex-start;gap:14px;padding:12px 14px;border-radius:10px;background:var(--ion-color-light, #f4f5f8)}:host-context(body.dark) .info-feature,:host-context(html.ion-palette-dark) .info-feature,:host-context([data-theme=\"dark\"]) .info-feature{background:#ffffff0d}.info-feature__icon{font-size:22px;color:var(--ion-color-primary);flex-shrink:0;margin-top:2px}.info-feature__title{font-weight:600;font-size:.9rem;color:var(--ion-color-dark)}.info-feature__desc{font-size:.82rem;color:var(--ion-color-medium);margin-top:2px}.sheet-footer{margin-top:20px}\n"] }]
46295
46457
  }], ctorParameters: () => [], propDecorators: { title: [{
46296
46458
  type: Input
46297
46459
  }], subtitle: [{
@@ -47824,7 +47986,11 @@ class InviteMemberModalComponent {
47824
47986
  return [];
47825
47987
  }
47826
47988
  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));
47989
+ // Prefijo: el sentinel alto `` cierra el rango (antes `cleanQ + ''`
47990
+ // era exact-match → solo encontraba el handle idéntico). NOTA: solo busca
47991
+ // por `handle`; la búsqueda por nombre requiere un campo normalizado en
47992
+ // /profiles (pendiente, ver TODO de búsqueda por nombre).
47993
+ const q$ = query$1(collection(this.firestore, 'profiles'), orderBy('handle'), startAt(cleanQ), endAt(cleanQ + '\uf8ff'), limit(8));
47828
47994
  return from(getDocs(q$)).pipe(map$1(snap => ({
47829
47995
  users: snap.docs.map(d => ({
47830
47996
  userId: d.id,
@@ -47837,10 +48003,7 @@ class InviteMemberModalComponent {
47837
48003
  next: res => {
47838
48004
  if (res && 'users' in res) {
47839
48005
  const currentUserId = this.auth.user()?.userId;
47840
- const excluded = new Set([
47841
- ...(currentUserId ? [currentUserId] : []),
47842
- ...this.existingMemberIds,
47843
- ]);
48006
+ const excluded = new Set([...(currentUserId ? [currentUserId] : []), ...this.existingMemberIds]);
47844
48007
  this.searchResults.set(res.users.filter(u => !excluded.has(u.userId)));
47845
48008
  }
47846
48009
  this.searching.set(false);
@@ -49340,6 +49503,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
49340
49503
  args: [VALTECH_AUTH_CONFIG]
49341
49504
  }] }, { type: i1$3.HttpClient }] });
49342
49505
 
49506
+ /**
49507
+ * Consume el catálogo de permisos del backend (`GET /org/{orgId}/permissions-catalog`).
49508
+ * El backend es la fuente de verdad de qué permisos existen y de su alcance
49509
+ * (globales de plataforma vs. propios de una app). La respuesta incluye el
49510
+ * `appId` del request para que la vista distinga la app actual.
49511
+ *
49512
+ * Promovido desde `showcase` a la lib bajo el proceso de ADR-021. Usa
49513
+ * `VALTECH_AUTH_CONFIG.apiUrl` (como `OrgService`) en vez del `environment` de la
49514
+ * app — la lib no importa el environment del consumer.
49515
+ */
49516
+ class PermissionCatalogService {
49517
+ constructor(config, http) {
49518
+ this.config = config;
49519
+ this.http = http;
49520
+ }
49521
+ getCatalog(orgId) {
49522
+ return this.http.get(`${this.config.apiUrl}/org/${orgId}/permissions-catalog`);
49523
+ }
49524
+ 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 }); }
49525
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, providedIn: 'root' }); }
49526
+ }
49527
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PermissionCatalogService, decorators: [{
49528
+ type: Injectable,
49529
+ args: [{ providedIn: 'root' }]
49530
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
49531
+ type: Inject,
49532
+ args: [VALTECH_AUTH_CONFIG]
49533
+ }] }, { type: i1$3.HttpClient }] });
49534
+
49343
49535
  /**
49344
49536
  * Defaults i18n (es/en) embebidos en `val-api-keys-modal` (ADR-023).
49345
49537
  * Auto-registrados si el consumer no proveyó el namespace `Settings.ApiKeysModal`.
@@ -49415,10 +49607,17 @@ class ApiKeysModalComponent {
49415
49607
  constructor() {
49416
49608
  this.i18n = inject(I18nService);
49417
49609
  this.apiKeys = inject(ApiKeyService);
49610
+ this.catalog = inject(PermissionCatalogService);
49611
+ this.auth = inject(AuthService);
49418
49612
  /** Namespace i18n. */
49419
49613
  this.i18nNamespace = DEFAULT_NAMESPACE$5;
49614
+ /** Permisos del catálogo YA filtrados (sin internal, sin otras apps). */
49615
+ this.catalogPermissions = signal([]);
49616
+ /** Labels de acción (es/en) del backend, para el selector. */
49617
+ this.actionLabels = signal({});
49618
+ /** Permisos seleccionados para la nueva key (`resource:action`). */
49619
+ this.selectedPerms = signal([]);
49420
49620
  this.keys = signal([]);
49421
- this.availablePermissions = signal([]);
49422
49621
  this.loading = signal(true);
49423
49622
  this.showCreate = signal(false);
49424
49623
  this.submitting = signal(false);
@@ -49446,24 +49645,6 @@ class ApiKeysModalComponent {
49446
49645
  value: '',
49447
49646
  state: ComponentStates.ENABLED,
49448
49647
  };
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
49648
  const expiresField = {
49468
49649
  token: 'apikey-expires',
49469
49650
  name: 'expiresInDays',
@@ -49491,7 +49672,7 @@ class ApiKeysModalComponent {
49491
49672
  return {
49492
49673
  name: '',
49493
49674
  state: working ? ComponentStates.WORKING : ComponentStates.ENABLED,
49494
- sections: [{ name: '', order: 1, fields: [nameField, permsField, expiresField] }],
49675
+ sections: [{ name: '', order: 1, fields: [nameField, expiresField] }],
49495
49676
  actions: submitButton,
49496
49677
  };
49497
49678
  });
@@ -49504,11 +49685,34 @@ class ApiKeysModalComponent {
49504
49685
  this.i18n.registerContent(this.i18nNamespace, API_KEYS_MODAL_I18N);
49505
49686
  }
49506
49687
  this.refresh();
49507
- this.apiKeys.availablePermissions().subscribe({
49508
- next: perms => this.availablePermissions.set(perms),
49509
- error: () => { },
49688
+ this.loadCatalog();
49689
+ }
49690
+ /**
49691
+ * Carga el catálogo de permisos y lo filtra a lo asignable a una API Key de la
49692
+ * org: descarta `scope:internal` (el backend ya los omite para no-staff) y los
49693
+ * permisos de OTRAS apps (`appId !== appId del catálogo`). Quedan los permisos de
49694
+ * org (users/roles/rbac) + los de la app actual.
49695
+ */
49696
+ loadCatalog() {
49697
+ const orgId = this.activeOrgId();
49698
+ if (!orgId)
49699
+ return;
49700
+ this.catalog.getCatalog(orgId).subscribe({
49701
+ next: res => {
49702
+ const appId = res.appId;
49703
+ const filtered = (res.permissions ?? []).filter(p => p.scope !== 'internal' && (p.scope !== 'app' || p.appId === appId));
49704
+ this.catalogPermissions.set(filtered);
49705
+ this.actionLabels.set(res.actionLabels ?? {});
49706
+ },
49707
+ error: () => {
49708
+ // Sin catálogo: el selector queda vacío (el form valida ≥1 permiso).
49709
+ },
49510
49710
  });
49511
49711
  }
49712
+ activeOrgId() {
49713
+ const u = this.auth.user();
49714
+ return u?.activeOrgId ?? u?.activeOrg ?? '';
49715
+ }
49512
49716
  refresh() {
49513
49717
  this.loading.set(true);
49514
49718
  this.apiKeys.list().subscribe({
@@ -49521,6 +49725,7 @@ class ApiKeysModalComponent {
49521
49725
  }
49522
49726
  openCreate() {
49523
49727
  this.errorMsg.set('');
49728
+ this.selectedPerms.set([]);
49524
49729
  this.showCreate.set(true);
49525
49730
  }
49526
49731
  onCreateSubmit(event) {
@@ -49528,14 +49733,7 @@ class ApiKeysModalComponent {
49528
49733
  return;
49529
49734
  this.errorMsg.set('');
49530
49735
  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);
49736
+ const permissions = this.selectedPerms();
49539
49737
  const expiresRaw = Number(event.fields['expiresInDays']);
49540
49738
  if (!name) {
49541
49739
  this.errorMsg.set(this.t('noName'));
@@ -49655,9 +49853,16 @@ class ApiKeysModalComponent {
49655
49853
  <p class="apikey-error">{{ errorMsg() }}</p>
49656
49854
  }
49657
49855
 
49658
- <!-- Crear — val-form (consistencia con el resto de modales del factory). -->
49856
+ <!-- Crear — val-form (nombre + expiración) + selector de permisos. -->
49659
49857
  @if (showCreate()) {
49660
49858
  <div class="apikey-create">
49859
+ <val-permission-selector
49860
+ [header]="t('permissionsLabel')"
49861
+ [permissions]="catalogPermissions()"
49862
+ [actionLabels]="actionLabels()"
49863
+ [selected]="selectedPerms()"
49864
+ (selectedChange)="selectedPerms.set($event)"
49865
+ />
49661
49866
  <val-form [props]="createForm()" (onSubmit)="onCreateSubmit($event)" />
49662
49867
  <ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
49663
49868
  {{ t('cancel') }}
@@ -49673,7 +49878,7 @@ class ApiKeysModalComponent {
49673
49878
  }
49674
49879
  }
49675
49880
  </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"] }] }); }
49881
+ `, isInline: true, styles: ["ion-content{--padding-bottom: 64px}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:4px 0 0}.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", "header", "selected"], outputs: ["selectedChange"] }] }); }
49677
49882
  }
49678
49883
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeysModalComponent, decorators: [{
49679
49884
  type: Component,
@@ -49688,6 +49893,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
49688
49893
  DisplayComponent,
49689
49894
  TextComponent,
49690
49895
  TitleComponent,
49896
+ PermissionSelectorComponent,
49691
49897
  ], template: `
49692
49898
  <ion-header>
49693
49899
  <ion-toolbar>
@@ -49750,9 +49956,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
49750
49956
  <p class="apikey-error">{{ errorMsg() }}</p>
49751
49957
  }
49752
49958
 
49753
- <!-- Crear — val-form (consistencia con el resto de modales del factory). -->
49959
+ <!-- Crear — val-form (nombre + expiración) + selector de permisos. -->
49754
49960
  @if (showCreate()) {
49755
49961
  <div class="apikey-create">
49962
+ <val-permission-selector
49963
+ [header]="t('permissionsLabel')"
49964
+ [permissions]="catalogPermissions()"
49965
+ [actionLabels]="actionLabels()"
49966
+ [selected]="selectedPerms()"
49967
+ (selectedChange)="selectedPerms.set($event)"
49968
+ />
49756
49969
  <val-form [props]="createForm()" (onSubmit)="onCreateSubmit($event)" />
49757
49970
  <ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
49758
49971
  {{ t('cancel') }}
@@ -49768,7 +49981,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
49768
49981
  }
49769
49982
  }
49770
49983
  </ion-content>
49771
- `, 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"] }]
49984
+ `, styles: ["ion-content{--padding-bottom: 64px}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:4px 0 0}.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"] }]
49772
49985
  }], ctorParameters: () => [], propDecorators: { _modalRef: [{
49773
49986
  type: Input
49774
49987
  }], i18nNamespace: [{
@@ -50195,7 +50408,7 @@ class OrganizationViewComponent {
50195
50408
  },
50196
50409
  },
50197
50410
  breakpoints: {
50198
- breakpoints: [0, 0.85],
50411
+ breakpoints: [0, 0.85, 1],
50199
50412
  initialBreakpoint: 0.85,
50200
50413
  showHandle: true,
50201
50414
  },
@@ -50281,7 +50494,7 @@ class OrganizationViewComponent {
50281
50494
  void this.modalService.open({
50282
50495
  component: ApiKeysModalComponent,
50283
50496
  breakpoints: {
50284
- breakpoints: [0, 0.92],
50497
+ breakpoints: [0, 0.92, 1],
50285
50498
  initialBreakpoint: 0.92,
50286
50499
  showHandle: true,
50287
50500
  },
@@ -50307,7 +50520,7 @@ class OrganizationViewComponent {
50307
50520
  type: 'button',
50308
50521
  },
50309
50522
  },
50310
- breakpoints: { breakpoints: [0, 0.85], initialBreakpoint: 0.85, showHandle: true },
50523
+ breakpoints: { breakpoints: [0, 0.85, 1], initialBreakpoint: 0.85, showHandle: true },
50311
50524
  backdropDismiss: true,
50312
50525
  });
50313
50526
  }
@@ -50332,7 +50545,7 @@ class OrganizationViewComponent {
50332
50545
  type: 'button',
50333
50546
  },
50334
50547
  },
50335
- breakpoints: { breakpoints: [0, 0.85], initialBreakpoint: 0.85, showHandle: true },
50548
+ breakpoints: { breakpoints: [0, 0.85, 1], initialBreakpoint: 0.85, showHandle: true },
50336
50549
  backdropDismiss: true,
50337
50550
  });
50338
50551
  }
@@ -50499,9 +50712,22 @@ class OrganizationViewComponent {
50499
50712
  admin: 'roleAdmin',
50500
50713
  super_admin: 'roleSuperAdmin',
50501
50714
  };
50502
- const key = keyMap[name] ?? name;
50503
- const label = this.tt(key);
50504
- return label && !label.startsWith('[') ? label : name;
50715
+ // 1) Rol genérico conocido → label i18n. 2) displayName/descripción del backend.
50716
+ // 3) Fallback: humanizar el nombre crudo (ej. "bingo_admin" → "Bingo Admin")
50717
+ // para no mostrar el código técnico a app-specific roles.
50718
+ const mapped = keyMap[name];
50719
+ if (mapped) {
50720
+ const label = this.tt(mapped);
50721
+ if (label && !label.startsWith('['))
50722
+ return label;
50723
+ }
50724
+ if (found?.description)
50725
+ return found.description;
50726
+ return name
50727
+ .split(/[_-]/)
50728
+ .filter(Boolean)
50729
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
50730
+ .join(' ');
50505
50731
  }
50506
50732
  permissionLabel(perm) {
50507
50733
  if (perm === '*:*')
@@ -51920,35 +52146,6 @@ function provideValtechNotificationPreferencesRoutes(opts) {
51920
52146
  ];
51921
52147
  }
51922
52148
 
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
52149
  /**
51953
52150
  * Defaults i18n (es/en) embebidos en `val-permissions-view`. Auto-registrados en
51954
52151
  * el constructor del componente si el consumer no proveyó el namespace
@@ -64421,5 +64618,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
64421
64618
  * Generated bundle index. Do not edit.
64422
64619
  */
64423
64620
 
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 };
64621
+ 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
64622
  //# sourceMappingURL=valtech-components.mjs.map