valtech-components 4.0.140 → 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.140';
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;
@@ -341,10 +341,12 @@ function interpretError(err) {
341
341
  isNetwork: false,
342
342
  };
343
343
  }
344
- // 1c. HttpErrorResponse sin body estructurado (ej. body string / null).
344
+ // 1c. HttpErrorResponse sin body estructurado (504, 502, proxy errors, CORS…).
345
+ // err.message de Angular es "Http failure response for URL: NNN statusText",
346
+ // nunca mostrar eso al usuario.
345
347
  return {
346
348
  code: UNKNOWN_CODE,
347
- message: asNonEmptyString(err.message) ?? UNKNOWN_MESSAGE,
349
+ message: UNKNOWN_MESSAGE,
348
350
  status,
349
351
  isNetwork: false,
350
352
  };
@@ -51467,6 +51469,66 @@ function createPermissionLabeler(catalog, locale, opts) {
51467
51469
  return `${res}: ${act}`;
51468
51470
  };
51469
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
+ }
51470
51532
 
51471
51533
  /**
51472
51534
  * Defaults i18n (es/en) embebidos en `val-member-detail-modal`. Auto-registrados
@@ -51494,6 +51556,12 @@ const MEMBER_DETAIL_MODAL_I18N = {
51494
51556
  removeSuccess: 'Miembro eliminado.',
51495
51557
  removeError: 'No se pudo eliminar al miembro.',
51496
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',
51497
51565
  permAll: 'Todo',
51498
51566
  permUsers: 'Usuarios',
51499
51567
  permDocuments: 'Documentos',
@@ -51547,6 +51615,11 @@ const MEMBER_DETAIL_MODAL_I18N = {
51547
51615
  removeSuccess: 'Member removed.',
51548
51616
  removeError: 'Could not remove member.',
51549
51617
  permissionsTitle: 'Role permissions',
51618
+ groupApp: 'App permissions',
51619
+ groupOrg: 'Organization permissions',
51620
+ groupOther: 'Other apps',
51621
+ app_showcase: 'Showcase',
51622
+ app_bingo: 'Bingo',
51550
51623
  permAll: 'All',
51551
51624
  permUsers: 'Users',
51552
51625
  permDocuments: 'Documents',
@@ -51609,6 +51682,16 @@ class MemberDetailModalComponent {
51609
51682
  this.catalog = inject(PermissionCatalogService);
51610
51683
  /** Labeler de permisos con la SSOT del backend (catálogo). Se llena al cargar. */
51611
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);
51612
51695
  /** Organización a la que pertenece el miembro. */
51613
51696
  this.orgId = '';
51614
51697
  /** Si true, habilita cambio de rol y eliminación. */
@@ -51640,6 +51723,31 @@ class MemberDetailModalComponent {
51640
51723
  const role = this.availableRoles.find(r => r.id === roleId || r.name === roleId);
51641
51724
  return role?.permissions ?? [];
51642
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
+ });
51643
51751
  this.roleSelectProps = computed(() => ({
51644
51752
  control: this.roleControl,
51645
51753
  label: '',
@@ -51677,15 +51785,31 @@ class MemberDetailModalComponent {
51677
51785
  if (v && v !== this.currentRole())
51678
51786
  void this.onChangeRole(v);
51679
51787
  });
51680
- // Catálogo del backend = SSOT de los labels de permisos (ADR-024). Si falla,
51681
- // `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).
51682
51793
  if (this.orgId) {
51794
+ this.permsLoading.set(true);
51683
51795
  this.catalog.getCatalog(this.orgId).subscribe({
51684
- next: catalog => this.permLabeler.set(createPermissionLabeler(catalog, this.i18n.lang(), { allLabel: this.t('permAll') })),
51685
- 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
+ },
51686
51804
  });
51687
51805
  }
51688
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
+ }
51689
51813
  permissionLabel(perm) {
51690
51814
  // SSOT = catálogo del backend. Hasta que cargue (o si falló), fallback a un
51691
51815
  // labeler vacío que humaniza el código crudo (evita salidas vacías como
@@ -51826,12 +51950,24 @@ class MemberDetailModalComponent {
51826
51950
  }
51827
51951
  </div>
51828
51952
 
51829
- @if (permissionsForCurrentRole().length > 0) {
51953
+ @if (permsLoading()) {
51830
51954
  <div class="perms-section">
51831
51955
  <span class="perms-label">{{ t('permissionsTitle') }}</span>
51832
- <div class="perms-list">
51833
- @for (perm of permissionsForCurrentRole(); track perm) {
51834
- <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>
51835
51971
  }
51836
51972
  </div>
51837
51973
  </div>
@@ -51849,7 +51985,7 @@ class MemberDetailModalComponent {
51849
51985
  </ion-button>
51850
51986
  </div>
51851
51987
  </ion-content>
51852
- `, 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"] }] }); }
51853
51989
  }
51854
51990
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MemberDetailModalComponent, decorators: [{
51855
51991
  type: Component,
@@ -51863,6 +51999,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51863
51999
  ButtonComponent,
51864
52000
  DisplayComponent,
51865
52001
  SearchSelectorComponent,
52002
+ SkeletonLayoutComponent,
51866
52003
  TextComponent,
51867
52004
  TitleComponent,
51868
52005
  UserAvatarComponent,
@@ -51923,12 +52060,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51923
52060
  }
51924
52061
  </div>
51925
52062
 
51926
- @if (permissionsForCurrentRole().length > 0) {
52063
+ @if (permsLoading()) {
51927
52064
  <div class="perms-section">
51928
52065
  <span class="perms-label">{{ t('permissionsTitle') }}</span>
51929
- <div class="perms-list">
51930
- @for (perm of permissionsForCurrentRole(); track perm) {
51931
- <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>
51932
52081
  }
51933
52082
  </div>
51934
52083
  </div>
@@ -51946,7 +52095,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51946
52095
  </ion-button>
51947
52096
  </div>
51948
52097
  </ion-content>
51949
- `, 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"] }]
51950
52099
  }], ctorParameters: () => [], propDecorators: { _modalRef: [{
51951
52100
  type: Input
51952
52101
  }], member: [{
@@ -52167,9 +52316,6 @@ class PermissionsViewComponent {
52167
52316
  catalog: this.catalog.getCatalog(orgId),
52168
52317
  }).subscribe({
52169
52318
  next: ({ roles: rawRoles, catalog }) => {
52170
- const byResource = new Map();
52171
- for (const r of catalog.permissions)
52172
- byResource.set(r.resource, r);
52173
52319
  const currentAppId = catalog.appId;
52174
52320
  // Labeler con la SSOT del backend (labels del catálogo) — reemplaza el
52175
52321
  // mapa hardcodeado `perm*`. Locale del momento de carga (igual que antes:
@@ -52183,7 +52329,7 @@ class PermissionsViewComponent {
52183
52329
  description: r.description,
52184
52330
  permissions: r.permissions ?? [],
52185
52331
  isSystem: r.isSystem ?? false,
52186
- }, byResource, currentAppId, labeler)));
52332
+ }, catalog, currentAppId, labeler)));
52187
52333
  this.loading.set(false);
