valtech-components 4.0.141 → 4.0.143

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.
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
56
56
  * Current version of valtech-components.
57
57
  * This is automatically updated during the publish process.
58
58
  */
59
- const VERSION = '4.0.141';
59
+ const VERSION = '4.0.143';
60
60
 
61
61
  // Control de estado de refresco (singleton a nivel de módulo)
62
62
  let isRefreshing = false;
@@ -30426,6 +30426,8 @@ class EmptyStateComponent {
30426
30426
  this.variantClass = computed(() => this.props().variant ?? 'empty');
30427
30427
  /** Icono final — custom si se pasó, default de la variante si no. */
30428
30428
  this.iconName = computed(() => this.props().icon ?? DEFAULT_ICON_BY_VARIANT[this.variantClass()]);
30429
+ /** Emoji opcional — si está, se renderiza en lugar del icono Ionicons. */
30430
+ this.emoji = computed(() => this.props().emoji);
30429
30431
  /** Tamaño en px. Default 64. */
30430
30432
  this.iconSize = computed(() => this.props().iconSize ?? 64);
30431
30433
  /**
@@ -30455,12 +30457,13 @@ class EmptyStateComponent {
30455
30457
  role="status"
30456
30458
  aria-live="polite"
30457
30459
  >
30458
- <ion-icon
30459
- class="empty-state__icon"
30460
- [name]="iconName()"
30461
- [style.font-size.px]="iconSize()"
30462
- aria-hidden="true"
30463
- />
30460
+ @if (emoji(); as e) {
30461
+ <div class="empty-state__emoji" [style.font-size.px]="iconSize()" aria-hidden="true">
30462
+ {{ e }}
30463
+ </div>
30464
+ } @else {
30465
+ <ion-icon class="empty-state__icon" [name]="iconName()" [style.font-size.px]="iconSize()" aria-hidden="true" />
30466
+ }
30464
30467
 
30465
30468
  <val-title
30466
30469
  [props]="{
@@ -30483,14 +30486,10 @@ class EmptyStateComponent {
30483
30486
  }
30484
30487
 
30485
30488
  @if (props().action; as a) {
30486
- <val-button
30487
- class="empty-state__cta"
30488
- [props]="ctaProps()"
30489
- (click)="a.handler()"
30490
- />
30489
+ <val-button class="empty-state__cta" [props]="ctaProps()" (click)="a.handler()" />
30491
30490
  }
30492
30491
  </section>
30493
- `, isInline: true, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;padding:32px 16px;min-height:240px}.empty-state__icon{color:var(--ion-color-medium)}.empty-state--error .empty-state__icon{color:var(--ion-color-warning, #ffb800)}.empty-state--offline .empty-state__icon{color:var(--ion-color-medium);opacity:.7}.empty-state__cta{margin-top:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
30492
+ `, isInline: true, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;padding:32px 16px;min-height:240px}.empty-state__icon{color:var(--ion-color-medium)}.empty-state__emoji{line-height:1}.empty-state--error .empty-state__icon{color:var(--ion-color-warning, #ffb800)}.empty-state--offline .empty-state__icon{color:var(--ion-color-medium);opacity:.7}.empty-state__cta{margin-top:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
30494
30493
  }
30495
30494
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, decorators: [{
30496
30495
  type: Component,
@@ -30502,12 +30501,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
30502
30501
  role="status"
30503
30502
  aria-live="polite"
30504
30503
  >
30505
- <ion-icon
30506
- class="empty-state__icon"
30507
- [name]="iconName()"
30508
- [style.font-size.px]="iconSize()"
30509
- aria-hidden="true"
30510
- />
30504
+ @if (emoji(); as e) {
30505
+ <div class="empty-state__emoji" [style.font-size.px]="iconSize()" aria-hidden="true">
30506
+ {{ e }}
30507
+ </div>
30508
+ } @else {
30509
+ <ion-icon class="empty-state__icon" [name]="iconName()" [style.font-size.px]="iconSize()" aria-hidden="true" />
30510
+ }
30511
30511
 
30512
30512
  <val-title
30513
30513
  [props]="{
@@ -30530,14 +30530,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
30530
30530
  }
30531
30531
 
30532
30532
  @if (props().action; as a) {
30533
- <val-button
30534
- class="empty-state__cta"
30535
- [props]="ctaProps()"
30536
- (click)="a.handler()"
30537
- />
30533
+ <val-button class="empty-state__cta" [props]="ctaProps()" (click)="a.handler()" />
30538
30534
  }
30539
30535
  </section>
30540
- `, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;padding:32px 16px;min-height:240px}.empty-state__icon{color:var(--ion-color-medium)}.empty-state--error .empty-state__icon{color:var(--ion-color-warning, #ffb800)}.empty-state--offline .empty-state__icon{color:var(--ion-color-medium);opacity:.7}.empty-state__cta{margin-top:8px}\n"] }]
30536
+ `, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;padding:32px 16px;min-height:240px}.empty-state__icon{color:var(--ion-color-medium)}.empty-state__emoji{line-height:1}.empty-state--error .empty-state__icon{color:var(--ion-color-warning, #ffb800)}.empty-state--offline .empty-state__icon{color:var(--ion-color-medium);opacity:.7}.empty-state__cta{margin-top:8px}\n"] }]
30541
30537
  }] });
30542
30538
 
30543
30539
  /**
@@ -30590,6 +30586,7 @@ function createErrorStateProps(err, opts) {
30590
30586
  title: pick(opts.title),
30591
30587
  description: opts.description ? pick(opts.description) : undefined,
30592
30588
  action,
30589
+ emoji: opts.emoji ? pick(opts.emoji) : undefined,
30593
30590
  };
30594
30591
  }
30595
30592
 
@@ -51469,6 +51466,66 @@ function createPermissionLabeler(catalog, locale, opts) {
51469
51466
  return `${res}: ${act}`;
51470
51467
  };
51471
51468
  }
51469
+ /**
51470
+ * Agrupa una lista de permisos (`resource:action`) por alcance — app actual /
51471
+ * organización / otras apps — usando el catálogo del backend como SSOT del scope
51472
+ * (`PermissionResource.scope` + `appId`). Cada permiso se etiqueta con `labeler`.
51473
+ *
51474
+ * Reutilizado por `val-permissions-view` y `val-member-detail-modal` para que
51475
+ * ambos muestren los chips agrupados y tintados de forma idéntica. Función pura
51476
+ * (sin Angular DI) — el consumer pasa los labels i18n ya resueltos.
51477
+ *
51478
+ * - Recursos ausentes del catálogo o con `scope === 'internal'` se descartan
51479
+ * (defensa en profundidad junto al filtro del backend, ADR-024).
51480
+ * - `scope === 'app'` con `appId === currentAppId` → grupo `app`; otro appId →
51481
+ * grupo `other:{appId}`. `scope === 'org'` → grupo `org`.
51482
+ */
51483
+ function groupPermissionsByScope(permissions, catalog, currentAppId, labeler, labels) {
51484
+ const byResource = new Map();
51485
+ for (const r of catalog.permissions ?? [])
51486
+ byResource.set(r.resource, r);
51487
+ const appPerms = [];
51488
+ const orgPerms = [];
51489
+ const otherByApp = new Map();
51490
+ for (const perm of permissions ?? []) {
51491
+ const [resource] = perm.split(':');
51492
+ const entry = byResource.get(resource);
51493
+ if (!entry || entry.scope === 'internal')
51494
+ continue;
51495
+ const label = labeler(perm);
51496
+ if (entry.scope === 'app') {
51497
+ if (entry.appId === currentAppId) {
51498
+ appPerms.push(label);
51499
+ }
51500
+ else {
51501
+ const appId = entry.appId ?? '?';
51502
+ const arr = otherByApp.get(appId) ?? [];
51503
+ arr.push(label);
51504
+ otherByApp.set(appId, arr);
51505
+ }
51506
+ }
51507
+ else {
51508
+ orgPerms.push(label);
51509
+ }
51510
+ }
51511
+ const groups = [];
51512
+ if (appPerms.length) {
51513
+ groups.push({ key: 'app', label: labels.app, scope: 'app', perms: appPerms });
51514
+ }
51515
+ if (orgPerms.length) {
51516
+ groups.push({ key: 'org', label: labels.org, scope: 'org', perms: orgPerms });
51517
+ }
51518
+ for (const [appId, perms] of otherByApp) {
51519
+ groups.push({
51520
+ key: `other:${appId}`,
51521
+ label: `${labels.other}: ${labels.appLabel(appId)}`,
51522
+ scope: 'other',
51523
+ appId,
51524
+ perms,
51525
+ });
51526
+ }
51527
+ return groups;
51528
+ }
51472
51529
 
51473
51530
  /**
51474
51531
  * Defaults i18n (es/en) embebidos en `val-member-detail-modal`. Auto-registrados
@@ -51496,6 +51553,12 @@ const MEMBER_DETAIL_MODAL_I18N = {
51496
51553
  removeSuccess: 'Miembro eliminado.',
51497
51554
  removeError: 'No se pudo eliminar al miembro.',
51498
51555
  permissionsTitle: 'Permisos del rol',
51556
+ // Grupos de alcance (mismas keys/valores que val-permissions-view)
51557
+ groupApp: 'Permisos de la app',
51558
+ groupOrg: 'Permisos de la organización',
51559
+ groupOther: 'Otras apps',
51560
+ app_showcase: 'Showcase',
51561
+ app_bingo: 'Bingo',
51499
51562
  permAll: 'Todo',
51500
51563
  permUsers: 'Usuarios',
51501
51564
  permDocuments: 'Documentos',
@@ -51549,6 +51612,11 @@ const MEMBER_DETAIL_MODAL_I18N = {
51549
51612
  removeSuccess: 'Member removed.',
51550
51613
  removeError: 'Could not remove member.',
51551
51614
  permissionsTitle: 'Role permissions',
51615
+ groupApp: 'App permissions',
51616
+ groupOrg: 'Organization permissions',
51617
+ groupOther: 'Other apps',
51618
+ app_showcase: 'Showcase',
51619
+ app_bingo: 'Bingo',
51552
51620
  permAll: 'All',
51553
51621
  permUsers: 'Users',
51554
51622
  permDocuments: 'Documents',
@@ -51611,6 +51679,16 @@ class MemberDetailModalComponent {
51611
51679
  this.catalog = inject(PermissionCatalogService);
51612
51680
  /** Labeler de permisos con la SSOT del backend (catálogo). Se llena al cargar. */
51613
51681
  this.permLabeler = signal(null);
51682
+ /** Catálogo del backend (define el alcance de cada recurso para agrupar). */
51683
+ this.catalogResp = signal(null);
51684
+ /**
51685
+ * `true` mientras el catálogo aún no llegó (y hay `orgId` para pedirlo, sin
51686
+ * error). Mientras tanto, la sección de permisos muestra skeleton — evita el
51687
+ * parpadeo inglés→español del fallback humanizado antes de tener los labels es.
51688
+ * Sin `orgId` el catálogo nunca se pide → `false` desde el arranque (se renderiza
51689
+ * con el fallback, sin skeleton infinito).
51690
+ */
51691
+ this.permsLoading = signal(false);
51614
51692
  /** Organización a la que pertenece el miembro. */
51615
51693
  this.orgId = '';
51616
51694
  /** Si true, habilita cambio de rol y eliminación. */
@@ -51642,6 +51720,31 @@ class MemberDetailModalComponent {
51642
51720
  const role = this.availableRoles.find(r => r.id === roleId || r.name === roleId);
51643
51721
  return role?.permissions ?? [];
51644
51722
  });
