valtech-components 2.0.1009 → 2.0.1011

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.
Files changed (42) hide show
  1. package/esm2022/lib/components/molecules/date-input/date-input.component.mjs +38 -18
  2. package/esm2022/lib/components/organisms/about-view/about-view.component.mjs +436 -0
  3. package/esm2022/lib/components/organisms/about-view/about-view.i18n.mjs +61 -0
  4. package/esm2022/lib/components/organisms/about-view/about.routes.mjs +36 -0
  5. package/esm2022/lib/components/organisms/about-view/types.mjs +19 -0
  6. package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.component.mjs +385 -0
  7. package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.mjs +63 -0
  8. package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.component.mjs +313 -0
  9. package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.i18n.mjs +63 -0
  10. package/esm2022/lib/components/organisms/organization-view/organization-view.component.mjs +141 -3
  11. package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +21 -1
  12. package/esm2022/lib/services/apikeys/api-keys.service.mjs +46 -0
  13. package/esm2022/lib/services/apikeys/types.mjs +7 -0
  14. package/esm2022/lib/services/auth/auth.service.mjs +14 -1
  15. package/esm2022/lib/services/auth/types.mjs +1 -1
  16. package/esm2022/lib/services/org/org.service.mjs +8 -1
  17. package/esm2022/lib/services/org/types.mjs +1 -1
  18. package/esm2022/lib/services/page-refresh/page-refresh.service.mjs +15 -4
  19. package/esm2022/lib/version.mjs +2 -2
  20. package/esm2022/public-api.mjs +7 -1
  21. package/fesm2022/valtech-components.mjs +1913 -330
  22. package/fesm2022/valtech-components.mjs.map +1 -1
  23. package/lib/components/molecules/date-input/date-input.component.d.ts +16 -0
  24. package/lib/components/organisms/about-view/about-view.component.d.ts +88 -0
  25. package/lib/components/organisms/about-view/about-view.i18n.d.ts +14 -0
  26. package/lib/components/organisms/about-view/about.routes.d.ts +31 -0
  27. package/lib/components/organisms/about-view/types.d.ts +76 -0
  28. package/lib/components/organisms/api-keys-modal/api-keys-modal.component.d.ts +44 -0
  29. package/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.d.ts +6 -0
  30. package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +47 -0
  31. package/lib/components/organisms/member-import-modal/member-import-modal.i18n.d.ts +6 -0
  32. package/lib/components/organisms/organization-view/organization-view.component.d.ts +6 -0
  33. package/lib/services/apikeys/api-keys.service.d.ts +25 -0
  34. package/lib/services/apikeys/types.d.ts +46 -0
  35. package/lib/services/auth/auth.service.d.ts +7 -1
  36. package/lib/services/auth/types.d.ts +23 -0
  37. package/lib/services/org/org.service.d.ts +6 -1
  38. package/lib/services/org/types.d.ts +30 -0
  39. package/lib/services/page-refresh/page-refresh.service.d.ts +10 -2
  40. package/lib/version.d.ts +1 -1
  41. package/package.json +1 -1
  42. package/public-api.d.ts +8 -1