52188
52334
  },
52189
52335
  error: err => {
@@ -52192,64 +52338,13 @@ class PermissionsViewComponent {
52192
52338
  },
52193
52339
  });
52194
52340
  }
52195
- buildRoleView(role, byResource, currentAppId, labeler) {
52196
- const appPerms = [];
52197
- const orgPerms = [];
52198
- const otherByApp = new Map();
52199
- for (const perm of role.permissions) {
52200
- const [resource] = perm.split(':');
52201
- const entry = byResource.get(resource);
52202
- // Sin entrada en el catálogo (el backend omite los recursos internal para
52203
- // no-platform-admins) o entrada internal → NUNCA se muestra a nivel de
52204
- // producto. Defensa en profundidad junto al filtro del backend (ADR-024).
52205
- // Nota: el rol puede traer el permiso aunque el recurso esté filtrado del
52206
- // catálogo (ej. admin tiene templates:*); por eso se descarta lo no resuelto.
52207
- if (!entry || entry.scope === 'internal') {
52208
- continue;
52209
- }
52210
- const label = labeler(perm);
52211
- if (entry.scope === 'app') {
52212
- if (entry.appId === currentAppId) {
52213
- appPerms.push(label);
52214
- }
52215
- else {
52216
- const appId = entry.appId ?? '?';
52217
- const arr = otherByApp.get(appId) ?? [];
52218
- arr.push(label);
52219
- otherByApp.set(appId, arr);
52220
- }
52221
- }
52222
- else {
52223
- // scope === 'org' → gestión de la organización del cliente
52224
- orgPerms.push(label);
52225
- }
52226
- }
52227
- const groups = [];
52228
- if (appPerms.length) {
52229
- groups.push({
52230
- key: 'app',
52231
- label: this.tt('groupApp'),
52232
- scope: 'app',
52233
- perms: appPerms,
52234
- });
52235
- }
52236
- if (orgPerms.length) {
52237
- groups.push({
52238
- key: 'org',
52239
- label: this.tt('groupOrg'),
52240
- scope: 'org',
52241
- perms: orgPerms,
52242
- });
52243
- }
52244
- for (const [appId, perms] of otherByApp) {
52245
- groups.push({
52246
- key: `other:${appId}`,
52247
- label: `${this.tt('groupOther')}: ${this.appLabel(appId)}`,
52248
- scope: 'other',
52249
- appId,
52250
- perms,
52251
- });
52252
- }
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
+ });
52253
52348
  return {
52254
52349
  id: role.id,
52255
52350
  name: role.name,
@@ -70046,5 +70141,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
70046
70141
  * Generated bundle index. Do not edit.
70047
70142
  */
70048
70143
 
70049
- 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 };
70050
70145
  //# sourceMappingURL=valtech-components.mjs.map