valtech-components 2.0.1005 → 2.0.1007
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/api-keys-modal/api-keys-modal.component.mjs +385 -0
- package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.mjs +63 -0
- package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.component.mjs +313 -0
- package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.i18n.mjs +63 -0
- package/esm2022/lib/components/organisms/organization-view/organization-view.component.mjs +141 -3
- package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +21 -1
- package/esm2022/lib/components/organisms/permissions-view/permissions-view.component.mjs +9 -6
- package/esm2022/lib/services/apikeys/api-keys.service.mjs +46 -0
- package/esm2022/lib/services/apikeys/types.mjs +7 -0
- package/esm2022/lib/services/auth/auth.service.mjs +14 -1
- package/esm2022/lib/services/auth/types.mjs +1 -1
- package/esm2022/lib/services/org/org.service.mjs +8 -1
- package/esm2022/lib/services/org/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +4 -1
- package/fesm2022/valtech-components.mjs +1070 -49
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/api-keys-modal/api-keys-modal.component.d.ts +44 -0
- package/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.d.ts +6 -0
- package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +47 -0
- package/lib/components/organisms/member-import-modal/member-import-modal.i18n.d.ts +6 -0
- package/lib/components/organisms/organization-view/organization-view.component.d.ts +6 -0
- package/lib/services/apikeys/api-keys.service.d.ts +25 -0
- package/lib/services/apikeys/types.d.ts +46 -0
- package/lib/services/auth/auth.service.d.ts +7 -1
- package/lib/services/auth/types.d.ts +23 -0
- package/lib/services/org/org.service.d.ts +6 -1
- package/lib/services/org/types.d.ts +30 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +5 -1
|
@@ -54,7 +54,7 @@ import 'prismjs/components/prism-json';
|
|
|
54
54
|
* Current version of valtech-components.
|
|
55
55
|
* This is automatically updated during the publish process.
|
|
56
56
|
*/
|
|
57
|
-
const VERSION = '2.0.
|
|
57
|
+
const VERSION = '2.0.1007';
|
|
58
58
|
|
|
59
59
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
60
60
|
let isRefreshing = false;
|
|
@@ -8658,6 +8658,19 @@ class AuthService {
|
|
|
8658
8658
|
.post(`${this.baseUrl}/reset-password`, request)
|
|
8659
8659
|
.pipe(catchError(error => this.handleAuthError(error)));
|
|
8660
8660
|
}
|
|
8661
|
+
/**
|
|
8662
|
+
* Activa una cuenta pre-aprovisionada por una organización (ADR-023): define
|
|
8663
|
+
* la contraseña con el token del enlace de email. En éxito el backend devuelve
|
|
8664
|
+
* tokens de auto-signin → el usuario queda logueado (mismo flujo que verify-email).
|
|
8665
|
+
*/
|
|
8666
|
+
activateAccount(request) {
|
|
8667
|
+
this.stateService.clearError();
|
|
8668
|
+
return this.http.post(`${this.baseUrl}/activate`, request).pipe(tap(response => {
|
|
8669
|
+
if (response.activated && response.accessToken) {
|
|
8670
|
+
this.handleSuccessfulAuth(response);
|
|
8671
|
+
}
|
|
8672
|
+
}), catchError(error => this.handleAuthError(error)));
|
|
8673
|
+
}
|
|
8661
8674
|
/**
|
|
8662
8675
|
* Cambia la contraseña del usuario autenticado.
|
|
8663
8676
|
* Requiere la contraseña actual para verificación.
|
|
@@ -41737,7 +41750,7 @@ const PROFILE_VIEW_I18N = {
|
|
|
41737
41750
|
const HANDLE_PATTERN = /^[a-z_][a-z0-9_]*$/;
|
|
41738
41751
|
const HANDLE_MIN = 3;
|
|
41739
41752
|
const HANDLE_MAX = 20;
|
|
41740
|
-
const DEFAULT_NAMESPACE$
|
|
41753
|
+
const DEFAULT_NAMESPACE$i = 'Settings.Profile';
|
|
41741
41754
|
/**
|
|
41742
41755
|
* `val-profile-view` — vista Perfil full-feature autocontenida (organism).
|
|
41743
41756
|
*
|
|
@@ -41787,7 +41800,7 @@ class ProfileViewComponent {
|
|
|
41787
41800
|
showPhone: merged.showPhone ?? true,
|
|
41788
41801
|
showShareCta: merged.showShareCta ?? true,
|
|
41789
41802
|
profileBaseUrl: merged.profileBaseUrl ?? '',
|
|
41790
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
41803
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$i,
|
|
41791
41804
|
onSaved: merged.onSaved,
|
|
41792
41805
|
onAvatarUploaded: merged.onAvatarUploaded,
|
|
41793
41806
|
};
|
|
@@ -42703,7 +42716,7 @@ const PREFERENCES_VIEW_I18N = {
|
|
|
42703
42716
|
},
|
|
42704
42717
|
};
|
|
42705
42718
|
|
|
42706
|
-
const DEFAULT_NAMESPACE$
|
|
42719
|
+
const DEFAULT_NAMESPACE$h = 'Settings.General';
|
|
42707
42720
|
const DEFAULT_LANGUAGES = ['es', 'en'];
|
|
42708
42721
|
/**
|
|
42709
42722
|
* `val-preferences-view` — vista de preferencias de UI cross-app (tema +
|
|
@@ -42740,7 +42753,7 @@ class PreferencesViewComponent {
|
|
|
42740
42753
|
showLanguage: merged.showLanguage ?? true,
|
|
42741
42754
|
showFontSize: merged.showFontSize ?? true,
|
|
42742
42755
|
supportedLanguages: merged.supportedLanguages ?? DEFAULT_LANGUAGES,
|
|
42743
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
42756
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$h,
|
|
42744
42757
|
onThemeChanged: merged.onThemeChanged,
|
|
42745
42758
|
onLanguageChanged: merged.onLanguageChanged,
|
|
42746
42759
|
onFontSizeChanged: merged.onFontSizeChanged,
|
|
@@ -44496,7 +44509,7 @@ const SECURITY_VIEW_I18N = {
|
|
|
44496
44509
|
};
|
|
44497
44510
|
|
|
44498
44511
|
addIcons({ laptopOutline, phonePortraitOutline });
|
|
44499
|
-
const DEFAULT_NAMESPACE$
|
|
44512
|
+
const DEFAULT_NAMESPACE$g = 'Settings.Security';
|
|
44500
44513
|
/**
|
|
44501
44514
|
* `val-security-view` — vista Seguridad full-feature autocontenida (organism).
|
|
44502
44515
|
*
|
|
@@ -44545,7 +44558,7 @@ class SecurityViewComponent {
|
|
|
44545
44558
|
showChangeEmail: merged.showChangeEmail ?? true,
|
|
44546
44559
|
showMfa: merged.showMfa ?? true,
|
|
44547
44560
|
showPolicies: merged.showPolicies ?? true,
|
|
44548
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
44561
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$g,
|
|
44549
44562
|
handleDeepLinks: merged.handleDeepLinks ?? true,
|
|
44550
44563
|
homeRoute: merged.homeRoute ?? '/app/home',
|
|
44551
44564
|
onMfaCompleted: merged.onMfaCompleted,
|
|
@@ -45347,6 +45360,13 @@ class OrgService {
|
|
|
45347
45360
|
inviteUser(orgId, req) {
|
|
45348
45361
|
return this.http.post(`${this.baseUrl}/${orgId}/invite`, req);
|
|
45349
45362
|
}
|
|
45363
|
+
/**
|
|
45364
|
+
* Crea/asigna miembros en masa (ADR-023). Resultado por-fila (partial success):
|
|
45365
|
+
* `created` (pre-aprovisionado), `assigned` (ya existía), `skipped`, `error`.
|
|
45366
|
+
*/
|
|
45367
|
+
importMembers(orgId, req) {
|
|
45368
|
+
return this.http.post(`${this.baseUrl}/${orgId}/members/import`, req);
|
|
45369
|
+
}
|
|
45350
45370
|
leaveOrg(orgId) {
|
|
45351
45371
|
return this.http.post(`${this.baseUrl}/${orgId}/leave`, {});
|
|
45352
45372
|
}
|
|
@@ -45451,7 +45471,7 @@ const CREATE_ORG_MODAL_I18N = {
|
|
|
45451
45471
|
},
|
|
45452
45472
|
};
|
|
45453
45473
|
|
|
45454
|
-
const DEFAULT_NAMESPACE$
|
|
45474
|
+
const DEFAULT_NAMESPACE$f = 'CreateOrgModal';
|
|
45455
45475
|
/**
|
|
45456
45476
|
* `val-create-org-modal` — modal de creación de organización (organism
|
|
45457
45477
|
* compartido). Promovido desde `showcase` bajo el proceso de ADR-021. Reusado por
|
|
@@ -45477,10 +45497,10 @@ class CreateOrgModalComponent {
|
|
|
45477
45497
|
this.toast = inject(ToastService);
|
|
45478
45498
|
this.errors = inject(ValtechErrorService);
|
|
45479
45499
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
45480
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
45500
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$f;
|
|
45481
45501
|
this._busy = signal(false);
|
|
45482
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
45483
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
45502
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$f)) {
|
|
45503
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$f, CREATE_ORG_MODAL_I18N);
|
|
45484
45504
|
}
|
|
45485
45505
|
this.formMeta = signal(this.buildFormMeta());
|
|
45486
45506
|
effect(() => {
|
|
@@ -45716,7 +45736,7 @@ const DELETE_ACCOUNT_MODAL_I18N = {
|
|
|
45716
45736
|
},
|
|
45717
45737
|
};
|
|
45718
45738
|
|
|
45719
|
-
const DEFAULT_NAMESPACE$
|
|
45739
|
+
const DEFAULT_NAMESPACE$e = 'Settings.DeleteAccount';
|
|
45720
45740
|
/**
|
|
45721
45741
|
* `val-delete-account-modal` — modal de eliminación de cuenta (organism,
|
|
45722
45742
|
* cuenta-específico). Promovido desde `showcase` bajo el proceso de ADR-021.
|
|
@@ -45742,7 +45762,7 @@ class DeleteAccountModalComponent {
|
|
|
45742
45762
|
this.i18n = inject(I18nService);
|
|
45743
45763
|
this.toast = inject(ToastService);
|
|
45744
45764
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
45745
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
45765
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$e;
|
|
45746
45766
|
this.hasPassword = signal(null);
|
|
45747
45767
|
this.codeSent = signal(false);
|
|
45748
45768
|
this.formState = signal(ComponentStates.ENABLED);
|
|
@@ -45809,8 +45829,8 @@ class DeleteAccountModalComponent {
|
|
|
45809
45829
|
],
|
|
45810
45830
|
actions: this.submitBtn('delete-code-submit', 'confirmCta'),
|
|
45811
45831
|
}));
|
|
45812
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
45813
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
45832
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$e)) {
|
|
45833
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$e, DELETE_ACCOUNT_MODAL_I18N);
|
|
45814
45834
|
}
|
|
45815
45835
|
}
|
|
45816
45836
|
ngOnInit() {
|
|
@@ -46011,7 +46031,7 @@ const ORG_INFO_SHEET_I18N = {
|
|
|
46011
46031
|
},
|
|
46012
46032
|
};
|
|
46013
46033
|
|
|
46014
|
-
const DEFAULT_NAMESPACE$
|
|
46034
|
+
const DEFAULT_NAMESPACE$d = 'OrgInfoSheet';
|
|
46015
46035
|
/**
|
|
46016
46036
|
* `val-org-info-sheet` — sheet informativo "¿Qué son las organizaciones?".
|
|
46017
46037
|
* Extraído del `OrgInfoSheetComponent` inline de `AccountPage` bajo el proceso de
|
|
@@ -46056,15 +46076,15 @@ class OrgInfoSheetComponent {
|
|
|
46056
46076
|
text: this.closeProps.text || this.resolvedCloseLabel(),
|
|
46057
46077
|
}));
|
|
46058
46078
|
addIcons({ peopleOutline, swapHorizontalOutline, mailOutline });
|
|
46059
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
46060
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
46079
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$d)) {
|
|
46080
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$d, ORG_INFO_SHEET_I18N);
|
|
46061
46081
|
}
|
|
46062
46082
|
}
|
|
46063
46083
|
dismiss() {
|
|
46064
46084
|
this._modalRef?.dismiss(null, 'cancel');
|
|
46065
46085
|
}
|
|
46066
46086
|
tt(key) {
|
|
46067
|
-
return this.i18n.t(key, DEFAULT_NAMESPACE$
|
|
46087
|
+
return this.i18n.t(key, DEFAULT_NAMESPACE$d);
|
|
46068
46088
|
}
|
|
46069
46089
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgInfoSheetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
46070
46090
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: OrgInfoSheetComponent, isStandalone: true, selector: "val-org-info-sheet", inputs: { title: "title", subtitle: "subtitle", body: "body", closeLabel: "closeLabel", closeProps: "closeProps", _modalRef: "_modalRef" }, ngImport: i0, template: `
|
|
@@ -46231,7 +46251,7 @@ const SWITCH_ORG_MODAL_I18N = {
|
|
|
46231
46251
|
},
|
|
46232
46252
|
};
|
|
46233
46253
|
|
|
46234
|
-
const DEFAULT_NAMESPACE$
|
|
46254
|
+
const DEFAULT_NAMESPACE$c = 'Settings.SwitchOrg';
|
|
46235
46255
|
addIcons({ businessOutline, checkmarkCircleOutline });
|
|
46236
46256
|
/**
|
|
46237
46257
|
* `val-switch-org-modal` — modal de cambio de organización activa (organism
|
|
@@ -46257,7 +46277,7 @@ class SwitchOrgModalComponent {
|
|
|
46257
46277
|
this.orgSwitch = inject(OrgSwitchService);
|
|
46258
46278
|
this.errors = inject(ValtechErrorService);
|
|
46259
46279
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
46260
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
46280
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$c;
|
|
46261
46281
|
this.orgs = signal([]);
|
|
46262
46282
|
this.loading = signal(false);
|
|
46263
46283
|
this.query = signal('');
|
|
@@ -46273,8 +46293,8 @@ class SwitchOrgModalComponent {
|
|
|
46273
46293
|
return list;
|
|
46274
46294
|
return list.filter(o => o.name.toLowerCase().includes(q));
|
|
46275
46295
|
});
|
|
46276
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
46277
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
46296
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$c)) {
|
|
46297
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$c, SWITCH_ORG_MODAL_I18N);
|
|
46278
46298
|
}
|
|
46279
46299
|
this.loadOrgs();
|
|
46280
46300
|
}
|
|
@@ -46592,7 +46612,7 @@ const ACCOUNT_VIEW_I18N = {
|
|
|
46592
46612
|
};
|
|
46593
46613
|
|
|
46594
46614
|
addIcons({ peopleOutline, businessOutline, chevronForwardOutline, swapHorizontalOutline, mailOutline });
|
|
46595
|
-
const DEFAULT_NAMESPACE$
|
|
46615
|
+
const DEFAULT_NAMESPACE$b = 'Settings.Account';
|
|
46596
46616
|
const DEFAULT_MANAGE_ORG_ROUTE = '/app/settings/organization';
|
|
46597
46617
|
/**
|
|
46598
46618
|
* `val-account-view` — vista Cuenta full-feature autocontenida (organism).
|
|
@@ -46633,7 +46653,7 @@ class AccountViewComponent {
|
|
|
46633
46653
|
showNewOrgCta: merged.showNewOrgCta ?? true,
|
|
46634
46654
|
showLogout: merged.showLogout ?? true,
|
|
46635
46655
|
showDeleteAccount: merged.showDeleteAccount ?? true,
|
|
46636
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
46656
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$b,
|
|
46637
46657
|
manageOrgRoute: merged.manageOrgRoute ?? DEFAULT_MANAGE_ORG_ROUTE,
|
|
46638
46658
|
onOrgSwitched: merged.onOrgSwitched,
|
|
46639
46659
|
onOrgCreated: merged.onOrgCreated,
|
|
@@ -47358,7 +47378,7 @@ const EDIT_ORG_MODAL_I18N = {
|
|
|
47358
47378
|
},
|
|
47359
47379
|
};
|
|
47360
47380
|
|
|
47361
|
-
const DEFAULT_NAMESPACE$
|
|
47381
|
+
const DEFAULT_NAMESPACE$a = 'EditOrgModal';
|
|
47362
47382
|
/**
|
|
47363
47383
|
* `val-edit-org-modal` — modal de edición de organización (nombre + descripción).
|
|
47364
47384
|
* Promovido desde `showcase` bajo el proceso de ADR-021. Reusado por la vista de
|
|
@@ -47385,10 +47405,10 @@ class EditOrgModalComponent {
|
|
|
47385
47405
|
/** Organización a editar (pasada por `componentProps`). */
|
|
47386
47406
|
this.org = null;
|
|
47387
47407
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
47388
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
47408
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$a;
|
|
47389
47409
|
this.saving = signal(false);
|
|
47390
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
47391
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
47410
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$a)) {
|
|
47411
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$a, EDIT_ORG_MODAL_I18N);
|
|
47392
47412
|
}
|
|
47393
47413
|
this.formMeta = signal(this.buildFormMeta());
|
|
47394
47414
|
effect(() => {
|
|
@@ -47626,7 +47646,7 @@ const INVITE_MEMBER_MODAL_I18N = {
|
|
|
47626
47646
|
},
|
|
47627
47647
|
};
|
|
47628
47648
|
|
|
47629
|
-
const DEFAULT_NAMESPACE$
|
|
47649
|
+
const DEFAULT_NAMESPACE$9 = 'InviteModal';
|
|
47630
47650
|
addIcons({ personOutline, mailOutline, closeOutline, checkmarkCircleOutline });
|
|
47631
47651
|
/**
|
|
47632
47652
|
* `val-invite-member-modal` — invitación de miembros a una organización.
|
|
@@ -47657,7 +47677,7 @@ class InviteMemberModalComponent {
|
|
|
47657
47677
|
/** Ids de miembros ya existentes (excluidos de los resultados). */
|
|
47658
47678
|
this.existingMemberIds = [];
|
|
47659
47679
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
47660
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
47680
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$9;
|
|
47661
47681
|
this.query = signal('');
|
|
47662
47682
|
this.searching = signal(false);
|
|
47663
47683
|
this.searchResults = signal([]);
|
|
@@ -47704,8 +47724,8 @@ class InviteMemberModalComponent {
|
|
|
47704
47724
|
state: this.sending() ? ComponentStates.WORKING : ComponentStates.ENABLED,
|
|
47705
47725
|
}));
|
|
47706
47726
|
this.searchSubject = new Subject();
|
|
47707
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
47708
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
47727
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$9)) {
|
|
47728
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$9, INVITE_MEMBER_MODAL_I18N);
|
|
47709
47729
|
}
|
|
47710
47730
|
this.loadRoles();
|
|
47711
47731
|
this.roleSub = this.roleControl.valueChanges.subscribe(v => {
|
|
@@ -48194,7 +48214,7 @@ const MEMBER_DETAIL_MODAL_I18N = {
|
|
|
48194
48214
|
},
|
|
48195
48215
|
};
|
|
48196
48216
|
|
|
48197
|
-
const DEFAULT_NAMESPACE$
|
|
48217
|
+
const DEFAULT_NAMESPACE$8 = 'Settings.MemberDetail';
|
|
48198
48218
|
/**
|
|
48199
48219
|
* `val-member-detail-modal` — detalle de miembro de organización: perfil, rol y
|
|
48200
48220
|
* permisos. Promovido desde `showcase` bajo el proceso de ADR-021.
|
|
@@ -48231,7 +48251,7 @@ class MemberDetailModalComponent {
|
|
|
48231
48251
|
{ id: 'admin', name: 'admin' },
|
|
48232
48252
|
];
|
|
48233
48253
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
48234
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
48254
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$8;
|
|
48235
48255
|
this.working = signal(false);
|
|
48236
48256
|
this.currentRole = signal('');
|
|
48237
48257
|
this.roleControl = new FormControl('');
|
|
@@ -48271,8 +48291,8 @@ class MemberDetailModalComponent {
|
|
|
48271
48291
|
type: 'button',
|
|
48272
48292
|
state: this.working() ? ComponentStates.WORKING : ComponentStates.ENABLED,
|
|
48273
48293
|
}));
|
|
48274
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
48275
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
48294
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$8)) {
|
|
48295
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$8, MEMBER_DETAIL_MODAL_I18N);
|
|
48276
48296
|
}
|
|
48277
48297
|
}
|
|
48278
48298
|
ngOnInit() {
|
|
@@ -48609,7 +48629,7 @@ const TRANSFER_OWNERSHIP_MODAL_I18N = {
|
|
|
48609
48629
|
},
|
|
48610
48630
|
};
|
|
48611
48631
|
|
|
48612
|
-
const DEFAULT_NAMESPACE$
|
|
48632
|
+
const DEFAULT_NAMESPACE$7 = 'Settings.TransferModal';
|
|
48613
48633
|
/**
|
|
48614
48634
|
* `val-transfer-ownership-modal` — selector de miembro para transferir la
|
|
48615
48635
|
* propiedad de la organización. Promovido desde `showcase` bajo el proceso de
|
|
@@ -48633,7 +48653,7 @@ class TransferOwnershipModalComponent {
|
|
|
48633
48653
|
/** Lista de miembros transferibles (todos excepto el owner actual). */
|
|
48634
48654
|
this.members = [];
|
|
48635
48655
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
48636
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
48656
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$7;
|
|
48637
48657
|
this.query = signal('');
|
|
48638
48658
|
this.selectedId = signal('');
|
|
48639
48659
|
this.filtered = computed(() => {
|
|
@@ -48645,8 +48665,8 @@ class TransferOwnershipModalComponent {
|
|
|
48645
48665
|
m.userId.toLowerCase().includes(q));
|
|
48646
48666
|
});
|
|
48647
48667
|
this.noResultsLabel = computed(() => `${this.t('noResults')} "${this.query()}"`);
|
|
48648
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
48649
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
48668
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$7)) {
|
|
48669
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$7, TRANSFER_OWNERSHIP_MODAL_I18N);
|
|
48650
48670
|
}
|
|
48651
48671
|
}
|
|
48652
48672
|
ngOnInit() {
|
|
@@ -48831,6 +48851,849 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
48831
48851
|
type: Input
|
|
48832
48852
|
}] } });
|
|
48833
48853
|
|
|
48854
|
+
/**
|
|
48855
|
+
* Defaults i18n (es/en) embebidos en `val-member-import-modal` (ADR-023).
|
|
48856
|
+
* Auto-registrados si el consumer no proveyó el namespace `Settings.ImportModal`.
|
|
48857
|
+
*/
|
|
48858
|
+
const MEMBER_IMPORT_MODAL_I18N = {
|
|
48859
|
+
es: {
|
|
48860
|
+
title: 'Importar miembros',
|
|
48861
|
+
hint: 'Pega un CSV con columnas: email, nombre, rol (una fila por persona).',
|
|
48862
|
+
csvPlaceholder: 'email,nombre,rol\nana@x.com,Ana,editor\nbeto@x.com,Beto,viewer',
|
|
48863
|
+
rolesAvailable: 'Roles disponibles:',
|
|
48864
|
+
onConflictLabel: 'Si el email ya existe',
|
|
48865
|
+
conflictAssign: 'Asignar el rol',
|
|
48866
|
+
conflictSkip: 'Omitir',
|
|
48867
|
+
conflictError: 'Marcar error',
|
|
48868
|
+
sendActivation: 'Enviar email de activación a las cuentas nuevas',
|
|
48869
|
+
submit: 'Importar',
|
|
48870
|
+
submitting: 'Importando...',
|
|
48871
|
+
parseError: 'No se pudo interpretar el CSV. Revisa el formato.',
|
|
48872
|
+
noRows: 'Pega al menos una fila válida (email y rol).',
|
|
48873
|
+
summary: 'Resumen',
|
|
48874
|
+
created: 'creados',
|
|
48875
|
+
assigned: 'asignados',
|
|
48876
|
+
skipped: 'omitidos',
|
|
48877
|
+
failed: 'con error',
|
|
48878
|
+
colEmail: 'Email',
|
|
48879
|
+
colStatus: 'Estado',
|
|
48880
|
+
colDetail: 'Detalle',
|
|
48881
|
+
activationSent: 'activación enviada',
|
|
48882
|
+
activationPending: 'activación pendiente',
|
|
48883
|
+
again: 'Importar otro lote',
|
|
48884
|
+
close: 'Cerrar',
|
|
48885
|
+
genericError: 'No se pudo completar la importación. Intenta de nuevo.',
|
|
48886
|
+
},
|
|
48887
|
+
en: {
|
|
48888
|
+
title: 'Import members',
|
|
48889
|
+
hint: 'Paste a CSV with columns: email, name, role (one row per person).',
|
|
48890
|
+
csvPlaceholder: 'email,name,role\nana@x.com,Ana,editor\nbeto@x.com,Beto,viewer',
|
|
48891
|
+
rolesAvailable: 'Available roles:',
|
|
48892
|
+
onConflictLabel: 'If the email already exists',
|
|
48893
|
+
conflictAssign: 'Assign the role',
|
|
48894
|
+
conflictSkip: 'Skip',
|
|
48895
|
+
conflictError: 'Mark as error',
|
|
48896
|
+
sendActivation: 'Send activation email to new accounts',
|
|
48897
|
+
submit: 'Import',
|
|
48898
|
+
submitting: 'Importing...',
|
|
48899
|
+
parseError: "Couldn't parse the CSV. Check the format.",
|
|
48900
|
+
noRows: 'Paste at least one valid row (email and role).',
|
|
48901
|
+
summary: 'Summary',
|
|
48902
|
+
created: 'created',
|
|
48903
|
+
assigned: 'assigned',
|
|
48904
|
+
skipped: 'skipped',
|
|
48905
|
+
failed: 'failed',
|
|
48906
|
+
colEmail: 'Email',
|
|
48907
|
+
colStatus: 'Status',
|
|
48908
|
+
colDetail: 'Detail',
|
|
48909
|
+
activationSent: 'activation sent',
|
|
48910
|
+
activationPending: 'activation pending',
|
|
48911
|
+
again: 'Import another batch',
|
|
48912
|
+
close: 'Close',
|
|
48913
|
+
genericError: "Couldn't complete the import. Try again.",
|
|
48914
|
+
},
|
|
48915
|
+
};
|
|
48916
|
+
|
|
48917
|
+
const DEFAULT_NAMESPACE$6 = 'Settings.ImportModal';
|
|
48918
|
+
/**
|
|
48919
|
+
* `val-member-import-modal` — panel de carga masiva de miembros (ADR-023 fase 6).
|
|
48920
|
+
*
|
|
48921
|
+
* El admin pega un CSV (`email,nombre,rol`); el modal lo parsea a filas y llama
|
|
48922
|
+
* `OrgService.importMembers`. Muestra el resultado por-fila (partial success):
|
|
48923
|
+
* `created` / `assigned` / `skipped` / `error`. Header canónico (Regla #5).
|
|
48924
|
+
*
|
|
48925
|
+
* Auto-registra defaults i18n (es/en) en `Settings.ImportModal`.
|
|
48926
|
+
*/
|
|
48927
|
+
class MemberImportModalComponent {
|
|
48928
|
+
constructor() {
|
|
48929
|
+
this.i18n = inject(I18nService);
|
|
48930
|
+
this.orgService = inject(OrgService);
|
|
48931
|
+
/** Org destino del import. */
|
|
48932
|
+
this.orgId = '';
|
|
48933
|
+
/** Nombres de roles disponibles (para el hint). Opcional. */
|
|
48934
|
+
this.availableRoles = [];
|
|
48935
|
+
/** Namespace i18n. */
|
|
48936
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$6;
|
|
48937
|
+
this.csv = '';
|
|
48938
|
+
this.onConflict = 'assignRole';
|
|
48939
|
+
this.sendActivation = true;
|
|
48940
|
+
this.submitting = signal(false);
|
|
48941
|
+
this.errorMsg = signal('');
|
|
48942
|
+
this.results = signal(null);
|
|
48943
|
+
this.rolesHint = computed(() => this.availableRoles.length ? `${this.t('rolesAvailable')} ${this.availableRoles.join(', ')}` : '');
|
|
48944
|
+
this.summaryLabel = computed(() => {
|
|
48945
|
+
const s = this.results()?.summary;
|
|
48946
|
+
if (!s)
|
|
48947
|
+
return this.t('summary');
|
|
48948
|
+
return `${this.t('summary')}: ${s.created} ${this.t('created')} · ${s.assigned} ${this.t('assigned')} · ${s.skipped} ${this.t('skipped')} · ${s.failed} ${this.t('failed')}`;
|
|
48949
|
+
});
|
|
48950
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$6)) {
|
|
48951
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$6, MEMBER_IMPORT_MODAL_I18N);
|
|
48952
|
+
}
|
|
48953
|
+
}
|
|
48954
|
+
ngOnInit() {
|
|
48955
|
+
if (!this.i18n.hasNamespace(this.i18nNamespace)) {
|
|
48956
|
+
this.i18n.registerContent(this.i18nNamespace, MEMBER_IMPORT_MODAL_I18N);
|
|
48957
|
+
}
|
|
48958
|
+
}
|
|
48959
|
+
/** Parsea el CSV pegado a filas {email,name,roleName}. Tolera header. */
|
|
48960
|
+
parseCsv() {
|
|
48961
|
+
const rows = [];
|
|
48962
|
+
for (const raw of this.csv.split(/\r?\n/)) {
|
|
48963
|
+
const line = raw.trim();
|
|
48964
|
+
if (!line)
|
|
48965
|
+
continue;
|
|
48966
|
+
const cols = line.split(',').map(c => c.trim());
|
|
48967
|
+
const email = (cols[0] ?? '').toLowerCase();
|
|
48968
|
+
// Saltar header (primera col "email") o líneas sin @.
|
|
48969
|
+
if (!email || !email.includes('@'))
|
|
48970
|
+
continue;
|
|
48971
|
+
rows.push({ email, name: cols[1] ?? '', roleName: cols[2] ?? '' });
|
|
48972
|
+
}
|
|
48973
|
+
return rows;
|
|
48974
|
+
}
|
|
48975
|
+
submit() {
|
|
48976
|
+
this.errorMsg.set('');
|
|
48977
|
+
const users = this.parseCsv();
|
|
48978
|
+
if (users.length === 0) {
|
|
48979
|
+
this.errorMsg.set(this.t('noRows'));
|
|
48980
|
+
return;
|
|
48981
|
+
}
|
|
48982
|
+
if (users.some(u => !u.roleName)) {
|
|
48983
|
+
this.errorMsg.set(this.t('parseError'));
|
|
48984
|
+
return;
|
|
48985
|
+
}
|
|
48986
|
+
this.submitting.set(true);
|
|
48987
|
+
this.orgService
|
|
48988
|
+
.importMembers(this.orgId, {
|
|
48989
|
+
users,
|
|
48990
|
+
onConflict: this.onConflict,
|
|
48991
|
+
sendActivation: this.sendActivation,
|
|
48992
|
+
})
|
|
48993
|
+
.subscribe({
|
|
48994
|
+
next: res => {
|
|
48995
|
+
this.submitting.set(false);
|
|
48996
|
+
this.results.set(res);
|
|
48997
|
+
// Refrescar lista del consumer si hubo altas/asignaciones efectivas.
|
|
48998
|
+
if (res.summary.created + res.summary.assigned > 0) {
|
|
48999
|
+
this.onSuccess?.();
|
|
49000
|
+
}
|
|
49001
|
+
},
|
|
49002
|
+
error: err => {
|
|
49003
|
+
this.submitting.set(false);
|
|
49004
|
+
this.errorMsg.set(err?.error?.message ?? this.t('genericError'));
|
|
49005
|
+
},
|
|
49006
|
+
});
|
|
49007
|
+
}
|
|
49008
|
+
statusLabel(r) {
|
|
49009
|
+
const base = this.t(r.status === 'error' ? 'failed' : r.status);
|
|
49010
|
+
if (r.status === 'created' && r.activation) {
|
|
49011
|
+
return `${base} · ${this.t(r.activation === 'sent' ? 'activationSent' : 'activationPending')}`;
|
|
49012
|
+
}
|
|
49013
|
+
return base;
|
|
49014
|
+
}
|
|
49015
|
+
reset() {
|
|
49016
|
+
this.csv = '';
|
|
49017
|
+
this.errorMsg.set('');
|
|
49018
|
+
this.results.set(null);
|
|
49019
|
+
}
|
|
49020
|
+
dismiss() {
|
|
49021
|
+
this._modalRef?.dismiss(null, 'cancel');
|
|
49022
|
+
}
|
|
49023
|
+
t(key) {
|
|
49024
|
+
return this.i18n.t(key, this.i18nNamespace);
|
|
49025
|
+
}
|
|
49026
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MemberImportModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
49027
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: MemberImportModalComponent, isStandalone: true, selector: "val-member-import-modal", inputs: { orgId: "orgId", availableRoles: "availableRoles", onSuccess: "onSuccess", _modalRef: "_modalRef", i18nNamespace: "i18nNamespace" }, ngImport: i0, template: `
|
|
49028
|
+
<ion-header>
|
|
49029
|
+
<ion-toolbar>
|
|
49030
|
+
<ion-buttons slot="end">
|
|
49031
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49032
|
+
<strong>{{ t('close') }}</strong>
|
|
49033
|
+
</ion-button>
|
|
49034
|
+
</ion-buttons>
|
|
49035
|
+
</ion-toolbar>
|
|
49036
|
+
</ion-header>
|
|
49037
|
+
|
|
49038
|
+
<ion-content class="ion-padding">
|
|
49039
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49040
|
+
|
|
49041
|
+
@if (!results()) {
|
|
49042
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49043
|
+
|
|
49044
|
+
@if (rolesHint()) {
|
|
49045
|
+
<val-text [props]="{ content: rolesHint(), size: 'small', color: 'medium', bold: false }" />
|
|
49046
|
+
}
|
|
49047
|
+
|
|
49048
|
+
<ion-textarea
|
|
49049
|
+
class="import-csv"
|
|
49050
|
+
[autoGrow]="true"
|
|
49051
|
+
[rows]="6"
|
|
49052
|
+
[placeholder]="t('csvPlaceholder')"
|
|
49053
|
+
[(ngModel)]="csv"
|
|
49054
|
+
/>
|
|
49055
|
+
|
|
49056
|
+
<ion-select
|
|
49057
|
+
class="import-conflict"
|
|
49058
|
+
label="{{ t('onConflictLabel') }}"
|
|
49059
|
+
labelPlacement="stacked"
|
|
49060
|
+
interface="popover"
|
|
49061
|
+
[(ngModel)]="onConflict"
|
|
49062
|
+
>
|
|
49063
|
+
<ion-select-option value="assignRole">{{ t('conflictAssign') }}</ion-select-option>
|
|
49064
|
+
<ion-select-option value="skip">{{ t('conflictSkip') }}</ion-select-option>
|
|
49065
|
+
<ion-select-option value="error">{{ t('conflictError') }}</ion-select-option>
|
|
49066
|
+
</ion-select>
|
|
49067
|
+
|
|
49068
|
+
<ion-checkbox class="import-activation" labelPlacement="end" [(ngModel)]="sendActivation">
|
|
49069
|
+
{{ t('sendActivation') }}
|
|
49070
|
+
</ion-checkbox>
|
|
49071
|
+
|
|
49072
|
+
@if (errorMsg()) {
|
|
49073
|
+
<p class="import-error">{{ errorMsg() }}</p>
|
|
49074
|
+
}
|
|
49075
|
+
|
|
49076
|
+
<div class="import-actions">
|
|
49077
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49078
|
+
@if (submitting()) {
|
|
49079
|
+
<ion-spinner name="dots" />
|
|
49080
|
+
{{ t('submitting') }}
|
|
49081
|
+
} @else {
|
|
49082
|
+
{{ t('submit') }}
|
|
49083
|
+
}
|
|
49084
|
+
</ion-button>
|
|
49085
|
+
</div>
|
|
49086
|
+
} @else {
|
|
49087
|
+
<!-- Resultados -->
|
|
49088
|
+
<val-title [props]="{ content: summaryLabel(), size: 'large', color: '', bold: true }" />
|
|
49089
|
+
<div class="import-results">
|
|
49090
|
+
@for (r of results()!.results; track r.email) {
|
|
49091
|
+
<div class="import-row import-row--{{ r.status }}">
|
|
49092
|
+
<span class="import-row__email">{{ r.email }}</span>
|
|
49093
|
+
<span class="import-row__status">{{ statusLabel(r) }}</span>
|
|
49094
|
+
@if (r.reason) {
|
|
49095
|
+
<span class="import-row__reason">{{ r.reason }}</span>
|
|
49096
|
+
}
|
|
49097
|
+
</div>
|
|
49098
|
+
}
|
|
49099
|
+
</div>
|
|
49100
|
+
<div class="import-actions">
|
|
49101
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="reset()">
|
|
49102
|
+
{{ t('again') }}
|
|
49103
|
+
</ion-button>
|
|
49104
|
+
</div>
|
|
49105
|
+
}
|
|
49106
|
+
</ion-content>
|
|
49107
|
+
`, isInline: true, styles: ["val-display{display:block;margin-bottom:4px}val-title{display:block;margin-bottom:12px}.import-csv{--background: var(--ion-color-light);border-radius:10px;margin-bottom:16px;font-family:monospace;font-size:13px}.import-conflict{margin-bottom:12px}.import-activation{display:block;margin-bottom:16px;font-size:14px}.import-error{margin:0 0 12px;font-size:.875rem;color:var(--ion-color-danger, #c0392b)}.import-actions{margin-top:8px}.import-results{display:flex;flex-direction:column;gap:6px;margin:12px 0}.import-row{display:grid;grid-template-columns:1fr auto;grid-row-gap:2px;align-items:center;padding:10px 12px;border-radius:8px;border-left:3px solid var(--ion-color-medium);background:var(--ion-color-light);font-size:14px}.import-row--created{border-left-color:var(--ion-color-success, #2dd36f)}.import-row--assigned{border-left-color:var(--ion-color-primary, #7026df)}.import-row--skipped{border-left-color:var(--ion-color-medium, #92949c)}.import-row--error{border-left-color:var(--ion-color-danger, #c0392b)}.import-row__email{font-weight:600;color:var(--ion-color-dark)}.import-row__status{text-align:right;color:var(--ion-color-medium-shade, #6b6e76)}.import-row__reason{grid-column:1 / -1;font-size:12px;color:var(--ion-color-danger, #c0392b)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
49108
|
+
}
|
|
49109
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MemberImportModalComponent, decorators: [{
|
|
49110
|
+
type: Component,
|
|
49111
|
+
args: [{ selector: 'val-member-import-modal', standalone: true, imports: [
|
|
49112
|
+
FormsModule,
|
|
49113
|
+
IonHeader,
|
|
49114
|
+
IonToolbar,
|
|
49115
|
+
IonButtons,
|
|
49116
|
+
IonButton,
|
|
49117
|
+
IonContent,
|
|
49118
|
+
IonTextarea,
|
|
49119
|
+
IonSelect,
|
|
49120
|
+
IonSelectOption,
|
|
49121
|
+
IonCheckbox,
|
|
49122
|
+
IonSpinner,
|
|
49123
|
+
DisplayComponent,
|
|
49124
|
+
TextComponent,
|
|
49125
|
+
TitleComponent,
|
|
49126
|
+
], template: `
|
|
49127
|
+
<ion-header>
|
|
49128
|
+
<ion-toolbar>
|
|
49129
|
+
<ion-buttons slot="end">
|
|
49130
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49131
|
+
<strong>{{ t('close') }}</strong>
|
|
49132
|
+
</ion-button>
|
|
49133
|
+
</ion-buttons>
|
|
49134
|
+
</ion-toolbar>
|
|
49135
|
+
</ion-header>
|
|
49136
|
+
|
|
49137
|
+
<ion-content class="ion-padding">
|
|
49138
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49139
|
+
|
|
49140
|
+
@if (!results()) {
|
|
49141
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49142
|
+
|
|
49143
|
+
@if (rolesHint()) {
|
|
49144
|
+
<val-text [props]="{ content: rolesHint(), size: 'small', color: 'medium', bold: false }" />
|
|
49145
|
+
}
|
|
49146
|
+
|
|
49147
|
+
<ion-textarea
|
|
49148
|
+
class="import-csv"
|
|
49149
|
+
[autoGrow]="true"
|
|
49150
|
+
[rows]="6"
|
|
49151
|
+
[placeholder]="t('csvPlaceholder')"
|
|
49152
|
+
[(ngModel)]="csv"
|
|
49153
|
+
/>
|
|
49154
|
+
|
|
49155
|
+
<ion-select
|
|
49156
|
+
class="import-conflict"
|
|
49157
|
+
label="{{ t('onConflictLabel') }}"
|
|
49158
|
+
labelPlacement="stacked"
|
|
49159
|
+
interface="popover"
|
|
49160
|
+
[(ngModel)]="onConflict"
|
|
49161
|
+
>
|
|
49162
|
+
<ion-select-option value="assignRole">{{ t('conflictAssign') }}</ion-select-option>
|
|
49163
|
+
<ion-select-option value="skip">{{ t('conflictSkip') }}</ion-select-option>
|
|
49164
|
+
<ion-select-option value="error">{{ t('conflictError') }}</ion-select-option>
|
|
49165
|
+
</ion-select>
|
|
49166
|
+
|
|
49167
|
+
<ion-checkbox class="import-activation" labelPlacement="end" [(ngModel)]="sendActivation">
|
|
49168
|
+
{{ t('sendActivation') }}
|
|
49169
|
+
</ion-checkbox>
|
|
49170
|
+
|
|
49171
|
+
@if (errorMsg()) {
|
|
49172
|
+
<p class="import-error">{{ errorMsg() }}</p>
|
|
49173
|
+
}
|
|
49174
|
+
|
|
49175
|
+
<div class="import-actions">
|
|
49176
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49177
|
+
@if (submitting()) {
|
|
49178
|
+
<ion-spinner name="dots" />
|
|
49179
|
+
{{ t('submitting') }}
|
|
49180
|
+
} @else {
|
|
49181
|
+
{{ t('submit') }}
|
|
49182
|
+
}
|
|
49183
|
+
</ion-button>
|
|
49184
|
+
</div>
|
|
49185
|
+
} @else {
|
|
49186
|
+
<!-- Resultados -->
|
|
49187
|
+
<val-title [props]="{ content: summaryLabel(), size: 'large', color: '', bold: true }" />
|
|
49188
|
+
<div class="import-results">
|
|
49189
|
+
@for (r of results()!.results; track r.email) {
|
|
49190
|
+
<div class="import-row import-row--{{ r.status }}">
|
|
49191
|
+
<span class="import-row__email">{{ r.email }}</span>
|
|
49192
|
+
<span class="import-row__status">{{ statusLabel(r) }}</span>
|
|
49193
|
+
@if (r.reason) {
|
|
49194
|
+
<span class="import-row__reason">{{ r.reason }}</span>
|
|
49195
|
+
}
|
|
49196
|
+
</div>
|
|
49197
|
+
}
|
|
49198
|
+
</div>
|
|
49199
|
+
<div class="import-actions">
|
|
49200
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="reset()">
|
|
49201
|
+
{{ t('again') }}
|
|
49202
|
+
</ion-button>
|
|
49203
|
+
</div>
|
|
49204
|
+
}
|
|
49205
|
+
</ion-content>
|
|
49206
|
+
`, styles: ["val-display{display:block;margin-bottom:4px}val-title{display:block;margin-bottom:12px}.import-csv{--background: var(--ion-color-light);border-radius:10px;margin-bottom:16px;font-family:monospace;font-size:13px}.import-conflict{margin-bottom:12px}.import-activation{display:block;margin-bottom:16px;font-size:14px}.import-error{margin:0 0 12px;font-size:.875rem;color:var(--ion-color-danger, #c0392b)}.import-actions{margin-top:8px}.import-results{display:flex;flex-direction:column;gap:6px;margin:12px 0}.import-row{display:grid;grid-template-columns:1fr auto;grid-row-gap:2px;align-items:center;padding:10px 12px;border-radius:8px;border-left:3px solid var(--ion-color-medium);background:var(--ion-color-light);font-size:14px}.import-row--created{border-left-color:var(--ion-color-success, #2dd36f)}.import-row--assigned{border-left-color:var(--ion-color-primary, #7026df)}.import-row--skipped{border-left-color:var(--ion-color-medium, #92949c)}.import-row--error{border-left-color:var(--ion-color-danger, #c0392b)}.import-row__email{font-weight:600;color:var(--ion-color-dark)}.import-row__status{text-align:right;color:var(--ion-color-medium-shade, #6b6e76)}.import-row__reason{grid-column:1 / -1;font-size:12px;color:var(--ion-color-danger, #c0392b)}\n"] }]
|
|
49207
|
+
}], ctorParameters: () => [], propDecorators: { orgId: [{
|
|
49208
|
+
type: Input
|
|
49209
|
+
}], availableRoles: [{
|
|
49210
|
+
type: Input
|
|
49211
|
+
}], onSuccess: [{
|
|
49212
|
+
type: Input
|
|
49213
|
+
}], _modalRef: [{
|
|
49214
|
+
type: Input
|
|
49215
|
+
}], i18nNamespace: [{
|
|
49216
|
+
type: Input
|
|
49217
|
+
}] } });
|
|
49218
|
+
|
|
49219
|
+
/**
|
|
49220
|
+
* Cliente HTTP de Client API Keys org-scopeadas (ADR-023). La org activa se
|
|
49221
|
+
* resuelve en backend desde el JWT, así que el path no la incluye.
|
|
49222
|
+
*/
|
|
49223
|
+
class ApiKeyService {
|
|
49224
|
+
constructor(config, http) {
|
|
49225
|
+
this.config = config;
|
|
49226
|
+
this.http = http;
|
|
49227
|
+
}
|
|
49228
|
+
get baseUrl() {
|
|
49229
|
+
return `${this.config.apiUrl}/org/api-keys`;
|
|
49230
|
+
}
|
|
49231
|
+
/** Lista las API keys de la org activa. */
|
|
49232
|
+
list() {
|
|
49233
|
+
return this.http.get(`${this.baseUrl}/`).pipe(map$1(r => r.keys ?? []));
|
|
49234
|
+
}
|
|
49235
|
+
/** Crea una API key. La respuesta incluye el secreto (se muestra UNA vez). */
|
|
49236
|
+
create(req) {
|
|
49237
|
+
return this.http.post(`${this.baseUrl}/`, req);
|
|
49238
|
+
}
|
|
49239
|
+
/** Revoca (elimina) una API key por id. */
|
|
49240
|
+
revoke(keyId) {
|
|
49241
|
+
return this.http.delete(`${this.baseUrl}/${keyId}`);
|
|
49242
|
+
}
|
|
49243
|
+
/** Catálogo de permisos asignables a una key. */
|
|
49244
|
+
availablePermissions() {
|
|
49245
|
+
return this.http
|
|
49246
|
+
.get(`${this.baseUrl}/permissions`)
|
|
49247
|
+
.pipe(map$1(r => r.permissions ?? []));
|
|
49248
|
+
}
|
|
49249
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeyService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1$3.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
49250
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeyService, providedIn: 'root' }); }
|
|
49251
|
+
}
|
|
49252
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeyService, decorators: [{
|
|
49253
|
+
type: Injectable,
|
|
49254
|
+
args: [{ providedIn: 'root' }]
|
|
49255
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
49256
|
+
type: Inject,
|
|
49257
|
+
args: [VALTECH_AUTH_CONFIG]
|
|
49258
|
+
}] }, { type: i1$3.HttpClient }] });
|
|
49259
|
+
|
|
49260
|
+
/**
|
|
49261
|
+
* Defaults i18n (es/en) embebidos en `val-api-keys-modal` (ADR-023).
|
|
49262
|
+
* Auto-registrados si el consumer no proveyó el namespace `Settings.ApiKeysModal`.
|
|
49263
|
+
*/
|
|
49264
|
+
const API_KEYS_MODAL_I18N = {
|
|
49265
|
+
es: {
|
|
49266
|
+
title: 'Client API Keys',
|
|
49267
|
+
hint: 'Llaves M2M org-scopeadas para integraciones (p. ej. importar miembros).',
|
|
49268
|
+
empty: 'Aún no hay API keys en esta organización.',
|
|
49269
|
+
newKey: 'Nueva API key',
|
|
49270
|
+
nameLabel: 'Nombre',
|
|
49271
|
+
namePlaceholder: 'Ej: Integración RRHH',
|
|
49272
|
+
permissionsLabel: 'Permisos',
|
|
49273
|
+
expiresLabel: 'Expira en (días, opcional)',
|
|
49274
|
+
create: 'Crear key',
|
|
49275
|
+
creating: 'Creando...',
|
|
49276
|
+
cancel: 'Cancelar',
|
|
49277
|
+
revoke: 'Revocar',
|
|
49278
|
+
revokeConfirm: '¿Revocar esta API key? Las integraciones que la usen dejarán de funcionar.',
|
|
49279
|
+
secretTitle: 'Copia tu API key ahora',
|
|
49280
|
+
secretWarning: 'Este secreto se muestra una sola vez. Guárdalo en un lugar seguro.',
|
|
49281
|
+
copy: 'Copiar',
|
|
49282
|
+
copied: 'Copiada',
|
|
49283
|
+
done: 'Listo',
|
|
49284
|
+
statusActive: 'activa',
|
|
49285
|
+
lastUsed: 'Último uso',
|
|
49286
|
+
never: 'nunca',
|
|
49287
|
+
permsCount: 'permisos',
|
|
49288
|
+
noName: 'El nombre es obligatorio.',
|
|
49289
|
+
noPerms: 'Selecciona al menos un permiso.',
|
|
49290
|
+
close: 'Cerrar',
|
|
49291
|
+
genericError: 'No se pudo completar la operación. Intenta de nuevo.',
|
|
49292
|
+
},
|
|
49293
|
+
en: {
|
|
49294
|
+
title: 'Client API Keys',
|
|
49295
|
+
hint: 'Org-scoped M2M keys for integrations (e.g. member import).',
|
|
49296
|
+
empty: 'No API keys in this organization yet.',
|
|
49297
|
+
newKey: 'New API key',
|
|
49298
|
+
nameLabel: 'Name',
|
|
49299
|
+
namePlaceholder: 'E.g: HR integration',
|
|
49300
|
+
permissionsLabel: 'Permissions',
|
|
49301
|
+
expiresLabel: 'Expires in (days, optional)',
|
|
49302
|
+
create: 'Create key',
|
|
49303
|
+
creating: 'Creating...',
|
|
49304
|
+
cancel: 'Cancel',
|
|
49305
|
+
revoke: 'Revoke',
|
|
49306
|
+
revokeConfirm: 'Revoke this API key? Integrations using it will stop working.',
|
|
49307
|
+
secretTitle: 'Copy your API key now',
|
|
49308
|
+
secretWarning: 'This secret is shown only once. Store it somewhere safe.',
|
|
49309
|
+
copy: 'Copy',
|
|
49310
|
+
copied: 'Copied',
|
|
49311
|
+
done: 'Done',
|
|
49312
|
+
statusActive: 'active',
|
|
49313
|
+
lastUsed: 'Last used',
|
|
49314
|
+
never: 'never',
|
|
49315
|
+
permsCount: 'permissions',
|
|
49316
|
+
noName: 'Name is required.',
|
|
49317
|
+
noPerms: 'Select at least one permission.',
|
|
49318
|
+
close: 'Close',
|
|
49319
|
+
genericError: "Couldn't complete the operation. Try again.",
|
|
49320
|
+
},
|
|
49321
|
+
};
|
|
49322
|
+
|
|
49323
|
+
const DEFAULT_NAMESPACE$5 = 'Settings.ApiKeysModal';
|
|
49324
|
+
/**
|
|
49325
|
+
* `val-api-keys-modal` — gestión de Client API Keys org-scopeadas (ADR-023 fase 6).
|
|
49326
|
+
*
|
|
49327
|
+
* Lista las keys de la org, permite crear (mostrando el secreto UNA vez con copia)
|
|
49328
|
+
* y revocar. Pensado para habilitar integraciones M2M del import de miembros, pero
|
|
49329
|
+
* sirve a cualquier permiso del catálogo. Header canónico (Regla #5).
|
|
49330
|
+
*/
|
|
49331
|
+
class ApiKeysModalComponent {
|
|
49332
|
+
constructor() {
|
|
49333
|
+
this.i18n = inject(I18nService);
|
|
49334
|
+
this.apiKeys = inject(ApiKeyService);
|
|
49335
|
+
/** Namespace i18n. */
|
|
49336
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$5;
|
|
49337
|
+
this.keys = signal([]);
|
|
49338
|
+
this.availablePermissions = signal([]);
|
|
49339
|
+
this.loading = signal(true);
|
|
49340
|
+
this.showCreate = signal(false);
|
|
49341
|
+
this.submitting = signal(false);
|
|
49342
|
+
this.errorMsg = signal('');
|
|
49343
|
+
this.secret = signal(null);
|
|
49344
|
+
this.copied = signal(false);
|
|
49345
|
+
this.name = '';
|
|
49346
|
+
this.expiresInDays = null;
|
|
49347
|
+
this.selectedPerms = signal(new Set());
|
|
49348
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$5)) {
|
|
49349
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$5, API_KEYS_MODAL_I18N);
|
|
49350
|
+
}
|
|
49351
|
+
}
|
|
49352
|
+
ngOnInit() {
|
|
49353
|
+
if (!this.i18n.hasNamespace(this.i18nNamespace)) {
|
|
49354
|
+
this.i18n.registerContent(this.i18nNamespace, API_KEYS_MODAL_I18N);
|
|
49355
|
+
}
|
|
49356
|
+
this.refresh();
|
|
49357
|
+
this.apiKeys.availablePermissions().subscribe({
|
|
49358
|
+
next: perms => this.availablePermissions.set(perms),
|
|
49359
|
+
error: () => { },
|
|
49360
|
+
});
|
|
49361
|
+
}
|
|
49362
|
+
refresh() {
|
|
49363
|
+
this.loading.set(true);
|
|
49364
|
+
this.apiKeys.list().subscribe({
|
|
49365
|
+
next: keys => {
|
|
49366
|
+
this.keys.set(keys);
|
|
49367
|
+
this.loading.set(false);
|
|
49368
|
+
},
|
|
49369
|
+
error: () => this.loading.set(false),
|
|
49370
|
+
});
|
|
49371
|
+
}
|
|
49372
|
+
openCreate() {
|
|
49373
|
+
this.errorMsg.set('');
|
|
49374
|
+
this.name = '';
|
|
49375
|
+
this.expiresInDays = null;
|
|
49376
|
+
this.selectedPerms.set(new Set());
|
|
49377
|
+
this.showCreate.set(true);
|
|
49378
|
+
}
|
|
49379
|
+
togglePerm(perm, ev) {
|
|
49380
|
+
const checked = ev.detail?.checked ?? false;
|
|
49381
|
+
const next = new Set(this.selectedPerms());
|
|
49382
|
+
if (checked) {
|
|
49383
|
+
next.add(perm);
|
|
49384
|
+
}
|
|
49385
|
+
else {
|
|
49386
|
+
next.delete(perm);
|
|
49387
|
+
}
|
|
49388
|
+
this.selectedPerms.set(next);
|
|
49389
|
+
}
|
|
49390
|
+
submit() {
|
|
49391
|
+
this.errorMsg.set('');
|
|
49392
|
+
if (!this.name.trim()) {
|
|
49393
|
+
this.errorMsg.set(this.t('noName'));
|
|
49394
|
+
return;
|
|
49395
|
+
}
|
|
49396
|
+
const permissions = Array.from(this.selectedPerms());
|
|
49397
|
+
if (permissions.length === 0) {
|
|
49398
|
+
this.errorMsg.set(this.t('noPerms'));
|
|
49399
|
+
return;
|
|
49400
|
+
}
|
|
49401
|
+
this.submitting.set(true);
|
|
49402
|
+
this.apiKeys
|
|
49403
|
+
.create({
|
|
49404
|
+
name: this.name.trim(),
|
|
49405
|
+
permissions,
|
|
49406
|
+
expiresInDays: this.expiresInDays && this.expiresInDays > 0 ? this.expiresInDays : undefined,
|
|
49407
|
+
})
|
|
49408
|
+
.subscribe({
|
|
49409
|
+
next: res => {
|
|
49410
|
+
this.submitting.set(false);
|
|
49411
|
+
this.showCreate.set(false);
|
|
49412
|
+
this.secret.set(res.key);
|
|
49413
|
+
},
|
|
49414
|
+
error: err => {
|
|
49415
|
+
this.submitting.set(false);
|
|
49416
|
+
this.errorMsg.set(err?.error?.message ?? this.t('genericError'));
|
|
49417
|
+
},
|
|
49418
|
+
});
|
|
49419
|
+
}
|
|
49420
|
+
revoke(key) {
|
|
49421
|
+
if (!confirm(this.t('revokeConfirm')))
|
|
49422
|
+
return;
|
|
49423
|
+
this.apiKeys.revoke(key.keyId).subscribe({
|
|
49424
|
+
next: () => this.refresh(),
|
|
49425
|
+
error: err => this.errorMsg.set(err?.error?.message ?? this.t('genericError')),
|
|
49426
|
+
});
|
|
49427
|
+
}
|
|
49428
|
+
async copy(secret) {
|
|
49429
|
+
try {
|
|
49430
|
+
await navigator.clipboard.writeText(secret);
|
|
49431
|
+
this.copied.set(true);
|
|
49432
|
+
}
|
|
49433
|
+
catch {
|
|
49434
|
+
// clipboard no disponible — el user puede seleccionar el texto manualmente
|
|
49435
|
+
}
|
|
49436
|
+
}
|
|
49437
|
+
finishSecret() {
|
|
49438
|
+
this.secret.set(null);
|
|
49439
|
+
this.copied.set(false);
|
|
49440
|
+
this.refresh();
|
|
49441
|
+
}
|
|
49442
|
+
dismiss() {
|
|
49443
|
+
this._modalRef?.dismiss(null, 'cancel');
|
|
49444
|
+
}
|
|
49445
|
+
t(key) {
|
|
49446
|
+
return this.i18n.t(key, this.i18nNamespace);
|
|
49447
|
+
}
|
|
49448
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeysModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
49449
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ApiKeysModalComponent, isStandalone: true, selector: "val-api-keys-modal", inputs: { _modalRef: "_modalRef", i18nNamespace: "i18nNamespace" }, ngImport: i0, template: `
|
|
49450
|
+
<ion-header>
|
|
49451
|
+
<ion-toolbar>
|
|
49452
|
+
<ion-buttons slot="end">
|
|
49453
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49454
|
+
<strong>{{ t('close') }}</strong>
|
|
49455
|
+
</ion-button>
|
|
49456
|
+
</ion-buttons>
|
|
49457
|
+
</ion-toolbar>
|
|
49458
|
+
</ion-header>
|
|
49459
|
+
|
|
49460
|
+
<ion-content class="ion-padding">
|
|
49461
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49462
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49463
|
+
|
|
49464
|
+
@if (secret(); as s) {
|
|
49465
|
+
<!-- Secreto recién creado: mostrar UNA vez -->
|
|
49466
|
+
<div class="apikey-secret">
|
|
49467
|
+
<val-title [props]="{ content: t('secretTitle'), size: 'large', color: '', bold: true }" />
|
|
49468
|
+
<p class="apikey-secret__warn">{{ t('secretWarning') }}</p>
|
|
49469
|
+
<div class="apikey-secret__box">
|
|
49470
|
+
<code>{{ s.secret }}</code>
|
|
49471
|
+
</div>
|
|
49472
|
+
<div class="apikey-actions">
|
|
49473
|
+
<ion-button expand="block" color="dark" (click)="copy(s.secret)">
|
|
49474
|
+
{{ copied() ? t('copied') : t('copy') }}
|
|
49475
|
+
</ion-button>
|
|
49476
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="finishSecret()">
|
|
49477
|
+
{{ t('done') }}
|
|
49478
|
+
</ion-button>
|
|
49479
|
+
</div>
|
|
49480
|
+
</div>
|
|
49481
|
+
} @else {
|
|
49482
|
+
@if (loading()) {
|
|
49483
|
+
<ion-spinner name="dots" />
|
|
49484
|
+
} @else {
|
|
49485
|
+
<!-- Lista -->
|
|
49486
|
+
@if (keys().length === 0) {
|
|
49487
|
+
<val-text [props]="{ content: t('empty'), size: 'medium', color: 'medium', bold: false }" />
|
|
49488
|
+
} @else {
|
|
49489
|
+
<div class="apikey-list">
|
|
49490
|
+
@for (k of keys(); track k.keyId) {
|
|
49491
|
+
<div class="apikey-row">
|
|
49492
|
+
<div class="apikey-row__main">
|
|
49493
|
+
<span class="apikey-row__name">{{ k.name }}</span>
|
|
49494
|
+
<span class="apikey-row__meta">
|
|
49495
|
+
{{ k.permissions.length }} {{ t('permsCount') }} · {{ t('lastUsed') }}:
|
|
49496
|
+
{{ k.lastUsedAt || t('never') }}
|
|
49497
|
+
</span>
|
|
49498
|
+
</div>
|
|
49499
|
+
<ion-button fill="clear" color="danger" size="small" (click)="revoke(k)">
|
|
49500
|
+
{{ t('revoke') }}
|
|
49501
|
+
</ion-button>
|
|
49502
|
+
</div>
|
|
49503
|
+
}
|
|
49504
|
+
</div>
|
|
49505
|
+
}
|
|
49506
|
+
|
|
49507
|
+
@if (errorMsg()) {
|
|
49508
|
+
<p class="apikey-error">{{ errorMsg() }}</p>
|
|
49509
|
+
}
|
|
49510
|
+
|
|
49511
|
+
<!-- Crear -->
|
|
49512
|
+
@if (showCreate()) {
|
|
49513
|
+
<div class="apikey-create">
|
|
49514
|
+
<ion-input
|
|
49515
|
+
label="{{ t('nameLabel') }}"
|
|
49516
|
+
labelPlacement="stacked"
|
|
49517
|
+
[placeholder]="t('namePlaceholder')"
|
|
49518
|
+
[(ngModel)]="name"
|
|
49519
|
+
/>
|
|
49520
|
+
<p class="apikey-create__label">{{ t('permissionsLabel') }}</p>
|
|
49521
|
+
<div class="apikey-perms">
|
|
49522
|
+
@for (p of availablePermissions(); track p) {
|
|
49523
|
+
<ion-checkbox
|
|
49524
|
+
labelPlacement="end"
|
|
49525
|
+
[checked]="selectedPerms().has(p)"
|
|
49526
|
+
(ionChange)="togglePerm(p, $event)"
|
|
49527
|
+
>
|
|
49528
|
+
{{ p }}
|
|
49529
|
+
</ion-checkbox>
|
|
49530
|
+
}
|
|
49531
|
+
</div>
|
|
49532
|
+
<ion-input
|
|
49533
|
+
label="{{ t('expiresLabel') }}"
|
|
49534
|
+
labelPlacement="stacked"
|
|
49535
|
+
type="number"
|
|
49536
|
+
[(ngModel)]="expiresInDays"
|
|
49537
|
+
/>
|
|
49538
|
+
<div class="apikey-actions">
|
|
49539
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49540
|
+
@if (submitting()) {
|
|
49541
|
+
<ion-spinner name="dots" /> {{ t('creating') }}
|
|
49542
|
+
} @else {
|
|
49543
|
+
{{ t('create') }}
|
|
49544
|
+
}
|
|
49545
|
+
</ion-button>
|
|
49546
|
+
<ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
|
|
49547
|
+
{{ t('cancel') }}
|
|
49548
|
+
</ion-button>
|
|
49549
|
+
</div>
|
|
49550
|
+
</div>
|
|
49551
|
+
} @else {
|
|
49552
|
+
<div class="apikey-actions">
|
|
49553
|
+
<ion-button expand="block" color="primary" (click)="openCreate()">
|
|
49554
|
+
{{ t('newKey') }}
|
|
49555
|
+
</ion-button>
|
|
49556
|
+
</div>
|
|
49557
|
+
}
|
|
49558
|
+
}
|
|
49559
|
+
}
|
|
49560
|
+
</ion-content>
|
|
49561
|
+
`, isInline: true, styles: ["val-display{display:block;margin-bottom:4px}val-title{display:block;margin-bottom:12px}.apikey-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}.apikey-row{display:flex;align-items:center;justify-content:space-between;padding:12px;border-radius:10px;border:1.5px solid var(--ion-color-light)}.apikey-row__main{display:flex;flex-direction:column}.apikey-row__name{font-weight:600;color:var(--ion-color-dark)}.apikey-row__meta{font-size:12px;color:var(--ion-color-medium-shade, #6b6e76)}.apikey-create{margin-top:8px;padding:16px;border-radius:12px;background:var(--ion-color-light)}.apikey-create__label{margin:12px 0 4px;font-size:13px;font-weight:600;color:var(--ion-color-dark)}.apikey-perms{display:flex;flex-direction:column;gap:6px;margin-bottom:12px;font-size:13px}.apikey-actions{margin-top:16px;display:flex;flex-direction:column;gap:8px}.apikey-error{margin:8px 0;font-size:.875rem;color:var(--ion-color-danger, #c0392b)}.apikey-secret__warn{font-size:.875rem;color:var(--ion-color-warning-shade, #b88600);margin:0 0 12px}.apikey-secret__box{padding:12px;border-radius:8px;background:var(--ion-color-dark);color:#fff;word-break:break-all;font-family:monospace;font-size:13px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }] }); }
|
|
49562
|
+
}
|
|
49563
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeysModalComponent, decorators: [{
|
|
49564
|
+
type: Component,
|
|
49565
|
+
args: [{ selector: 'val-api-keys-modal', standalone: true, imports: [
|
|
49566
|
+
FormsModule,
|
|
49567
|
+
IonHeader,
|
|
49568
|
+
IonToolbar,
|
|
49569
|
+
IonButtons,
|
|
49570
|
+
IonButton,
|
|
49571
|
+
IonContent,
|
|
49572
|
+
IonInput,
|
|
49573
|
+
IonCheckbox,
|
|
49574
|
+
IonSpinner,
|
|
49575
|
+
DisplayComponent,
|
|
49576
|
+
TextComponent,
|
|
49577
|
+
TitleComponent,
|
|
49578
|
+
], template: `
|
|
49579
|
+
<ion-header>
|
|
49580
|
+
<ion-toolbar>
|
|
49581
|
+
<ion-buttons slot="end">
|
|
49582
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49583
|
+
<strong>{{ t('close') }}</strong>
|
|
49584
|
+
</ion-button>
|
|
49585
|
+
</ion-buttons>
|
|
49586
|
+
</ion-toolbar>
|
|
49587
|
+
</ion-header>
|
|
49588
|
+
|
|
49589
|
+
<ion-content class="ion-padding">
|
|
49590
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49591
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49592
|
+
|
|
49593
|
+
@if (secret(); as s) {
|
|
49594
|
+
<!-- Secreto recién creado: mostrar UNA vez -->
|
|
49595
|
+
<div class="apikey-secret">
|
|
49596
|
+
<val-title [props]="{ content: t('secretTitle'), size: 'large', color: '', bold: true }" />
|
|
49597
|
+
<p class="apikey-secret__warn">{{ t('secretWarning') }}</p>
|
|
49598
|
+
<div class="apikey-secret__box">
|
|
49599
|
+
<code>{{ s.secret }}</code>
|
|
49600
|
+
</div>
|
|
49601
|
+
<div class="apikey-actions">
|
|
49602
|
+
<ion-button expand="block" color="dark" (click)="copy(s.secret)">
|
|
49603
|
+
{{ copied() ? t('copied') : t('copy') }}
|
|
49604
|
+
</ion-button>
|
|
49605
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="finishSecret()">
|
|
49606
|
+
{{ t('done') }}
|
|
49607
|
+
</ion-button>
|
|
49608
|
+
</div>
|
|
49609
|
+
</div>
|
|
49610
|
+
} @else {
|
|
49611
|
+
@if (loading()) {
|
|
49612
|
+
<ion-spinner name="dots" />
|
|
49613
|
+
} @else {
|
|
49614
|
+
<!-- Lista -->
|
|
49615
|
+
@if (keys().length === 0) {
|
|
49616
|
+
<val-text [props]="{ content: t('empty'), size: 'medium', color: 'medium', bold: false }" />
|
|
49617
|
+
} @else {
|
|
49618
|
+
<div class="apikey-list">
|
|
49619
|
+
@for (k of keys(); track k.keyId) {
|
|
49620
|
+
<div class="apikey-row">
|
|
49621
|
+
<div class="apikey-row__main">
|
|
49622
|
+
<span class="apikey-row__name">{{ k.name }}</span>
|
|
49623
|
+
<span class="apikey-row__meta">
|
|
49624
|
+
{{ k.permissions.length }} {{ t('permsCount') }} · {{ t('lastUsed') }}:
|
|
49625
|
+
{{ k.lastUsedAt || t('never') }}
|
|
49626
|
+
</span>
|
|
49627
|
+
</div>
|
|
49628
|
+
<ion-button fill="clear" color="danger" size="small" (click)="revoke(k)">
|
|
49629
|
+
{{ t('revoke') }}
|
|
49630
|
+
</ion-button>
|
|
49631
|
+
</div>
|
|
49632
|
+
}
|
|
49633
|
+
</div>
|
|
49634
|
+
}
|
|
49635
|
+
|
|
49636
|
+
@if (errorMsg()) {
|
|
49637
|
+
<p class="apikey-error">{{ errorMsg() }}</p>
|
|
49638
|
+
}
|
|
49639
|
+
|
|
49640
|
+
<!-- Crear -->
|
|
49641
|
+
@if (showCreate()) {
|
|
49642
|
+
<div class="apikey-create">
|
|
49643
|
+
<ion-input
|
|
49644
|
+
label="{{ t('nameLabel') }}"
|
|
49645
|
+
labelPlacement="stacked"
|
|
49646
|
+
[placeholder]="t('namePlaceholder')"
|
|
49647
|
+
[(ngModel)]="name"
|
|
49648
|
+
/>
|
|
49649
|
+
<p class="apikey-create__label">{{ t('permissionsLabel') }}</p>
|
|
49650
|
+
<div class="apikey-perms">
|
|
49651
|
+
@for (p of availablePermissions(); track p) {
|
|
49652
|
+
<ion-checkbox
|
|
49653
|
+
labelPlacement="end"
|
|
49654
|
+
[checked]="selectedPerms().has(p)"
|
|
49655
|
+
(ionChange)="togglePerm(p, $event)"
|
|
49656
|
+
>
|
|
49657
|
+
{{ p }}
|
|
49658
|
+
</ion-checkbox>
|
|
49659
|
+
}
|
|
49660
|
+
</div>
|
|
49661
|
+
<ion-input
|
|
49662
|
+
label="{{ t('expiresLabel') }}"
|
|
49663
|
+
labelPlacement="stacked"
|
|
49664
|
+
type="number"
|
|
49665
|
+
[(ngModel)]="expiresInDays"
|
|
49666
|
+
/>
|
|
49667
|
+
<div class="apikey-actions">
|
|
49668
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49669
|
+
@if (submitting()) {
|
|
49670
|
+
<ion-spinner name="dots" /> {{ t('creating') }}
|
|
49671
|
+
} @else {
|
|
49672
|
+
{{ t('create') }}
|
|
49673
|
+
}
|
|
49674
|
+
</ion-button>
|
|
49675
|
+
<ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
|
|
49676
|
+
{{ t('cancel') }}
|
|
49677
|
+
</ion-button>
|
|
49678
|
+
</div>
|
|
49679
|
+
</div>
|
|
49680
|
+
} @else {
|
|
49681
|
+
<div class="apikey-actions">
|
|
49682
|
+
<ion-button expand="block" color="primary" (click)="openCreate()">
|
|
49683
|
+
{{ t('newKey') }}
|
|
49684
|
+
</ion-button>
|
|
49685
|
+
</div>
|
|
49686
|
+
}
|
|
49687
|
+
}
|
|
49688
|
+
}
|
|
49689
|
+
</ion-content>
|
|
49690
|
+
`, styles: ["val-display{display:block;margin-bottom:4px}val-title{display:block;margin-bottom:12px}.apikey-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}.apikey-row{display:flex;align-items:center;justify-content:space-between;padding:12px;border-radius:10px;border:1.5px solid var(--ion-color-light)}.apikey-row__main{display:flex;flex-direction:column}.apikey-row__name{font-weight:600;color:var(--ion-color-dark)}.apikey-row__meta{font-size:12px;color:var(--ion-color-medium-shade, #6b6e76)}.apikey-create{margin-top:8px;padding:16px;border-radius:12px;background:var(--ion-color-light)}.apikey-create__label{margin:12px 0 4px;font-size:13px;font-weight:600;color:var(--ion-color-dark)}.apikey-perms{display:flex;flex-direction:column;gap:6px;margin-bottom:12px;font-size:13px}.apikey-actions{margin-top:16px;display:flex;flex-direction:column;gap:8px}.apikey-error{margin:8px 0;font-size:.875rem;color:var(--ion-color-danger, #c0392b)}.apikey-secret__warn{font-size:.875rem;color:var(--ion-color-warning-shade, #b88600);margin:0 0 12px}.apikey-secret__box{padding:12px;border-radius:8px;background:var(--ion-color-dark);color:#fff;word-break:break-all;font-family:monospace;font-size:13px}\n"] }]
|
|
49691
|
+
}], ctorParameters: () => [], propDecorators: { _modalRef: [{
|
|
49692
|
+
type: Input
|
|
49693
|
+
}], i18nNamespace: [{
|
|
49694
|
+
type: Input
|
|
49695
|
+
}] } });
|
|
49696
|
+
|
|
48834
49697
|
/**
|
|
48835
49698
|
* Defaults i18n (es/en) embebidos en `val-organization-view`. Auto-registrados en
|
|
48836
49699
|
* el constructor del componente si el consumer no proveyó el namespace
|
|
@@ -48886,6 +49749,16 @@ const ORGANIZATION_VIEW_I18N = {
|
|
|
48886
49749
|
inviteCtaTitle: '¿Deseas agregar a alguien?',
|
|
48887
49750
|
inviteCtaHint: 'Invita a usuarios a unirse a tu organización.',
|
|
48888
49751
|
inviteOpen: 'Invitar',
|
|
49752
|
+
importOpen: 'Importar',
|
|
49753
|
+
apiKeysOpen: 'Gestionar',
|
|
49754
|
+
apiKeysSectionTitle: 'Integraciones (API Keys)',
|
|
49755
|
+
apiKeysSectionHint: 'También puedes operar tu organización vía API: crea una Client API Key org-scopeada para integraciones máquina-a-máquina (por ejemplo, dar de alta miembros en masa desde tu propio sistema).',
|
|
49756
|
+
apiKeysMoreInfo: 'Más información',
|
|
49757
|
+
orgsMoreInfo: 'Más información',
|
|
49758
|
+
orgsInfoTitle: '¿Qué son las organizaciones?',
|
|
49759
|
+
orgsInfoSubtitle: 'Todo lo que necesitas saber',
|
|
49760
|
+
orgsInfoClose: 'Cerrar',
|
|
49761
|
+
orgsInfoContent: 'Las organizaciones te permiten separar tus proyectos y datos por empresa, equipo o contexto. Puedes pertenecer a varias organizaciones y cambiar entre ellas en cualquier momento.\n\nCada organización tiene sus propios miembros, roles y permisos. La organización activa determina qué datos ves y qué acciones puedes realizar.\n\nPuedes crear una organización nueva o unirte a una existente mediante invitación.',
|
|
48889
49762
|
viewMemberCta: 'Ver miembro',
|
|
48890
49763
|
roleViewer: 'Visor',
|
|
48891
49764
|
roleEditor: 'Editor',
|
|
@@ -48955,6 +49828,16 @@ const ORGANIZATION_VIEW_I18N = {
|
|
|
48955
49828
|
inviteCtaTitle: 'Want to add someone?',
|
|
48956
49829
|
inviteCtaHint: 'Invite users to join your organization.',
|
|
48957
49830
|
inviteOpen: 'Invite',
|
|
49831
|
+
importOpen: 'Import',
|
|
49832
|
+
apiKeysOpen: 'Manage',
|
|
49833
|
+
apiKeysSectionTitle: 'Integrations (API Keys)',
|
|
49834
|
+
apiKeysSectionHint: 'You can also operate your organization via API: create an org-scoped Client API Key for machine-to-machine integrations (for example, bulk-provisioning members from your own system).',
|
|
49835
|
+
apiKeysMoreInfo: 'More information',
|
|
49836
|
+
orgsMoreInfo: 'More information',
|
|
49837
|
+
orgsInfoTitle: 'What are organizations?',
|
|
49838
|
+
orgsInfoSubtitle: 'Everything you need to know',
|
|
49839
|
+
orgsInfoClose: 'Close',
|
|
49840
|
+
orgsInfoContent: 'Organizations let you separate your projects and data by company, team, or context. You can belong to multiple organizations and switch between them at any time.\n\nEach organization has its own members, roles, and permissions. The active organization determines what data you see and what actions you can take.\n\nYou can create a new organization or join an existing one via invitation.',
|
|
48958
49841
|
viewMemberCta: 'View member',
|
|
48959
49842
|
roleViewer: 'Viewer',
|
|
48960
49843
|
roleEditor: 'Editor',
|
|
@@ -49068,6 +49951,22 @@ class OrganizationViewComponent {
|
|
|
49068
49951
|
this.members = signal([]);
|
|
49069
49952
|
this.membersLoading = signal(false);
|
|
49070
49953
|
this.membersLoadError = signal(null);
|
|
49954
|
+
this.membersErrorState = computed(() => {
|
|
49955
|
+
this.i18n.lang();
|
|
49956
|
+
const err = this.membersLoadError();
|
|
49957
|
+
if (!err)
|
|
49958
|
+
return null;
|
|
49959
|
+
return createErrorStateProps(err, {
|
|
49960
|
+
title: { offline: this.tt('offlineTitle'), error: this.tt('errorTitle') },
|
|
49961
|
+
description: {
|
|
49962
|
+
offline: this.tt('offlineHint'),
|
|
49963
|
+
error: interpretError(err).message,
|
|
49964
|
+
},
|
|
49965
|
+
retryLabel: this.tt('retry'),
|
|
49966
|
+
onRetry: () => this.loadMembers(),
|
|
49967
|
+
retrying: this.membersLoading(),
|
|
49968
|
+
});
|
|
49969
|
+
});
|
|
49071
49970
|
this.membersNextToken = signal(null);
|
|
49072
49971
|
this.loadingMoreMembers = signal(false);
|
|
49073
49972
|
this.showAllMembers = signal(false);
|
|
@@ -49154,6 +50053,22 @@ class OrganizationViewComponent {
|
|
|
49154
50053
|
shape: 'round',
|
|
49155
50054
|
type: 'button',
|
|
49156
50055
|
}));
|
|
50056
|
+
this.openImportButtonProps = computed(() => ({
|
|
50057
|
+
text: this.tt('importOpen'),
|
|
50058
|
+
color: 'dark',
|
|
50059
|
+
fill: 'outline',
|
|
50060
|
+
size: 'default',
|
|
50061
|
+
shape: 'round',
|
|
50062
|
+
type: 'button',
|
|
50063
|
+
}));
|
|
50064
|
+
this.openApiKeysButtonProps = computed(() => ({
|
|
50065
|
+
text: this.tt('apiKeysOpen'),
|
|
50066
|
+
color: 'dark',
|
|
50067
|
+
fill: 'clear',
|
|
50068
|
+
size: 'default',
|
|
50069
|
+
shape: 'round',
|
|
50070
|
+
type: 'button',
|
|
50071
|
+
}));
|
|
49157
50072
|
/** Guarda para detectar el primer disparo del effect (evita doble carga). */
|
|
49158
50073
|
this.lastLoadedOrgId = null;
|
|
49159
50074
|
const ns = this.ns;
|
|
@@ -49254,6 +50169,59 @@ class OrganizationViewComponent {
|
|
|
49254
50169
|
backdropDismiss: true,
|
|
49255
50170
|
});
|
|
49256
50171
|
}
|
|
50172
|
+
onOpenImport() {
|
|
50173
|
+
void this.modalService.open({
|
|
50174
|
+
component: MemberImportModalComponent,
|
|
50175
|
+
componentProps: {
|
|
50176
|
+
orgId: this.activeOrgId(),
|
|
50177
|
+
availableRoles: this.availableRoles().map(r => r.name),
|
|
50178
|
+
onSuccess: () => {
|
|
50179
|
+
this.loadMembers();
|
|
50180
|
+
this.resolvedConfig().onMemberInvited?.();
|
|
50181
|
+
},
|
|
50182
|
+
},
|
|
50183
|
+
breakpoints: {
|
|
50184
|
+
breakpoints: [0, 0.92],
|
|
50185
|
+
initialBreakpoint: 0.92,
|
|
50186
|
+
showHandle: true,
|
|
50187
|
+
},
|
|
50188
|
+
backdropDismiss: true,
|
|
50189
|
+
});
|
|
50190
|
+
}
|
|
50191
|
+
onOpenApiKeys() {
|
|
50192
|
+
void this.modalService.open({
|
|
50193
|
+
component: ApiKeysModalComponent,
|
|
50194
|
+
breakpoints: {
|
|
50195
|
+
breakpoints: [0, 0.92],
|
|
50196
|
+
initialBreakpoint: 0.92,
|
|
50197
|
+
showHandle: true,
|
|
50198
|
+
},
|
|
50199
|
+
backdropDismiss: true,
|
|
50200
|
+
});
|
|
50201
|
+
}
|
|
50202
|
+
// "Más información" sobre organizaciones — mismo sheet explicativo que muestra
|
|
50203
|
+
// account-view sin org, pero disponible siempre (todo user tiene org por defecto).
|
|
50204
|
+
onOrgInfo() {
|
|
50205
|
+
void this.modalService.open({
|
|
50206
|
+
component: OrgInfoSheetComponent,
|
|
50207
|
+
componentProps: {
|
|
50208
|
+
title: this.tt('orgsInfoTitle'),
|
|
50209
|
+
subtitle: this.tt('orgsInfoSubtitle'),
|
|
50210
|
+
body: this.tt('orgsInfoContent'),
|
|
50211
|
+
closeLabel: this.tt('orgsInfoClose'),
|
|
50212
|
+
closeProps: {
|
|
50213
|
+
text: this.tt('orgsInfoClose'),
|
|
50214
|
+
fill: 'outline',
|
|
50215
|
+
color: 'dark',
|
|
50216
|
+
size: 'default',
|
|
50217
|
+
expand: 'block',
|
|
50218
|
+
type: 'button',
|
|
50219
|
+
},
|
|
50220
|
+
},
|
|
50221
|
+
breakpoints: { breakpoints: [0, 0.85], initialBreakpoint: 0.85, showHandle: true },
|
|
50222
|
+
backdropDismiss: true,
|
|
50223
|
+
});
|
|
50224
|
+
}
|
|
49257
50225
|
onViewPermissions() {
|
|
49258
50226
|
this.nav.navigateByUrl(this.resolvedConfig().viewPermissionsRoute);
|
|
49259
50227
|
}
|
|
@@ -49335,6 +50303,7 @@ class OrganizationViewComponent {
|
|
|
49335
50303
|
if (!orgId)
|
|
49336
50304
|
return Promise.resolve();
|
|
49337
50305
|
this.membersLoading.set(true);
|
|
50306
|
+
this.membersLoadError.set(null);
|
|
49338
50307
|
this.membersNextToken.set(null);
|
|
49339
50308
|
this.showAllMembers.set(false);
|
|
49340
50309
|
return new Promise(resolve => {
|
|
@@ -49498,6 +50467,12 @@ class OrganizationViewComponent {
|
|
|
49498
50467
|
}
|
|
49499
50468
|
</div>
|
|
49500
50469
|
|
|
50470
|
+
<!-- "Más información" sobre organizaciones — disponible siempre (todo
|
|
50471
|
+
user tiene org por defecto y no ve el empty-state de account). -->
|
|
50472
|
+
<button class="org-more-info-link" type="button" (click)="onOrgInfo()">
|
|
50473
|
+
{{ tt('orgsMoreInfo') }}
|
|
50474
|
+
</button>
|
|
50475
|
+
|
|
49501
50476
|
<div class="section-body">
|
|
49502
50477
|
@if (loading()) {
|
|
49503
50478
|
<val-skeleton-layout [props]="{ preset: 'detail', rows: 4 }" />
|
|
@@ -49545,6 +50520,8 @@ class OrganizationViewComponent {
|
|
|
49545
50520
|
<div class="section-body">
|
|
49546
50521
|
@if (membersLoading()) {
|
|
49547
50522
|
<val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
|
|
50523
|
+
} @else if (membersErrorState()) {
|
|
50524
|
+
<val-empty-state [props]="membersErrorState()!" />
|
|
49548
50525
|
} @else if (members().length === 0) {
|
|
49549
50526
|
<val-text
|
|
49550
50527
|
[props]="{
|
|
@@ -49637,10 +50614,25 @@ class OrganizationViewComponent {
|
|
|
49637
50614
|
/>
|
|
49638
50615
|
</div>
|
|
49639
50616
|
<val-button [props]="openInviteButtonProps()" (click)="onOpenInvite()" />
|
|
50617
|
+
<val-button [props]="openImportButtonProps()" (click)="onOpenImport()" />
|
|
49640
50618
|
</div>
|
|
49641
50619
|
</section>
|
|
49642
50620
|
}
|
|
49643
50621
|
|
|
50622
|
+
<!-- API Keys: sección propia. Integraciones M2M (import de miembros, etc.). -->
|
|
50623
|
+
<section *valHasPermission="'api-keys:read'" class="settings-section" data-testid="org-apikeys-section">
|
|
50624
|
+
<div class="invite-cta">
|
|
50625
|
+
<div class="invite-cta__text">
|
|
50626
|
+
<val-title [props]="{ size: 'medium', color: 'dark', bold: true, content: tt('apiKeysSectionTitle') }" />
|
|
50627
|
+
<val-text [props]="{ size: 'medium', color: 'dark', bold: false, content: tt('apiKeysSectionHint') }" />
|
|
50628
|
+
<button class="org-more-info-link" type="button" (click)="onOpenApiKeys()">
|
|
50629
|
+
{{ tt('apiKeysMoreInfo') }}
|
|
50630
|
+
</button>
|
|
50631
|
+
</div>
|
|
50632
|
+
<val-button [props]="openApiKeysButtonProps()" (click)="onOpenApiKeys()" />
|
|
50633
|
+
</div>
|
|
50634
|
+
</section>
|
|
50635
|
+
|
|
49644
50636
|
@if (resolvedConfig().showTransferOwnership && isOwner()) {
|
|
49645
50637
|
<!-- Transfer ownership: solo owner (gating RBAC interno) -->
|
|
49646
50638
|
<section class="settings-section" data-testid="org-transfer-section">
|
|
@@ -49731,7 +50723,7 @@ class OrganizationViewComponent {
|
|
|
49731
50723
|
</section>
|
|
49732
50724
|
}
|
|
49733
50725
|
</div>
|
|
49734
|
-
`, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field--full{width:100%}.org-info-field:last-child{border-bottom:none}.org-info-row{display:flex}.org-info-row .org-info-field{flex:1}.org-info-row .org-info-field:first-child{border-right:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "directive", type: HasPermissionDirective, selector: "[valHasPermission]", inputs: ["valHasPermission"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: MemberCardComponent, selector: "val-member-card", inputs: ["props"], outputs: ["onAction"] }] }); }
|
|
50726
|
+
`, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field--full{width:100%}.org-info-field:last-child{border-bottom:none}.org-info-row{display:flex}.org-info-row .org-info-field{flex:1}.org-info-row .org-info-field:first-child{border-right:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "directive", type: HasPermissionDirective, selector: "[valHasPermission]", inputs: ["valHasPermission"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: MemberCardComponent, selector: "val-member-card", inputs: ["props"], outputs: ["onAction"] }] }); }
|
|
49735
50727
|
}
|
|
49736
50728
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrganizationViewComponent, decorators: [{
|
|
49737
50729
|
type: Component,
|
|
@@ -49745,6 +50737,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49745
50737
|
ButtonComponent,
|
|
49746
50738
|
MemberCardComponent,
|
|
49747
50739
|
TransferOwnershipModalComponent,
|
|
50740
|
+
MemberImportModalComponent,
|
|
50741
|
+
ApiKeysModalComponent,
|
|
50742
|
+
OrgInfoSheetComponent,
|
|
49748
50743
|
], template: `
|
|
49749
50744
|
<div class="page">
|
|
49750
50745
|
<header class="page-header">
|
|
@@ -49776,6 +50771,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49776
50771
|
}
|
|
49777
50772
|
</div>
|
|
49778
50773
|
|
|
50774
|
+
<!-- "Más información" sobre organizaciones — disponible siempre (todo
|
|
50775
|
+
user tiene org por defecto y no ve el empty-state de account). -->
|
|
50776
|
+
<button class="org-more-info-link" type="button" (click)="onOrgInfo()">
|
|
50777
|
+
{{ tt('orgsMoreInfo') }}
|
|
50778
|
+
</button>
|
|
50779
|
+
|
|
49779
50780
|
<div class="section-body">
|
|
49780
50781
|
@if (loading()) {
|
|
49781
50782
|
<val-skeleton-layout [props]="{ preset: 'detail', rows: 4 }" />
|
|
@@ -49823,6 +50824,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49823
50824
|
<div class="section-body">
|
|
49824
50825
|
@if (membersLoading()) {
|
|
49825
50826
|
<val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
|
|
50827
|
+
} @else if (membersErrorState()) {
|
|
50828
|
+
<val-empty-state [props]="membersErrorState()!" />
|
|
49826
50829
|
} @else if (members().length === 0) {
|
|
49827
50830
|
<val-text
|
|
49828
50831
|
[props]="{
|
|
@@ -49915,10 +50918,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49915
50918
|
/>
|
|
49916
50919
|
</div>
|
|
49917
50920
|
<val-button [props]="openInviteButtonProps()" (click)="onOpenInvite()" />
|
|
50921
|
+
<val-button [props]="openImportButtonProps()" (click)="onOpenImport()" />
|
|
49918
50922
|
</div>
|
|
49919
50923
|
</section>
|
|
49920
50924
|
}
|
|
49921
50925
|
|
|
50926
|
+
<!-- API Keys: sección propia. Integraciones M2M (import de miembros, etc.). -->
|
|
50927
|
+
<section *valHasPermission="'api-keys:read'" class="settings-section" data-testid="org-apikeys-section">
|
|
50928
|
+
<div class="invite-cta">
|
|
50929
|
+
<div class="invite-cta__text">
|
|
50930
|
+
<val-title [props]="{ size: 'medium', color: 'dark', bold: true, content: tt('apiKeysSectionTitle') }" />
|
|
50931
|
+
<val-text [props]="{ size: 'medium', color: 'dark', bold: false, content: tt('apiKeysSectionHint') }" />
|
|
50932
|
+
<button class="org-more-info-link" type="button" (click)="onOpenApiKeys()">
|
|
50933
|
+
{{ tt('apiKeysMoreInfo') }}
|
|
50934
|
+
</button>
|
|
50935
|
+
</div>
|
|
50936
|
+
<val-button [props]="openApiKeysButtonProps()" (click)="onOpenApiKeys()" />
|
|
50937
|
+
</div>
|
|
50938
|
+
</section>
|
|
50939
|
+
|
|
49922
50940
|
@if (resolvedConfig().showTransferOwnership && isOwner()) {
|
|
49923
50941
|
<!-- Transfer ownership: solo owner (gating RBAC interno) -->
|
|
49924
50942
|
<section class="settings-section" data-testid="org-transfer-section">
|
|
@@ -50009,7 +51027,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
50009
51027
|
</section>
|
|
50010
51028
|
}
|
|
50011
51029
|
</div>
|
|
50012
|
-
`, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field--full{width:100%}.org-info-field:last-child{border-bottom:none}.org-info-row{display:flex}.org-info-row .org-info-field{flex:1}.org-info-row .org-info-field:first-child{border-right:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"] }]
|
|
51030
|
+
`, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field--full{width:100%}.org-info-field:last-child{border-bottom:none}.org-info-row{display:flex}.org-info-row .org-info-field{flex:1}.org-info-row .org-info-field:first-child{border-right:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"] }]
|
|
50013
51031
|
}], ctorParameters: () => [], propDecorators: { config: [{
|
|
50014
51032
|
type: Input
|
|
50015
51033
|
}] } });
|
|
@@ -51042,13 +52060,16 @@ class PermissionsViewComponent {
|
|
|
51042
52060
|
for (const perm of role.permissions) {
|
|
51043
52061
|
const [resource, action] = perm.split(':');
|
|
51044
52062
|
const entry = byResource.get(resource);
|
|
51045
|
-
//
|
|
51046
|
-
//
|
|
51047
|
-
|
|
52063
|
+
// Sin entrada en el catálogo (el backend omite los recursos internal para
|
|
52064
|
+
// no-platform-admins) o entrada internal → NUNCA se muestra a nivel de
|
|
52065
|
+
// producto. Defensa en profundidad junto al filtro del backend (ADR-024).
|
|
52066
|
+
// Nota: el rol puede traer el permiso aunque el recurso esté filtrado del
|
|
52067
|
+
// catálogo (ej. admin tiene templates:*); por eso se descarta lo no resuelto.
|
|
52068
|
+
if (!entry || entry.scope === 'internal') {
|
|
51048
52069
|
continue;
|
|
51049
52070
|
}
|
|
51050
52071
|
const label = this.permLabel(resource, action);
|
|
51051
|
-
if (entry
|
|
52072
|
+
if (entry.scope === 'app') {
|
|
51052
52073
|
if (entry.appId === currentAppId) {
|
|
51053
52074
|
appPerms.push(label);
|
|
51054
52075
|
}
|
|
@@ -51060,7 +52081,7 @@ class PermissionsViewComponent {
|
|
|
51060
52081
|
}
|
|
51061
52082
|
}
|
|
51062
52083
|
else {
|
|
51063
|
-
//
|
|
52084
|
+
// scope === 'org' → gestión de la organización del cliente
|
|
51064
52085
|
orgPerms.push(label);
|
|
51065
52086
|
}
|
|
51066
52087
|
}
|
|
@@ -63219,5 +64240,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
63219
64240
|
* Generated bundle index. Do not edit.
|
|
63220
64241
|
*/
|
|
63221
64242
|
|
|
63222
|
-
export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, 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, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CONTENT_CARD_DEFAULTS, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentCardComponent, 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_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_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, 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, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, 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, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, 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_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
|
|
64243
|
+
export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, 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, ApiKeyService, ApiKeysModalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CONTENT_CARD_DEFAULTS, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentCardComponent, 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_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_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, 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, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, 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, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, 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_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
|
|
63223
64244
|
//# sourceMappingURL=valtech-components.mjs.map
|