valtech-components 4.0.141 → 4.0.142

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.142';
60
60
 
61
61
  // Control de estado de refresco (singleton a nivel de módulo)
62
62
  let isRefreshing = false;
@@ -51469,6 +51469,66 @@ function createPermissionLabeler(catalog, locale, opts) {
51469
51469
  return `${res}: ${act}`;
51470
51470
  };
51471
51471
  }
51472
+ /**
51473
+ * Agrupa una lista de permisos (`resource:action`) por alcance — app actual /
51474
+ * organización / otras apps — usando el catálogo del backend como SSOT del scope
51475
+ * (`PermissionResource.scope` + `appId`). Cada permiso se etiqueta con `labeler`.
51476
+ *
51477
+ * Reutilizado por `val-permissions-view` y `val-member-detail-modal` para que
51478
+ * ambos muestren los chips agrupados y tintados de forma idéntica. Función pura
51479
+ * (sin Angular DI) — el consumer pasa los labels i18n ya resueltos.
51480
+ *
51481
+ * - Recursos ausentes del catálogo o con `scope === 'internal'` se descartan
51482
+ * (defensa en profundidad junto al filtro del backend, ADR-024).
51483
+ * - `scope === 'app'` con `appId === currentAppId` → grupo `app`; otro appId →
51484
+ * grupo `other:{appId}`. `scope === 'org'` → grupo `org`.
51485
+ */
51486
+ function groupPermissionsByScope(permissions, catalog, currentAppId, labeler, labels) {
51487
+ const byResource = new Map();
51488
+ for (const r of catalog.permissions ?? [])
51489
+ byResource.set(r.resource, r);
51490
+ const appPerms = [];
51491
+ const orgPerms = [];
51492
+ const otherByApp = new Map();
51493
+ for (const perm of permissions ?? []) {
51494
+ const [resource] = perm.split(':');
51495
+ const entry = byResource.get(resource);
51496
+ if (!entry || entry.scope === 'internal')
51497
+ continue;
51498
+ const label = labeler(perm);
51499
+ if (entry.scope === 'app') {
51500
+ if (entry.appId === currentAppId) {
51501
+ appPerms.push(label);
51502
+ }
51503
+ else {
51504
+ const appId = entry.appId ?? '?';
51505
+ const arr = otherByApp.get(appId) ?? [];
51506
+ arr.push(label);
51507
+ otherByApp.set(appId, arr);
51508
+ }
51509
+ }
51510
+ else {
51511
+ orgPerms.push(label);
51512
+ }
51513
+ }
51514
+ const groups = [];
51515
+ if (appPerms.length) {
51516
+ groups.push({ key: 'app', label: labels.app, scope: 'app', perms: appPerms });
51517
+ }
51518
+ if (orgPerms.length) {
51519
+ groups.push({ key: 'org', label: labels.org, scope: 'org', perms: orgPerms });
51520
+ }
51521
+ for (const [appId, perms] of otherByApp) {
51522
+ groups.push({
51523
+ key: `other:${appId}`,
51524
+ label: `${labels.other}: ${labels.appLabel(appId)}`,
51525
+ scope: 'other',
51526
+ appId,
51527
+ perms,
51528
+ });
51529
+ }
51530
+ return groups;
51531
+ }
51472
51532
 
51473
51533
  /**
51474
51534
  * Defaults i18n (es/en) embebidos en `val-member-detail-modal`. Auto-registrados
@@ -51496,6 +51556,12 @@ const MEMBER_DETAIL_MODAL_I18N = {
51496
51556
  removeSuccess: 'Miembro eliminado.',
51497
51557
  removeError: 'No se pudo eliminar al miembro.',
51498
51558
  permissionsTitle: 'Permisos del rol',
51559
+ // Grupos de alcance (mismas keys/valores que val-permissions-view)
51560
+ groupApp: 'Permisos de la app',
51561
+ groupOrg: 'Permisos de la organización',
51562
+ groupOther: 'Otras apps',
51563
+ app_showcase: 'Showcase',
51564
+ app_bingo: 'Bingo',
51499
51565
  permAll: 'Todo',
51500
51566
  permUsers: 'Usuarios',
51501
51567
  permDocuments: 'Documentos',
@@ -51549,6 +51615,11 @@ const MEMBER_DETAIL_MODAL_I18N = {
51549
51615
  removeSuccess: 'Member removed.',
51550
51616
  removeError: 'Could not remove member.',
51551
51617
  permissionsTitle: 'Role permissions',
51618
+ groupApp: 'App permissions',
51619
+ groupOrg: 'Organization permissions',
51620
+ groupOther: 'Other apps',
51621
+ app_showcase: 'Showcase',
51622
+ app_bingo: 'Bingo',
51552
51623
  permAll: 'All',
51553
51624
  permUsers: 'Users',
51554
51625
  permDocuments: 'Documents',
@@ -51611,6 +51682,16 @@ class MemberDetailModalComponent {
51611
51682
  this.catalog = inject(PermissionCatalogService);
51612
51683
  /** Labeler de permisos con la SSOT del backend (catálogo). Se llena al cargar. */
