oip-common 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +68 -68
  2. package/assets/demo/code.scss +17 -17
  3. package/assets/demo/demo.scss +2 -2
  4. package/assets/demo/flags/flags.scss +984 -984
  5. package/assets/i18n/extensions.en.json +1 -1
  6. package/assets/layout/_core.scss +30 -30
  7. package/assets/layout/_footer.scss +8 -8
  8. package/assets/layout/_main.scss +12 -12
  9. package/assets/layout/_menu.scss +148 -148
  10. package/assets/layout/_mixins.scss +15 -15
  11. package/assets/layout/_preloading.scss +49 -49
  12. package/assets/layout/_responsive.scss +108 -108
  13. package/assets/layout/_topbar.scss +168 -168
  14. package/assets/layout/_typography.scss +68 -68
  15. package/assets/layout/_utils.scss +25 -25
  16. package/assets/layout/layout.scss +13 -13
  17. package/assets/layout/variables/_common.scss +20 -20
  18. package/assets/layout/variables/_dark.scss +5 -5
  19. package/assets/layout/variables/_light.scss +5 -5
  20. package/assets/oip-common.scss +6 -6
  21. package/assets/tailwind.css +3 -3
  22. package/fesm2022/oip-common.mjs +1877 -669
  23. package/fesm2022/oip-common.mjs.map +1 -1
  24. package/index.d.ts +177 -18
  25. package/package.json +1 -1
  26. package/templates/http-client.ejs +34 -8
  27. package/assets/i18n/app-modules.en.json +0 -30
  28. package/assets/i18n/app-modules.ru.json +0 -30
  29. package/assets/i18n/applications.en.json +0 -46
  30. package/assets/i18n/applications.ru.json +0 -46
  31. package/assets/i18n/config.en.json +0 -18
  32. package/assets/i18n/config.ru.json +0 -18
  33. package/assets/i18n/db-migration.en.json +0 -19
  34. package/assets/i18n/db-migration.ru.json +0 -19
  35. package/assets/i18n/en.json +0 -138
  36. package/assets/i18n/iframe-module.en.json +0 -10
  37. package/assets/i18n/iframe-module.ru.json +0 -10
  38. package/assets/i18n/notfound.en.json +0 -8
  39. package/assets/i18n/notfound.ru.json +0 -8
  40. package/assets/i18n/ru.json +0 -282
package/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { OnDestroy, OnInit, DestroyRef, WritableSignal, OnChanges, SimpleChanges, Type, InjectionToken, Provider, EventEmitter, Renderer2, EnvironmentProviders } from '@angular/core';
2
+ import { OnDestroy, OnInit, DestroyRef, WritableSignal, OnChanges, SimpleChanges, Type, Provider, InjectionToken, EventEmitter, Renderer2, EnvironmentProviders } from '@angular/core';
3
3
  import * as rxjs from 'rxjs';
4
4
  import { Observable, BehaviorSubject, Subscription, Subject } from 'rxjs';
5
5
  import { MessageService, ToastMessageOptions, ConfirmationService, MenuItem, FilterMetadata } from 'primeng/api';
6
- import { ActivatedRoute, QueryParamsHandling, IsActiveMatchOptions, Params, Router } from '@angular/router';
7
- import { InterpolationParameters, Translation, TranslationObject, TranslateService } from '@ngx-translate/core';
6
+ import { Router, ActivatedRoute, QueryParamsHandling, IsActiveMatchOptions, Params, CanActivateChildFn } from '@angular/router';
7
+ import { TranslationObject, InterpolationParameters, Translation, TranslateService } from '@ngx-translate/core';
8
8
  import { ContextMenu } from 'primeng/contextmenu';
9
9
  import { PaletteDesignToken, Preset } from '@primeuix/themes/types';
10
10
  import { PrimeNG } from 'primeng/config';
@@ -147,6 +147,10 @@ declare class LayoutService {
147
147
  static ɵprov: i0.ɵɵInjectableDeclaration<LayoutService>;
148
148
  }
149
149
 