@@ -30,6 +30,22 @@ export declare class DateInputComponent implements OnInit, OnChanges {
30
30
  get cancelText(): string;
31
31
  /** Presentación del datetime (default: date). */
32
32
  get presentation(): string;
33
+ /** Locale del datetime — honra el prop del consumer (default es-ES). */
34
+ get datetimeLocale(): string;
35
+ /** Primer día de la semana — honra el prop del consumer (default lunes). */
36
+ get firstDayOfWeek(): number;
37
+ /**
38
+ * Opciones de formato para `ion-datetime` (binding, NO string). Honra el prop
39
+ * del consumer y cae a un default sensato (date medium / time short).
40
+ */
41
+ get datetimeFormatOptions(): {
42
+ date?: {
43
+ dateStyle?: 'full' | 'long' | 'medium' | 'short';
44
+ };
45
+ time?: {
46
+ timeStyle?: 'full' | 'long' | 'medium' | 'short';
47
+ };
48
+ };
33
49
  /** Texto del trigger cuando NO hay valor (placeholder explícito o default i18n). */
34
50
  get placeholderText(): string;
35
51
  /** Id del trigger/datetime — estable; se garantiza no vacío en resolveProps. */
@@ -0,0 +1,88 @@
1
+ import { ActionCardMetadata } from '../../molecules/action-card/types';
2
+ import { TitleMetadata } from '../../atoms/title/types';
3
+ import { AboutAction, AboutViewConfig } from './types';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * `val-about-view` — vista About full-feature autocontenida (organism).
7
+ * Promovida desde `showcase` bajo el proceso de ADR-021. Reúne:
8
+ * - **HERO** — logo + nombre de marca + tagline + pill de versión (copiable).
9
+ * - **Descripción** — título + cuerpo.
10
+ * - **Acciones** — action-card de rating built-in (abre `val-content-reaction`
11
+ * DIRECTAMENTE vía `ModalService`, sin wrapper local — decisión CTO) + las
12
+ * acciones genéricas que el consumer aporte por `config.actions`.
13
+ * - **Redes** — links sociales (`config.socialLinks`); sección oculta si vacía.
14
+ * - **Footer** — copyright con el año actual.
15
+ *
16
+ * Lo app-specific (logo, nombre, versión, redes, acciones share/faq) viaja como
17
+ * DATA de config — NO como slots (ADR-021). La versión la pasa el consumer
18
+ * (`config.version` = su `APP_VERSION`); la lib NO importa el `version.ts` de la
19
+ * app. Si no se pasa versión, el pill se oculta.
20
+ *
21
+ * NO renderiza ion-content — vive dentro de val-page-wrapper. `ActivatedRoute`
22
+ * se inyecta `{ optional: true }` solo para leer el route data de config.
23
+ *
24
+ * Auto-registra sus defaults i18n (es/en) en el constructor si el consumer no
25
+ * proveyó el namespace configurado (default `Settings.About`).
26
+ *
27
+ * GOTCHA i18n ContentReaction: `val-content-reaction` exige su namespace
28
+ * `ContentReaction` registrado donde se use (key faltante en binding + CD =
29
+ * navegador congelado en dev). `ContentReactionComponent` se auto-registra ese
30
+ * namespace en SU constructor, y como se abre vía `ModalService` ese constructor
31
+ * corre antes de que su template binde — queda cubierto. Igual lo importamos
32
+ * como dependencia explícita de esta vista para que la garantía sea local.
33
+ */
34
+ export declare class AboutViewComponent {
35
+ private nav;
36
+ private i18n;
37
+ private modalService;
38
+ private toast;
39
+ private route;
40
+ /**
41
+ * Config vía @Input (object-first). Si no se pasa, se cae al route data
42
+ * `aboutConfig` (poblado por `provideValtechAboutRoutes`). `resolvedConfig`
43
+ * mergea con los defaults — `@Input` gana sobre route data.
44
+ */
45
+ config?: AboutViewConfig;
46
+ readonly resolvedConfig: import("@angular/core").Signal<Required<Omit<AboutViewConfig, "onRated">> & Pick<AboutViewConfig, "onRated">>;
47
+ /** Namespace i18n resuelto (capturado para llamadas no-reactivas). */
48
+ private get ns();
49
+ readonly brandName: import("@angular/core").Signal<string>;
50
+ readonly logoSrc: import("@angular/core").Signal<string>;
51
+ readonly version: import("@angular/core").Signal<string>;
52
+ readonly socialLinks: import("@angular/core").Signal<{
53
+ icon: string;
54
+ url: string;
55
+ label: string;
56
+ }[]>;
57
+ readonly showRating: import("@angular/core").Signal<boolean>;
58
+ readonly actions: import("@angular/core").Signal<AboutAction[]>;
59
+ /** Copyright del footer — año actual interpolado en `copyrightText`. */
60
+ readonly copyright: import("@angular/core").Signal<string>;
61
+ /** Title metadata para secciones — bold + size small. */
62
+ readonly rateActionCard: import("@angular/core").Signal<ActionCardMetadata>;
63
+ constructor();
64
+ /** Helper i18n bound al namespace resuelto. Reactivo vía `lang()`. */
65
+ protected tt(key: string): string;
66
+ /** Title metadata para secciones — bold + size small. */
67
+ protected sectionTitle(key: string): TitleMetadata;
68
+ /** ActionCardMetadata para una acción genérica del consumer. */
69
+ protected extraActionCard(action: AboutAction): ActionCardMetadata;
70
+ /** Copia la versión al portapapeles + toast (color dark). */
71
+ copyVersion(): Promise<void>;
72
+ /** Abre una URL externa en nueva tab. `mailto:` queda en la misma tab. */
73
+ openUrl(url: string): void;
74
+ /**
75
+ * "Calificar la app" — abre `val-content-reaction` DIRECTAMENTE como sheet
76
+ * modal (sin wrapper local — decisión CTO). El componente persiste la reacción
77
+ * contra el backend de feedback y muestra su propio estado de "gracias"; el
78
+ * sheet se cierra arrastrando (breakpoint 0). El namespace i18n
79
+ * `ContentReaction` lo auto-registra `ContentReactionComponent` en su
80
+ * constructor, que corre al crear el modal — sin riesgo de key faltante.
81
+ *
82
+ * Sheet (bottom sheet): el contenido scrollea dentro y el botón "Enviar" queda
83
+ * siempre alcanzable, también en viewports chicos.
84
+ */
85
+ openRating(): Promise<void>;
86
+ static ɵfac: i0.ɵɵFactoryDeclaration<AboutViewComponent, never>;
87
+ static ɵcmp: i0.ɵɵComponentDeclaration<AboutViewComponent, "val-about-view", never, { "config": { "alias": "config"; "required": false; }; }, {}, never, never, true, never>;
88
+ }
@@ -0,0 +1,14 @@
1
+ import { LanguagesContent } from '../../../services/i18n/types';
2
+ /**
3
+ * Defaults i18n (es/en) embebidos en `val-about-view`. Auto-registrados en el
4
+ * constructor del componente si el consumer no proveyó el namespace
5
+ * (`Settings.About` por default). SOLO incluye las keys que la vista usa.
6
+ *
7
+ * Textos portados EXACTOS del override `Settings.About` de showcase
8
+ * (`frontend/showcase/src/i18n/index.ts`). Las keys de las acciones
9
+ * showcase-specific (`feedback*`, `share*`, `faq*`, `donate*`) NO se incluyen:
10
+ * esas acciones se modelan ahora como `actions[]` de la config (el consumer
11
+ * aporta sus propios textos). `copyrightText` se incluye aquí (antes salía del
12
+ * namespace `Layout`) para que la vista sea autocontenida.
13
+ */
14
+ export declare const ABOUT_VIEW_I18N: LanguagesContent;
@@ -0,0 +1,31 @@
1
+ import { Routes } from '@angular/router';
2
+ import { AboutViewConfig } from './types';
3
+ /**
4
+ * Helper para montar la vista About (`val-about-view`) como ruta en una app del
5
+ * factory. El `config` se pasa por route `data` (`aboutConfig`) y el componente
6
+ * lo lee como fallback de su `@Input() config` (el `@Input` gana).
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // settings.routes.ts
11
+ * import { APP_VERSION } from '../version';
12
+ *
13
+ * export const settingsRoutes: Routes = [
14
+ * ...provideValtechAboutRoutes({ config: { version: APP_VERSION } }), // → /app/about
15
+ * { path: 'preferences', loadComponent: () => ... },
16
+ * ];
17
+ *
18
+ * // con redes y acciones extra:
19
+ * ...provideValtechAboutRoutes({
20
+ * config: {
21
+ * version: APP_VERSION,
22
+ * socialLinks: VALTECH_SOCIAL_LINKS.map(s => ({ icon: s.icon, url: s.url, label: s.name })),
23
+ * actions: [{ label: 'Compartir', icon: 'share-social-outline', onClick: () => share() }],
24
+ * },
25
+ * }),
26
+ * ```
27
+ */
28
+ export declare function provideValtechAboutRoutes(opts?: {
29
+ path?: string;
30
+ config?: AboutViewConfig;
31
+ }): Routes;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Configuración acotada de `val-about-view` (object-first). La vista About es
3
+ * app-specific por naturaleza (logo, nombre, versión, redes, acciones extra),
4
+ * así que lo propio de cada app se parametriza como **DATA de config** — NO como
5
+ * slots arbitrarios (ADR-021: una vista full-feature no abre slots; si falta
6
+ * algo, se promueve un nuevo punto de extensión).
7
+ *
8
+ * Ejes de variación permitidos:
9
+ * - **branding** — `brand.name` / `brand.logoSrc` (qué muestra el HERO).
10
+ * - **versión** — `version` la pasa el consumer (la lib NO puede importar el
11
+ * `version.ts` de la app). Si no se pasa, se oculta el pill de versión.
12
+ * - **redes** — `socialLinks`; si está vacío se oculta la sección social.
13
+ * - **rating** — `showRating` + `ratingEntityId` + `onRated`.
14
+ * - **acciones extra** — `actions[]` genéricas que el consumer agrega junto a
15
+ * la acción de rating built-in.
16
+ * - **branding i18n** — `i18nNamespace` (default `'Settings.About'`).
17
+ */
18
+ /** Marca a mostrar en el HERO (logo + nombre). */
19
+ export interface AboutBrand {
20
+ /** Nombre de la marca. Default `'Valtech'`. */
21
+ name?: string;
22
+ /** Ruta del logo. Default `'assets/images/main-icon.png'`. */
23
+ logoSrc?: string;
24
+ }
25
+ /**
26
+ * Acción genérica extra de la sección "Acciones" (además del rating built-in).
27
+ * El consumer la modela completa (label/descripción/ícono + handler). Las
28
+ * acciones share/faq de showcase NO son genéricas (Web Share API y ruta interna
29
+ * de la app), por eso se exponen como `actions` para que cada app aporte las
30
+ * suyas en vez de hardcodearlas en la lib.
31
+ */
32
+ export interface AboutAction {
33
+ /** Texto principal de la action-card. */
34
+ label: string;
35
+ /** Texto secundario (opcional). */
36
+ description?: string;
37
+ /** Ionicon name (ej. `'share-social-outline'`). */
38
+ icon?: string;
39
+ /** Handler del click. */
40
+ onClick: () => void;
41
+ }
42
+ export interface AboutViewConfig {
43
+ /** Marca del HERO (logo + nombre). Default Valtech. */
44
+ brand?: AboutBrand;
45
+ /**
46
+ * Versión a mostrar en el pill (el consumer pasa su `APP_VERSION`). La lib NO
47
+ * importa el `version.ts` de la app. Si no se pasa, el pill de versión se
48
+ * oculta.
49
+ */
50
+ version?: string;
51
+ /**
52
+ * Redes sociales. Si está vacío (o no se pasa), la sección social se oculta.
53
+ * `icon` = ionicon name; `url` = destino; `label` = aria-label.
54
+ */
55
+ socialLinks?: {
56
+ icon: string;
57
+ url: string;
58
+ label: string;
59
+ }[];
60
+ /** Muestra la action-card de rating built-in. Default `true`. */
61
+ showRating?: boolean;
62
+ /**
63
+ * `entityId` del `entityRef` que recibe `val-content-reaction` al calificar
64
+ * (el `entityType` es siempre `'app'`). Default `'experience'`.
65
+ */
66
+ ratingEntityId?: string;
67
+ /** Acciones genéricas extra de la sección "Acciones". Default `[]`. */
68
+ actions?: AboutAction[];
69
+ /**
70
+ * Namespace i18n con el que la vista resuelve sus textos.
71
+ * Default `'Settings.About'`.
72
+ */
73
+ i18nNamespace?: string;
74
+ /** Hook tras enviar la calificación (rating) desde `val-content-reaction`. */
75
+ onRated?: () => void;
76
+ }
@@ -0,0 +1,44 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { ClientApiKey, ClientApiKeyWithSecret } from '../../../services/apikeys/types';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * `val-api-keys-modal` — gestión de Client API Keys org-scopeadas (ADR-023 fase 6).
6
+ *
7
+ * Lista las keys de la org, permite crear (mostrando el secreto UNA vez con copia)
8
+ * y revocar. Pensado para habilitar integraciones M2M del import de miembros, pero
9
+ * sirve a cualquier permiso del catálogo. Header canónico (Regla #5).
10
+ */
11
+ export declare class ApiKeysModalComponent implements OnInit {
12
+ private i18n;
13
+ private apiKeys;
14
+ /** Inyectado por `ModalService.open`. */
15
+ _modalRef?: {
16
+ dismiss: (data?: unknown, role?: string) => void;
17
+ };
18
+ /** Namespace i18n. */
19
+ i18nNamespace: string;
20
+ readonly keys: import("@angular/core").WritableSignal<ClientApiKey[]>;
21
+ readonly availablePermissions: import("@angular/core").WritableSignal<string[]>;
22
+ readonly loading: import("@angular/core").WritableSignal<boolean>;
23
+ readonly showCreate: import("@angular/core").WritableSignal<boolean>;
24
+ readonly submitting: import("@angular/core").WritableSignal<boolean>;
25
+ readonly errorMsg: import("@angular/core").WritableSignal<string>;
26
+ readonly secret: import("@angular/core").WritableSignal<ClientApiKeyWithSecret>;
27
+ readonly copied: import("@angular/core").WritableSignal<boolean>;
28
+ name: string;
29
+ expiresInDays: number | null;
30
+ readonly selectedPerms: import("@angular/core").WritableSignal<Set<string>>;
31
+ constructor();
32
+ ngOnInit(): void;
33
+ private refresh;
34
+ openCreate(): void;
35
+ togglePerm(perm: string, ev: Event): void;
36
+ submit(): void;
37
+ revoke(key: ClientApiKey): void;
38
+ copy(secret: string): Promise<void>;
39
+ finishSecret(): void;
40
+ dismiss(): void;
41
+ t(key: string): string;
42
+ static ɵfac: i0.ɵɵFactoryDeclaration<ApiKeysModalComponent, never>;
43
+ static ɵcmp: i0.ɵɵComponentDeclaration<ApiKeysModalComponent, "val-api-keys-modal", never, { "_modalRef": { "alias": "_modalRef"; "required": false; }; "i18nNamespace": { "alias": "i18nNamespace"; "required": false; }; }, {}, never, never, true, never>;
44
+ }
@@ -0,0 +1,6 @@
1
+ import { LanguagesContent } from '../../../services/i18n/types';
2
+ /**
3
+ * Defaults i18n (es/en) embebidos en `val-api-keys-modal` (ADR-023).
4
+ * Auto-registrados si el consumer no proveyó el namespace `Settings.ApiKeysModal`.
5
+ */
6
+ export declare const API_KEYS_MODAL_I18N: LanguagesContent;
@@ -0,0 +1,47 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { ImportMembersResponse, ImportOnConflict, ImportRowResult } from '../../../services/org/types';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * `val-member-import-modal` — panel de carga masiva de miembros (ADR-023 fase 6).
6
+ *
7
+ * El admin pega un CSV (`email,nombre,rol`); el modal lo parsea a filas y llama
8
+ * `OrgService.importMembers`. Muestra el resultado por-fila (partial success):
9
+ * `created` / `assigned` / `skipped` / `error`. Header canónico (Regla #5).
10
+ *
11
+ * Auto-registra defaults i18n (es/en) en `Settings.ImportModal`.
12
+ */
13
+ export declare class MemberImportModalComponent implements OnInit {
14
+ private i18n;
15
+ private orgService;
16
+ /** Org destino del import. */
17
+ orgId: string;
18
+ /** Nombres de roles disponibles (para el hint). Opcional. */
19
+ availableRoles: string[];
20
+ /** Callback tras una importación exitosa (≥1 fila procesada) — refresca la lista. */
21
+ onSuccess?: () => void;
22
+ /** Inyectado por `ModalService.open`. */
23
+ _modalRef?: {
24
+ dismiss: (data?: unknown, role?: string) => void;
25
+ };
26
+ /** Namespace i18n. */
27
+ i18nNamespace: string;
28
+ csv: string;
29
+ onConflict: ImportOnConflict;
30
+ sendActivation: boolean;
31
+ readonly submitting: import("@angular/core").WritableSignal<boolean>;
32
+ readonly errorMsg: import("@angular/core").WritableSignal<string>;
33
+ readonly results: import("@angular/core").WritableSignal<ImportMembersResponse>;
34
+ readonly rolesHint: import("@angular/core").Signal<string>;
35
+ readonly summaryLabel: import("@angular/core").Signal<string>;
36
+ constructor();
37
+ ngOnInit(): void;
38
+ /** Parsea el CSV pegado a filas {email,name,roleName}. Tolera header. */
39
+ private parseCsv;
40
+ submit(): void;
41
+ statusLabel(r: ImportRowResult): string;
42
+ reset(): void;
43
+ dismiss(): void;
44
+ t(key: string): string;
45
+ static ɵfac: i0.ɵɵFactoryDeclaration<MemberImportModalComponent, never>;
46
+ static ɵcmp: i0.ɵɵComponentDeclaration<MemberImportModalComponent, "val-member-import-modal", never, { "orgId": { "alias": "orgId"; "required": false; }; "availableRoles": { "alias": "availableRoles"; "required": false; }; "onSuccess": { "alias": "onSuccess"; "required": false; }; "_modalRef": { "alias": "_modalRef"; "required": false; }; "i18nNamespace": { "alias": "i18nNamespace"; "required": false; }; }, {}, never, never, true, never>;
47
+ }
@@ -0,0 +1,6 @@
1
+ import { LanguagesContent } from '../../../services/i18n/types';
2
+ /**
3
+ * Defaults i18n (es/en) embebidos en `val-member-import-modal` (ADR-023).
4
+ * Auto-registrados si el consumer no proveyó el namespace `Settings.ImportModal`.
5
+ */
6
+ export declare const MEMBER_IMPORT_MODAL_I18N: LanguagesContent;
@@ -61,6 +61,7 @@ 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>;
64
65
  readonly membersNextToken: import("@angular/core").WritableSignal<string>;
65
66
  readonly loadingMoreMembers: import("@angular/core").WritableSignal<boolean>;
66
67
  readonly showAllMembers: import("@angular/core").WritableSignal<boolean>;
@@ -81,12 +82,17 @@ export declare class OrganizationViewComponent {
81
82
  readonly viewPermissionsButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
82
83
  readonly transferButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
83
84
  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>>;
84
87
  /** Guarda para detectar el primer disparo del effect (evita doble carga). */
85
88
  private lastLoadedOrgId;
86
89
  constructor();
87
90
  onEdit(): void;
88
91
  onLeave(): Promise<void>;
89
92
  onOpenInvite(): void;
93
+ onOpenImport(): void;
94
+ onOpenApiKeys(): void;
95
+ onOrgInfo(): void;
90
96
  onViewPermissions(): void;
91
97
  onOpenTransfer(): void;
92
98
  onTransfer(newOwnerId: string): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { Observable } from 'rxjs';
3
+ import { ValtechAuthConfig } from '../auth/types';
4
+ import { ClientApiKey, CreateApiKeyRequest, CreateApiKeyResponse, RevokeApiKeyResponse } from './types';
5
+ import * as i0 from "@angular/core";
6
+ /**
7
+ * Cliente HTTP de Client API Keys org-scopeadas (ADR-023). La org activa se
8
+ * resuelve en backend desde el JWT, así que el path no la incluye.
9
+ */
10
+ export declare class ApiKeyService {
11
+ private config;
12
+ private http;
13
+ constructor(config: ValtechAuthConfig, http: HttpClient);
14
+ private get baseUrl();
15
+ /** Lista las API keys de la org activa. */
16
+ list(): Observable<ClientApiKey[]>;
17
+ /** Crea una API key. La respuesta incluye el secreto (se muestra UNA vez). */
18
+ create(req: CreateApiKeyRequest): Observable<CreateApiKeyResponse>;
19
+ /** Revoca (elimina) una API key por id. */
20
+ revoke(keyId: string): Observable<RevokeApiKeyResponse>;
21
+ /** Catálogo de permisos asignables a una key. */
22
+ availablePermissions(): Observable<string[]>;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<ApiKeyService, never>;
24
+ static ɵprov: i0.ɵɵInjectableDeclaration<ApiKeyService>;
25
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Tipos de Client API Keys org-scopeadas (ADR-023). Contrato espejo de
3
+ * `lambdas/org` `/org/api-keys/*`. El orgID se resuelve del JWT (ActiveOrgID),
4
+ * no va en el path.
5
+ */
6
+ export interface ClientApiKey {
7
+ keyId: string;
8
+ name: string;
9
+ organizationId: string;
10
+ status: string;
11
+ permissions: string[];
12
+ rateLimit?: number;
13
+ expiresAt?: string;
14
+ allowedIps?: string[];
15
+ createdBy: string;
16
+ createdAt: string;
17
+ lastUsedAt?: string;
18
+ }
19
+ /** Solo en la respuesta de creación: el secreto se muestra UNA vez. */
20
+ export interface ClientApiKeyWithSecret extends ClientApiKey {
21
+ secret: string;
22
+ }
23
+ export interface CreateApiKeyRequest {
24
+ name: string;
25
+ permissions: string[];
26
+ rateLimit?: number;
27
+ expiresInDays?: number;
28
+ allowedIps?: string[];
29
+ }
30
+ export interface CreateApiKeyResponse {
31
+ operationId: string;
32
+ key: ClientApiKeyWithSecret;
33
+ }
34
+ export interface ListApiKeysResponse {
35
+ operationId: string;
36
+ keys: ClientApiKey[];
37
+ nextToken?: string;
38
+ }
39
+ export interface AvailablePermissionsResponse {
40
+ operationId: string;
41
+ permissions: string[];
42
+ }
43
+ export interface RevokeApiKeyResponse {
44
+ operationId: string;
45
+ message: string;
46
+ }
@@ -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, 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';
9
+ import { SigninRequest, SigninResponse, SignupRequest, SignupResponse, VerifyEmailRequest, VerifyEmailResponse, ResendCodeRequest, ResendCodeResponse, MFAVerifyResponse, RefreshResponse, GetPermissionsResponse, GetProfileResponse, UpdateProfileRequest, UpdateProfileResponse, MFASetupResponse, MFAConfirmResponse, MFADisableRequest, MFADisableResponse, ForgotPasswordRequest, ForgotPasswordResponse, ResetPasswordRequest, ResetPasswordResponse, ActivateAccountRequest, ActivateAccountResponse, 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,6 +288,12 @@ 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>;
291
297
  /**
292
298
  * Cambia la contraseña del usuario autenticado.
293
299
  * Requiere la contraseña actual para verificación.
@@ -238,6 +238,29 @@ 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
+ }
241
264
  /**
242
265
  * Request para reenviar código de verificación.
243
266
  */
@@ -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 } from './types';
4
+ import { Organization, ListMyOrgsResponse, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListOrgMembersResponse, OrgRole, ChangeMemberRoleResponse, PendingInvitation, AcceptInvitationResponse, ImportMembersRequest, ImportMembersResponse } from './types';
5
5
  import * as i0 from "@angular/core";
6
6
  export declare class OrgService {
7
7
  private config;
@@ -21,6 +21,11 @@ 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>;
24
29
  leaveOrg(orgId: string): Observable<LeaveOrgResponse>;
25
30
  getOrgMembers(orgId: string, params?: {
26
31
  limit?: number;
@@ -97,3 +97,33 @@ 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
+ }
@@ -55,8 +55,16 @@ export declare class PageRefreshService {
55
55
  */
56
56
  unregister(): void;
57
57
  /**
58
- * Ejecuta el handler registrado y espera a que termine. Lo invoca
59
- * `val-page-wrapper` al detectar el gesto de pull. No-op si no hay handler.
58
+ * Duración mínima (ms) que el spinner permanece visible, aunque el handler
59
+ * termine antes. Sin esto, un reload rápido (data cacheada) cierra el spinner
60
+ * al instante → se percibe como "no hubo refresh". Con el mínimo, el gesto se
61
+ * siente smooth y CONSISTENTE en todas las vistas que usan el page-wrapper.
62
+ */
63
+ private static readonly MIN_SPINNER_MS;
64
+ /**
65
+ * Ejecuta el handler registrado y espera a que termine, garantizando una
66
+ * duración mínima de spinner. Lo invoca `val-page-wrapper` al detectar el
67
+ * gesto de pull. No-op si no hay handler.
60
68
  */
61
69
  run(): Promise<void>;
62
70
  static ɵfac: i0.ɵɵFactoryDeclaration<PageRefreshService, never>;
package/lib/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Current version of valtech-components.
3
3
  * This is automatically updated during the publish process.
4
4
  */
5
- export declare const VERSION = "2.0.1009";
5
+ export declare const VERSION = "2.0.1011";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valtech-components",
3
- "version": "2.0.1009",
3
+ "version": "2.0.1011",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "valtech-firebase-config": "./src/lib/services/firebase/scripts/generate-sw-config.js"
package/public-api.d.ts CHANGED
@@ -293,6 +293,9 @@ export * from './lib/components/organisms/notification-preferences-view/notifica
293
293
  export * from './lib/components/organisms/permissions-view/permissions-view.component';
294
294
  export * from './lib/components/organisms/permissions-view/types';
295
295
  export * from './lib/components/organisms/permissions-view/permissions.routes';
296
+ export * from './lib/components/organisms/about-view/about-view.component';
297
+ export * from './lib/components/organisms/about-view/types';
298
+ export * from './lib/components/organisms/about-view/about.routes';
296
299
  export * from './lib/services/org/permission-catalog.service';
297
300
  export * from './lib/components/organisms/delete-account-modal/delete-account-modal.component';
298
301
  export * from './lib/components/organisms/switch-org-modal/switch-org-modal.component';
@@ -301,6 +304,8 @@ export * from './lib/components/organisms/org-info-sheet/org-info-sheet.componen
301
304
  export * from './lib/components/organisms/invite-member-modal/invite-member-modal.component';
302
305
  export * from './lib/components/organisms/member-detail-modal/member-detail-modal.component';
303
306
  export * from './lib/components/organisms/member-detail-modal/types';
307
+ export * from './lib/components/organisms/member-import-modal/member-import-modal.component';
308
+ export * from './lib/components/organisms/api-keys-modal/api-keys-modal.component';
304
309
  export * from './lib/components/organisms/edit-org-modal/edit-org-modal.component';
305
310
  export * from './lib/components/organisms/transfer-ownership-modal/transfer-ownership-modal.component';
306
311
  export * from './lib/components/organisms/transfer-ownership-modal/types';
@@ -347,7 +352,9 @@ export * from './lib/services/legal-link/legal-link.service';
347
352
  export * from './lib/services/firebase';
348
353
  export * from './lib/services/auth';
349
354
  export { OrgService } from './lib/services/org/org.service';
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';
355
+ export type { Organization, OrgType, OrgPlan, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListMyOrgsResponse, OrgResponse, OrgMember, ListOrgMembersResponse, PendingInvitation, ListPendingInvitationsResponse, AcceptInvitationResponse, OrgRole, ListOrgRolesResponse, ChangeMemberRoleRequest, ChangeMemberRoleResponse, ImportUserRow, ImportOnConflict, ImportMembersRequest, ImportRowStatus, ImportRowResult, ImportSummary, ImportMembersResponse, } from './lib/services/org/types';
356
+ export { ApiKeyService } from './lib/services/apikeys/api-keys.service';
357
+ export type { ClientApiKey, ClientApiKeyWithSecret, CreateApiKeyRequest, CreateApiKeyResponse, ListApiKeysResponse, AvailablePermissionsResponse, RevokeApiKeyResponse, } from './lib/services/apikeys/types';
351
358
  export * from './lib/services/i18n';
352
359
  export * from './lib/services/preferences';
353
360
  export * from './lib/services/network-status';