51613
51684
  this.permLabeler = signal(null);
51685
+ /** Catálogo del backend (define el alcance de cada recurso para agrupar). */
51686
+ this.catalogResp = signal(null);
51687
+ /**
51688
+ * `true` mientras el catálogo aún no llegó (y hay `orgId` para pedirlo, sin
51689
+ * error). Mientras tanto, la sección de permisos muestra skeleton — evita el
51690
+ * parpadeo inglés→español del fallback humanizado antes de tener los labels es.
51691
+ * Sin `orgId` el catálogo nunca se pide → `false` desde el arranque (se renderiza
51692
+ * con el fallback, sin skeleton infinito).
51693
+ */
51694
+ this.permsLoading = signal(false);
51614
51695
  /** Organización a la que pertenece el miembro. */
51615
51696
  this.orgId = '';
51616
51697
  /** Si true, habilita cambio de rol y eliminación. */
@@ -51642,6 +51723,31 @@ class MemberDetailModalComponent {
51642
51723
  const role = this.availableRoles.find(r => r.id === roleId || r.name === roleId);
51643
51724
  return role?.permissions ?? [];
51644
51725
  });
51726
+ /**
51727
+ * Permisos del rol actual agrupados por alcance (app actual / organización /
51728
+ * otras apps) con sus labels ya resueltos — mismo patrón que `val-permissions-view`.
51729
+ * Si el catálogo no cargó (sin `orgId` o falló), agrupa con un catálogo vacío:
51730
+ * sin scope no se pueden clasificar los recursos → cae a un único grupo `org`
51731
+ * con el labeler humanizado, manteniendo los chips visibles.
51732
+ */
51733
+ this.permissionGroups = computed(() => {
51734
+ this.i18n.lang();
51735
+ const perms = this.permissionsForCurrentRole();
51736
+ if (perms.length === 0)
51737
+ return [];
51738
+ const catalog = this.catalogResp();
51739
+ const labels = {
51740
+ app: this.t('groupApp'),
51741
+ org: this.t('groupOrg'),
51742
+ other: this.t('groupOther'),
51743
+ appLabel: (appId) => this.appLabel(appId),
51744
+ };
51745
+ if (catalog) {
51746
+ return groupPermissionsByScope(perms, catalog, catalog.appId, this.permissionLabel.bind(this), labels);
51747
+ }
51748
+ // Sin catálogo: no hay scope → un solo grupo "organización" con el fallback.
51749
+ return [{ key: 'org', label: labels.org, scope: 'org', perms: perms.map(p => this.permissionLabel(p)) }];
51750
+ });
51645
51751
  this.roleSelectProps = computed(() => ({
51646
51752
  control: this.roleControl,
51647
51753
  label: '',
@@ -51679,15 +51785,31 @@ class MemberDetailModalComponent {
51679
51785
  if (v && v !== this.currentRole())
51680
51786
  void this.onChangeRole(v);
51681
51787
  });
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).
51788
+ // Catálogo del backend = SSOT de los labels de permisos + del alcance para
51789
+ // agrupar (ADR-024). Mientras carga mostramos skeleton (mata el parpadeo
51790
+ // inglés→español del fallback). Si falla, `permissionLabel` cae al fallback
51791
+ // humanizado (no rompe el modal). Sin `orgId` el catálogo nunca se pide →
51792
+ // permsLoading queda false (se renderiza con el fallback, sin skeleton infinito).
51684
51793
  if (this.orgId) {
51794
+ this.permsLoading.set(true);
51685
51795
  this.catalog.getCatalog(this.orgId).subscribe({
51686
- next: catalog => this.permLabeler.set(createPermissionLabeler(catalog, this.i18n.lang(), { allLabel: this.t('permAll') })),
51687
- error: () => { },
51796
+ next: catalog => {
51797
+ this.catalogResp.set(catalog);
51798
+ this.permLabeler.set(createPermissionLabeler(catalog, this.i18n.lang(), { allLabel: this.t('permAll') }));
51799
+ this.permsLoading.set(false);
51800
+ },
51801
+ error: () => {
51802
+ this.permsLoading.set(false);
51803
+ },
51688
51804
  });
51689
51805
  }
51690
51806
  }
