valtech-components 2.0.996 → 2.0.997
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.
- package/esm2022/lib/components/organisms/notification-preferences-view/notification-preferences-view.component.mjs +667 -0
- package/esm2022/lib/components/organisms/notification-preferences-view/notification-preferences-view.i18n.mjs +71 -0
- package/esm2022/lib/components/organisms/notification-preferences-view/notification-preferences.routes.mjs +31 -0
- package/esm2022/lib/components/organisms/notification-preferences-view/types.mjs +2 -0
- package/esm2022/lib/components/organisms/organization-view/organization-view.component.mjs +1 -76
- package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +1 -5
- package/esm2022/lib/components/organisms/permissions-view/permissions-view.component.mjs +511 -0
- package/esm2022/lib/components/organisms/permissions-view/permissions-view.i18n.mjs +116 -0
- package/esm2022/lib/components/organisms/permissions-view/permissions.routes.mjs +29 -0
- package/esm2022/lib/components/organisms/permissions-view/types.mjs +2 -0
- package/esm2022/lib/components/organisms/settings-hub/settings.routes.mjs +12 -1
- package/esm2022/lib/services/auth/auth.service.mjs +1 -14
- package/esm2022/lib/services/auth/types.mjs +1 -1
- package/esm2022/lib/services/org/org.service.mjs +1 -8
- package/esm2022/lib/services/org/permission-catalog.service.mjs +33 -0
- package/esm2022/lib/services/org/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +8 -4
- package/fesm2022/valtech-components.mjs +1484 -1003
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/notification-preferences-view/notification-preferences-view.component.d.ts +146 -0
- package/lib/components/organisms/notification-preferences-view/notification-preferences-view.i18n.d.ts +11 -0
- package/lib/components/organisms/notification-preferences-view/notification-preferences.routes.d.ts +26 -0
- package/lib/components/organisms/notification-preferences-view/types.d.ts +36 -0
- package/lib/components/organisms/organization-view/organization-view.component.d.ts +0 -5
- package/lib/components/organisms/permissions-view/permissions-view.component.d.ts +71 -0
- package/lib/components/organisms/permissions-view/permissions-view.i18n.d.ts +9 -0
- package/lib/components/organisms/permissions-view/permissions.routes.d.ts +24 -0
- package/lib/components/organisms/permissions-view/types.d.ts +26 -0
- package/lib/components/organisms/settings-hub/settings.routes.d.ts +15 -0
- package/lib/services/auth/auth.service.d.ts +1 -7
- package/lib/services/auth/types.d.ts +0 -23
- package/lib/services/org/org.service.d.ts +1 -6
- package/lib/services/org/permission-catalog.service.d.ts +34 -0
- package/lib/services/org/types.d.ts +0 -30
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +8 -5
- package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.component.mjs +0 -385
- package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.mjs +0 -63
- package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.component.mjs +0 -313
- package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.i18n.mjs +0 -63
- package/esm2022/lib/services/apikeys/api-keys.service.mjs +0 -46
- package/esm2022/lib/services/apikeys/types.mjs +0 -7
- package/lib/components/organisms/api-keys-modal/api-keys-modal.component.d.ts +0 -44
- package/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.d.ts +0 -6
- package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +0 -47
- package/lib/components/organisms/member-import-modal/member-import-modal.i18n.d.ts +0 -6
- package/lib/services/apikeys/api-keys.service.d.ts +0 -25
- package/lib/services/apikeys/types.d.ts +0 -46
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { OnDestroy, OnInit } from '@angular/core';
|
|
2
|
+
import { FormControl } from '@angular/forms';
|
|
3
|
+
import { ToggleInputMetadata } from '../../molecules/toggle-input/types';
|
|
4
|
+
import { ButtonMetadata } from '../../types';
|
|
5
|
+
import { NotificationPermissionState } from '../../../services/auth/types';
|
|
6
|
+
import { PreferencesService } from '../../../services/preferences/preferences.service';
|
|
7
|
+
import { NotificationPreferencesViewConfig } from './types';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
/**
|
|
10
|
+
* Estados de la vista de preferencias push:
|
|
11
|
+
* - `idle`: toggle off, sin operación en curso, sin errores
|
|
12
|
+
* - `enabling`: secuencia de activación en curso (toggle spinner)
|
|
13
|
+
* - `enabled`: todo OK (master=true + permission=granted + token registrado)
|
|
14
|
+
* - `disabling`: desactivación en curso
|
|
15
|
+
* - `error`: último intento falló → mensaje + botón "Reintentar"
|
|
16
|
+
* - `blocked`: navegador denegó permisos → mensaje + cómo arreglar
|
|
17
|
+
* - `unsupported`: navegador no soporta FCM → mensaje
|
|
18
|
+
* - `needs-install`: iOS sin standalone → instrucciones de instalación PWA
|
|
19
|
+
*/
|
|
20
|
+
type UiState = 'idle' | 'enabling' | 'enabled' | 'disabling' | 'error' | 'blocked' | 'unsupported' | 'needs-install';
|
|
21
|
+
/**
|
|
22
|
+
* `val-notification-preferences-view` — **preferencias de notificaciones push**
|
|
23
|
+
* (FCM) full-feature autocontenida (organism). Promovida desde `showcase` bajo el
|
|
24
|
+
* proceso de ADR-021.
|
|
25
|
+
*
|
|
26
|
+
* Separada de `val-notifications-view` (el inbox / feed). Aquí el user **activa o
|
|
27
|
+
* desactiva** las notificaciones push en este dispositivo.
|
|
28
|
+
*
|
|
29
|
+
* UX simplificado: UN solo toggle que ejecuta toda la secuencia (pedir permiso →
|
|
30
|
+
* SW ready → getToken → registrar en backend → set master pref) vía
|
|
31
|
+
* `MessagingService.enable()`. El registro del device en el backend va como
|
|
32
|
+
* callback (la lib no depende de `AuthService` para evitar ciclos). Mensajes
|
|
33
|
+
* contextuales y botón "Reintentar" aparecen solo cuando aplican.
|
|
34
|
+
*
|
|
35
|
+
* NO renderiza ion-content — vive dentro de val-page-wrapper. `ActivatedRoute` se
|
|
36
|
+
* inyecta `{ optional: true }` → funciona sin router (embebida / Storybook).
|
|
37
|
+
*/
|
|
38
|
+
export declare class NotificationPreferencesViewComponent implements OnInit, OnDestroy {
|
|
39
|
+
private nav;
|
|
40
|
+
private i18n;
|
|
41
|
+
private toast;
|
|
42
|
+
private auth;
|
|
43
|
+
private messaging;
|
|
44
|
+
private pageRefresh;
|
|
45
|
+
readonly prefs: PreferencesService;
|
|
46
|
+
private route;
|
|
47
|
+
/**
|
|
48
|
+
* Config vía @Input (object-first). Si no se pasa, se cae al route data
|
|
49
|
+
* `notificationPreferencesConfig` (poblado por
|
|
50
|
+
* `provideValtechNotificationPreferencesRoutes`). `resolvedConfig` mergea con
|
|
51
|
+
* los defaults — `@Input` gana sobre route data.
|
|
52
|
+
*/
|
|
53
|
+
config?: NotificationPreferencesViewConfig;
|
|
54
|
+
readonly resolvedConfig: import("@angular/core").Signal<Required<Omit<NotificationPreferencesViewConfig, "onPushEnabled" | "onPushDisabled">> & Pick<NotificationPreferencesViewConfig, "onPushEnabled" | "onPushDisabled">>;
|
|
55
|
+
/** Namespace i18n resuelto (capturado para llamadas no-reactivas). */
|
|
56
|
+
private get ns();
|
|
57
|
+
/** Operación en curso (gobierna spinner del toggle + label "Activando…"). */
|
|
58
|
+
private readonly _busy;
|
|
59
|
+
/** True si el último intento falló — gobierna estado `error` + retry button. */
|
|
60
|
+
private readonly _lastFailed;
|
|
61
|
+
/** True mientras se re-obtiene el token FCM en background (no afecta la UI). */
|
|
62
|
+
private _repairingToken;
|
|
63
|
+
/** Toggle del expand de detalles técnicos. */
|
|
64
|
+
readonly showDetails: import("@angular/core").WritableSignal<boolean>;
|
|
65
|
+
readonly permission: import("@angular/core").WritableSignal<NotificationPermissionState>;
|
|
66
|
+
readonly isSupported: import("@angular/core").WritableSignal<boolean>;
|
|
67
|
+
readonly currentToken: import("@angular/core").WritableSignal<string>;
|
|
68
|
+
readonly needsIOSInstall: import("@angular/core").WritableSignal<boolean>;
|
|
69
|
+
/** FormControl del toggle (sync-eado con `isEnabled` via effect). */
|
|
70
|
+
readonly toggleControl: FormControl<boolean>;
|
|
71
|
+
/** Handler del listener `focus` — referencia guardada para poder removerlo. */
|
|
72
|
+
private readonly onWindowFocus;
|
|
73
|
+
/** Timer del debounce del refresh disparado por `focus`. */
|
|
74
|
+
private focusDebounceTimer;
|
|
75
|
+
/** Ventana de debounce (ms) para el refresh disparado por `focus`. */
|
|
76
|
+
private readonly FOCUS_DEBOUNCE_MS;
|
|
77
|
+
readonly pageTitle: import("@angular/core").Signal<string>;
|
|
78
|
+
readonly pageDescription: import("@angular/core").Signal<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Estado efectivo del toggle: "el usuario tiene push activo".
|
|
81
|
+
*
|
|
82
|
+
* Se deriva SOLO de la decisión del usuario (`master`) y del permiso del SO
|
|
83
|
+
* (`permission`). El token FCM NO forma parte del estado de UI: vive en
|
|
84
|
+
* memoria, se pierde en cada recarga/suspensión de la PWA y produciría flicker.
|
|
85
|
+
* Si falta token con `master && granted`, es un detalle reparable en
|
|
86
|
+
* background (ver `repairTokenIfNeeded`), no un cambio del toggle.
|
|
87
|
+
*/
|
|
88
|
+
readonly isEnabled: import("@angular/core").Signal<boolean>;
|
|
89
|
+
readonly state: import("@angular/core").Signal<UiState>;
|
|
90
|
+
readonly busyLabel: import("@angular/core").Signal<string>;
|
|
91
|
+
readonly contextMessage: import("@angular/core").Signal<string>;
|
|
92
|
+
readonly alertVariant: import("@angular/core").Signal<"warning" | "danger" | "info">;
|
|
93
|
+
readonly alertIcon: import("@angular/core").Signal<"alert-circle-outline" | "close-circle-outline">;
|
|
94
|
+
readonly toggleProps: import("@angular/core").Signal<ToggleInputMetadata>;
|
|
95
|
+
readonly retryButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
|
|
96
|
+
readonly tokenPreview: import("@angular/core").Signal<string>;
|
|
97
|
+
constructor();
|
|
98
|
+
/**
|
|
99
|
+
* Registra el pull-to-refresh estándar. Aunque esta vista no muestra una
|
|
100
|
+
* lista remota, sí refleja estado mutable del browser (permiso, token,
|
|
101
|
+
* soporte FCM) que puede cambiar fuera de la app — el refresh re-evalúa todo.
|
|
102
|
+
*
|
|
103
|
+
* Se usa `ngOnInit`/`ngOnDestroy` (NO `ionViewWillEnter`) porque
|
|
104
|
+
* `val-page-wrapper` usa `<router-outlet>` plano — los hooks `ionView*` solo
|
|
105
|
+
* disparan dentro de `<ion-router-outlet>`.
|
|
106
|
+
*/
|
|
107
|
+
ngOnInit(): void;
|
|
108
|
+
ngOnDestroy(): void;
|
|
109
|
+
/** Refresca el estado del browser con debounce — evita ráfagas de `focus`. */
|
|
110
|
+
private scheduleBrowserRefresh;
|
|
111
|
+
/**
|
|
112
|
+
* Secuencia completa de activación.
|
|
113
|
+
*
|
|
114
|
+
* Toda la mecánica (permission → SW ready → getToken con retry → watchdog de
|
|
115
|
+
* auto-reload) vive en `MessagingService.enable()` de la lib. El paso de
|
|
116
|
+
* registro del device en el backend se pasa como callback (`registerDevice`)
|
|
117
|
+
* porque la lib no puede depender de `AuthService` sin crear un ciclo.
|
|
118
|
+
*
|
|
119
|
+
* `enable()` no hace throw: resuelve con un `EnablePushResult` descriptivo.
|
|
120
|
+
*/
|
|
121
|
+
onEnable(): Promise<void>;
|
|
122
|
+
onDisable(): Promise<void>;
|
|
123
|
+
/** Reintentar la secuencia completa de activación, sin importar el estado actual. */
|
|
124
|
+
onRetry(): Promise<void>;
|
|
125
|
+
toggleDetails(): void;
|
|
126
|
+
private refreshBrowserState;
|
|
127
|
+
/**
|
|
128
|
+
* Repara el token FCM en background.
|
|
129
|
+
*
|
|
130
|
+
* Si el usuario tiene push activo (`master && granted`) pero no hay token en
|
|
131
|
+
* memoria — caso típico tras un cold start de la PWA — re-obtenemos el token
|
|
132
|
+
* y re-registramos el device sin tocar el toggle ni mostrar un error
|
|
133
|
+
* alarmista. El token es un detalle de implementación reparable, no parte del
|
|
134
|
+
* estado de UI (ver `isEnabled`).
|
|
135
|
+
*/
|
|
136
|
+
private repairTokenIfNeeded;
|
|
137
|
+
/**
|
|
138
|
+
* iOS browser sin estar instalado como PWA — push web no disponible.
|
|
139
|
+
* Aplica a Safari y a Edge/Chrome/Firefox en iOS (todos WebKit por mandato Apple).
|
|
140
|
+
*/
|
|
141
|
+
private detectNeedsIOSInstall;
|
|
142
|
+
protected tt(key: string): string;
|
|
143
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NotificationPreferencesViewComponent, never>;
|
|
144
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<NotificationPreferencesViewComponent, "val-notification-preferences-view", never, { "config": { "alias": "config"; "required": false; }; }, {}, never, never, true, never>;
|
|
145
|
+
}
|
|
146
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LanguagesContent } from '../../../services/i18n/types';
|
|
2
|
+
/**
|
|
3
|
+
* Defaults i18n (es/en) embebidos en `val-notification-preferences-view`.
|
|
4
|
+
* Auto-registrados en el constructor del componente si el consumer no proveyó
|
|
5
|
+
* el namespace (`Settings.Notifications` por default). SOLO incluye las keys que
|
|
6
|
+
* la vista usa.
|
|
7
|
+
*
|
|
8
|
+
* Portado del override `Settings.Notifications` (showcase) bajo el proceso de
|
|
9
|
+
* ADR-021.
|
|
10
|
+
*/
|
|
11
|
+
export declare const NOTIFICATION_PREFERENCES_VIEW_I18N: LanguagesContent;
|
package/lib/components/organisms/notification-preferences-view/notification-preferences.routes.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Routes } from '@angular/router';
|
|
2
|
+
import { NotificationPreferencesViewConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Helper para montar las **preferencias de notificaciones push**
|
|
5
|
+
* (`val-notification-preferences-view`) como ruta en una app del factory. El
|
|
6
|
+
* `config` se pasa por route `data` (`notificationPreferencesConfig`) y el
|
|
7
|
+
* componente lo lee como fallback de su `@Input() config`.
|
|
8
|
+
*
|
|
9
|
+
* No confundir con `provideValtechNotificationsRoutes` (el inbox / feed).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // app.routes.ts (típicamente bajo settings)
|
|
14
|
+
* export const settingsRoutes: Routes = [
|
|
15
|
+
* ...provideValtechNotificationPreferencesRoutes(), // → notifications
|
|
16
|
+
* ];
|
|
17
|
+
*
|
|
18
|
+
* // con config acotada:
|
|
19
|
+
* ...provideValtechNotificationPreferencesRoutes({ config: { showDetails: false } }),
|
|
20
|
+
* ...provideValtechNotificationPreferencesRoutes({ path: 'push' }),
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function provideValtechNotificationPreferencesRoutes(opts?: {
|
|
24
|
+
path?: string;
|
|
25
|
+
config?: NotificationPreferencesViewConfig;
|
|
26
|
+
}): Routes;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuración acotada de `val-notification-preferences-view` (object-first).
|
|
3
|
+
* Tres ejes de variación permitidos — **NADA de slots arbitrarios** (ADR-021:
|
|
4
|
+
* una vista full-feature no abre slots; si falta algo, se promueve un nuevo
|
|
5
|
+
* punto de extensión):
|
|
6
|
+
*
|
|
7
|
+
* - **secciones / flags** — gatean el render de bloques opcionales (panel de
|
|
8
|
+
* detalles técnicos expandible).
|
|
9
|
+
* - **branding** — `i18nNamespace` para resolver los textos (default
|
|
10
|
+
* `'Settings.Notifications'`).
|
|
11
|
+
* - **comportamiento / callbacks** — `onPushEnabled` / `onPushDisabled`
|
|
12
|
+
* (telemetría tras activar/desactivar push).
|
|
13
|
+
*/
|
|
14
|
+
export interface NotificationPreferencesViewConfig {
|
|
15
|
+
/**
|
|
16
|
+
* Muestra el panel "Ver detalles técnicos" (token FCM, permiso del navegador,
|
|
17
|
+
* soporte). Se oculta de todos modos en los estados `unsupported` y
|
|
18
|
+
* `needs-install`. Default `true`.
|
|
19
|
+
*/
|
|
20
|
+
showDetails?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Namespace i18n con el que la vista resuelve sus textos.
|
|
23
|
+
* Default `'Settings.Notifications'`.
|
|
24
|
+
*/
|
|
25
|
+
i18nNamespace?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Hook de telemetría tras activar push correctamente (permiso concedido +
|
|
28
|
+
* token registrado + master en `true`).
|
|
29
|
+
*/
|
|
30
|
+
onPushEnabled?: () => void;
|
|
31
|
+
/**
|
|
32
|
+
* Hook de telemetría tras desactivar push (device desregistrado + master en
|
|
33
|
+
* `false`).
|
|
34
|
+
*/
|
|
35
|
+
onPushDisabled?: () => void;
|
|
36
|
+
}
|
|
@@ -61,7 +61,6 @@ export declare class OrganizationViewComponent {
|
|
|
61
61
|
readonly members: import("@angular/core").WritableSignal<MemberDetail[]>;
|
|
62
62
|
readonly membersLoading: import("@angular/core").WritableSignal<boolean>;
|
|
63
63
|
private readonly membersLoadError;
|
|
64
|
-
readonly membersErrorState: import("@angular/core").Signal<EmptyStateMetadata>;
|
|
65
64
|
readonly membersNextToken: import("@angular/core").WritableSignal<string>;
|
|
66
65
|
readonly loadingMoreMembers: import("@angular/core").WritableSignal<boolean>;
|
|
67
66
|
readonly showAllMembers: import("@angular/core").WritableSignal<boolean>;
|
|
@@ -82,16 +81,12 @@ export declare class OrganizationViewComponent {
|
|
|
82
81
|
readonly viewPermissionsButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
|
|
83
82
|
readonly transferButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
|
|
84
83
|
readonly openInviteButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
|
|
85
|
-
readonly openImportButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
|
|
86
|
-
readonly openApiKeysButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
|
|
87
84
|
/** Guarda para detectar el primer disparo del effect (evita doble carga). */
|
|
88
85
|
private lastLoadedOrgId;
|
|
89
86
|
constructor();
|
|
90
87
|
onEdit(): void;
|
|
91
88
|
onLeave(): Promise<void>;
|
|
92
89
|
onOpenInvite(): void;
|
|
93
|
-
onOpenImport(): void;
|
|
94
|
-
onOpenApiKeys(): void;
|
|
95
90
|
onViewPermissions(): void;
|
|
96
91
|
onOpenTransfer(): void;
|
|
97
92
|
onTransfer(newOwnerId: string): Promise<void>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ButtonMetadata } from '../../types';
|
|
2
|
+
import { PermissionsViewConfig } from './types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
interface PermGroupView {
|
|
5
|
+
key: string;
|
|
6
|
+
label: string;
|
|
7
|
+
perms: string[];
|
|
8
|
+
}
|
|
9
|
+
interface RoleView {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
isSystem: boolean;
|
|
14
|
+
groups: PermGroupView[];
|
|
15
|
+
hasPerms: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `val-permissions-view` — vista Permisos full-feature autocontenida (organism).
|
|
19
|
+
* Visor RBAC de solo lectura: muestra los roles del sistema (Visor/Editor/Admin +
|
|
20
|
+
* roles de plataforma) y los roles personalizados de la org activa, con el
|
|
21
|
+
* catálogo de permisos agrupado por alcance (app actual / plataforma / otras apps).
|
|
22
|
+
* Promovida desde `showcase` bajo el proceso de ADR-021.
|
|
23
|
+
*
|
|
24
|
+
* **RBAC interno** (como `organization-view`): lee la org activa vía
|
|
25
|
+
* `AuthService.user().activeOrgId`. La vista NO muta nada — el control de quién
|
|
26
|
+
* puede verla es responsabilidad del guard de ruta del consumer; no hay gating
|
|
27
|
+
* fino interno ni se expone como config.
|
|
28
|
+
*
|
|
29
|
+
* Datos: `forkJoin` de `OrgService.listOrgRoles(orgId)` (roles de la org) +
|
|
30
|
+
* `PermissionCatalogService.getCatalog(orgId)` (catálogo + appId actual). El
|
|
31
|
+
* catálogo define el alcance (`scope`/`appId`) de cada recurso para agrupar.
|
|
32
|
+
*
|
|
33
|
+
* NO renderiza ion-content — vive dentro de val-page-wrapper. `ActivatedRoute` se
|
|
34
|
+
* inyecta `{ optional: true }` solo para leer el route data de config. Auto-registra
|
|
35
|
+
* sus defaults i18n (es/en) si el consumer no proveyó el namespace (default
|
|
36
|
+
* `Settings.Permissions`).
|
|
37
|
+
*/
|
|
38
|
+
export declare class PermissionsViewComponent {
|
|
39
|
+
private i18n;
|
|
40
|
+
private orgService;
|
|
41
|
+
private catalog;
|
|
42
|
+
private auth;
|
|
43
|
+
private nav;
|
|
44
|
+
private route;
|
|
45
|
+
/**
|
|
46
|
+
* Config vía @Input (object-first). Si no se pasa, se cae al route data
|
|
47
|
+
* `permissionsConfig` (poblado por `provideValtechPermissionsRoutes`).
|
|
48
|
+
* `resolvedConfig` mergea con los defaults — `@Input` gana sobre route data.
|
|
49
|
+
*/
|
|
50
|
+
config?: PermissionsViewConfig;
|
|
51
|
+
readonly resolvedConfig: import("@angular/core").Signal<Required<PermissionsViewConfig>>;
|
|
52
|
+
/** Namespace i18n resuelto (capturado para llamadas no-reactivas). */
|
|
53
|
+
private get ns();
|
|
54
|
+
readonly loading: import("@angular/core").WritableSignal<boolean>;
|
|
55
|
+
readonly loadError: import("@angular/core").WritableSignal<unknown>;
|
|
56
|
+
private readonly roles;
|
|
57
|
+
readonly systemRoles: import("@angular/core").Signal<RoleView[]>;
|
|
58
|
+
readonly customRoles: import("@angular/core").Signal<RoleView[]>;
|
|
59
|
+
readonly activeOrgId: import("@angular/core").Signal<string>;
|
|
60
|
+
readonly retryButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
|
|
61
|
+
constructor();
|
|
62
|
+
load(): void;
|
|
63
|
+
private buildRoleView;
|
|
64
|
+
protected tt(key: string): string;
|
|
65
|
+
appLabel(appId: string): string;
|
|
66
|
+
roleLabel(name: string): string;
|
|
67
|
+
permLabel(resource: string, action: string): string;
|
|
68
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PermissionsViewComponent, never>;
|
|
69
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<PermissionsViewComponent, "val-permissions-view", never, { "config": { "alias": "config"; "required": false; }; }, {}, never, never, true, never>;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { LanguagesContent } from '../../../services/i18n/types';
|
|
2
|
+
/**
|
|
3
|
+
* Defaults i18n (es/en) embebidos en `val-permissions-view`. Auto-registrados en
|
|
4
|
+
* el constructor del componente si el consumer no proveyó el namespace
|
|
5
|
+
* (`Settings.Permissions` por default). SOLO incluye las keys que la vista usa.
|
|
6
|
+
*
|
|
7
|
+
* Portado EXACTO de `PERMISSIONS_I18N` (showcase) bajo el proceso de ADR-021.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PERMISSIONS_VIEW_I18N: LanguagesContent;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Routes } from '@angular/router';
|
|
2
|
+
import { PermissionsViewConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Helper para montar la vista Permisos (`val-permissions-view`) como ruta en una
|
|
5
|
+
* app del factory. El `config` se pasa por route `data` (`permissionsConfig`) y el
|
|
6
|
+
* componente lo lee como fallback de su `@Input() config`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // settings.routes.ts
|
|
11
|
+
* export const settingsRoutes: Routes = [
|
|
12
|
+
* ...provideValtechPermissionsRoutes(), // → /app/settings/permissions
|
|
13
|
+
* { path: 'preferences', loadComponent: () => ... },
|
|
14
|
+
* ];
|
|
15
|
+
*
|
|
16
|
+
* // con config acotada:
|
|
17
|
+
* ...provideValtechPermissionsRoutes({ config: { showCustomRoles: false } }),
|
|
18
|
+
* ...provideValtechPermissionsRoutes({ path: 'roles' }),
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function provideValtechPermissionsRoutes(opts?: {
|
|
22
|
+
path?: string;
|
|
23
|
+
config?: PermissionsViewConfig;
|
|
24
|
+
}): Routes;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuración acotada de `val-permissions-view` (object-first). Tres ejes de
|
|
3
|
+
* variación permitidos — **NADA de slots arbitrarios** (ADR-021: una vista
|
|
4
|
+
* full-feature no abre slots; si falta algo, se promueve un nuevo punto de
|
|
5
|
+
* extensión):
|
|
6
|
+
*
|
|
7
|
+
* - **secciones visibles** — gatean el render de cada bloque (roles del sistema,
|
|
8
|
+
* roles personalizados). El acceso a la vista en sí (¿quién puede ver
|
|
9
|
+
* permisos?) es responsabilidad del guard de ruta del consumer; la vista es
|
|
10
|
+
* de solo lectura y no muta nada, por lo que no hay gating RBAC fino interno —
|
|
11
|
+
* solo lee la org activa vía `AuthService` (como `organization-view`). Estos
|
|
12
|
+
* flags solo permiten ocultar la sección por completo.
|
|
13
|
+
* - **branding** — `i18nNamespace` para resolver los textos (default
|
|
14
|
+
* `'Settings.Permissions'`).
|
|
15
|
+
*/
|
|
16
|
+
export interface PermissionsViewConfig {
|
|
17
|
+
/** Muestra la sección "Roles del sistema". Default `true`. */
|
|
18
|
+
showSystemRoles?: boolean;
|
|
19
|
+
/** Muestra la sección "Roles personalizados". Default `true`. */
|
|
20
|
+
showCustomRoles?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Namespace i18n con el que la vista resuelve sus textos.
|
|
23
|
+
* Default `'Settings.Permissions'`.
|
|
24
|
+
*/
|
|
25
|
+
i18nNamespace?: string;
|
|
26
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Routes } from '@angular/router';
|
|
2
2
|
import { ProfileViewConfig } from '../profile-view/types';
|
|
3
3
|
import { PreferencesViewConfig } from '../preferences-view/types';
|
|
4
|
+
import { SecurityViewConfig } from '../security-view/types';
|
|
5
|
+
import { AccountViewConfig } from '../account-view/types';
|
|
6
|
+
import { OrganizationViewConfig } from '../organization-view/types';
|
|
4
7
|
import { SettingsHubConfig } from './types';
|
|
5
8
|
/**
|
|
6
9
|
* Opciones de `provideValtechSettingsRoutes`. Agrupa el HUB (`val-settings-hub`)
|
|
@@ -17,10 +20,22 @@ export interface ValtechSettingsRoutesOptions {
|
|
|
17
20
|
profileConfig?: ProfileViewConfig;
|
|
18
21
|
/** Config de la vista Preferencias (pass-through a `provideValtechPreferencesRoutes`). */
|
|
19
22
|
preferencesConfig?: PreferencesViewConfig;
|
|
23
|
+
/** Config de la vista Seguridad (pass-through a `provideValtechSecurityRoutes`). */
|
|
24
|
+
securityConfig?: SecurityViewConfig;
|
|
25
|
+
/** Config de la vista Cuenta (pass-through a `provideValtechAccountRoutes`). */
|
|
26
|
+
accountConfig?: AccountViewConfig;
|
|
27
|
+
/** Config de la vista Gestión de organización (pass-through a `provideValtechOrganizationRoutes`). */
|
|
28
|
+
organizationConfig?: OrganizationViewConfig;
|
|
20
29
|
/** Monta la ruta `profile`. Default `true`. */
|
|
21
30
|
includeProfile?: boolean;
|
|
22
31
|
/** Monta la ruta de preferencias. Default `true`. */
|
|
23
32
|
includePreferences?: boolean;
|
|
33
|
+
/** Monta la ruta `security`. Default `true`. */
|
|
34
|
+
includeSecurity?: boolean;
|
|
35
|
+
/** Monta la ruta `account`. Default `true`. */
|
|
36
|
+
includeAccount?: boolean;
|
|
37
|
+
/** Monta la ruta `organization`. Default `true`. */
|
|
38
|
+
includeOrganization?: boolean;
|
|
24
39
|
/** Path de la vista Preferencias. Default `'preferences'`. */
|
|
25
40
|
preferencesPath?: string;
|
|
26
41
|
/** Rutas extra a sumar como hijas (secciones de la app no promovidas). */
|
|
@@ -6,7 +6,7 @@ import { AuthStateService } from './auth-state.service';
|
|
|
6
6
|
import { TokenService } from './token.service';
|
|
7
7
|
import { AuthStorageService } from './storage.service';
|
|
8
8
|
import { AuthSyncService } from './sync.service';
|
|
9
|
-
import { SigninRequest, SigninResponse, SignupRequest, SignupResponse, VerifyEmailRequest, VerifyEmailResponse, ResendCodeRequest, ResendCodeResponse, MFAVerifyResponse, RefreshResponse, GetPermissionsResponse, GetProfileResponse, UpdateProfileRequest, UpdateProfileResponse, MFASetupResponse, MFAConfirmResponse, MFADisableRequest, MFADisableResponse, ForgotPasswordRequest, ForgotPasswordResponse, ResetPasswordRequest, ResetPasswordResponse,
|
|
9
|
+
import { SigninRequest, SigninResponse, SignupRequest, SignupResponse, VerifyEmailRequest, VerifyEmailResponse, ResendCodeRequest, ResendCodeResponse, MFAVerifyResponse, RefreshResponse, GetPermissionsResponse, GetProfileResponse, UpdateProfileRequest, UpdateProfileResponse, MFASetupResponse, MFAConfirmResponse, MFADisableRequest, MFADisableResponse, ForgotPasswordRequest, ForgotPasswordResponse, ResetPasswordRequest, ResetPasswordResponse, ChangePasswordResponse, DeleteAccountResponse, SendDeleteAccountCodeResponse, SwitchOrgResponse, MFAMethod, AuthError, ValtechAuthConfig, EnableNotificationsResult, NotificationPermissionState, RegisterDeviceResult, TOTPSetupResponse, TOTPVerifySetupResponse, TOTPDisableResponse, RegenerateBackupCodesResponse, BackupCodesCountResponse, OAuthProvider, LinkedProvider, HasPasswordResponse, UpdateHandleResponse, CheckHandleResponse, UpdateAvatarRequest, UpdateAvatarResponse, InitiateEmailChangeResponse, ConfirmEmailChangeStep1Response, ConfirmEmailChangeStep2Response } from './types';
|
|
10
10
|
import { OAuthService } from './oauth.service';
|
|
11
11
|
import { FirebaseService, MessagingService } from '../firebase';
|
|
12
12
|
import { I18nService } from '../i18n';
|
|
@@ -288,12 +288,6 @@ export declare class AuthService implements OnDestroy {
|
|
|
288
288
|
* Resetea la contraseña usando el código enviado por email.
|
|
289
289
|
*/
|
|
290
290
|
resetPassword(request: ResetPasswordRequest): Observable<ResetPasswordResponse>;
|
|
291
|
-
/**
|
|
292
|
-
* Activa una cuenta pre-aprovisionada por una organización (ADR-023): define
|
|
293
|
-
* la contraseña con el token del enlace de email. En éxito el backend devuelve
|
|
294
|
-
* tokens de auto-signin → el usuario queda logueado (mismo flujo que verify-email).
|
|
295
|
-
*/
|
|
296
|
-
activateAccount(request: ActivateAccountRequest): Observable<ActivateAccountResponse>;
|
|
297
291
|
/**
|
|
298
292
|
* Cambia la contraseña del usuario autenticado.
|
|
299
293
|
* Requiere la contraseña actual para verificación.
|
|
@@ -238,29 +238,6 @@ export interface VerifyEmailResponse {
|
|
|
238
238
|
expiresIn?: number;
|
|
239
239
|
tokenType?: string;
|
|
240
240
|
}
|
|
241
|
-
/**
|
|
242
|
-
* Request para activar una cuenta pre-aprovisionada por una organización
|
|
243
|
-
* (ADR-023): el usuario define su contraseña con el token del enlace de email.
|
|
244
|
-
*/
|
|
245
|
-
export interface ActivateAccountRequest {
|
|
246
|
-
token: string;
|
|
247
|
-
newPassword: string;
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Response de activación de cuenta. En éxito incluye tokens de auto-signin
|
|
251
|
-
* (mismo shape que verify-email) — el usuario queda logueado tras activar.
|
|
252
|
-
*/
|
|
253
|
-
export interface ActivateAccountResponse {
|
|
254
|
-
operationId: string;
|
|
255
|
-
activated: boolean;
|
|
256
|
-
accessToken?: string;
|
|
257
|
-
refreshToken?: string;
|
|
258
|
-
firebaseToken?: string;
|
|
259
|
-
expiresIn?: number;
|
|
260
|
-
tokenType?: string;
|
|
261
|
-
roles?: string[];
|
|
262
|
-
permissions?: string[];
|
|
263
|
-
}
|
|
264
241
|
/**
|
|
265
242
|
* Request para reenviar código de verificación.
|
|
266
243
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HttpClient } from '@angular/common/http';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { ValtechAuthConfig } from '../auth/types';
|
|
4
|
-
import { Organization, ListMyOrgsResponse, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListOrgMembersResponse, OrgRole, ChangeMemberRoleResponse, PendingInvitation, AcceptInvitationResponse
|
|
4
|
+
import { Organization, ListMyOrgsResponse, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListOrgMembersResponse, OrgRole, ChangeMemberRoleResponse, PendingInvitation, AcceptInvitationResponse } from './types';
|
|
5
5
|
import * as i0 from "@angular/core";
|
|
6
6
|
export declare class OrgService {
|
|
7
7
|
private config;
|
|
@@ -21,11 +21,6 @@ export declare class OrgService {
|
|
|
21
21
|
message: string;
|
|
22
22
|
}>;
|
|
23
23
|
inviteUser(orgId: string, req: InviteUserRequest): Observable<InviteUserResponse>;
|
|
24
|
-
/**
|
|
25
|
-
* Crea/asigna miembros en masa (ADR-023). Resultado por-fila (partial success):
|
|
26
|
-
* `created` (pre-aprovisionado), `assigned` (ya existía), `skipped`, `error`.
|
|
27
|
-
*/
|
|
28
|
-
importMembers(orgId: string, req: ImportMembersRequest): Observable<ImportMembersResponse>;
|
|
29
24
|
leaveOrg(orgId: string): Observable<LeaveOrgResponse>;
|
|
30
25
|
getOrgMembers(orgId: string, params?: {
|
|
31
26
|
limit?: number;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HttpClient } from '@angular/common/http';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { ValtechAuthConfig } from '../auth/types';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export type PermissionScope = 'global' | 'app';
|
|
6
|
+
export interface PermissionResource {
|
|
7
|
+
resource: string;
|
|
8
|
+
scope: PermissionScope;
|
|
9
|
+
appId?: string;
|
|
10
|
+
actions: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface PermissionCatalogResponse {
|
|
13
|
+
operationId: string;
|
|
14
|
+
appId: string;
|
|
15
|
+
permissions: PermissionResource[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Consume el catálogo de permisos del backend (`GET /org/{orgId}/permissions-catalog`).
|
|
19
|
+
* El backend es la fuente de verdad de qué permisos existen y de su alcance
|
|
20
|
+
* (globales de plataforma vs. propios de una app). La respuesta incluye el
|
|
21
|
+
* `appId` del request para que la vista distinga la app actual.
|
|
22
|
+
*
|
|
23
|
+
* Promovido desde `showcase` a la lib bajo el proceso de ADR-021. Usa
|
|
24
|
+
* `VALTECH_AUTH_CONFIG.apiUrl` (como `OrgService`) en vez del `environment` de la
|
|
25
|
+
* app — la lib no importa el environment del consumer.
|
|
26
|
+
*/
|
|
27
|
+
export declare class PermissionCatalogService {
|
|
28
|
+
private config;
|
|
29
|
+
private http;
|
|
30
|
+
constructor(config: ValtechAuthConfig, http: HttpClient);
|
|
31
|
+
getCatalog(orgId: string): Observable<PermissionCatalogResponse>;
|
|
32
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PermissionCatalogService, never>;
|
|
33
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<PermissionCatalogService>;
|
|
34
|
+
}
|
|
@@ -97,33 +97,3 @@ export interface ChangeMemberRoleResponse {
|
|
|
97
97
|
orgId: string;
|
|
98
98
|
roleId: string;
|
|
99
99
|
}
|
|
100
|
-
export type ImportOnConflict = 'assignRole' | 'skip' | 'error';
|
|
101
|
-
export interface ImportUserRow {
|
|
102
|
-
email: string;
|
|
103
|
-
name?: string;
|
|
104
|
-
roleName: string;
|
|
105
|
-
}
|
|
106
|
-
export interface ImportMembersRequest {
|
|
107
|
-
users: ImportUserRow[];
|
|
108
|
-
onConflict?: ImportOnConflict;
|
|
109
|
-
sendActivation?: boolean;
|
|
110
|
-
}
|
|
111
|
-
export type ImportRowStatus = 'created' | 'assigned' | 'skipped' | 'error';
|
|
112
|
-
export interface ImportRowResult {
|
|
113
|
-
email: string;
|
|
114
|
-
status: ImportRowStatus;
|
|
115
|
-
userId?: string;
|
|
116
|
-
activation?: 'sent' | 'pending';
|
|
117
|
-
reason?: string;
|
|
118
|
-
}
|
|
119
|
-
export interface ImportSummary {
|
|
120
|
-
created: number;
|
|
121
|
-
assigned: number;
|
|
122
|
-
skipped: number;
|
|
123
|
-
failed: number;
|
|
124
|
-
}
|
|
125
|
-
export interface ImportMembersResponse {
|
|
126
|
-
operationId: string;
|
|
127
|
-
summary: ImportSummary;
|
|
128
|
-
results: ImportRowResult[];
|
|
129
|
-
}
|
package/lib/version.d.ts
CHANGED
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -287,6 +287,13 @@ export * from './lib/components/organisms/organization-view/organization.routes'
|
|
|
287
287
|
export * from './lib/components/organisms/notifications-view/notifications-view.component';
|
|
288
288
|
export * from './lib/components/organisms/notifications-view/types';
|
|
289
289
|
export * from './lib/components/organisms/notifications-view/notifications.routes';
|
|
290
|
+
export * from './lib/components/organisms/notification-preferences-view/notification-preferences-view.component';
|
|
291
|
+
export * from './lib/components/organisms/notification-preferences-view/types';
|
|
292
|
+
export * from './lib/components/organisms/notification-preferences-view/notification-preferences.routes';
|
|
293
|
+
export * from './lib/components/organisms/permissions-view/permissions-view.component';
|
|
294
|
+
export * from './lib/components/organisms/permissions-view/types';
|
|
295
|
+
export * from './lib/components/organisms/permissions-view/permissions.routes';
|
|
296
|
+
export * from './lib/services/org/permission-catalog.service';
|
|
290
297
|
export * from './lib/components/organisms/delete-account-modal/delete-account-modal.component';
|
|
291
298
|
export * from './lib/components/organisms/switch-org-modal/switch-org-modal.component';
|
|
292
299
|
export * from './lib/components/organisms/create-org-modal/create-org-modal.component';
|
|
@@ -294,8 +301,6 @@ export * from './lib/components/organisms/org-info-sheet/org-info-sheet.componen
|
|
|
294
301
|
export * from './lib/components/organisms/invite-member-modal/invite-member-modal.component';
|
|
295
302
|
export * from './lib/components/organisms/member-detail-modal/member-detail-modal.component';
|
|
296
303
|
export * from './lib/components/organisms/member-detail-modal/types';
|
|
297
|
-
export * from './lib/components/organisms/member-import-modal/member-import-modal.component';
|
|
298
|
-
export * from './lib/components/organisms/api-keys-modal/api-keys-modal.component';
|
|
299
304
|
export * from './lib/components/organisms/edit-org-modal/edit-org-modal.component';
|
|
300
305
|
export * from './lib/components/organisms/transfer-ownership-modal/transfer-ownership-modal.component';
|
|
301
306
|
export * from './lib/components/organisms/transfer-ownership-modal/types';
|
|
@@ -342,9 +347,7 @@ export * from './lib/services/legal-link/legal-link.service';
|
|
|
342
347
|
export * from './lib/services/firebase';
|
|
343
348
|
export * from './lib/services/auth';
|
|
344
349
|
export { OrgService } from './lib/services/org/org.service';
|
|
345
|
-
export type { Organization, OrgType, OrgPlan, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListMyOrgsResponse, OrgResponse, OrgMember, ListOrgMembersResponse, PendingInvitation, ListPendingInvitationsResponse, AcceptInvitationResponse, OrgRole, ListOrgRolesResponse, ChangeMemberRoleRequest, ChangeMemberRoleResponse,
|
|
346
|
-
export { ApiKeyService } from './lib/services/apikeys/api-keys.service';
|
|
347
|
-
export type { ClientApiKey, ClientApiKeyWithSecret, CreateApiKeyRequest, CreateApiKeyResponse, ListApiKeysResponse, AvailablePermissionsResponse, RevokeApiKeyResponse, } from './lib/services/apikeys/types';
|
|
350
|
+
export type { Organization, OrgType, OrgPlan, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListMyOrgsResponse, OrgResponse, OrgMember, ListOrgMembersResponse, PendingInvitation, ListPendingInvitationsResponse, AcceptInvitationResponse, OrgRole, ListOrgRolesResponse, ChangeMemberRoleRequest, ChangeMemberRoleResponse, } from './lib/services/org/types';
|
|
348
351
|
export * from './lib/services/i18n';
|
|
349
352
|
export * from './lib/services/preferences';
|
|
350
353
|
export * from './lib/services/network-status';
|