150
+ /**
151
+ * Translations of a single namespace grouped by language code, e.g. { en: {...}, ru: {...} }
152
+ */
153
+ type TranslationsByLang = Record<string, TranslationObject>;
150
154
  interface LanguageDto {
151
155
  code: string;
152
156
  name: string;
@@ -163,6 +167,20 @@ declare class L10nService {
163
167
  private readonly primeNg;
164
168
  private readonly layoutService;
165
169
  availableLanguages: LanguageDto[];
170
+ /**
171
+ * Translations bundled with components, registered at module load time.
172
+ */
173
+ private static readonly staticTranslations;
174
+ /**
175
+ * Registers translations bundled with a component instead of loading them over HTTP.
176
+ * Namespaces are taken from the root keys of the passed dictionaries.
177
+ * Components derived from <c>BaseModuleComponent</c> don't call it directly - it is enough
178
+ * to declare the static <c>translations</c> field.
179
+ * @param byLang - Translations grouped by language code
180
+ * @param namespace - Explicit namespace, needed when the dictionaries are still empty
181
+ */
182
+ static registerTranslations(byLang: TranslationsByLang | undefined, namespace?: string): void;
183
+ constructor();
166
184
  /**
167
185
  * Loads translations for a specific component
168
186
  * @param component - Name of the component to load translations for
@@ -184,6 +202,12 @@ declare class L10nService {
184
202
  * @param lang - Language code to load translations for
185
203
  */
186
204
  private loadTranslations;
205
+ /**
206
+ * Merges a translation dictionary into the dictionary of the given language
207
+ * @param lang - Language code
208
+ * @param translations - Translations to merge
209
+ */
210
+ private mergeTranslation;
187
211
  /**
188
212
  * Changes the lang currently used
189
213
  */
@@ -291,8 +315,14 @@ declare enum ContentType {
291
315
  declare class HttpClient<SecurityDataType = unknown> {
292
316
  protected securityService: SecurityService;
293
317
  protected layoutService: LayoutService;
318
+ protected router: Router;
294
319
  baseUrl: string;
295
320
  private securityWorker?;
321
+ /**
322
+ * Reads the module instance id of the deepest activated route.
323
+ * The backend uses it to check module instance rights on endpoints that do not carry the id in their contract.
324
+ */
325
+ protected getCurrentModuleInstanceId(): number | undefined;
296
326
  private abortControllers;
297
327
  private customFetch;
298
328
  private baseApiParams;
@@ -307,6 +337,7 @@ declare class HttpClient<SecurityDataType = unknown> {
307
337
  protected createAbortSignal: (cancelToken: CancelToken) => AbortSignal | undefined;
308
338
  abortRequest: (cancelToken: CancelToken) => void;
309
339
  request: <T = any, E = any>({ body, secure, path, type, query, format, baseUrl, cancelToken, ...params }: FullRequestParams) => Promise<T>;
340
+ private authorizeOnUnauthorized;
310
341
  private getCsrfRequestParams;
311
342
  static ɵfac: i0.ɵɵFactoryDeclaration<HttpClient<any>, never>;
312
343
  static ɵprov: i0.ɵɵInjectableDeclaration<HttpClient<any>>;
@@ -391,6 +422,16 @@ declare abstract class BaseModuleComponent<TBackendStoreSettings, TLocalStoreSet
391
422
  * @type {string}
392
423
  */
393
424
  title: string;
425
+ /**
426
+ * Translations bundled with the component, grouped by language code.
427
+ * Declare it in a derived component to load translations from the component folder
428
+ * instead of `assets/i18n`:
429
+ *
430
+ * ```ts
431
+ * static override readonly translations = { en, ru };
432
+ * ```
433
+ */
434
+ static readonly translations: TranslationsByLang | undefined;
394
435
  l10nService: L10nService;
395
436
  l10n$: Observable<Translation | TranslationObject>;
396
437
  canRead: boolean;
@@ -481,13 +522,13 @@ declare abstract class BaseModuleComponent<TBackendStoreSettings, TLocalStoreSet
481
522
  /**
482
523
  * Starts watching current token roles and maps them to module instance security settings.
483
524
  */
484
- protected watchSecurityRights(controller?: string, id?: number | undefined): void;
525
+ protected watchSecurityRights(controller?: string, id?: number | undefined): Promise<void>;
485
526
  private resetRightsState;
486
527
  private updateRightsState;
487
528
  protected hasSecurityRight(roles: string[], securitySettings: SecurityDto[], code: string): boolean;
488
529
  protected getSecurity(controller?: string, id?: number | undefined): Promise<SecurityDto[]>;
489
530
  protected saveSecurity(request: PutSecurityDto, controller?: string): Promise<unknown>;
490
- protected getModuleInstanceSettings<TSettings>(controller?: string, id?: number | undefined): Promise<TSettings>;
531
+ protected getModuleInstanceSettings<TSettings>(controller?: string): Promise<TSettings>;
491
532
  protected saveModuleInstanceSettings<TSettings>(request: {
492
533
  id: number;
493
534
  settings: TSettings;
@@ -509,6 +550,7 @@ declare class SecurityComponent implements OnChanges, OnInit, OnDestroy {
509
550
  id?: number;
510
551
  controller?: string;
511
552
  roles: string[];
553
+ constructor(l10nService: L10nService);
512
554
  ngOnDestroy(): void;
513
555
  ngOnChanges(changes: SimpleChanges): void;
514
556
  ngOnInit(): void;
@@ -651,10 +693,7 @@ interface ModuleInstanceDto {
651
693
  order?: number;
652
694
  separator?: boolean;
653
695
  }
654
- interface GetModuleInstanceSettingsParams2 {
655
- id?: number;
656
- }
657
- interface GetModuleInstanceSettingsParams4 {
696
+ interface GetModuleInstanceRightsParams {
658
697
  id?: number;
659
698
  }
660
699
  interface DeleteModuleInstanceParams {
@@ -749,6 +788,7 @@ declare class MenuService {
749
788
 
750
789
  declare class MenuApi<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
751
790
  get: (params?: RequestParams) => Promise<ModuleInstanceDto[]>;
791
+ getModuleInstanceRights: (query: GetModuleInstanceRightsParams, params?: RequestParams) => Promise<string[]>;
752
792
  getAdminMenu: (params?: RequestParams) => Promise<ModuleInstanceDto[]>;
753
793
  getModules: (params?: RequestParams) => Promise<IntKeyValueDto[]>;
754
794
  addModuleInstance: (data: AddModuleInstanceDto, params?: RequestParams) => Promise<void>;
@@ -795,7 +835,6 @@ declare class MenuItemEditDialogComponent {
795
835
  private readonly msgService;
796
836
  visible: boolean;
797
837
  visibleChange: EventEmitter<boolean>;
798
- modules: any[];
799
838
  roles: string[];
800
839
  iconOptions: PrimeIconOption[];
801
840
  item: EditModuleInstanceDto;
@@ -875,6 +914,11 @@ declare class UnauthorizedComponent implements OnInit {
875
914
  static ɵcmp: i0.ɵɵComponentDeclaration<UnauthorizedComponent, "ng-component", never, {}, {}, never, never, true, never>;
876
915
  }
877
916
 
917
+ declare class AccessComponent {
918
+ static ɵfac: i0.ɵɵFactoryDeclaration<AccessComponent, never>;
919
+ static ɵcmp: i0.ɵɵComponentDeclaration<AccessComponent, "app-access", never, {}, {}, never, never, true, never>;
920
+ }
921
+
878
922
  declare class ErrorComponent {
879
923
  static ɵfac: i0.ɵɵFactoryDeclaration<ErrorComponent, never>;
880
924
  static ɵcmp: i0.ɵɵComponentDeclaration<ErrorComponent, "app-error", never, {}, {}, never, never, true, never>;
@@ -902,20 +946,25 @@ declare class UserProfileApi<SecurityDataType = unknown> extends HttpClient<Secu
902
946
  getUserPhoto: (params?: RequestParams) => Promise<Blob>;
903
947
  getUserPhotoById: ({ userId, ...query }: GetUserPhotoByIdParams, params?: RequestParams) => Promise<Blob>;
904
948
  postUserPhoto: (data: PostUserPhotoPayload, params?: RequestParams) => Promise<void>;
949
+ deleteUserPhoto: (params?: RequestParams) => Promise<void>;
905
950
  getSettings: (params?: RequestParams) => Promise<UserSettingsDto>;
906
951
  setSettings: (data: UserSettingsDto, params?: RequestParams) => Promise<void>;
907
952
  static ɵfac: i0.ɵɵFactoryDeclaration<UserProfileApi<any>, never>;
908
953
  static ɵprov: i0.ɵɵInjectableDeclaration<UserProfileApi<any>>;
909
954
  }
910
955
 
911
- declare class ProfileComponent {
956
+ declare class UserProfileComponent {
912
957
  readonly userService: UserService;
913
958
  readonly msgService: MsgService;
914
959
  readonly translateService: TranslateService;
915
960
  readonly userProfileApi: UserProfileApi<any>;
961
+ private readonly confirmationService;
962
+ constructor(l10nService: L10nService);
916
963
  uploadPhoto(event: any): Promise<void>;
917
- static ɵfac: i0.ɵɵFactoryDeclaration<ProfileComponent, never>;
918
- static ɵcmp: i0.ɵɵComponentDeclaration<ProfileComponent, "user-profile", never, {}, {}, never, never, true, never>;
964
+ confirmDeletePhoto(event: Event): void;
965
+ private deletePhoto;
966
+ static ɵfac: i0.ɵɵFactoryDeclaration<UserProfileComponent, never>;
967
+ static ɵcmp: i0.ɵɵComponentDeclaration<UserProfileComponent, "user-profile", never, {}, {}, never, never, true, never>;
919
968
  }
920
969
 
921
970
  declare class ConfigComponent {
@@ -954,8 +1003,47 @@ interface MigrationDto {
954
1003
  exist: boolean;
955
1004
  }
956
1005
  declare class DbMigrationComponent extends BaseModuleComponent<NoSettingsDto, NoSettingsDto> implements OnInit, OnDestroy {
1006
+ static readonly translations: {
1007
+ en: {
1008
+ "db-migration": {
1009
+ migrationManager: string;
1010
+ actions: {
1011
+ refresh: string;
1012
+ cleanFilter: string;
1013
+ applyMigration: string;
1014
+ };
1015
+ columns: {
1016
+ name: string;
1017
+ applied: string;
1018
+ exist: string;
1019
+ pending: string;
1020
+ };
1021
+ messages: {
1022
+ errorRefreshing: string;
1023
+ };
1024
+ };
1025
+ };
1026
+ ru: {
1027
+ "db-migration": {
1028
+ migrationManager: string;
1029
+ actions: {
1030
+ refresh: string;
1031
+ cleanFilter: string;
1032
+ applyMigration: string;
1033
+ };
1034
+ columns: {
1035
+ name: string;
1036
+ applied: string;
1037
+ exist: string;
1038
+ pending: string;
1039
+ };
1040
+ messages: {
1041
+ errorRefreshing: string;
1042
+ };
1043
+ };
1044
+ };
1045
+ };
957
1046
  data: MigrationDto[];
958
- constructor();
959
1047
  ngOnInit(): Promise<void>;
960
1048
  refreshAction(): Promise<void>;
961
1049
  getData(): Promise<MigrationDto[]>;
@@ -1091,6 +1179,7 @@ declare class AppConfiguratorComponent implements OnInit {
1091
1179
  label: string;
1092
1180
  value: string;
1093
1181
  }[];
1182
+ constructor(l10nService: L10nService);
1094
1183
  ngOnInit(): void;
1095
1184
  surfaces: SurfacesType[];
1096
1185
  selectedPrimaryColor: i0.Signal<string>;
@@ -1252,6 +1341,7 @@ declare class DiscussionComponent implements OnChanges, OnDestroy, OnInit {
1252
1341
  historyByComment: Record<number, HistoryState>;
1253
1342
  emojiPalette: string[];
1254
1343
  private mentionSearchTimer;
1344
+ constructor(l10nService: L10nService);
1255
1345
  ngOnChanges(changes: SimpleChanges): void;
1256
1346
  ngOnInit(): Promise<void>;
1257
1347
  ngOnDestroy(): void;
@@ -1292,6 +1382,28 @@ declare class DiscussionComponent implements OnChanges, OnDestroy, OnInit {
1292
1382
  }
1293
1383
 
1294
1384
  declare class IframeModuleComponent extends BaseModuleComponent<IframeModuleSettings, IframeModuleSettings> implements OnInit, OnDestroy {
1385
+ static readonly translations: {
1386
+ en: {
1387
+ "iframe-module": {
1388
+ iframeModule: {
1389
+ urlPlaceholder: string;
1390
+ settingSaveButtonLabel: string;
1391
+ emptyUrlMessage: string;
1392
+ siteLoadingMessage: string;
1393
+ };
1394
+ };
1395
+ };
1396
+ ru: {
1397
+ "iframe-module": {
1398
+ iframeModule: {
1399
+ urlPlaceholder: string;
1400
+ settingSaveButtonLabel: string;
1401
+ emptyUrlMessage: string;
1402
+ siteLoadingMessage: string;
1403
+ };
1404
+ };
1405
+ };
1406
+ };
1295
1407
  private iframe?;
1296
1408
  private readonly renderer;
1297
1409
  private readonly translate;
@@ -1395,6 +1507,7 @@ declare class UserNotificationsComponent {
1395
1507
  private readonly translateService;
1396
1508
  protected readonly unreadNotificationCount: i0.Signal<number>;
1397
1509
  protected readonly unreadNotificationBadge: i0.Signal<string>;
1510
+ constructor(l10nService: L10nService);
1398
1511
  protected toggle(event: Event): Promise<void>;
1399
1512
  loadNotifications(): Promise<void>;
1400
1513
  onPageChange(event: PaginatorState): Promise<void>;
@@ -1443,6 +1556,52 @@ declare class AuthGuardService {
1443
1556
  static ɵprov: i0.ɵɵInjectableDeclaration<AuthGuardService>;
1444
1557
  }
1445
1558
 
1559
+ /**
1560
+ * Route data flag marking a route that only administrators may open.
1561
+ */
1562
+ interface ModuleAccessRouteData {
1563
+ requireAdmin?: boolean;
1564
+ }
1565
+ /**
1566
+ * Guards module routes against direct navigation without the required rights.
1567
+ *
1568
+ * - Routes flagged with `data: { requireAdmin: true }` require the `admin` role.
1569
+ * - Routes carrying an `:id` segment require the `read` right on that module instance.
1570
+ * - Everything else is left to {@link AuthGuardService}.
1571
+ *
1572
+ * Denied navigation is redirected to the access denied page. This is a UX guard only:
1573
+ * the backend checks the same rights on every module endpoint.
1574
+ */
1575
+ declare const moduleAccessGuard: CanActivateChildFn;
1576
+
1577
+ /**
1578
+ * Reads the rights the current user has on a module instance.
1579
+ *
1580
+ * Results are cached per instance and dropped whenever the authenticated user changes.
1581
+ */
1582
+ declare class ModuleInstanceRightsService {
1583
+ static readonly readRight = "read";
1584
+ private readonly menuApi;
1585
+ private readonly securityService;
1586
+ private readonly cache;
1587
+ private cachedIdentity;
1588
+ constructor();
1589
+ /**
1590
+ * Gets the rights of the current user on the given module instance.
1591
+ */
1592
+ getRights(moduleInstanceId: number): Promise<string[]>;
1593
+ /**
1594
+ * Checks whether the current user has the `read` right on the given module instance.
1595
+ */
1596
+ canRead(moduleInstanceId: number): Promise<boolean>;
1597
+ /**
1598
+ * Drops every cached result, for example after module security was changed.
1599
+ */
1600
+ clearCache(): void;
1601
+ static ɵfac: i0.ɵɵFactoryDeclaration<ModuleInstanceRightsService, never>;
1602
+ static ɵprov: i0.ɵɵInjectableDeclaration<ModuleInstanceRightsService>;
1603
+ }
1604
+
1446
1605
  declare class NotificationService {
1447
1606
  private connection;
1448
1607
  private securityService;
@@ -1590,13 +1749,13 @@ declare function emitOipError(element: HTMLElement, error: unknown): void;
1590
1749
  declare function emitOipContextChange(element: HTMLElement, context: OipExtensionHostContext): void;
1591
1750
 
1592
1751
  declare class FolderModuleApi<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
1593
- getModuleInstanceSettings: (query: GetModuleInstanceSettingsParams2, params?: RequestParams) => Promise<FolderModuleSettings>;
1752
+ getModuleInstanceSettings: (params?: RequestParams) => Promise<FolderModuleSettings>;
1594
1753
  static ɵfac: i0.ɵɵFactoryDeclaration<FolderModuleApi<any>, never>;
1595
1754
  static ɵprov: i0.ɵɵInjectableDeclaration<FolderModuleApi<any>>;
1596
1755
  }
1597
1756
 
1598
1757
  declare class IframeModuleApi<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
1599
- getModuleInstanceSettings: (query: GetModuleInstanceSettingsParams4, params?: RequestParams) => Promise<IframeModuleSettings>;
1758
+ getModuleInstanceSettings: (params?: RequestParams) => Promise<IframeModuleSettings>;
1600
1759
  static ɵfac: i0.ɵɵFactoryDeclaration<IframeModuleApi<any>, never>;
1601
1760
  static ɵprov: i0.ɵɵInjectableDeclaration<IframeModuleApi<any>>;
1602
1761
  }
@@ -1674,5 +1833,5 @@ declare class CustomElementExtensionModuleHostComponent extends BaseModuleCompon
1674
1833
  static ɵcmp: i0.ɵɵComponentDeclaration<CustomElementExtensionModuleHostComponent, "ng-component", never, {}, {}, never, never, true, never>;
1675
1834
  }
1676
1835
 
1677
- export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AppTopbarApplicationSwitcherComponent, ApplicationRegistryService, ApplicationsApi, ApplicationsComponent, AuthGuardService, BaseModuleComponent, BffSecurityService, ConfigComponent, ContentType, CustomElementExtensionModuleHostComponent, DbMigrationComponent, DiscussionComponent, ErrorComponent, ExtensionLoaderService, ExtensionModuleHostComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationApi, NotificationService, OIP_EXTENSION_EVENTS, ProfileComponent, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserService, convertToPrimeNgDateFormat, defaultTheme, emitOipContextChange, emitOipError, emitOipNavigate, emitOipNotify, emitOipSettingsChange, emitOipTitleChange, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, provideOip, replaceDefaults };
1678
- export type { AppConfig, AppThemePreset, AppThemePresetMergeMode, AuthCsrfToken, LanguageDto, MenuChangeEvent, NoSettingsDto, OipExtensionHostContext, OipExtensionLoadType, OipExtensionManifest, OipExtensionModuleMetadata, OipExtensionNavigateEvent, OipExtensionNotifyEvent, PutSecurityDto, RequestParams, SecurityDto, TopBarDto };
1836
+ export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AccessComponent, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AppTopbarApplicationSwitcherComponent, ApplicationRegistryService, ApplicationsApi, ApplicationsComponent, AuthGuardService, BaseModuleComponent, BffSecurityService, ConfigComponent, ContentType, CustomElementExtensionModuleHostComponent, DbMigrationComponent, DiscussionComponent, ErrorComponent, ExtensionLoaderService, ExtensionModuleHostComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, ModuleInstanceRightsService, MsgService, NotfoundComponent, NotificationApi, NotificationService, OIP_EXTENSION_EVENTS, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserProfileComponent, UserService, convertToPrimeNgDateFormat, defaultTheme, emitOipContextChange, emitOipError, emitOipNavigate, emitOipNotify, emitOipSettingsChange, emitOipTitleChange, langIntercept, mergeWithDefaults, moduleAccessGuard, provideAppThemes, provideLogoComponent, provideOip, replaceDefaults };
1837
+ export type { AppConfig, AppThemePreset, AppThemePresetMergeMode, AuthCsrfToken, LanguageDto, MenuChangeEvent, ModuleAccessRouteData, NoSettingsDto, OipExtensionHostContext, OipExtensionLoadType, OipExtensionManifest, OipExtensionModuleMetadata, OipExtensionNavigateEvent, OipExtensionNotifyEvent, PutSecurityDto, RequestParams, SecurityDto, TopBarDto };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oip-common",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "A template for cross-platform web applications based on sakai-ng and primeNG",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -8,6 +8,7 @@ const { apiConfig, generateResponses, config } = it;
8
8
  import { LayoutService } from "../services/app.layout.service";
9
9
  import { SecurityService } from "../services/security.service";
10
10
  import { inject, Injectable } from "@angular/core";
11
+ import { ActivatedRoute, Router } from "@angular/router";
11
12
  import { firstValueFrom } from "rxjs";
12
13
 
13
14
  export type QueryParamsType = Record<string | number, any>;
@@ -61,16 +62,41 @@ export enum ContentType {
61
62
  export class HttpClient<SecurityDataType = unknown> {
62
63
  protected securityService = inject(SecurityService);
63
64
  protected layoutService = inject(LayoutService);
65
+ protected router = inject(Router);
64
66
  public baseUrl: string = "<%~ apiConfig.baseUrl %>";
65
67
  private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"] =
66
- () => ({
67
- headers: {
68
- "Accept-language": this.layoutService.language()
69
- ? this.layoutService.language()
70
- : 'en',
71
- "X-Timezone": this.layoutService.timeZone(),
72
- },
73
- });
68
+ () => {
69
+ const moduleInstanceId = this.getCurrentModuleInstanceId();
70
+ return {
71
+ headers: {
72
+ "Accept-language": this.layoutService.language()
73
+ ? this.layoutService.language()
74
+ : 'en',
75
+ "X-Timezone": this.layoutService.timeZone(),
76
+ ...(moduleInstanceId != null
77
+ ? { "X-Module-Instance-Id": String(moduleInstanceId) }
78
+ : {}),
79
+ },
80
+ };
81
+ };
82
+
83
+ /**
84
+ * Reads the module instance id of the deepest activated route.
85
+ * The backend uses it to check module instance rights on endpoints that do not carry the id in their contract.
86
+ */
87
+ protected getCurrentModuleInstanceId(): number | undefined {
88
+ // May run before the first navigation completes, when route snapshots are not available yet.
89
+ let route: ActivatedRoute | null | undefined = this.router.routerState?.root;
90
+ let id: string | null = null;
91
+
92
+ while (route) {
93
+ id = route.snapshot?.paramMap?.get("id") ?? id;
94
+ route = route.firstChild;
95
+ }
96
+
97
+ const parsed = id != null ? Number(id) : Number.NaN;
98
+ return Number.isFinite(parsed) ? parsed : undefined;
99
+ }
74
100
 
75
101
  private abortControllers = new Map<CancelToken, AbortController>();
76
102
  private customFetch = (...fetchParams: Parameters<typeof fetch>) => fetch(...fetchParams);
@@ -1,30 +0,0 @@
1
- {
2
- "app-modules": {
3
- "title": "Modules",
4
- "refreshTooltip": "Refresh",
5
- "register": {
6
- "manifestUrlPlaceholder": "External module manifest URL",
7
- "button": "Register"
8
- },
9
- "table": {
10
- "moduleId": "Module ID",
11
- "name": "Name",
12
- "currentlyLoaded": "Currently Loaded",
13
- "yes": "Yes",
14
- "no": "No",
15
- "deleteTooltip": "Delete"
16
- },
17
- "confirm": {
18
- "header": "Warning",
19
- "message": "Are you sure you want to delete the module?",
20
- "cancel": "Cancel",
21
- "delete": "Delete"
22
- },
23
- "messages": {
24
- "deleteSuccess": "Module deleted",
25
- "deleteError": "Module delete failed",
26
- "registerError": "External module registration failed",
27
- "registerSuccess": "External module registered"
28
- }
29
- }
30
- }
@@ -1,30 +0,0 @@
1
- {
2
- "app-modules": {
3
- "title": "Модули",
4
- "refreshTooltip": "Обновить",
5
- "register": {
6
- "manifestUrlPlaceholder": "URL манифеста внешнего модуля",
7
- "button": "Зарегистрировать"
8
- },
9
- "table": {
10
- "moduleId": "ID модуля",
11
- "name": "Название",
12
- "currentlyLoaded": "Загружен",
13
- "yes": "Да",
14
- "no": "Нет",
15
- "deleteTooltip": "Удалить"
16
- },
17
- "confirm": {
18
- "header": "Внимание",
19
- "message": "Вы уверены, что хотите удалить модуль?",
20
- "cancel": "Отмена",
21
- "delete": "Удалить"
22
- },
23
- "messages": {
24
- "deleteSuccess": "Модуль удален",
25
- "deleteError": "Не удалось удалить модуль",
26
- "registerError": "Не удалось зарегистрировать внешний модуль",
27
- "registerSuccess": "Внешний модуль зарегистрирован"
28
- }
29
- }
30
- }
@@ -1,46 +0,0 @@
1
- {
2
- "applications": {
3
- "title": "Applications",
4
- "subtitle": "Manage the frontend application registry",
5
- "searchPlaceholder": "Search applications",
6
- "search": "Search",
7
- "clear": "Clear",
8
- "add": "Add",
9
- "refreshTooltip": "Refresh",
10
- "empty": "No applications found",
11
- "table": {
12
- "code": "Code",
13
- "displayName": "Name",
14
- "baseUrl": "Base URL",
15
- "internalBaseUrl": "Internal Base URL",
16
- "icon": "Icon",
17
- "order": "Order",
18
- "enabled": "Enabled",
19
- "serviceType": "Service type",
20
- "current": "Current",
21
- "actions": "Actions",
22
- "yes": "Yes",
23
- "no": "No",
24
- "editTooltip": "Edit",
25
- "deleteTooltip": "Delete",
26
- "saveTooltip": "Save",
27
- "cancelTooltip": "Cancel"
28
- },
29
- "serviceTypes": {
30
- "service": "Service",
31
- "application": "Application"
32
- },
33
- "confirm": {
34
- "header": "Warning",
35
- "message": "Are you sure you want to delete application {{displayName}}?",
36
- "cancel": "Cancel",
37
- "delete": "Delete"
38
- },
39
- "messages": {
40
- "requiredFields": "Fill code, name and Base URL",
41
- "createSuccess": "Application created",
42
- "updateSuccess": "Application updated",
43
- "deleteSuccess": "Application deleted"
44
- }
45
- }
46
- }
@@ -1,46 +0,0 @@
1
- {
2
- "applications": {
3
- "title": "Приложения",
4
- "subtitle": "Управление реестром фронтенд-приложений",
5
- "searchPlaceholder": "Поиск по приложениям",
6
- "search": "Найти",
7
- "clear": "Очистить",
8
- "add": "Добавить",
9
- "refreshTooltip": "Обновить",
10
- "empty": "Приложения не найдены",
11
- "table": {
12
- "code": "Код",
13
- "displayName": "Название",
14
- "baseUrl": "Base URL",
15
- "internalBaseUrl": "Internal Base URL",
16
- "icon": "Иконка",
17
- "order": "Порядок",
18
- "enabled": "Включено",
19
- "serviceType": "Тип сервиса",
20
- "current": "Текущее",
21
- "actions": "Действия",
22
- "yes": "Да",
23
- "no": "Нет",
24
- "editTooltip": "Редактировать",
25
- "deleteTooltip": "Удалить",
26
- "saveTooltip": "Сохранить",
27
- "cancelTooltip": "Отменить"
28
- },
29
- "serviceTypes": {
30
- "service": "Сервис",
31
- "application": "Приложение"
32
- },
33
- "confirm": {
34
- "header": "Внимание",
35
- "message": "Вы уверены, что хотите удалить приложение {{displayName}}?",
36
- "cancel": "Отмена",
37
- "delete": "Удалить"
38
- },
39
- "messages": {
40
- "requiredFields": "Заполните код, название и Base URL",
41
- "createSuccess": "Приложение создано",
42
- "updateSuccess": "Приложение обновлено",
43
- "deleteSuccess": "Приложение удалено"
44
- }
45
- }
46
- }
@@ -1,18 +0,0 @@
1
- {
2
- "config": {
3
- "all": "All",
4
- "applicationManagement": "Application management",
5
- "dateFormat": "Date format",
6
- "dateTimeFormat": "Date and time format:",
7
- "goTo": "Go to",
8
- "localization": "Localization",
9
- "menu": "Menu",
10
- "moduleManagement": "Module management",
11
- "photo": "Photo",
12
- "profile": "Profile",
13
- "selectLanguage": "Select language",
14
- "timeFormat": "Time format",
15
- "timeZone": "Time zone",
16
- "usePhoto256x256Pixel": "Use photo 256x256 pixel"
17
- }
18
- }
@@ -1,18 +0,0 @@
1
- {
2
- "config": {
3
- "all": "Все",
4
- "applicationManagement": "Управление приложениями",
5
- "dateFormat": "Формат даты",
6
- "dateTimeFormat": "Формат даты и времени:",
7
- "goTo": "Перейти",
8
- "localization": "Локализация",
9
- "menu": "Меню",
10
- "moduleManagement": "Управление модулями",
11
- "photo": "Фото",
12
- "profile": "Профиль",
13
- "selectLanguage": "Выберите язык",
14
- "timeFormat": "Формат времени",
15
- "timeZone": "Часовой пояс",
16
- "usePhoto256x256Pixel": "Используйте фото 256x256 пикселей"
17
- }
18
- }
@@ -1,19 +0,0 @@
1
- {
2
- "db-migration": {
3
- "migrationManager": "Migration manager",
4
- "actions": {
5
- "refresh": "Refresh",
6
- "cleanFilter": "Clean filter",
7
- "applyMigration": "Apply migration"
8
- },
9
- "columns": {
10
- "name": "Migration name",
11
- "applied": "Applied",
12
- "exist": "Exist",
13
- "pending": "Pending"
14
- },
15
- "messages": {
16
- "errorRefreshing": "Error refreshing database"
17
- }
18
- }
19
- }
@@ -1,19 +0,0 @@
1
- {
2
- "db-migration": {
3
- "migrationManager": "Менеджер миграций",
4
- "actions": {
5
- "refresh": "Обновить",
6
- "cleanFilter": "Очистить фильтр",
7
- "applyMigration": "Применить миграцию"
8
- },
9
- "columns": {
10
- "name": "Название миграции",
11
- "applied": "Применена",
12
- "exist": "Существует",
13
- "pending": "Ожидает"
14
- },
15
- "messages": {
16
- "errorRefreshing": "Ошибка обновления базы данных"
17
- }
18
- }
19
- }