51807
+ /** Resuelve el nombre legible de una app por su appId (key `app_{id}`). */
51808
+ appLabel(appId) {
51809
+ const key = `app_${appId}`;
51810
+ const label = this.t(key);
51811
+ return label === key ? appId : label;
51812
+ }
51691
51813
  permissionLabel(perm) {
51692
51814
  // SSOT = catálogo del backend. Hasta que cargue (o si falló), fallback a un
51693
51815
  // labeler vacío que humaniza el código crudo (evita salidas vacías como
@@ -51828,12 +51950,24 @@ class MemberDetailModalComponent {
51828
51950
  }
51829
51951
  </div>
51830
51952
 
51831
- @if (permissionsForCurrentRole().length > 0) {
51953
+ @if (permsLoading()) {
51832
51954
  <div class="perms-section">
51833
51955
  <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>
51956
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
51957
+ </div>
51958
+ } @else if (permissionsForCurrentRole().length > 0) {
51959
+ <div class="perms-section">
51960
+ <span class="perms-label">{{ t('permissionsTitle') }}</span>
51961
+ <div class="perm-groups">
51962
+ @for (g of permissionGroups(); track g.key) {
51963
+ <div [class]="'perm-group perm-group--' + g.scope">
51964
+ <span class="perm-group__badge">{{ g.label }}</span>
51965
+ <div class="perm-chips">
51966
+ @for (p of g.perms; track p) {
51967
+ <span class="perm-chip">{{ p }}</span>
51968
+ }
51969
+ </div>
51970
+ </div>
51837
51971
  }
51838
51972
  </div>
51839
51973
  </div>
@@ -51851,7 +51985,7 @@ class MemberDetailModalComponent {
51851
51985
  </ion-button>
51852
51986
  </div>
51853
51987
  </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"] }] }); }
51988
+ `, 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
51989
  }
51856
51990
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MemberDetailModalComponent, decorators: [{
51857
51991
  type: Component,
@@ -51865,6 +51999,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51865
51999
  ButtonComponent,
51866
52000
  DisplayComponent,
51867
52001
  SearchSelectorComponent,
52002
+ SkeletonLayoutComponent,
51868
52003
  TextComponent,
51869
52004
  TitleComponent,
51870
52005
  UserAvatarComponent,
@@ -51925,12 +52060,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51925
52060
  }
51926
52061
  </div>
51927
52062
 
51928
- @if (permissionsForCurrentRole().length > 0) {
52063
+ @if (permsLoading()) {
51929
52064
  <div class="perms-section">
51930
52065
  <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>
52066
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
52067
+ </div>
52068
+ } @else if (permissionsForCurrentRole().length > 0) {
52069
+ <div class="perms-section">
52070
+ <span class="perms-label">{{ t('permissionsTitle') }}</span>
52071
+ <div class="perm-groups">
52072
+ @for (g of permissionGroups(); track g.key) {
52073
+ <div [class]="'perm-group perm-group--' + g.scope">
52074
+ <span class="perm-group__badge">{{ g.label }}</span>
52075
+ <div class="perm-chips">
52076
+ @for (p of g.perms; track p) {
52077
+ <span class="perm-chip">{{ p }}</span>
52078
+ }
52079
+ </div>
52080
+ </div>
51934
52081
  }
51935
52082
  </div>
51936
52083
  </div>
@@ -51948,7 +52095,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51948
52095
  </ion-button>
51949
52096
  </div>
51950
52097
  </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"] }]
52098
+ `, 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
52099
  }], ctorParameters: () => [], propDecorators: { _modalRef: [{
51953
52100
  type: Input
51954
52101
  }], member: [{
@@ -52169,9 +52316,6 @@ class PermissionsViewComponent {
52169
52316
  catalog: this.catalog.getCatalog(orgId),
52170
52317
  }).subscribe({
52171
52318
  next: ({ roles: rawRoles, catalog }) => {
52172
- const byResource = new Map();
52173
- for (const r of catalog.permissions)
52174
- byResource.set(r.resource, r);
52175
52319
  const currentAppId = catalog.appId;
52176
52320
  // Labeler con la SSOT del backend (labels del catálogo) — reemplaza el
52177
52321
  // mapa hardcodeado `perm*`. Locale del momento de carga (igual que antes:
@@ -52185,7 +52329,7 @@ class PermissionsViewComponent {
52185
52329
  description: r.description,
52186
52330
  permissions: r.permissions ?? [],
52187
52331
  isSystem: r.isSystem ?? false,
52188
- }, byResource, currentAppId, labeler)));
52332
+ }, catalog, currentAppId, labeler)));
52189
52333
  this.loading.set(false);
52190
52334
  },
52191
52335
  error: err => {
@@ -52194,64 +52338,13 @@ class PermissionsViewComponent {
52194
52338
  },
52195
52339
  });
52196
52340
  }
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
- }
52341
+ buildRoleView(role, catalog, currentAppId, labeler) {
52342
+ const groups = groupPermissionsByScope(role.permissions, catalog, currentAppId, labeler, {
52343
+ app: this.tt('groupApp'),
52344
+ org: this.tt('groupOrg'),
52345
+ other: this.tt('groupOther'),
52346
+ appLabel: (appId) => this.appLabel(appId),
52347
+ });
52255
52348
  return {
52256
52349
  id: role.id,
52257
52350
  name: role.name,
@@ -70048,5 +70141,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
70048
70141
  * Generated bundle index. Do not edit.
70049
70142
  */
70050
70143
 
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 };
70144
+ 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
70145
  //# sourceMappingURL=valtech-components.mjs.map