valtech-components 2.0.994 → 2.0.996
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 +76 -1
- package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +5 -1
- package/esm2022/lib/services/apikeys/api-keys.service.mjs +46 -0
- package/esm2022/lib/services/apikeys/types.mjs +7 -0
- 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 +969 -42
- 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 +5 -0
- package/lib/services/apikeys/api-keys.service.d.ts +25 -0
- package/lib/services/apikeys/types.d.ts +46 -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.996';
|
|
58
58
|
|
|
59
59
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
60
60
|
let isRefreshing = false;
|
|
@@ -41750,7 +41750,7 @@ const PROFILE_VIEW_I18N = {
|
|
|
41750
41750
|
const HANDLE_PATTERN = /^[a-z_][a-z0-9_]*$/;
|
|
41751
41751
|
const HANDLE_MIN = 3;
|
|
41752
41752
|
const HANDLE_MAX = 20;
|
|
41753
|
-
const DEFAULT_NAMESPACE$
|
|
41753
|
+
const DEFAULT_NAMESPACE$f = 'Settings.Profile';
|
|
41754
41754
|
/**
|
|
41755
41755
|
* `val-profile-view` — vista Perfil full-feature autocontenida (organism).
|
|
41756
41756
|
*
|
|
@@ -41800,7 +41800,7 @@ class ProfileViewComponent {
|
|
|
41800
41800
|
showPhone: merged.showPhone ?? true,
|
|
41801
41801
|
showShareCta: merged.showShareCta ?? true,
|
|
41802
41802
|
profileBaseUrl: merged.profileBaseUrl ?? '',
|
|
41803
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
41803
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$f,
|
|
41804
41804
|
onSaved: merged.onSaved,
|
|
41805
41805
|
onAvatarUploaded: merged.onAvatarUploaded,
|
|
41806
41806
|
};
|
|
@@ -42716,7 +42716,7 @@ const PREFERENCES_VIEW_I18N = {
|
|
|
42716
42716
|
},
|
|
42717
42717
|
};
|
|
42718
42718
|
|
|
42719
|
-
const DEFAULT_NAMESPACE$
|
|
42719
|
+
const DEFAULT_NAMESPACE$e = 'Settings.General';
|
|
42720
42720
|
const DEFAULT_LANGUAGES = ['es', 'en'];
|
|
42721
42721
|
/**
|
|
42722
42722
|
* `val-preferences-view` — vista de preferencias de UI cross-app (tema +
|
|
@@ -42753,7 +42753,7 @@ class PreferencesViewComponent {
|
|
|
42753
42753
|
showLanguage: merged.showLanguage ?? true,
|
|
42754
42754
|
showFontSize: merged.showFontSize ?? true,
|
|
42755
42755
|
supportedLanguages: merged.supportedLanguages ?? DEFAULT_LANGUAGES,
|
|
42756
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
42756
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$e,
|
|
42757
42757
|
onThemeChanged: merged.onThemeChanged,
|
|
42758
42758
|
onLanguageChanged: merged.onLanguageChanged,
|
|
42759
42759
|
onFontSizeChanged: merged.onFontSizeChanged,
|
|
@@ -44565,7 +44565,7 @@ const SECURITY_VIEW_I18N = {
|
|
|
44565
44565
|
};
|
|
44566
44566
|
|
|
44567
44567
|
addIcons({ laptopOutline, phonePortraitOutline });
|
|
44568
|
-
const DEFAULT_NAMESPACE$
|
|
44568
|
+
const DEFAULT_NAMESPACE$d = 'Settings.Security';
|
|
44569
44569
|
/**
|
|
44570
44570
|
* `val-security-view` — vista Seguridad full-feature autocontenida (organism).
|
|
44571
44571
|
*
|
|
@@ -44614,7 +44614,7 @@ class SecurityViewComponent {
|
|
|
44614
44614
|
showChangeEmail: merged.showChangeEmail ?? true,
|
|
44615
44615
|
showMfa: merged.showMfa ?? true,
|
|
44616
44616
|
showPolicies: merged.showPolicies ?? true,
|
|
44617
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
44617
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$d,
|
|
44618
44618
|
handleDeepLinks: merged.handleDeepLinks ?? true,
|
|
44619
44619
|
homeRoute: merged.homeRoute ?? '/app/home',
|
|
44620
44620
|
onMfaCompleted: merged.onMfaCompleted,
|
|
@@ -45416,6 +45416,13 @@ class OrgService {
|
|
|
45416
45416
|
inviteUser(orgId, req) {
|
|
45417
45417
|
return this.http.post(`${this.baseUrl}/${orgId}/invite`, req);
|
|
45418
45418
|
}
|
|
45419
|
+
/**
|
|
45420
|
+
* Crea/asigna miembros en masa (ADR-023). Resultado por-fila (partial success):
|
|
45421
|
+
* `created` (pre-aprovisionado), `assigned` (ya existía), `skipped`, `error`.
|
|
45422
|
+
*/
|
|
45423
|
+
importMembers(orgId, req) {
|
|
45424
|
+
return this.http.post(`${this.baseUrl}/${orgId}/members/import`, req);
|
|
45425
|
+
}
|
|
45419
45426
|
leaveOrg(orgId) {
|
|
45420
45427
|
return this.http.post(`${this.baseUrl}/${orgId}/leave`, {});
|
|
45421
45428
|
}
|
|
@@ -45520,7 +45527,7 @@ const CREATE_ORG_MODAL_I18N = {
|
|
|
45520
45527
|
},
|
|
45521
45528
|
};
|
|
45522
45529
|
|
|
45523
|
-
const DEFAULT_NAMESPACE$
|
|
45530
|
+
const DEFAULT_NAMESPACE$c = 'CreateOrgModal';
|
|
45524
45531
|
/**
|
|
45525
45532
|
* `val-create-org-modal` — modal de creación de organización (organism
|
|
45526
45533
|
* compartido). Promovido desde `showcase` bajo el proceso de ADR-021. Reusado por
|
|
@@ -45546,10 +45553,10 @@ class CreateOrgModalComponent {
|
|
|
45546
45553
|
this.toast = inject(ToastService);
|
|
45547
45554
|
this.errors = inject(ValtechErrorService);
|
|
45548
45555
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
45549
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
45556
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$c;
|
|
45550
45557
|
this._busy = signal(false);
|
|
45551
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
45552
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
45558
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$c)) {
|
|
45559
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$c, CREATE_ORG_MODAL_I18N);
|
|
45553
45560
|
}
|
|
45554
45561
|
this.formMeta = signal(this.buildFormMeta());
|
|
45555
45562
|
effect(() => {
|
|
@@ -45785,7 +45792,7 @@ const DELETE_ACCOUNT_MODAL_I18N = {
|
|
|
45785
45792
|
},
|
|
45786
45793
|
};
|
|
45787
45794
|
|
|
45788
|
-
const DEFAULT_NAMESPACE$
|
|
45795
|
+
const DEFAULT_NAMESPACE$b = 'Settings.DeleteAccount';
|
|
45789
45796
|
/**
|
|
45790
45797
|
* `val-delete-account-modal` — modal de eliminación de cuenta (organism,
|
|
45791
45798
|
* cuenta-específico). Promovido desde `showcase` bajo el proceso de ADR-021.
|
|
@@ -45811,7 +45818,7 @@ class DeleteAccountModalComponent {
|
|
|
45811
45818
|
this.i18n = inject(I18nService);
|
|
45812
45819
|
this.toast = inject(ToastService);
|
|
45813
45820
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
45814
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
45821
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$b;
|
|
45815
45822
|
this.hasPassword = signal(null);
|
|
45816
45823
|
this.codeSent = signal(false);
|
|
45817
45824
|
this.formState = signal(ComponentStates.ENABLED);
|
|
@@ -45878,8 +45885,8 @@ class DeleteAccountModalComponent {
|
|
|
45878
45885
|
],
|
|
45879
45886
|
actions: this.submitBtn('delete-code-submit', 'confirmCta'),
|
|
45880
45887
|
}));
|
|
45881
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
45882
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
45888
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$b)) {
|
|
45889
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$b, DELETE_ACCOUNT_MODAL_I18N);
|
|
45883
45890
|
}
|
|
45884
45891
|
}
|
|
45885
45892
|
ngOnInit() {
|
|
@@ -46080,7 +46087,7 @@ const ORG_INFO_SHEET_I18N = {
|
|
|
46080
46087
|
},
|
|
46081
46088
|
};
|
|
46082
46089
|
|
|
46083
|
-
const DEFAULT_NAMESPACE$
|
|
46090
|
+
const DEFAULT_NAMESPACE$a = 'OrgInfoSheet';
|
|
46084
46091
|
/**
|
|
46085
46092
|
* `val-org-info-sheet` — sheet informativo "¿Qué son las organizaciones?".
|
|
46086
46093
|
* Extraído del `OrgInfoSheetComponent` inline de `AccountPage` bajo el proceso de
|
|
@@ -46125,15 +46132,15 @@ class OrgInfoSheetComponent {
|
|
|
46125
46132
|
text: this.closeProps.text || this.resolvedCloseLabel(),
|
|
46126
46133
|
}));
|
|
46127
46134
|
addIcons({ peopleOutline, swapHorizontalOutline, mailOutline });
|
|
46128
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
46129
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
46135
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$a)) {
|
|
46136
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$a, ORG_INFO_SHEET_I18N);
|
|
46130
46137
|
}
|
|
46131
46138
|
}
|
|
46132
46139
|
dismiss() {
|
|
46133
46140
|
this._modalRef?.dismiss(null, 'cancel');
|
|
46134
46141
|
}
|
|
46135
46142
|
tt(key) {
|
|
46136
|
-
return this.i18n.t(key, DEFAULT_NAMESPACE$
|
|
46143
|
+
return this.i18n.t(key, DEFAULT_NAMESPACE$a);
|
|
46137
46144
|
}
|
|
46138
46145
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgInfoSheetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
46139
46146
|
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: `
|
|
@@ -46300,7 +46307,7 @@ const SWITCH_ORG_MODAL_I18N = {
|
|
|
46300
46307
|
},
|
|
46301
46308
|
};
|
|
46302
46309
|
|
|
46303
|
-
const DEFAULT_NAMESPACE$
|
|
46310
|
+
const DEFAULT_NAMESPACE$9 = 'Settings.SwitchOrg';
|
|
46304
46311
|
addIcons({ businessOutline, checkmarkCircleOutline });
|
|
46305
46312
|
/**
|
|
46306
46313
|
* `val-switch-org-modal` — modal de cambio de organización activa (organism
|
|
@@ -46326,7 +46333,7 @@ class SwitchOrgModalComponent {
|
|
|
46326
46333
|
this.orgSwitch = inject(OrgSwitchService);
|
|
46327
46334
|
this.errors = inject(ValtechErrorService);
|
|
46328
46335
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
46329
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
46336
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$9;
|
|
46330
46337
|
this.orgs = signal([]);
|
|
46331
46338
|
this.loading = signal(false);
|
|
46332
46339
|
this.query = signal('');
|
|
@@ -46342,8 +46349,8 @@ class SwitchOrgModalComponent {
|
|
|
46342
46349
|
return list;
|
|
46343
46350
|
return list.filter(o => o.name.toLowerCase().includes(q));
|
|
46344
46351
|
});
|
|
46345
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
46346
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
46352
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$9)) {
|
|
46353
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$9, SWITCH_ORG_MODAL_I18N);
|
|
46347
46354
|
}
|
|
46348
46355
|
this.loadOrgs();
|
|
46349
46356
|
}
|
|
@@ -46661,7 +46668,7 @@ const ACCOUNT_VIEW_I18N = {
|
|
|
46661
46668
|
};
|
|
46662
46669
|
|
|
46663
46670
|
addIcons({ peopleOutline, businessOutline, chevronForwardOutline, swapHorizontalOutline, mailOutline });
|
|
46664
|
-
const DEFAULT_NAMESPACE$
|
|
46671
|
+
const DEFAULT_NAMESPACE$8 = 'Settings.Account';
|
|
46665
46672
|
const DEFAULT_MANAGE_ORG_ROUTE = '/app/settings/organization';
|
|
46666
46673
|
/**
|
|
46667
46674
|
* `val-account-view` — vista Cuenta full-feature autocontenida (organism).
|
|
@@ -46702,7 +46709,7 @@ class AccountViewComponent {
|
|
|
46702
46709
|
showNewOrgCta: merged.showNewOrgCta ?? true,
|
|
46703
46710
|
showLogout: merged.showLogout ?? true,
|
|
46704
46711
|
showDeleteAccount: merged.showDeleteAccount ?? true,
|
|
46705
|
-
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$
|
|
46712
|
+
i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$8,
|
|
46706
46713
|
manageOrgRoute: merged.manageOrgRoute ?? DEFAULT_MANAGE_ORG_ROUTE,
|
|
46707
46714
|
onOrgSwitched: merged.onOrgSwitched,
|
|
46708
46715
|
onOrgCreated: merged.onOrgCreated,
|
|
@@ -47427,7 +47434,7 @@ const EDIT_ORG_MODAL_I18N = {
|
|
|
47427
47434
|
},
|
|
47428
47435
|
};
|
|
47429
47436
|
|
|
47430
|
-
const DEFAULT_NAMESPACE$
|
|
47437
|
+
const DEFAULT_NAMESPACE$7 = 'EditOrgModal';
|
|
47431
47438
|
/**
|
|
47432
47439
|
* `val-edit-org-modal` — modal de edición de organización (nombre + descripción).
|
|
47433
47440
|
* Promovido desde `showcase` bajo el proceso de ADR-021. Reusado por la vista de
|
|
@@ -47454,10 +47461,10 @@ class EditOrgModalComponent {
|
|
|
47454
47461
|
/** Organización a editar (pasada por `componentProps`). */
|
|
47455
47462
|
this.org = null;
|
|
47456
47463
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
47457
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
47464
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$7;
|
|
47458
47465
|
this.saving = signal(false);
|
|
47459
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
47460
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
47466
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$7)) {
|
|
47467
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$7, EDIT_ORG_MODAL_I18N);
|
|
47461
47468
|
}
|
|
47462
47469
|
this.formMeta = signal(this.buildFormMeta());
|
|
47463
47470
|
effect(() => {
|
|
@@ -47695,7 +47702,7 @@ const INVITE_MEMBER_MODAL_I18N = {
|
|
|
47695
47702
|
},
|
|
47696
47703
|
};
|
|
47697
47704
|
|
|
47698
|
-
const DEFAULT_NAMESPACE$
|
|
47705
|
+
const DEFAULT_NAMESPACE$6 = 'InviteModal';
|
|
47699
47706
|
addIcons({ personOutline, mailOutline, closeOutline, checkmarkCircleOutline });
|
|
47700
47707
|
/**
|
|
47701
47708
|
* `val-invite-member-modal` — invitación de miembros a una organización.
|
|
@@ -47726,7 +47733,7 @@ class InviteMemberModalComponent {
|
|
|
47726
47733
|
/** Ids de miembros ya existentes (excluidos de los resultados). */
|
|
47727
47734
|
this.existingMemberIds = [];
|
|
47728
47735
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
47729
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
47736
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$6;
|
|
47730
47737
|
this.query = signal('');
|
|
47731
47738
|
this.searching = signal(false);
|
|
47732
47739
|
this.searchResults = signal([]);
|
|
@@ -47773,8 +47780,8 @@ class InviteMemberModalComponent {
|
|
|
47773
47780
|
state: this.sending() ? ComponentStates.WORKING : ComponentStates.ENABLED,
|
|
47774
47781
|
}));
|
|
47775
47782
|
this.searchSubject = new Subject();
|
|
47776
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
47777
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
47783
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$6)) {
|
|
47784
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$6, INVITE_MEMBER_MODAL_I18N);
|
|
47778
47785
|
}
|
|
47779
47786
|
this.loadRoles();
|
|
47780
47787
|
this.roleSub = this.roleControl.valueChanges.subscribe(v => {
|
|
@@ -48263,7 +48270,7 @@ const MEMBER_DETAIL_MODAL_I18N = {
|
|
|
48263
48270
|
},
|
|
48264
48271
|
};
|
|
48265
48272
|
|
|
48266
|
-
const DEFAULT_NAMESPACE$
|
|
48273
|
+
const DEFAULT_NAMESPACE$5 = 'Settings.MemberDetail';
|
|
48267
48274
|
/**
|
|
48268
48275
|
* `val-member-detail-modal` — detalle de miembro de organización: perfil, rol y
|
|
48269
48276
|
* permisos. Promovido desde `showcase` bajo el proceso de ADR-021.
|
|
@@ -48300,7 +48307,7 @@ class MemberDetailModalComponent {
|
|
|
48300
48307
|
{ id: 'admin', name: 'admin' },
|
|
48301
48308
|
];
|
|
48302
48309
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
48303
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
48310
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$5;
|
|
48304
48311
|
this.working = signal(false);
|
|
48305
48312
|
this.currentRole = signal('');
|
|
48306
48313
|
this.roleControl = new FormControl('');
|
|
@@ -48340,8 +48347,8 @@ class MemberDetailModalComponent {
|
|
|
48340
48347
|
type: 'button',
|
|
48341
48348
|
state: this.working() ? ComponentStates.WORKING : ComponentStates.ENABLED,
|
|
48342
48349
|
}));
|
|
48343
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
48344
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
48350
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$5)) {
|
|
48351
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$5, MEMBER_DETAIL_MODAL_I18N);
|
|
48345
48352
|
}
|
|
48346
48353
|
}
|
|
48347
48354
|
ngOnInit() {
|
|
@@ -48678,7 +48685,7 @@ const TRANSFER_OWNERSHIP_MODAL_I18N = {
|
|
|
48678
48685
|
},
|
|
48679
48686
|
};
|
|
48680
48687
|
|
|
48681
|
-
const DEFAULT_NAMESPACE$
|
|
48688
|
+
const DEFAULT_NAMESPACE$4 = 'Settings.TransferModal';
|
|
48682
48689
|
/**
|
|
48683
48690
|
* `val-transfer-ownership-modal` — selector de miembro para transferir la
|
|
48684
48691
|
* propiedad de la organización. Promovido desde `showcase` bajo el proceso de
|
|
@@ -48702,7 +48709,7 @@ class TransferOwnershipModalComponent {
|
|
|
48702
48709
|
/** Lista de miembros transferibles (todos excepto el owner actual). */
|
|
48703
48710
|
this.members = [];
|
|
48704
48711
|
/** Namespace i18n con que la vista resuelve sus textos. */
|
|
48705
|
-
this.i18nNamespace = DEFAULT_NAMESPACE$
|
|
48712
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$4;
|
|
48706
48713
|
this.query = signal('');
|
|
48707
48714
|
this.selectedId = signal('');
|
|
48708
48715
|
this.filtered = computed(() => {
|
|
@@ -48714,8 +48721,8 @@ class TransferOwnershipModalComponent {
|
|
|
48714
48721
|
m.userId.toLowerCase().includes(q));
|
|
48715
48722
|
});
|
|
48716
48723
|
this.noResultsLabel = computed(() => `${this.t('noResults')} "${this.query()}"`);
|
|
48717
|
-
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$
|
|
48718
|
-
this.i18n.registerContent(DEFAULT_NAMESPACE$
|
|
48724
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$4)) {
|
|
48725
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$4, TRANSFER_OWNERSHIP_MODAL_I18N);
|
|
48719
48726
|
}
|
|
48720
48727
|
}
|
|
48721
48728
|
ngOnInit() {
|
|
@@ -48900,6 +48907,849 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
48900
48907
|
type: Input
|
|
48901
48908
|
}] } });
|
|
48902
48909
|
|
|
48910
|
+
/**
|
|
48911
|
+
* Defaults i18n (es/en) embebidos en `val-member-import-modal` (ADR-023).
|
|
48912
|
+
* Auto-registrados si el consumer no proveyó el namespace `Settings.ImportModal`.
|
|
48913
|
+
*/
|
|
48914
|
+
const MEMBER_IMPORT_MODAL_I18N = {
|
|
48915
|
+
es: {
|
|
48916
|
+
title: 'Importar miembros',
|
|
48917
|
+
hint: 'Pega un CSV con columnas: email, nombre, rol (una fila por persona).',
|
|
48918
|
+
csvPlaceholder: 'email,nombre,rol\nana@x.com,Ana,editor\nbeto@x.com,Beto,viewer',
|
|
48919
|
+
rolesAvailable: 'Roles disponibles:',
|
|
48920
|
+
onConflictLabel: 'Si el email ya existe',
|
|
48921
|
+
conflictAssign: 'Asignar el rol',
|
|
48922
|
+
conflictSkip: 'Omitir',
|
|
48923
|
+
conflictError: 'Marcar error',
|
|
48924
|
+
sendActivation: 'Enviar email de activación a las cuentas nuevas',
|
|
48925
|
+
submit: 'Importar',
|
|
48926
|
+
submitting: 'Importando...',
|
|
48927
|
+
parseError: 'No se pudo interpretar el CSV. Revisa el formato.',
|
|
48928
|
+
noRows: 'Pega al menos una fila válida (email y rol).',
|
|
48929
|
+
summary: 'Resumen',
|
|
48930
|
+
created: 'creados',
|
|
48931
|
+
assigned: 'asignados',
|
|
48932
|
+
skipped: 'omitidos',
|
|
48933
|
+
failed: 'con error',
|
|
48934
|
+
colEmail: 'Email',
|
|
48935
|
+
colStatus: 'Estado',
|
|
48936
|
+
colDetail: 'Detalle',
|
|
48937
|
+
activationSent: 'activación enviada',
|
|
48938
|
+
activationPending: 'activación pendiente',
|
|
48939
|
+
again: 'Importar otro lote',
|
|
48940
|
+
close: 'Cerrar',
|
|
48941
|
+
genericError: 'No se pudo completar la importación. Intenta de nuevo.',
|
|
48942
|
+
},
|
|
48943
|
+
en: {
|
|
48944
|
+
title: 'Import members',
|
|
48945
|
+
hint: 'Paste a CSV with columns: email, name, role (one row per person).',
|
|
48946
|
+
csvPlaceholder: 'email,name,role\nana@x.com,Ana,editor\nbeto@x.com,Beto,viewer',
|
|
48947
|
+
rolesAvailable: 'Available roles:',
|
|
48948
|
+
onConflictLabel: 'If the email already exists',
|
|
48949
|
+
conflictAssign: 'Assign the role',
|
|
48950
|
+
conflictSkip: 'Skip',
|
|
48951
|
+
conflictError: 'Mark as error',
|
|
48952
|
+
sendActivation: 'Send activation email to new accounts',
|
|
48953
|
+
submit: 'Import',
|
|
48954
|
+
submitting: 'Importing...',
|
|
48955
|
+
parseError: "Couldn't parse the CSV. Check the format.",
|
|
48956
|
+
noRows: 'Paste at least one valid row (email and role).',
|
|
48957
|
+
summary: 'Summary',
|
|
48958
|
+
created: 'created',
|
|
48959
|
+
assigned: 'assigned',
|
|
48960
|
+
skipped: 'skipped',
|
|
48961
|
+
failed: 'failed',
|
|
48962
|
+
colEmail: 'Email',
|
|
48963
|
+
colStatus: 'Status',
|
|
48964
|
+
colDetail: 'Detail',
|
|
48965
|
+
activationSent: 'activation sent',
|
|
48966
|
+
activationPending: 'activation pending',
|
|
48967
|
+
again: 'Import another batch',
|
|
48968
|
+
close: 'Close',
|
|
48969
|
+
genericError: "Couldn't complete the import. Try again.",
|
|
48970
|
+
},
|
|
48971
|
+
};
|
|
48972
|
+
|
|
48973
|
+
const DEFAULT_NAMESPACE$3 = 'Settings.ImportModal';
|
|
48974
|
+
/**
|
|
48975
|
+
* `val-member-import-modal` — panel de carga masiva de miembros (ADR-023 fase 6).
|
|
48976
|
+
*
|
|
48977
|
+
* El admin pega un CSV (`email,nombre,rol`); el modal lo parsea a filas y llama
|
|
48978
|
+
* `OrgService.importMembers`. Muestra el resultado por-fila (partial success):
|
|
48979
|
+
* `created` / `assigned` / `skipped` / `error`. Header canónico (Regla #5).
|
|
48980
|
+
*
|
|
48981
|
+
* Auto-registra defaults i18n (es/en) en `Settings.ImportModal`.
|
|
48982
|
+
*/
|
|
48983
|
+
class MemberImportModalComponent {
|
|
48984
|
+
constructor() {
|
|
48985
|
+
this.i18n = inject(I18nService);
|
|
48986
|
+
this.orgService = inject(OrgService);
|
|
48987
|
+
/** Org destino del import. */
|
|
48988
|
+
this.orgId = '';
|
|
48989
|
+
/** Nombres de roles disponibles (para el hint). Opcional. */
|
|
48990
|
+
this.availableRoles = [];
|
|
48991
|
+
/** Namespace i18n. */
|
|
48992
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$3;
|
|
48993
|
+
this.csv = '';
|
|
48994
|
+
this.onConflict = 'assignRole';
|
|
48995
|
+
this.sendActivation = true;
|
|
48996
|
+
this.submitting = signal(false);
|
|
48997
|
+
this.errorMsg = signal('');
|
|
48998
|
+
this.results = signal(null);
|
|
48999
|
+
this.rolesHint = computed(() => this.availableRoles.length ? `${this.t('rolesAvailable')} ${this.availableRoles.join(', ')}` : '');
|
|
49000
|
+
this.summaryLabel = computed(() => {
|
|
49001
|
+
const s = this.results()?.summary;
|
|
49002
|
+
if (!s)
|
|
49003
|
+
return this.t('summary');
|
|
49004
|
+
return `${this.t('summary')}: ${s.created} ${this.t('created')} · ${s.assigned} ${this.t('assigned')} · ${s.skipped} ${this.t('skipped')} · ${s.failed} ${this.t('failed')}`;
|
|
49005
|
+
});
|
|
49006
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$3)) {
|
|
49007
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$3, MEMBER_IMPORT_MODAL_I18N);
|
|
49008
|
+
}
|
|
49009
|
+
}
|
|
49010
|
+
ngOnInit() {
|
|
49011
|
+
if (!this.i18n.hasNamespace(this.i18nNamespace)) {
|
|
49012
|
+
this.i18n.registerContent(this.i18nNamespace, MEMBER_IMPORT_MODAL_I18N);
|
|
49013
|
+
}
|
|
49014
|
+
}
|
|
49015
|
+
/** Parsea el CSV pegado a filas {email,name,roleName}. Tolera header. */
|
|
49016
|
+
parseCsv() {
|
|
49017
|
+
const rows = [];
|
|
49018
|
+
for (const raw of this.csv.split(/\r?\n/)) {
|
|
49019
|
+
const line = raw.trim();
|
|
49020
|
+
if (!line)
|
|
49021
|
+
continue;
|
|
49022
|
+
const cols = line.split(',').map(c => c.trim());
|
|
49023
|
+
const email = (cols[0] ?? '').toLowerCase();
|
|
49024
|
+
// Saltar header (primera col "email") o líneas sin @.
|
|
49025
|
+
if (!email || !email.includes('@'))
|
|
49026
|
+
continue;
|
|
49027
|
+
rows.push({ email, name: cols[1] ?? '', roleName: cols[2] ?? '' });
|
|
49028
|
+
}
|
|
49029
|
+
return rows;
|
|
49030
|
+
}
|
|
49031
|
+
submit() {
|
|
49032
|
+
this.errorMsg.set('');
|
|
49033
|
+
const users = this.parseCsv();
|
|
49034
|
+
if (users.length === 0) {
|
|
49035
|
+
this.errorMsg.set(this.t('noRows'));
|
|
49036
|
+
return;
|
|
49037
|
+
}
|
|
49038
|
+
if (users.some(u => !u.roleName)) {
|
|
49039
|
+
this.errorMsg.set(this.t('parseError'));
|
|
49040
|
+
return;
|
|
49041
|
+
}
|
|
49042
|
+
this.submitting.set(true);
|
|
49043
|
+
this.orgService
|
|
49044
|
+
.importMembers(this.orgId, {
|
|
49045
|
+
users,
|
|
49046
|
+
onConflict: this.onConflict,
|
|
49047
|
+
sendActivation: this.sendActivation,
|
|
49048
|
+
})
|
|
49049
|
+
.subscribe({
|
|
49050
|
+
next: res => {
|
|
49051
|
+
this.submitting.set(false);
|
|
49052
|
+
this.results.set(res);
|
|
49053
|
+
// Refrescar lista del consumer si hubo altas/asignaciones efectivas.
|
|
49054
|
+
if (res.summary.created + res.summary.assigned > 0) {
|
|
49055
|
+
this.onSuccess?.();
|
|
49056
|
+
}
|
|
49057
|
+
},
|
|
49058
|
+
error: err => {
|
|
49059
|
+
this.submitting.set(false);
|
|
49060
|
+
this.errorMsg.set(err?.error?.message ?? this.t('genericError'));
|
|
49061
|
+
},
|
|
49062
|
+
});
|
|
49063
|
+
}
|
|
49064
|
+
statusLabel(r) {
|
|
49065
|
+
const base = this.t(r.status === 'error' ? 'failed' : r.status);
|
|
49066
|
+
if (r.status === 'created' && r.activation) {
|
|
49067
|
+
return `${base} · ${this.t(r.activation === 'sent' ? 'activationSent' : 'activationPending')}`;
|
|
49068
|
+
}
|
|
49069
|
+
return base;
|
|
49070
|
+
}
|
|
49071
|
+
reset() {
|
|
49072
|
+
this.csv = '';
|
|
49073
|
+
this.errorMsg.set('');
|
|
49074
|
+
this.results.set(null);
|
|
49075
|
+
}
|
|
49076
|
+
dismiss() {
|
|
49077
|
+
this._modalRef?.dismiss(null, 'cancel');
|
|
49078
|
+
}
|
|
49079
|
+
t(key) {
|
|
49080
|
+
return this.i18n.t(key, this.i18nNamespace);
|
|
49081
|
+
}
|
|
49082
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MemberImportModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
49083
|
+
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: `
|
|
49084
|
+
<ion-header>
|
|
49085
|
+
<ion-toolbar>
|
|
49086
|
+
<ion-buttons slot="end">
|
|
49087
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49088
|
+
<strong>{{ t('close') }}</strong>
|
|
49089
|
+
</ion-button>
|
|
49090
|
+
</ion-buttons>
|
|
49091
|
+
</ion-toolbar>
|
|
49092
|
+
</ion-header>
|
|
49093
|
+
|
|
49094
|
+
<ion-content class="ion-padding">
|
|
49095
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49096
|
+
|
|
49097
|
+
@if (!results()) {
|
|
49098
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49099
|
+
|
|
49100
|
+
@if (rolesHint()) {
|
|
49101
|
+
<val-text [props]="{ content: rolesHint(), size: 'small', color: 'medium', bold: false }" />
|
|
49102
|
+
}
|
|
49103
|
+
|
|
49104
|
+
<ion-textarea
|
|
49105
|
+
class="import-csv"
|
|
49106
|
+
[autoGrow]="true"
|
|
49107
|
+
[rows]="6"
|
|
49108
|
+
[placeholder]="t('csvPlaceholder')"
|
|
49109
|
+
[(ngModel)]="csv"
|
|
49110
|
+
/>
|
|
49111
|
+
|
|
49112
|
+
<ion-select
|
|
49113
|
+
class="import-conflict"
|
|
49114
|
+
label="{{ t('onConflictLabel') }}"
|
|
49115
|
+
labelPlacement="stacked"
|
|
49116
|
+
interface="popover"
|
|
49117
|
+
[(ngModel)]="onConflict"
|
|
49118
|
+
>
|
|
49119
|
+
<ion-select-option value="assignRole">{{ t('conflictAssign') }}</ion-select-option>
|
|
49120
|
+
<ion-select-option value="skip">{{ t('conflictSkip') }}</ion-select-option>
|
|
49121
|
+
<ion-select-option value="error">{{ t('conflictError') }}</ion-select-option>
|
|
49122
|
+
</ion-select>
|
|
49123
|
+
|
|
49124
|
+
<ion-checkbox class="import-activation" labelPlacement="end" [(ngModel)]="sendActivation">
|
|
49125
|
+
{{ t('sendActivation') }}
|
|
49126
|
+
</ion-checkbox>
|
|
49127
|
+
|
|
49128
|
+
@if (errorMsg()) {
|
|
49129
|
+
<p class="import-error">{{ errorMsg() }}</p>
|
|
49130
|
+
}
|
|
49131
|
+
|
|
49132
|
+
<div class="import-actions">
|
|
49133
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49134
|
+
@if (submitting()) {
|
|
49135
|
+
<ion-spinner name="dots" />
|
|
49136
|
+
{{ t('submitting') }}
|
|
49137
|
+
} @else {
|
|
49138
|
+
{{ t('submit') }}
|
|
49139
|
+
}
|
|
49140
|
+
</ion-button>
|
|
49141
|
+
</div>
|
|
49142
|
+
} @else {
|
|
49143
|
+
<!-- Resultados -->
|
|
49144
|
+
<val-title [props]="{ content: summaryLabel(), size: 'large', color: '', bold: true }" />
|
|
49145
|
+
<div class="import-results">
|
|
49146
|
+
@for (r of results()!.results; track r.email) {
|
|
49147
|
+
<div class="import-row import-row--{{ r.status }}">
|
|
49148
|
+
<span class="import-row__email">{{ r.email }}</span>
|
|
49149
|
+
<span class="import-row__status">{{ statusLabel(r) }}</span>
|
|
49150
|
+
@if (r.reason) {
|
|
49151
|
+
<span class="import-row__reason">{{ r.reason }}</span>
|
|
49152
|
+
}
|
|
49153
|
+
</div>
|
|
49154
|
+
}
|
|
49155
|
+
</div>
|
|
49156
|
+
<div class="import-actions">
|
|
49157
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="reset()">
|
|
49158
|
+
{{ t('again') }}
|
|
49159
|
+
</ion-button>
|
|
49160
|
+
</div>
|
|
49161
|
+
}
|
|
49162
|
+
</ion-content>
|
|
49163
|
+
`, 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"] }] }); }
|
|
49164
|
+
}
|
|
49165
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MemberImportModalComponent, decorators: [{
|
|
49166
|
+
type: Component,
|
|
49167
|
+
args: [{ selector: 'val-member-import-modal', standalone: true, imports: [
|
|
49168
|
+
FormsModule,
|
|
49169
|
+
IonHeader,
|
|
49170
|
+
IonToolbar,
|
|
49171
|
+
IonButtons,
|
|
49172
|
+
IonButton,
|
|
49173
|
+
IonContent,
|
|
49174
|
+
IonTextarea,
|
|
49175
|
+
IonSelect,
|
|
49176
|
+
IonSelectOption,
|
|
49177
|
+
IonCheckbox,
|
|
49178
|
+
IonSpinner,
|
|
49179
|
+
DisplayComponent,
|
|
49180
|
+
TextComponent,
|
|
49181
|
+
TitleComponent,
|
|
49182
|
+
], template: `
|
|
49183
|
+
<ion-header>
|
|
49184
|
+
<ion-toolbar>
|
|
49185
|
+
<ion-buttons slot="end">
|
|
49186
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49187
|
+
<strong>{{ t('close') }}</strong>
|
|
49188
|
+
</ion-button>
|
|
49189
|
+
</ion-buttons>
|
|
49190
|
+
</ion-toolbar>
|
|
49191
|
+
</ion-header>
|
|
49192
|
+
|
|
49193
|
+
<ion-content class="ion-padding">
|
|
49194
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49195
|
+
|
|
49196
|
+
@if (!results()) {
|
|
49197
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49198
|
+
|
|
49199
|
+
@if (rolesHint()) {
|
|
49200
|
+
<val-text [props]="{ content: rolesHint(), size: 'small', color: 'medium', bold: false }" />
|
|
49201
|
+
}
|
|
49202
|
+
|
|
49203
|
+
<ion-textarea
|
|
49204
|
+
class="import-csv"
|
|
49205
|
+
[autoGrow]="true"
|
|
49206
|
+
[rows]="6"
|
|
49207
|
+
[placeholder]="t('csvPlaceholder')"
|
|
49208
|
+
[(ngModel)]="csv"
|
|
49209
|
+
/>
|
|
49210
|
+
|
|
49211
|
+
<ion-select
|
|
49212
|
+
class="import-conflict"
|
|
49213
|
+
label="{{ t('onConflictLabel') }}"
|
|
49214
|
+
labelPlacement="stacked"
|
|
49215
|
+
interface="popover"
|
|
49216
|
+
[(ngModel)]="onConflict"
|
|
49217
|
+
>
|
|
49218
|
+
<ion-select-option value="assignRole">{{ t('conflictAssign') }}</ion-select-option>
|
|
49219
|
+
<ion-select-option value="skip">{{ t('conflictSkip') }}</ion-select-option>
|
|
49220
|
+
<ion-select-option value="error">{{ t('conflictError') }}</ion-select-option>
|
|
49221
|
+
</ion-select>
|
|
49222
|
+
|
|
49223
|
+
<ion-checkbox class="import-activation" labelPlacement="end" [(ngModel)]="sendActivation">
|
|
49224
|
+
{{ t('sendActivation') }}
|
|
49225
|
+
</ion-checkbox>
|
|
49226
|
+
|
|
49227
|
+
@if (errorMsg()) {
|
|
49228
|
+
<p class="import-error">{{ errorMsg() }}</p>
|
|
49229
|
+
}
|
|
49230
|
+
|
|
49231
|
+
<div class="import-actions">
|
|
49232
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49233
|
+
@if (submitting()) {
|
|
49234
|
+
<ion-spinner name="dots" />
|
|
49235
|
+
{{ t('submitting') }}
|
|
49236
|
+
} @else {
|
|
49237
|
+
{{ t('submit') }}
|
|
49238
|
+
}
|
|
49239
|
+
</ion-button>
|
|
49240
|
+
</div>
|
|
49241
|
+
} @else {
|
|
49242
|
+
<!-- Resultados -->
|
|
49243
|
+
<val-title [props]="{ content: summaryLabel(), size: 'large', color: '', bold: true }" />
|
|
49244
|
+
<div class="import-results">
|
|
49245
|
+
@for (r of results()!.results; track r.email) {
|
|
49246
|
+
<div class="import-row import-row--{{ r.status }}">
|
|
49247
|
+
<span class="import-row__email">{{ r.email }}</span>
|
|
49248
|
+
<span class="import-row__status">{{ statusLabel(r) }}</span>
|
|
49249
|
+
@if (r.reason) {
|
|
49250
|
+
<span class="import-row__reason">{{ r.reason }}</span>
|
|
49251
|
+
}
|
|
49252
|
+
</div>
|
|
49253
|
+
}
|
|
49254
|
+
</div>
|
|
49255
|
+
<div class="import-actions">
|
|
49256
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="reset()">
|
|
49257
|
+
{{ t('again') }}
|
|
49258
|
+
</ion-button>
|
|
49259
|
+
</div>
|
|
49260
|
+
}
|
|
49261
|
+
</ion-content>
|
|
49262
|
+
`, 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"] }]
|
|
49263
|
+
}], ctorParameters: () => [], propDecorators: { orgId: [{
|
|
49264
|
+
type: Input
|
|
49265
|
+
}], availableRoles: [{
|
|
49266
|
+
type: Input
|
|
49267
|
+
}], onSuccess: [{
|
|
49268
|
+
type: Input
|
|
49269
|
+
}], _modalRef: [{
|
|
49270
|
+
type: Input
|
|
49271
|
+
}], i18nNamespace: [{
|
|
49272
|
+
type: Input
|
|
49273
|
+
}] } });
|
|
49274
|
+
|
|
49275
|
+
/**
|
|
49276
|
+
* Cliente HTTP de Client API Keys org-scopeadas (ADR-023). La org activa se
|
|
49277
|
+
* resuelve en backend desde el JWT, así que el path no la incluye.
|
|
49278
|
+
*/
|
|
49279
|
+
class ApiKeyService {
|
|
49280
|
+
constructor(config, http) {
|
|
49281
|
+
this.config = config;
|
|
49282
|
+
this.http = http;
|
|
49283
|
+
}
|
|
49284
|
+
get baseUrl() {
|
|
49285
|
+
return `${this.config.apiUrl}/org/api-keys`;
|
|
49286
|
+
}
|
|
49287
|
+
/** Lista las API keys de la org activa. */
|
|
49288
|
+
list() {
|
|
49289
|
+
return this.http.get(`${this.baseUrl}/`).pipe(map$1(r => r.keys ?? []));
|
|
49290
|
+
}
|
|
49291
|
+
/** Crea una API key. La respuesta incluye el secreto (se muestra UNA vez). */
|
|
49292
|
+
create(req) {
|
|
49293
|
+
return this.http.post(`${this.baseUrl}/`, req);
|
|
49294
|
+
}
|
|
49295
|
+
/** Revoca (elimina) una API key por id. */
|
|
49296
|
+
revoke(keyId) {
|
|
49297
|
+
return this.http.delete(`${this.baseUrl}/${keyId}`);
|
|
49298
|
+
}
|
|
49299
|
+
/** Catálogo de permisos asignables a una key. */
|
|
49300
|
+
availablePermissions() {
|
|
49301
|
+
return this.http
|
|
49302
|
+
.get(`${this.baseUrl}/permissions`)
|
|
49303
|
+
.pipe(map$1(r => r.permissions ?? []));
|
|
49304
|
+
}
|
|
49305
|
+
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 }); }
|
|
49306
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeyService, providedIn: 'root' }); }
|
|
49307
|
+
}
|
|
49308
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeyService, decorators: [{
|
|
49309
|
+
type: Injectable,
|
|
49310
|
+
args: [{ providedIn: 'root' }]
|
|
49311
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
49312
|
+
type: Inject,
|
|
49313
|
+
args: [VALTECH_AUTH_CONFIG]
|
|
49314
|
+
}] }, { type: i1$3.HttpClient }] });
|
|
49315
|
+
|
|
49316
|
+
/**
|
|
49317
|
+
* Defaults i18n (es/en) embebidos en `val-api-keys-modal` (ADR-023).
|
|
49318
|
+
* Auto-registrados si el consumer no proveyó el namespace `Settings.ApiKeysModal`.
|
|
49319
|
+
*/
|
|
49320
|
+
const API_KEYS_MODAL_I18N = {
|
|
49321
|
+
es: {
|
|
49322
|
+
title: 'Client API Keys',
|
|
49323
|
+
hint: 'Llaves M2M org-scopeadas para integraciones (p. ej. importar miembros).',
|
|
49324
|
+
empty: 'Aún no hay API keys en esta organización.',
|
|
49325
|
+
newKey: 'Nueva API key',
|
|
49326
|
+
nameLabel: 'Nombre',
|
|
49327
|
+
namePlaceholder: 'Ej: Integración RRHH',
|
|
49328
|
+
permissionsLabel: 'Permisos',
|
|
49329
|
+
expiresLabel: 'Expira en (días, opcional)',
|
|
49330
|
+
create: 'Crear key',
|
|
49331
|
+
creating: 'Creando...',
|
|
49332
|
+
cancel: 'Cancelar',
|
|
49333
|
+
revoke: 'Revocar',
|
|
49334
|
+
revokeConfirm: '¿Revocar esta API key? Las integraciones que la usen dejarán de funcionar.',
|
|
49335
|
+
secretTitle: 'Copia tu API key ahora',
|
|
49336
|
+
secretWarning: 'Este secreto se muestra una sola vez. Guárdalo en un lugar seguro.',
|
|
49337
|
+
copy: 'Copiar',
|
|
49338
|
+
copied: 'Copiada',
|
|
49339
|
+
done: 'Listo',
|
|
49340
|
+
statusActive: 'activa',
|
|
49341
|
+
lastUsed: 'Último uso',
|
|
49342
|
+
never: 'nunca',
|
|
49343
|
+
permsCount: 'permisos',
|
|
49344
|
+
noName: 'El nombre es obligatorio.',
|
|
49345
|
+
noPerms: 'Selecciona al menos un permiso.',
|
|
49346
|
+
close: 'Cerrar',
|
|
49347
|
+
genericError: 'No se pudo completar la operación. Intenta de nuevo.',
|
|
49348
|
+
},
|
|
49349
|
+
en: {
|
|
49350
|
+
title: 'Client API Keys',
|
|
49351
|
+
hint: 'Org-scoped M2M keys for integrations (e.g. member import).',
|
|
49352
|
+
empty: 'No API keys in this organization yet.',
|
|
49353
|
+
newKey: 'New API key',
|
|
49354
|
+
nameLabel: 'Name',
|
|
49355
|
+
namePlaceholder: 'E.g: HR integration',
|
|
49356
|
+
permissionsLabel: 'Permissions',
|
|
49357
|
+
expiresLabel: 'Expires in (days, optional)',
|
|
49358
|
+
create: 'Create key',
|
|
49359
|
+
creating: 'Creating...',
|
|
49360
|
+
cancel: 'Cancel',
|
|
49361
|
+
revoke: 'Revoke',
|
|
49362
|
+
revokeConfirm: 'Revoke this API key? Integrations using it will stop working.',
|
|
49363
|
+
secretTitle: 'Copy your API key now',
|
|
49364
|
+
secretWarning: 'This secret is shown only once. Store it somewhere safe.',
|
|
49365
|
+
copy: 'Copy',
|
|
49366
|
+
copied: 'Copied',
|
|
49367
|
+
done: 'Done',
|
|
49368
|
+
statusActive: 'active',
|
|
49369
|
+
lastUsed: 'Last used',
|
|
49370
|
+
never: 'never',
|
|
49371
|
+
permsCount: 'permissions',
|
|
49372
|
+
noName: 'Name is required.',
|
|
49373
|
+
noPerms: 'Select at least one permission.',
|
|
49374
|
+
close: 'Close',
|
|
49375
|
+
genericError: "Couldn't complete the operation. Try again.",
|
|
49376
|
+
},
|
|
49377
|
+
};
|
|
49378
|
+
|
|
49379
|
+
const DEFAULT_NAMESPACE$2 = 'Settings.ApiKeysModal';
|
|
49380
|
+
/**
|
|
49381
|
+
* `val-api-keys-modal` — gestión de Client API Keys org-scopeadas (ADR-023 fase 6).
|
|
49382
|
+
*
|
|
49383
|
+
* Lista las keys de la org, permite crear (mostrando el secreto UNA vez con copia)
|
|
49384
|
+
* y revocar. Pensado para habilitar integraciones M2M del import de miembros, pero
|
|
49385
|
+
* sirve a cualquier permiso del catálogo. Header canónico (Regla #5).
|
|
49386
|
+
*/
|
|
49387
|
+
class ApiKeysModalComponent {
|
|
49388
|
+
constructor() {
|
|
49389
|
+
this.i18n = inject(I18nService);
|
|
49390
|
+
this.apiKeys = inject(ApiKeyService);
|
|
49391
|
+
/** Namespace i18n. */
|
|
49392
|
+
this.i18nNamespace = DEFAULT_NAMESPACE$2;
|
|
49393
|
+
this.keys = signal([]);
|
|
49394
|
+
this.availablePermissions = signal([]);
|
|
49395
|
+
this.loading = signal(true);
|
|
49396
|
+
this.showCreate = signal(false);
|
|
49397
|
+
this.submitting = signal(false);
|
|
49398
|
+
this.errorMsg = signal('');
|
|
49399
|
+
this.secret = signal(null);
|
|
49400
|
+
this.copied = signal(false);
|
|
49401
|
+
this.name = '';
|
|
49402
|
+
this.expiresInDays = null;
|
|
49403
|
+
this.selectedPerms = signal(new Set());
|
|
49404
|
+
if (!this.i18n.hasNamespace(DEFAULT_NAMESPACE$2)) {
|
|
49405
|
+
this.i18n.registerContent(DEFAULT_NAMESPACE$2, API_KEYS_MODAL_I18N);
|
|
49406
|
+
}
|
|
49407
|
+
}
|
|
49408
|
+
ngOnInit() {
|
|
49409
|
+
if (!this.i18n.hasNamespace(this.i18nNamespace)) {
|
|
49410
|
+
this.i18n.registerContent(this.i18nNamespace, API_KEYS_MODAL_I18N);
|
|
49411
|
+
}
|
|
49412
|
+
this.refresh();
|
|
49413
|
+
this.apiKeys.availablePermissions().subscribe({
|
|
49414
|
+
next: perms => this.availablePermissions.set(perms),
|
|
49415
|
+
error: () => { },
|
|
49416
|
+
});
|
|
49417
|
+
}
|
|
49418
|
+
refresh() {
|
|
49419
|
+
this.loading.set(true);
|
|
49420
|
+
this.apiKeys.list().subscribe({
|
|
49421
|
+
next: keys => {
|
|
49422
|
+
this.keys.set(keys);
|
|
49423
|
+
this.loading.set(false);
|
|
49424
|
+
},
|
|
49425
|
+
error: () => this.loading.set(false),
|
|
49426
|
+
});
|
|
49427
|
+
}
|
|
49428
|
+
openCreate() {
|
|
49429
|
+
this.errorMsg.set('');
|
|
49430
|
+
this.name = '';
|
|
49431
|
+
this.expiresInDays = null;
|
|
49432
|
+
this.selectedPerms.set(new Set());
|
|
49433
|
+
this.showCreate.set(true);
|
|
49434
|
+
}
|
|
49435
|
+
togglePerm(perm, ev) {
|
|
49436
|
+
const checked = ev.detail?.checked ?? false;
|
|
49437
|
+
const next = new Set(this.selectedPerms());
|
|
49438
|
+
if (checked) {
|
|
49439
|
+
next.add(perm);
|
|
49440
|
+
}
|
|
49441
|
+
else {
|
|
49442
|
+
next.delete(perm);
|
|
49443
|
+
}
|
|
49444
|
+
this.selectedPerms.set(next);
|
|
49445
|
+
}
|
|
49446
|
+
submit() {
|
|
49447
|
+
this.errorMsg.set('');
|
|
49448
|
+
if (!this.name.trim()) {
|
|
49449
|
+
this.errorMsg.set(this.t('noName'));
|
|
49450
|
+
return;
|
|
49451
|
+
}
|
|
49452
|
+
const permissions = Array.from(this.selectedPerms());
|
|
49453
|
+
if (permissions.length === 0) {
|
|
49454
|
+
this.errorMsg.set(this.t('noPerms'));
|
|
49455
|
+
return;
|
|
49456
|
+
}
|
|
49457
|
+
this.submitting.set(true);
|
|
49458
|
+
this.apiKeys
|
|
49459
|
+
.create({
|
|
49460
|
+
name: this.name.trim(),
|
|
49461
|
+
permissions,
|
|
49462
|
+
expiresInDays: this.expiresInDays && this.expiresInDays > 0 ? this.expiresInDays : undefined,
|
|
49463
|
+
})
|
|
49464
|
+
.subscribe({
|
|
49465
|
+
next: res => {
|
|
49466
|
+
this.submitting.set(false);
|
|
49467
|
+
this.showCreate.set(false);
|
|
49468
|
+
this.secret.set(res.key);
|
|
49469
|
+
},
|
|
49470
|
+
error: err => {
|
|
49471
|
+
this.submitting.set(false);
|
|
49472
|
+
this.errorMsg.set(err?.error?.message ?? this.t('genericError'));
|
|
49473
|
+
},
|
|
49474
|
+
});
|
|
49475
|
+
}
|
|
49476
|
+
revoke(key) {
|
|
49477
|
+
if (!confirm(this.t('revokeConfirm')))
|
|
49478
|
+
return;
|
|
49479
|
+
this.apiKeys.revoke(key.keyId).subscribe({
|
|
49480
|
+
next: () => this.refresh(),
|
|
49481
|
+
error: err => this.errorMsg.set(err?.error?.message ?? this.t('genericError')),
|
|
49482
|
+
});
|
|
49483
|
+
}
|
|
49484
|
+
async copy(secret) {
|
|
49485
|
+
try {
|
|
49486
|
+
await navigator.clipboard.writeText(secret);
|
|
49487
|
+
this.copied.set(true);
|
|
49488
|
+
}
|
|
49489
|
+
catch {
|
|
49490
|
+
// clipboard no disponible — el user puede seleccionar el texto manualmente
|
|
49491
|
+
}
|
|
49492
|
+
}
|
|
49493
|
+
finishSecret() {
|
|
49494
|
+
this.secret.set(null);
|
|
49495
|
+
this.copied.set(false);
|
|
49496
|
+
this.refresh();
|
|
49497
|
+
}
|
|
49498
|
+
dismiss() {
|
|
49499
|
+
this._modalRef?.dismiss(null, 'cancel');
|
|
49500
|
+
}
|
|
49501
|
+
t(key) {
|
|
49502
|
+
return this.i18n.t(key, this.i18nNamespace);
|
|
49503
|
+
}
|
|
49504
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeysModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
49505
|
+
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: `
|
|
49506
|
+
<ion-header>
|
|
49507
|
+
<ion-toolbar>
|
|
49508
|
+
<ion-buttons slot="end">
|
|
49509
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49510
|
+
<strong>{{ t('close') }}</strong>
|
|
49511
|
+
</ion-button>
|
|
49512
|
+
</ion-buttons>
|
|
49513
|
+
</ion-toolbar>
|
|
49514
|
+
</ion-header>
|
|
49515
|
+
|
|
49516
|
+
<ion-content class="ion-padding">
|
|
49517
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49518
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49519
|
+
|
|
49520
|
+
@if (secret(); as s) {
|
|
49521
|
+
<!-- Secreto recién creado: mostrar UNA vez -->
|
|
49522
|
+
<div class="apikey-secret">
|
|
49523
|
+
<val-title [props]="{ content: t('secretTitle'), size: 'large', color: '', bold: true }" />
|
|
49524
|
+
<p class="apikey-secret__warn">{{ t('secretWarning') }}</p>
|
|
49525
|
+
<div class="apikey-secret__box">
|
|
49526
|
+
<code>{{ s.secret }}</code>
|
|
49527
|
+
</div>
|
|
49528
|
+
<div class="apikey-actions">
|
|
49529
|
+
<ion-button expand="block" color="dark" (click)="copy(s.secret)">
|
|
49530
|
+
{{ copied() ? t('copied') : t('copy') }}
|
|
49531
|
+
</ion-button>
|
|
49532
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="finishSecret()">
|
|
49533
|
+
{{ t('done') }}
|
|
49534
|
+
</ion-button>
|
|
49535
|
+
</div>
|
|
49536
|
+
</div>
|
|
49537
|
+
} @else {
|
|
49538
|
+
@if (loading()) {
|
|
49539
|
+
<ion-spinner name="dots" />
|
|
49540
|
+
} @else {
|
|
49541
|
+
<!-- Lista -->
|
|
49542
|
+
@if (keys().length === 0) {
|
|
49543
|
+
<val-text [props]="{ content: t('empty'), size: 'medium', color: 'medium', bold: false }" />
|
|
49544
|
+
} @else {
|
|
49545
|
+
<div class="apikey-list">
|
|
49546
|
+
@for (k of keys(); track k.keyId) {
|
|
49547
|
+
<div class="apikey-row">
|
|
49548
|
+
<div class="apikey-row__main">
|
|
49549
|
+
<span class="apikey-row__name">{{ k.name }}</span>
|
|
49550
|
+
<span class="apikey-row__meta">
|
|
49551
|
+
{{ k.permissions.length }} {{ t('permsCount') }} · {{ t('lastUsed') }}:
|
|
49552
|
+
{{ k.lastUsedAt || t('never') }}
|
|
49553
|
+
</span>
|
|
49554
|
+
</div>
|
|
49555
|
+
<ion-button fill="clear" color="danger" size="small" (click)="revoke(k)">
|
|
49556
|
+
{{ t('revoke') }}
|
|
49557
|
+
</ion-button>
|
|
49558
|
+
</div>
|
|
49559
|
+
}
|
|
49560
|
+
</div>
|
|
49561
|
+
}
|
|
49562
|
+
|
|
49563
|
+
@if (errorMsg()) {
|
|
49564
|
+
<p class="apikey-error">{{ errorMsg() }}</p>
|
|
49565
|
+
}
|
|
49566
|
+
|
|
49567
|
+
<!-- Crear -->
|
|
49568
|
+
@if (showCreate()) {
|
|
49569
|
+
<div class="apikey-create">
|
|
49570
|
+
<ion-input
|
|
49571
|
+
label="{{ t('nameLabel') }}"
|
|
49572
|
+
labelPlacement="stacked"
|
|
49573
|
+
[placeholder]="t('namePlaceholder')"
|
|
49574
|
+
[(ngModel)]="name"
|
|
49575
|
+
/>
|
|
49576
|
+
<p class="apikey-create__label">{{ t('permissionsLabel') }}</p>
|
|
49577
|
+
<div class="apikey-perms">
|
|
49578
|
+
@for (p of availablePermissions(); track p) {
|
|
49579
|
+
<ion-checkbox
|
|
49580
|
+
labelPlacement="end"
|
|
49581
|
+
[checked]="selectedPerms().has(p)"
|
|
49582
|
+
(ionChange)="togglePerm(p, $event)"
|
|
49583
|
+
>
|
|
49584
|
+
{{ p }}
|
|
49585
|
+
</ion-checkbox>
|
|
49586
|
+
}
|
|
49587
|
+
</div>
|
|
49588
|
+
<ion-input
|
|
49589
|
+
label="{{ t('expiresLabel') }}"
|
|
49590
|
+
labelPlacement="stacked"
|
|
49591
|
+
type="number"
|
|
49592
|
+
[(ngModel)]="expiresInDays"
|
|
49593
|
+
/>
|
|
49594
|
+
<div class="apikey-actions">
|
|
49595
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49596
|
+
@if (submitting()) {
|
|
49597
|
+
<ion-spinner name="dots" /> {{ t('creating') }}
|
|
49598
|
+
} @else {
|
|
49599
|
+
{{ t('create') }}
|
|
49600
|
+
}
|
|
49601
|
+
</ion-button>
|
|
49602
|
+
<ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
|
|
49603
|
+
{{ t('cancel') }}
|
|
49604
|
+
</ion-button>
|
|
49605
|
+
</div>
|
|
49606
|
+
</div>
|
|
49607
|
+
} @else {
|
|
49608
|
+
<div class="apikey-actions">
|
|
49609
|
+
<ion-button expand="block" color="primary" (click)="openCreate()">
|
|
49610
|
+
{{ t('newKey') }}
|
|
49611
|
+
</ion-button>
|
|
49612
|
+
</div>
|
|
49613
|
+
}
|
|
49614
|
+
}
|
|
49615
|
+
}
|
|
49616
|
+
</ion-content>
|
|
49617
|
+
`, 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"] }] }); }
|
|
49618
|
+
}
|
|
49619
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ApiKeysModalComponent, decorators: [{
|
|
49620
|
+
type: Component,
|
|
49621
|
+
args: [{ selector: 'val-api-keys-modal', standalone: true, imports: [
|
|
49622
|
+
FormsModule,
|
|
49623
|
+
IonHeader,
|
|
49624
|
+
IonToolbar,
|
|
49625
|
+
IonButtons,
|
|
49626
|
+
IonButton,
|
|
49627
|
+
IonContent,
|
|
49628
|
+
IonInput,
|
|
49629
|
+
IonCheckbox,
|
|
49630
|
+
IonSpinner,
|
|
49631
|
+
DisplayComponent,
|
|
49632
|
+
TextComponent,
|
|
49633
|
+
TitleComponent,
|
|
49634
|
+
], template: `
|
|
49635
|
+
<ion-header>
|
|
49636
|
+
<ion-toolbar>
|
|
49637
|
+
<ion-buttons slot="end">
|
|
49638
|
+
<ion-button fill="clear" color="dark" (click)="dismiss()">
|
|
49639
|
+
<strong>{{ t('close') }}</strong>
|
|
49640
|
+
</ion-button>
|
|
49641
|
+
</ion-buttons>
|
|
49642
|
+
</ion-toolbar>
|
|
49643
|
+
</ion-header>
|
|
49644
|
+
|
|
49645
|
+
<ion-content class="ion-padding">
|
|
49646
|
+
<val-display [props]="{ content: t('title'), size: 'small', color: 'dark' }" />
|
|
49647
|
+
<val-title [props]="{ content: t('hint'), size: 'large', color: '', bold: false }" />
|
|
49648
|
+
|
|
49649
|
+
@if (secret(); as s) {
|
|
49650
|
+
<!-- Secreto recién creado: mostrar UNA vez -->
|
|
49651
|
+
<div class="apikey-secret">
|
|
49652
|
+
<val-title [props]="{ content: t('secretTitle'), size: 'large', color: '', bold: true }" />
|
|
49653
|
+
<p class="apikey-secret__warn">{{ t('secretWarning') }}</p>
|
|
49654
|
+
<div class="apikey-secret__box">
|
|
49655
|
+
<code>{{ s.secret }}</code>
|
|
49656
|
+
</div>
|
|
49657
|
+
<div class="apikey-actions">
|
|
49658
|
+
<ion-button expand="block" color="dark" (click)="copy(s.secret)">
|
|
49659
|
+
{{ copied() ? t('copied') : t('copy') }}
|
|
49660
|
+
</ion-button>
|
|
49661
|
+
<ion-button expand="block" fill="outline" color="dark" (click)="finishSecret()">
|
|
49662
|
+
{{ t('done') }}
|
|
49663
|
+
</ion-button>
|
|
49664
|
+
</div>
|
|
49665
|
+
</div>
|
|
49666
|
+
} @else {
|
|
49667
|
+
@if (loading()) {
|
|
49668
|
+
<ion-spinner name="dots" />
|
|
49669
|
+
} @else {
|
|
49670
|
+
<!-- Lista -->
|
|
49671
|
+
@if (keys().length === 0) {
|
|
49672
|
+
<val-text [props]="{ content: t('empty'), size: 'medium', color: 'medium', bold: false }" />
|
|
49673
|
+
} @else {
|
|
49674
|
+
<div class="apikey-list">
|
|
49675
|
+
@for (k of keys(); track k.keyId) {
|
|
49676
|
+
<div class="apikey-row">
|
|
49677
|
+
<div class="apikey-row__main">
|
|
49678
|
+
<span class="apikey-row__name">{{ k.name }}</span>
|
|
49679
|
+
<span class="apikey-row__meta">
|
|
49680
|
+
{{ k.permissions.length }} {{ t('permsCount') }} · {{ t('lastUsed') }}:
|
|
49681
|
+
{{ k.lastUsedAt || t('never') }}
|
|
49682
|
+
</span>
|
|
49683
|
+
</div>
|
|
49684
|
+
<ion-button fill="clear" color="danger" size="small" (click)="revoke(k)">
|
|
49685
|
+
{{ t('revoke') }}
|
|
49686
|
+
</ion-button>
|
|
49687
|
+
</div>
|
|
49688
|
+
}
|
|
49689
|
+
</div>
|
|
49690
|
+
}
|
|
49691
|
+
|
|
49692
|
+
@if (errorMsg()) {
|
|
49693
|
+
<p class="apikey-error">{{ errorMsg() }}</p>
|
|
49694
|
+
}
|
|
49695
|
+
|
|
49696
|
+
<!-- Crear -->
|
|
49697
|
+
@if (showCreate()) {
|
|
49698
|
+
<div class="apikey-create">
|
|
49699
|
+
<ion-input
|
|
49700
|
+
label="{{ t('nameLabel') }}"
|
|
49701
|
+
labelPlacement="stacked"
|
|
49702
|
+
[placeholder]="t('namePlaceholder')"
|
|
49703
|
+
[(ngModel)]="name"
|
|
49704
|
+
/>
|
|
49705
|
+
<p class="apikey-create__label">{{ t('permissionsLabel') }}</p>
|
|
49706
|
+
<div class="apikey-perms">
|
|
49707
|
+
@for (p of availablePermissions(); track p) {
|
|
49708
|
+
<ion-checkbox
|
|
49709
|
+
labelPlacement="end"
|
|
49710
|
+
[checked]="selectedPerms().has(p)"
|
|
49711
|
+
(ionChange)="togglePerm(p, $event)"
|
|
49712
|
+
>
|
|
49713
|
+
{{ p }}
|
|
49714
|
+
</ion-checkbox>
|
|
49715
|
+
}
|
|
49716
|
+
</div>
|
|
49717
|
+
<ion-input
|
|
49718
|
+
label="{{ t('expiresLabel') }}"
|
|
49719
|
+
labelPlacement="stacked"
|
|
49720
|
+
type="number"
|
|
49721
|
+
[(ngModel)]="expiresInDays"
|
|
49722
|
+
/>
|
|
49723
|
+
<div class="apikey-actions">
|
|
49724
|
+
<ion-button expand="block" color="dark" [disabled]="submitting()" (click)="submit()">
|
|
49725
|
+
@if (submitting()) {
|
|
49726
|
+
<ion-spinner name="dots" /> {{ t('creating') }}
|
|
49727
|
+
} @else {
|
|
49728
|
+
{{ t('create') }}
|
|
49729
|
+
}
|
|
49730
|
+
</ion-button>
|
|
49731
|
+
<ion-button expand="block" fill="clear" color="medium" (click)="showCreate.set(false)">
|
|
49732
|
+
{{ t('cancel') }}
|
|
49733
|
+
</ion-button>
|
|
49734
|
+
</div>
|
|
49735
|
+
</div>
|
|
49736
|
+
} @else {
|
|
49737
|
+
<div class="apikey-actions">
|
|
49738
|
+
<ion-button expand="block" color="primary" (click)="openCreate()">
|
|
49739
|
+
{{ t('newKey') }}
|
|
49740
|
+
</ion-button>
|
|
49741
|
+
</div>
|
|
49742
|
+
}
|
|
49743
|
+
}
|
|
49744
|
+
}
|
|
49745
|
+
</ion-content>
|
|
49746
|
+
`, 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"] }]
|
|
49747
|
+
}], ctorParameters: () => [], propDecorators: { _modalRef: [{
|
|
49748
|
+
type: Input
|
|
49749
|
+
}], i18nNamespace: [{
|
|
49750
|
+
type: Input
|
|
49751
|
+
}] } });
|
|
49752
|
+
|
|
48903
49753
|
/**
|
|
48904
49754
|
* Defaults i18n (es/en) embebidos en `val-organization-view`. Auto-registrados en
|
|
48905
49755
|
* el constructor del componente si el consumer no proveyó el namespace
|
|
@@ -48955,6 +49805,8 @@ const ORGANIZATION_VIEW_I18N = {
|
|
|
48955
49805
|
inviteCtaTitle: '¿Deseas agregar a alguien?',
|
|
48956
49806
|
inviteCtaHint: 'Invita a usuarios a unirse a tu organización.',
|
|
48957
49807
|
inviteOpen: 'Invitar',
|
|
49808
|
+
importOpen: 'Importar',
|
|
49809
|
+
apiKeysOpen: 'API Keys',
|
|
48958
49810
|
viewMemberCta: 'Ver miembro',
|
|
48959
49811
|
roleViewer: 'Visor',
|
|
48960
49812
|
roleEditor: 'Editor',
|
|
@@ -49024,6 +49876,8 @@ const ORGANIZATION_VIEW_I18N = {
|
|
|
49024
49876
|
inviteCtaTitle: 'Want to add someone?',
|
|
49025
49877
|
inviteCtaHint: 'Invite users to join your organization.',
|
|
49026
49878
|
inviteOpen: 'Invite',
|
|
49879
|
+
importOpen: 'Import',
|
|
49880
|
+
apiKeysOpen: 'API Keys',
|
|
49027
49881
|
viewMemberCta: 'View member',
|
|
49028
49882
|
roleViewer: 'Viewer',
|
|
49029
49883
|
roleEditor: 'Editor',
|
|
@@ -49137,6 +49991,22 @@ class OrganizationViewComponent {
|
|
|
49137
49991
|
this.members = signal([]);
|
|
49138
49992
|
this.membersLoading = signal(false);
|
|
49139
49993
|
this.membersLoadError = signal(null);
|
|
49994
|
+
this.membersErrorState = computed(() => {
|
|
49995
|
+
this.i18n.lang();
|
|
49996
|
+
const err = this.membersLoadError();
|
|
49997
|
+
if (!err)
|
|
49998
|
+
return null;
|
|
49999
|
+
return createErrorStateProps(err, {
|
|
50000
|
+
title: { offline: this.tt('offlineTitle'), error: this.tt('errorTitle') },
|
|
50001
|
+
description: {
|
|
50002
|
+
offline: this.tt('offlineHint'),
|
|
50003
|
+
error: interpretError(err).message,
|
|
50004
|
+
},
|
|
50005
|
+
retryLabel: this.tt('retry'),
|
|
50006
|
+
onRetry: () => this.loadMembers(),
|
|
50007
|
+
retrying: this.membersLoading(),
|
|
50008
|
+
});
|
|
50009
|
+
});
|
|
49140
50010
|
this.membersNextToken = signal(null);
|
|
49141
50011
|
this.loadingMoreMembers = signal(false);
|
|
49142
50012
|
this.showAllMembers = signal(false);
|
|
@@ -49223,6 +50093,22 @@ class OrganizationViewComponent {
|
|
|
49223
50093
|
shape: 'round',
|
|
49224
50094
|
type: 'button',
|
|
49225
50095
|
}));
|
|
50096
|
+
this.openImportButtonProps = computed(() => ({
|
|
50097
|
+
text: this.tt('importOpen'),
|
|
50098
|
+
color: 'dark',
|
|
50099
|
+
fill: 'outline',
|
|
50100
|
+
size: 'default',
|
|
50101
|
+
shape: 'round',
|
|
50102
|
+
type: 'button',
|
|
50103
|
+
}));
|
|
50104
|
+
this.openApiKeysButtonProps = computed(() => ({
|
|
50105
|
+
text: this.tt('apiKeysOpen'),
|
|
50106
|
+
color: 'dark',
|
|
50107
|
+
fill: 'clear',
|
|
50108
|
+
size: 'default',
|
|
50109
|
+
shape: 'round',
|
|
50110
|
+
type: 'button',
|
|
50111
|
+
}));
|
|
49226
50112
|
/** Guarda para detectar el primer disparo del effect (evita doble carga). */
|
|
49227
50113
|
this.lastLoadedOrgId = null;
|
|
49228
50114
|
const ns = this.ns;
|
|
@@ -49323,6 +50209,36 @@ class OrganizationViewComponent {
|
|
|
49323
50209
|
backdropDismiss: true,
|
|
49324
50210
|
});
|
|
49325
50211
|
}
|
|
50212
|
+
onOpenImport() {
|
|
50213
|
+
void this.modalService.open({
|
|
50214
|
+
component: MemberImportModalComponent,
|
|
50215
|
+
componentProps: {
|
|
50216
|
+
orgId: this.activeOrgId(),
|
|
50217
|
+
availableRoles: this.availableRoles().map(r => r.name),
|
|
50218
|
+
onSuccess: () => {
|
|
50219
|
+
this.loadMembers();
|
|
50220
|
+
this.resolvedConfig().onMemberInvited?.();
|
|
50221
|
+
},
|
|
50222
|
+
},
|
|
50223
|
+
breakpoints: {
|
|
50224
|
+
breakpoints: [0, 0.92],
|
|
50225
|
+
initialBreakpoint: 0.92,
|
|
50226
|
+
showHandle: true,
|
|
50227
|
+
},
|
|
50228
|
+
backdropDismiss: true,
|
|
50229
|
+
});
|
|
50230
|
+
}
|
|
50231
|
+
onOpenApiKeys() {
|
|
50232
|
+
void this.modalService.open({
|
|
50233
|
+
component: ApiKeysModalComponent,
|
|
50234
|
+
breakpoints: {
|
|
50235
|
+
breakpoints: [0, 0.92],
|
|
50236
|
+
initialBreakpoint: 0.92,
|
|
50237
|
+
showHandle: true,
|
|
50238
|
+
},
|
|
50239
|
+
backdropDismiss: true,
|
|
50240
|
+
});
|
|
50241
|
+
}
|
|
49326
50242
|
onViewPermissions() {
|
|
49327
50243
|
this.nav.navigateByUrl(this.resolvedConfig().viewPermissionsRoute);
|
|
49328
50244
|
}
|
|
@@ -49404,6 +50320,7 @@ class OrganizationViewComponent {
|
|
|
49404
50320
|
if (!orgId)
|
|
49405
50321
|
return Promise.resolve();
|
|
49406
50322
|
this.membersLoading.set(true);
|
|
50323
|
+
this.membersLoadError.set(null);
|
|
49407
50324
|
this.membersNextToken.set(null);
|
|
49408
50325
|
this.showAllMembers.set(false);
|
|
49409
50326
|
return new Promise(resolve => {
|
|
@@ -49614,6 +50531,8 @@ class OrganizationViewComponent {
|
|
|
49614
50531
|
<div class="section-body">
|
|
49615
50532
|
@if (membersLoading()) {
|
|
49616
50533
|
<val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
|
|
50534
|
+
} @else if (membersErrorState()) {
|
|
50535
|
+
<val-empty-state [props]="membersErrorState()!" />
|
|
49617
50536
|
} @else if (members().length === 0) {
|
|
49618
50537
|
<val-text
|
|
49619
50538
|
[props]="{
|
|
@@ -49706,6 +50625,8 @@ class OrganizationViewComponent {
|
|
|
49706
50625
|
/>
|
|
49707
50626
|
</div>
|
|
49708
50627
|
<val-button [props]="openInviteButtonProps()" (click)="onOpenInvite()" />
|
|
50628
|
+
<val-button [props]="openImportButtonProps()" (click)="onOpenImport()" />
|
|
50629
|
+
<val-button [props]="openApiKeysButtonProps()" (click)="onOpenApiKeys()" />
|
|
49709
50630
|
</div>
|
|
49710
50631
|
</section>
|
|
49711
50632
|
}
|
|
@@ -49814,6 +50735,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49814
50735
|
ButtonComponent,
|
|
49815
50736
|
MemberCardComponent,
|
|
49816
50737
|
TransferOwnershipModalComponent,
|
|
50738
|
+
MemberImportModalComponent,
|
|
50739
|
+
ApiKeysModalComponent,
|
|
49817
50740
|
], template: `
|
|
49818
50741
|
<div class="page">
|
|
49819
50742
|
<header class="page-header">
|
|
@@ -49892,6 +50815,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49892
50815
|
<div class="section-body">
|
|
49893
50816
|
@if (membersLoading()) {
|
|
49894
50817
|
<val-skeleton-layout [props]="{ preset: 'list', rows: 3 }" />
|
|
50818
|
+
} @else if (membersErrorState()) {
|
|
50819
|
+
<val-empty-state [props]="membersErrorState()!" />
|
|
49895
50820
|
} @else if (members().length === 0) {
|
|
49896
50821
|
<val-text
|
|
49897
50822
|
[props]="{
|
|
@@ -49984,6 +50909,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
49984
50909
|
/>
|
|
49985
50910
|
</div>
|
|
49986
50911
|
<val-button [props]="openInviteButtonProps()" (click)="onOpenInvite()" />
|
|
50912
|
+
<val-button [props]="openImportButtonProps()" (click)="onOpenImport()" />
|
|
50913
|
+
<val-button [props]="openApiKeysButtonProps()" (click)="onOpenApiKeys()" />
|
|
49987
50914
|
</div>
|
|
49988
50915
|
</section>
|
|
49989
50916
|
}
|
|
@@ -61254,5 +62181,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
61254
62181
|
* Generated bundle index. Do not edit.
|
|
61255
62182
|
*/
|
|
61256
62183
|
|
|
61257
|
-
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, 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, 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, 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, provideValtechAccountRoutes, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
|
|
62184
|
+
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, 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, 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, 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, provideValtechAccountRoutes, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
|
|
61258
62185
|
//# sourceMappingURL=valtech-components.mjs.map
|