51723
+ /**
51724
+ * Permisos del rol actual agrupados por alcance (app actual / organización /
51725
+ * otras apps) con sus labels ya resueltos — mismo patrón que `val-permissions-view`.
51726
+ * Si el catálogo no cargó (sin `orgId` o falló), agrupa con un catálogo vacío:
51727
+ * sin scope no se pueden clasificar los recursos → cae a un único grupo `org`
51728
+ * con el labeler humanizado, manteniendo los chips visibles.
51729
+ */
51730
+ this.permissionGroups = computed(() => {
51731
+ this.i18n.lang();
51732
+ const perms = this.permissionsForCurrentRole();
51733
+ if (perms.length === 0)
51734
+ return [];
51735
+ const catalog = this.catalogResp();
51736
+ const labels = {
51737
+ app: this.t('groupApp'),
51738
+ org: this.t('groupOrg'),
51739
+ other: this.t('groupOther'),
51740
+ appLabel: (appId) => this.appLabel(appId),
51741
+ };
51742
+ if (catalog) {
51743
+ return groupPermissionsByScope(perms, catalog, catalog.appId, this.permissionLabel.bind(this), labels);
51744
+ }
51745
+ // Sin catálogo: no hay scope → un solo grupo "organización" con el fallback.
51746
+ return [{ key: 'org', label: labels.org, scope: 'org', perms: perms.map(p => this.permissionLabel(p)) }];
51747
+ });
51645
51748
  this.roleSelectProps = computed(() => ({
51646
51749
  control: this.roleControl,
51647
51750
  label: '',
@@ -51679,15 +51782,31 @@ class MemberDetailModalComponent {
51679
51782
  if (v && v !== this.currentRole())
51680
51783
  void this.onChangeRole(v);
51681
51784
  });
51682
- // Catálogo del backend = SSOT de los labels de permisos (ADR-024). Si falla,
51683
- // `permissionLabel` cae al fallback humanizado (no rompe el modal).
51785
+ // Catálogo del backend = SSOT de los labels de permisos + del alcance para
51786
+ // agrupar (ADR-024). Mientras carga mostramos skeleton (mata el parpadeo
51787
+ // inglés→español del fallback). Si falla, `permissionLabel` cae al fallback
51788
+ // humanizado (no rompe el modal). Sin `orgId` el catálogo nunca se pide →
51789
+ // permsLoading queda false (se renderiza con el fallback, sin skeleton infinito).
51684
51790
  if (this.orgId) {
51791
+ this.permsLoading.set(true);
51685
51792
  this.catalog.getCatalog(this.orgId).subscribe({
51686
- next: catalog => this.permLabeler.set(createPermissionLabeler(catalog, this.i18n.lang(), { allLabel: this.t('permAll') })),
51687
- error: () => { },
51793
+ next: catalog => {
51794
+ this.catalogResp.set(catalog);
51795
+ this.permLabeler.set(createPermissionLabeler(catalog, this.i18n.lang(), { allLabel: this.t('permAll') }));
51796
+ this.permsLoading.set(false);
51797
+ },
51798
+ error: () => {
51799
+ this.permsLoading.set(false);
51800
+ },
51688
51801
  });
51689
51802
  }
51690
51803
  }
51804
+ /** Resuelve el nombre legible de una app por su appId (key `app_{id}`). */
51805
+ appLabel(appId) {
51806
+ const key = `app_${appId}`;
51807
+ const label = this.t(key);
51808
+ return label === key ? appId : label;
51809
+ }
51691
51810
  permissionLabel(perm) {
51692
51811
  // SSOT = catálogo del backend. Hasta que cargue (o si falló), fallback a un
51693
51812
  // labeler vacío que humaniza el código crudo (evita salidas vacías como
@@ -51828,12 +51947,24 @@ class MemberDetailModalComponent {
51828
51947
  }
51829
51948
  </div>
51830
51949
 
51831
- @if (permissionsForCurrentRole().length > 0) {
51950
+ @if (permsLoading()) {
51832
51951
  <div class="perms-section">
51833
51952
  <span class="perms-label">{{ t('permissionsTitle') }}</span>
51834
- <div class="perms-list">
51835
- @for (perm of permissionsForCurrentRole(); track perm) {
51836
- <span class="perm-chip">{{ permissionLabel(perm) }}</span>
51953
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
51954
+ </div>
51955
+ } @else if (permissionsForCurrentRole().length > 0) {
51956
+ <div class="perms-section">
51957
+ <span class="perms-label">{{ t('permissionsTitle') }}</span>
51958
+ <div class="perm-groups">
51959
+ @for (g of permissionGroups(); track g.key) {
51960
+ <div [class]="'perm-group perm-group--' + g.scope">
51961
+ <span class="perm-group__badge">{{ g.label }}</span>
51962
+ <div class="perm-chips">
51963
+ @for (p of g.perms; track p) {
51964
+ <span class="perm-chip">{{ p }}</span>
51965
+ }
51966
+ </div>
51967
+ </div>
51837
51968
  }
51838
51969
  </div>
51839
51970
  </div>
@@ -51851,7 +51982,7 @@ class MemberDetailModalComponent {
51851
51982
  </ion-button>
51852
51983
  </div>
51853
51984
  </ion-content>
51854
- `, isInline: true, styles: ["ion-content{--padding-bottom: 24px}.member-head{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;margin-bottom:20px}val-display{display:block}val-title{display:block}.role-section{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.role-readonly-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.member-role-badge{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:4px 12px;border-radius:20px;width:fit-content;background:color-mix(in srgb,var(--ion-color-primary) 12%,transparent);color:var(--ion-color-primary)}.perms-section{display:flex;flex-direction:column;gap:10px;margin-bottom:24px}.perms-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.perms-list{display:flex;flex-wrap:wrap;gap:6px}.perm-chip{font-size:.75rem;font-weight:500;padding:3px 10px;border-radius:20px;border:1px solid var(--val-border-color, rgba(0, 0, 0, .12));color:var(--ion-color-dark);background:transparent}.remove-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08));padding-top:20px}.modal-close-bottom{margin-top:16px}\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: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: UserAvatarComponent, selector: "val-user-avatar", inputs: ["props"], outputs: ["onClick"] }] }); }
51985
+ `, isInline: true, styles: ["ion-content{--padding-bottom: 24px}.member-head{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;margin-bottom:20px}val-display{display:block}val-title{display:block}.role-section{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.role-readonly-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.member-role-badge{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:4px 12px;border-radius:20px;width:fit-content;background:color-mix(in srgb,var(--ion-color-primary) 12%,transparent);color:var(--ion-color-primary)}.perms-section{display:flex;flex-direction:column;gap:10px;margin-bottom:24px}.perms-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.perm-groups{display:flex;flex-direction:column;gap:12px}.perm-group{display:flex;flex-direction:column;gap:6px}.perm-group__badge{align-self:flex-start;display:inline-flex;align-items:center;gap:4px;font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:3px 9px;border-radius:6px}.perm-group--app .perm-group__badge{color:var(--ion-color-primary);background:rgba(var(--ion-color-primary-rgb),.12)}.perm-group--org .perm-group__badge{color:var(--ion-color-medium-shade, var(--ion-color-medium));background:var(--ion-color-light-shade, rgba(0, 0, 0, .06))}.perm-group--other .perm-group__badge{color:var(--ion-color-tertiary);background:rgba(var(--ion-color-tertiary-rgb),.12)}.perm-chips{display:flex;flex-wrap:wrap;gap:6px}.perm-chip{font-size:.75rem;padding:3px 10px;border-radius:20px;background:var(--ion-color-light);color:var(--ion-color-dark)}.perm-group--app .perm-chip{background:rgba(var(--ion-color-primary-rgb),.08)}.perm-group--other .perm-chip{background:rgba(var(--ion-color-tertiary-rgb),.08)}.remove-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08));padding-top:20px}.modal-close-bottom{margin-top:16px}\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: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: UserAvatarComponent, selector: "val-user-avatar", inputs: ["props"], outputs: ["onClick"] }] }); }
51855
51986
  }
51856
51987
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MemberDetailModalComponent, decorators: [{
51857
51988
  type: Component,
@@ -51865,6 +51996,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51865
51996
  ButtonComponent,
51866
51997
  DisplayComponent,
51867
51998
  SearchSelectorComponent,
51999
+ SkeletonLayoutComponent,
51868
52000
  TextComponent,
51869
52001
  TitleComponent,
51870
52002
  UserAvatarComponent,
@@ -51925,12 +52057,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51925
52057
  }
51926
52058
  </div>
51927
52059
 
51928
- @if (permissionsForCurrentRole().length > 0) {
52060
+ @if (permsLoading()) {
51929
52061
  <div class="perms-section">
51930
52062
  <span class="perms-label">{{ t('permissionsTitle') }}</span>
51931
- <div class="perms-list">
51932
- @for (perm of permissionsForCurrentRole(); track perm) {
51933
- <span class="perm-chip">{{ permissionLabel(perm) }}</span>
52063
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
52064
+ </div>
52065
+ } @else if (permissionsForCurrentRole().length > 0) {
52066
+ <div class="perms-section">
52067
+ <span class="perms-label">{{ t('permissionsTitle') }}</span>
52068
+ <div class="perm-groups">
52069
+ @for (g of permissionGroups(); track g.key) {
52070
+ <div [class]="'perm-group perm-group--' + g.scope">
52071
+ <span class="perm-group__badge">{{ g.label }}</span>
52072
+ <div class="perm-chips">
52073
+ @for (p of g.perms; track p) {
52074
+ <span class="perm-chip">{{ p }}</span>
52075
+ }
52076
+ </div>
52077
+ </div>
51934
52078
  }
51935
52079
  </div>
51936
52080
  </div>
@@ -51948,7 +52092,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51948
52092
  </ion-button>
51949
52093
  </div>
51950
52094
  </ion-content>
51951
- `, styles: ["ion-content{--padding-bottom: 24px}.member-head{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;margin-bottom:20px}val-display{display:block}val-title{display:block}.role-section{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.role-readonly-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.member-role-badge{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:4px 12px;border-radius:20px;width:fit-content;background:color-mix(in srgb,var(--ion-color-primary) 12%,transparent);color:var(--ion-color-primary)}.perms-section{display:flex;flex-direction:column;gap:10px;margin-bottom:24px}.perms-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.perms-list{display:flex;flex-wrap:wrap;gap:6px}.perm-chip{font-size:.75rem;font-weight:500;padding:3px 10px;border-radius:20px;border:1px solid var(--val-border-color, rgba(0, 0, 0, .12));color:var(--ion-color-dark);background:transparent}.remove-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08));padding-top:20px}.modal-close-bottom{margin-top:16px}\n"] }]
52095
+ `, styles: ["ion-content{--padding-bottom: 24px}.member-head{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;margin-bottom:20px}val-display{display:block}val-title{display:block}.role-section{display:flex;flex-direction:column;gap:8px;margin-bottom:24px}.role-readonly-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.member-role-badge{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:4px 12px;border-radius:20px;width:fit-content;background:color-mix(in srgb,var(--ion-color-primary) 12%,transparent);color:var(--ion-color-primary)}.perms-section{display:flex;flex-direction:column;gap:10px;margin-bottom:24px}.perms-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.perm-groups{display:flex;flex-direction:column;gap:12px}.perm-group{display:flex;flex-direction:column;gap:6px}.perm-group__badge{align-self:flex-start;display:inline-flex;align-items:center;gap:4px;font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:3px 9px;border-radius:6px}.perm-group--app .perm-group__badge{color:var(--ion-color-primary);background:rgba(var(--ion-color-primary-rgb),.12)}.perm-group--org .perm-group__badge{color:var(--ion-color-medium-shade, var(--ion-color-medium));background:var(--ion-color-light-shade, rgba(0, 0, 0, .06))}.perm-group--other .perm-group__badge{color:var(--ion-color-tertiary);background:rgba(var(--ion-color-tertiary-rgb),.12)}.perm-chips{display:flex;flex-wrap:wrap;gap:6px}.perm-chip{font-size:.75rem;padding:3px 10px;border-radius:20px;background:var(--ion-color-light);color:var(--ion-color-dark)}.perm-group--app .perm-chip{background:rgba(var(--ion-color-primary-rgb),.08)}.perm-group--other .perm-chip{background:rgba(var(--ion-color-tertiary-rgb),.08)}.remove-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08));padding-top:20px}.modal-close-bottom{margin-top:16px}\n"] }]
51952
52096
  }], ctorParameters: () => [], propDecorators: { _modalRef: [{
51953
52097
  type: Input
51954
52098
  }], member: [{
@@ -52169,9 +52313,6 @@ class PermissionsViewComponent {
52169
52313
  catalog: this.catalog.getCatalog(orgId),
52170
52314
  }).subscribe({
52171
52315
  next: ({ roles: rawRoles, catalog }) => {
52172
- const byResource = new Map();
52173
- for (const r of catalog.permissions)
52174
- byResource.set(r.resource, r);
52175
52316
  const currentAppId = catalog.appId;
52176
52317
  // Labeler con la SSOT del backend (labels del catálogo) — reemplaza el
52177
52318
  // mapa hardcodeado `perm*`. Locale del momento de carga (igual que antes:
@@ -52185,7 +52326,7 @@ class PermissionsViewComponent {
52185
52326
  description: r.description,
52186
52327
  permissions: r.permissions ?? [],
52187
52328
  isSystem: r.isSystem ?? false,
52188
- }, byResource, currentAppId, labeler)));
52329
+ }, catalog, currentAppId, labeler)));
52189
52330
  this.loading.set(false);
52190
52331
  },
52191
52332
  error: err => {
@@ -52194,64 +52335,13 @@ class PermissionsViewComponent {
52194
52335
  },
52195
52336
  });
52196
52337
  }
52197
- buildRoleView(role, byResource, currentAppId, labeler) {
52198
- const appPerms = [];
52199
- const orgPerms = [];
52200
- const otherByApp = new Map();
52201
- for (const perm of role.permissions) {
52202
- const [resource] = perm.split(':');
52203
- const entry = byResource.get(resource);
52204
- // Sin entrada en el catálogo (el backend omite los recursos internal para
52205
- // no-platform-admins) o entrada internal → NUNCA se muestra a nivel de
52206
- // producto. Defensa en profundidad junto al filtro del backend (ADR-024).
52207
- // Nota: el rol puede traer el permiso aunque el recurso esté filtrado del
52208
- // catálogo (ej. admin tiene templates:*); por eso se descarta lo no resuelto.
52209
- if (!entry || entry.scope === 'internal') {
52210
- continue;
52211
- }
52212
- const label = labeler(perm);
52213
- if (entry.scope === 'app') {
52214
- if (entry.appId === currentAppId) {
52215
- appPerms.push(label);
52216
- }
52217
- else {
52218
- const appId = entry.appId ?? '?';
52219
- const arr = otherByApp.get(appId) ?? [];
52220
- arr.push(label);
52221
- otherByApp.set(appId, arr);
52222
- }
52223
- }
52224
- else {
52225
- // scope === 'org' → gestión de la organización del cliente
52226
- orgPerms.push(label);
52227
- }
52228
- }
52229
- const groups = [];
52230
- if (appPerms.length) {
52231
- groups.push({
52232
- key: 'app',
52233
- label: this.tt('groupApp'),
52234
- scope: 'app',
52235
- perms: appPerms,
52236
- });
52237
- }
52238
- if (orgPerms.length) {
52239
- groups.push({
52240
- key: 'org',
52241
- label: this.tt('groupOrg'),
52242
- scope: 'org',
52243
- perms: orgPerms,
52244
- });
52245
- }
52246
- for (const [appId, perms] of otherByApp) {
52247
- groups.push({
52248
- key: `other:${appId}`,
52249
- label: `${this.tt('groupOther')}: ${this.appLabel(appId)}`,
52250
- scope: 'other',
52251
- appId,
52252
- perms,
52253
- });
52254
- }
52338
+ buildRoleView(role, catalog, currentAppId, labeler) {
52339
+ const groups = groupPermissionsByScope(role.permissions, catalog, currentAppId, labeler, {
52340
+ app: this.tt('groupApp'),
52341
+ org: this.tt('groupOrg'),
52342
+ other: this.tt('groupOther'),
52343
+ appLabel: (appId) => this.appLabel(appId),
52344
+ });
52255
52345
  return {
52256
52346
  id: role.id,
52257
52347
  name: role.name,
@@ -70048,5 +70138,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
70048
70138
  * Generated bundle index. Do not edit.
70049
70139
  */
70050
70140
 
70051
- export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, 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, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, 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_BUTTON_PRESETS, 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_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmptyStateComponent, EntityCardComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, 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, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OptionCardsComponent, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, 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, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketCardComponent, TicketCardImageService, 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, VALTECH_WHATSAPP_CONFIG, VERSION, ValtechErrorService, VerifyViewComponent, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, button, canSubmitRequestType, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, query, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, selectableRequestTypes, storagePaths, superAdminGuard, toArticle };
70141
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, 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, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, 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_BUTTON_PRESETS, 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_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmptyStateComponent, EntityCardComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, 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, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OptionCardsComponent, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, 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, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketCardComponent, TicketCardImageService, 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, VALTECH_WHATSAPP_CONFIG, VERSION, ValtechErrorService, VerifyViewComponent, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, button, canSubmitRequestType, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, query, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resolveColor, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, selectableRequestTypes, storagePaths, superAdminGuard, toArticle };
70052
70142
  //# sourceMappingURL=valtech-components.mjs.map