oip-common 0.7.1 → 0.9.0

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.
@@ -413,6 +413,11 @@ class LayoutService {
413
413
  this.timeZone = computed(() => this.layoutConfig().timeZone, ...(ngDevMode ? [{ debugName: "timeZone" }] : []));
414
414
  this.adminMode = computed(() => this.layoutConfig().adminMode ?? false, ...(ngDevMode ? [{ debugName: "adminMode" }] : []));
415
415
  this.transitionComplete = signal(false, ...(ngDevMode ? [{ debugName: "transitionComplete" }] : []));
416
+ /**
417
+ * Controls the visibility of the layout footer.
418
+ * Modules can hide the footer to free up vertical space for full-screen content.
419
+ */
420
+ this.footerVisible = signal(true, ...(ngDevMode ? [{ debugName: "footerVisible" }] : []));
416
421
  this.initialized = false;
417
422
  effect(() => {
418
423
  const config = this.layoutConfig();
@@ -536,6 +541,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
536
541
  args: [{ providedIn: 'root' }]
537
542
  }], ctorParameters: () => [] });
538
543
 
544
+ var userService$1 = {
545
+ failedToLoadPhoto: "Failed to load user photo"
546
+ };
539
547
  var msgService$1 = {
540
548
  success: "Success",
541
549
  info: "Info",
@@ -544,11 +552,15 @@ var msgService$1 = {
544
552
  secondary: "Secondary"
545
553
  };
546
554
  var primeng$1 = "";
547
- var en$j = {
555
+ var en$k = {
556
+ userService: userService$1,
548
557
  msgService: msgService$1,
549
558
  primeng: primeng$1
550
559
  };
551
560
 
561
+ var userService = {
562
+ failedToLoadPhoto: "Не удалось загрузить фото пользователя"
563
+ };
552
564
  var msgService = {
553
565
  success: "Успешно",
554
566
  info: "Информация",
@@ -748,7 +760,8 @@ var primeng = {
748
760
  zoomOut: "Уменьшить"
749
761
  }
750
762
  };
751
- var ru$j = {
763
+ var ru$k = {
764
+ userService: userService,
752
765
  msgService: msgService,
753
766
  primeng: primeng
754
767
  };
@@ -757,7 +770,7 @@ var ru$j = {
757
770
  * Global dictionaries shared by all components. They are bundled with the library,
758
771
  * so the application never requests `assets/i18n/{lang}.json`.
759
772
  */
760
- const globalTranslations = { en: en$j, ru: ru$j };
773
+ const globalTranslations = { en: en$k, ru: ru$k };
761
774
  /**
762
775
  * Service for managing translation loading in the application
763
776
  */
@@ -1463,7 +1476,7 @@ var baseComponent$1 = {
1463
1476
  security: "Security",
1464
1477
  success: "Saved successfully"
1465
1478
  };
1466
- var en$i = {
1479
+ var en$j = {
1467
1480
  baseComponent: baseComponent$1
1468
1481
  };
1469
1482
 
@@ -1473,7 +1486,7 @@ var baseComponent = {
1473
1486
  security: "Безопасность",
1474
1487
  success: "Сохранено"
1475
1488
  };
1476
- var ru$i = {
1489
+ var ru$j = {
1477
1490
  baseComponent: baseComponent
1478
1491
  };
1479
1492
 
@@ -1545,6 +1558,11 @@ class BaseModuleComponent {
1545
1558
  */
1546
1559
  constructor() {
1547
1560
  this.isInitialized = false;
1561
+ /**
1562
+ * Set to true in a descendant to hide the layout footer while the module is active.
1563
+ * The footer is restored when the module is destroyed.
1564
+ */
1565
+ this.hideFooter = false;
1548
1566
  this.moduleInstanceReloadPromise = Promise.resolve();
1549
1567
  this.securityRoles = [];
1550
1568
  this.securitySettings = [];
@@ -1609,7 +1627,7 @@ class BaseModuleComponent {
1609
1627
  * @type {Subject<TLocalStoreSettings>}
1610
1628
  */
1611
1629
  this.localSettingsUpdate = new Subject();
1612
- this.baseTranslations = provideTranslations({ en: en$i, ru: ru$i });
1630
+ this.baseTranslations = provideTranslations({ en: en$j, ru: ru$j });
1613
1631
  this.l10nService = inject(L10nService);
1614
1632
  this.canRead = false;
1615
1633
  this.canEdit = false;
@@ -1651,22 +1669,25 @@ class BaseModuleComponent {
1651
1669
  /**
1652
1670
  * Lifecycle hook that is called when a component is destroyed.
1653
1671
  * Unsubscribes from all subscriptions to prevent memory leaks,
1654
- * resets the top bar items to an empty array, and sets the active ID
1655
- * to the ID of the first top bar item (if available).
1672
+ * restores the layout footer, resets the top bar items to an empty array,
1673
+ * and sets the active ID to the ID of the first top bar item (if available).
1656
1674
  */
1657
1675
  ngOnDestroy() {
1676
+ this.layoutService.footerVisible.set(true);
1658
1677
  this.topBarService.setTopBarItems([]);
1659
1678
  this.topBarService.activeId = this.topBarItems[0].id;
1660
1679
  this.rightsSubscription?.unsubscribe();
1661
1680
  this.subscriptions.forEach((s) => s.unsubscribe());
1662
1681
  }
1663
1682
  /**
1664
- * Initializes the component. Subscribes to translation service to set captions for top bar items,
1683
+ * Initializes the component. Applies the footer visibility declared by the module,
1684
+ * subscribes to translation service to set captions for top bar items,
1665
1685
  * sets the top bar items via the top bar service, sets the active ID,
1666
1686
  * subscribes to route parameters to get the ID, and retrieves settings.
1667
1687
  * @return {Promise<void>} A promise that resolves when the initialization is complete.
1668
1688
  */
1669
1689
  async ngOnInit() {
1690
+ this.layoutService.footerVisible.set(!this.hideFooter);
1670
1691
  this.subscriptions.push(this.translateService.stream('baseComponent').subscribe((value) => {
1671
1692
  this.topBarItems.forEach((item) => {
1672
1693
  item.caption = value[item.id];
@@ -1896,6 +1917,13 @@ class SecurityApi extends HttpClient {
1896
1917
  format: "json",
1897
1918
  ...params,
1898
1919
  });
1920
+ this.getDefaultSecretsReport = (params = {}) => this.request({
1921
+ path: `/api/security/get-default-secrets-report`,
1922
+ method: "GET",
1923
+ secure: true,
1924
+ format: "json",
1925
+ ...params,
1926
+ });
1899
1927
  }
1900
1928
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1901
1929
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi }); }
@@ -1910,7 +1938,7 @@ var securityComponent$1 = {
1910
1938
  savedSecurity: "Security settings saved",
1911
1939
  selectRoles: "Select roles"
1912
1940
  };
1913
- var en$h = {
1941
+ var en$i = {
1914
1942
  securityComponent: securityComponent$1
1915
1943
  };
1916
1944
 
@@ -1920,13 +1948,13 @@ var securityComponent = {
1920
1948
  savedSecurity: "Настройки сохранены",
1921
1949
  selectRoles: "Выберите роли"
1922
1950
  };
1923
- var ru$h = {
1951
+ var ru$i = {
1924
1952
  securityComponent: securityComponent
1925
1953
  };
1926
1954
 
1927
1955
  class SecurityComponent {
1928
1956
  constructor() {
1929
- this.translations = provideTranslations({ en: en$h, ru: ru$h });
1957
+ this.translations = provideTranslations({ en: en$i, ru: ru$i });
1930
1958
  this.msgService = inject(MsgService);
1931
1959
  this.translateService = inject(TranslateService);
1932
1960
  this.httpClient = inject(HttpClient);
@@ -2095,7 +2123,7 @@ const APP_THEME_PRESETS_MERGE_MODE = new InjectionToken('APP_THEME_PRESETS_MERGE
2095
2123
  factory: () => 'mergeWithDefaults'
2096
2124
  });
2097
2125
 
2098
- var en$g = {
2126
+ var en$h = {
2099
2127
  "app-configurator": {
2100
2128
  primary: "Primary",
2101
2129
  surface: "Surface",
@@ -2106,7 +2134,7 @@ var en$g = {
2106
2134
  }
2107
2135
  };
2108
2136
 
2109
- var ru$g = {
2137
+ var ru$h = {
2110
2138
  "app-configurator": {
2111
2139
  primary: "Основной",
2112
2140
  surface: "Фон",
@@ -2150,7 +2178,7 @@ const PRIMARY_COLORS = [
2150
2178
  ];
2151
2179
  class AppConfiguratorComponent {
2152
2180
  constructor() {
2153
- this.translations = provideTranslations({ en: en$g, ru: ru$g });
2181
+ this.translations = provideTranslations({ en: en$h, ru: ru$h });
2154
2182
  this.router = inject(Router);
2155
2183
  this.config = inject(PrimeNG);
2156
2184
  this.layoutService = inject(LayoutService);
@@ -2876,14 +2904,14 @@ class UserService {
2876
2904
  return;
2877
2905
  }
2878
2906
  this.requestedPhotoKey = photoKey;
2879
- this.userProfileApi.getUserPhoto({ format: 'blob' }).then((data) => {
2907
+ this.userProfileApi.getUserPhoto().then((data) => {
2880
2908
  this.createImageFromBlob(data);
2881
2909
  this.photoLoaded = true;
2882
2910
  }, (error) => {
2883
2911
  // A 404 just means the user hasn't uploaded a photo yet (e.g. on first login) —
2884
2912
  // that's an expected state, not a failure, so fall back to initials silently.
2885
2913
  if (error?.status !== 404) {
2886
- this.msgService.errorFromException(error, this.translateService.instant('profileComponent.failedToLoadPhoto'));
2914
+ this.msgService.errorFromException(error, this.translateService.instant('userService.failedToLoadPhoto'));
2887
2915
  }
2888
2916
  this.photoLoaded = false;
2889
2917
  });
@@ -3158,7 +3186,7 @@ var userNotifications$1 = {
3158
3186
  markAsRead: "Read",
3159
3187
  markedAsRead: "Notification marked as read"
3160
3188
  };
3161
- var en$f = {
3189
+ var en$g = {
3162
3190
  userNotifications: userNotifications$1
3163
3191
  };
3164
3192
 
@@ -3169,13 +3197,13 @@ var userNotifications = {
3169
3197
  markAsRead: "Прочитано",
3170
3198
  markedAsRead: "Оповещение отмечено прочитанным"
3171
3199
  };
3172
- var ru$f = {
3200
+ var ru$g = {
3173
3201
  userNotifications: userNotifications
3174
3202
  };
3175
3203
 
3176
3204
  class UserNotificationsComponent {
3177
3205
  constructor() {
3178
- this.translations = provideTranslations({ en: en$f, ru: ru$f });
3206
+ this.translations = provideTranslations({ en: en$g, ru: ru$g });
3179
3207
  this.notifications = [];
3180
3208
  this.totalCount = 0;
3181
3209
  this.skip = 0;
@@ -3604,7 +3632,7 @@ var topbar$1 = {
3604
3632
  profile: "Profile",
3605
3633
  applications: "Applications"
3606
3634
  };
3607
- var en$e = {
3635
+ var en$f = {
3608
3636
  topbar: topbar$1
3609
3637
  };
3610
3638
 
@@ -3617,13 +3645,13 @@ var topbar = {
3617
3645
  profile: "Профиль",
3618
3646
  applications: "Приложения"
3619
3647
  };
3620
- var ru$e = {
3648
+ var ru$f = {
3621
3649
  topbar: topbar
3622
3650
  };
3623
3651
 
3624
3652
  class AppTopbar {
3625
3653
  constructor() {
3626
- this.translations = provideTranslations({ en: en$e, ru: ru$e });
3654
+ this.translations = provideTranslations({ en: en$f, ru: ru$f });
3627
3655
  this.securityService = inject(SecurityService);
3628
3656
  this.topBarService = inject(TopBarService);
3629
3657
  this.userService = inject(UserService);
@@ -5204,7 +5232,7 @@ var menuItemCreateDialogComponent$1 = {
5204
5232
  cancel: "Cancel",
5205
5233
  save: "Save"
5206
5234
  };
5207
- var en$d = {
5235
+ var en$e = {
5208
5236
  menuComponent: menuComponent$1,
5209
5237
  menuItemComponent: menuItemComponent$1,
5210
5238
  menuItemEditDialogComponent: menuItemEditDialogComponent$1,
@@ -5253,7 +5281,7 @@ var menuItemCreateDialogComponent = {
5253
5281
  cancel: "Отмена",
5254
5282
  save: "Сохранить"
5255
5283
  };
5256
- var ru$d = {
5284
+ var ru$e = {
5257
5285
  menuComponent: menuComponent,
5258
5286
  menuItemComponent: menuItemComponent,
5259
5287
  menuItemEditDialogComponent: menuItemEditDialogComponent,
@@ -5264,7 +5292,7 @@ class MenuComponent {
5264
5292
  constructor() {
5265
5293
  // Registers the whole menu/l10n/menu.*.json bundle, which also covers
5266
5294
  // menuItemComponent, menuItemEditDialogComponent and menuItemCreateDialogComponent.
5267
- this.translations = provideTranslations({ en: en$d, ru: ru$d });
5295
+ this.translations = provideTranslations({ en: en$e, ru: ru$e });
5268
5296
  this.menuService = inject(MenuService);
5269
5297
  this.securityService = inject(SecurityService);
5270
5298
  this.translateService = inject(TranslateService);
@@ -5391,14 +5419,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5391
5419
  var blockLoader$1 = {
5392
5420
  loading: "Loading..."
5393
5421
  };
5394
- var en$c = {
5422
+ var en$d = {
5395
5423
  blockLoader: blockLoader$1
5396
5424
  };
5397
5425
 
5398
5426
  var blockLoader = {
5399
5427
  loading: "Загрузка..."
5400
5428
  };
5401
- var ru$c = {
5429
+ var ru$d = {
5402
5430
  blockLoader: blockLoader
5403
5431
  };
5404
5432
 
@@ -5415,7 +5443,7 @@ class BlockLoaderComponent {
5415
5443
  static { this.showDelayMs = 150; }
5416
5444
  static { this.minVisibleMs = 300; }
5417
5445
  constructor() {
5418
- this.translations = provideTranslations({ en: en$c, ru: ru$c });
5446
+ this.translations = provideTranslations({ en: en$d, ru: ru$d });
5419
5447
  this.moduleLoadingService = inject(ModuleLoadingService);
5420
5448
  this.shownAt = 0;
5421
5449
  this.visible = signal(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
@@ -5529,6 +5557,229 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5529
5557
  }]
5530
5558
  }], ctorParameters: () => [] });
5531
5559
 
5560
+ var defaultSecretsBanner$1 = {
5561
+ title: "Default secrets are still in use",
5562
+ description: "{{count}} of {{checked}} secret settings still hold a value shipped with the repository or are empty. Override them before this installation is used for real data.",
5563
+ kind: {
5564
+ ShippedDefault: "shipped default",
5565
+ Missing: "missing"
5566
+ },
5567
+ columns: {
5568
+ configKey: "Setting",
5569
+ kind: "Problem",
5570
+ environmentVariable: "Environment variable"
5571
+ },
5572
+ actions: {
5573
+ details: "Details",
5574
+ hide: "Hide",
5575
+ dismiss: "Dismiss"
5576
+ }
5577
+ };
5578
+ var en$c = {
5579
+ defaultSecretsBanner: defaultSecretsBanner$1
5580
+ };
5581
+
5582
+ var defaultSecretsBanner = {
5583
+ title: "Используются секреты по умолчанию",
5584
+ description: "{{count}} из {{checked}} секретных настроек всё ещё содержат значение из репозитория или пусты. Переопределите их, прежде чем использовать эту установку с реальными данными.",
5585
+ kind: {
5586
+ ShippedDefault: "значение по умолчанию",
5587
+ Missing: "не задано"
5588
+ },
5589
+ columns: {
5590
+ configKey: "Настройка",
5591
+ kind: "Проблема",
5592
+ environmentVariable: "Переменная окружения"
5593
+ },
5594
+ actions: {
5595
+ details: "Подробнее",
5596
+ hide: "Свернуть",
5597
+ dismiss: "Скрыть"
5598
+ }
5599
+ };
5600
+ var ru$c = {
5601
+ defaultSecretsBanner: defaultSecretsBanner
5602
+ };
5603
+
5604
+ /**
5605
+ * Administrator banner listing the secret settings that still hold a value shipped with the repository.
5606
+ *
5607
+ * The report comes from the same cached validator that feeds the startup log and the `default-secrets`
5608
+ * health check, so the three never disagree. Only administrators see it - the endpoint is admin-only.
5609
+ *
5610
+ * Whether the banner is raised at all is decided by the server through `showBanner`: findings are reported in
5611
+ * every environment, but the banner appears only in Production. Set `ASPNETCORE_ENVIRONMENT=Production` to see
5612
+ * it locally.
5613
+ */
5614
+ class DefaultSecretsBannerComponent {
5615
+ constructor() {
5616
+ this.translations = provideTranslations({ en: en$c, ru: ru$c });
5617
+ this.securityApi = inject(SecurityApi);
5618
+ this.securityService = inject(SecurityService);
5619
+ this.destroyRef = inject(DestroyRef);
5620
+ this.report = signal(null, ...(ngDevMode ? [{ debugName: "report" }] : []));
5621
+ this.expanded = signal(false, ...(ngDevMode ? [{ debugName: "expanded" }] : []));
5622
+ }
5623
+ ngOnInit() {
5624
+ // `payload` emits on every auth() call, and the auth guard calls it on every route activation. The report
5625
+ // cannot change while the page is open, so wait for the first payload that belongs to an administrator and
5626
+ // request it exactly once. A non-administrator never issues the request at all - it would only earn a 403.
5627
+ this.securityService.payload
5628
+ .pipe(filter(() => this.securityService.isAdmin()), take(1), takeUntilDestroyed(this.destroyRef))
5629
+ .subscribe(() => this.load());
5630
+ }
5631
+ kindLabel(finding) {
5632
+ return `defaultSecretsBanner.kind.${finding.kind}`;
5633
+ }
5634
+ dismiss() {
5635
+ this.report.set(null);
5636
+ }
5637
+ load() {
5638
+ this.securityApi
5639
+ .getDefaultSecretsReport()
5640
+ .then((data) => this.report.set(data?.showBanner ? data : null))
5641
+ // A service without the endpoint, or a revoked admin role, must not break the layout.
5642
+ .catch(() => this.report.set(null));
5643
+ }
5644
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DefaultSecretsBannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5645
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DefaultSecretsBannerComponent, isStandalone: true, selector: "default-secrets-banner", ngImport: i0, template: `
5646
+ @if (report(); as data) {
5647
+ <div
5648
+ class="mb-4 rounded-border border border-orange-300 bg-orange-50 p-4 dark:border-orange-700 dark:bg-orange-950">
5649
+ <div class="flex flex-row items-start gap-3">
5650
+ <i class="pi pi-exclamation-triangle mt-1 text-xl text-orange-600 dark:text-orange-400"></i>
5651
+ <div class="flex flex-col gap-1">
5652
+ <span class="font-bold text-surface-900 dark:text-surface-0">
5653
+ {{ 'defaultSecretsBanner.title' | translate }}
5654
+ </span>
5655
+ <span class="text-surface-700 dark:text-surface-200">
5656
+ {{
5657
+ 'defaultSecretsBanner.description'
5658
+ | translate: { count: data.findings?.length ?? 0, checked: data.checkedCount ?? 0 }
5659
+ }}
5660
+ </span>
5661
+ </div>
5662
+ <div class="ml-auto flex flex-row gap-2">
5663
+ <p-button
5664
+ severity="secondary"
5665
+ size="small"
5666
+ [icon]="expanded() ? 'pi pi-chevron-up' : 'pi pi-chevron-down'"
5667
+ [label]="
5668
+ (expanded() ? 'defaultSecretsBanner.actions.hide' : 'defaultSecretsBanner.actions.details') | translate
5669
+ "
5670
+ [text]="true"
5671
+ (click)="expanded.set(!expanded())" />
5672
+ <p-button
5673
+ icon="pi pi-times"
5674
+ severity="secondary"
5675
+ size="small"
5676
+ [ariaLabel]="'defaultSecretsBanner.actions.dismiss' | translate"
5677
+ [text]="true"
5678
+ (click)="dismiss()" />
5679
+ </div>
5680
+ </div>
5681
+
5682
+ @if (expanded()) {
5683
+ <div class="mt-3 overflow-x-auto">
5684
+ <table class="w-full text-left text-sm">
5685
+ <thead>
5686
+ <tr class="text-surface-600 dark:text-surface-300">
5687
+ <th class="py-1 pr-4" scope="col">{{ 'defaultSecretsBanner.columns.configKey' | translate }}</th>
5688
+ <th class="py-1 pr-4" scope="col">{{ 'defaultSecretsBanner.columns.kind' | translate }}</th>
5689
+ <th class="py-1" scope="col">
5690
+ {{ 'defaultSecretsBanner.columns.environmentVariable' | translate }}
5691
+ </th>
5692
+ </tr>
5693
+ </thead>
5694
+ <tbody>
5695
+ @for (finding of data.findings; track finding.configKey) {
5696
+ <tr class="text-surface-900 dark:text-surface-0">
5697
+ <td class="py-1 pr-4 font-mono">{{ finding.configKey }}</td>
5698
+ <td class="py-1 pr-4">{{ kindLabel(finding) | translate }}</td>
5699
+ <td class="py-1 font-mono">{{ finding.environmentVariable }}</td>
5700
+ </tr>
5701
+ }
5702
+ </tbody>
5703
+ </table>
5704
+ </div>
5705
+ }
5706
+ </div>
5707
+ }
5708
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5709
+ }
5710
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DefaultSecretsBannerComponent, decorators: [{
5711
+ type: Component,
5712
+ args: [{
5713
+ selector: 'default-secrets-banner',
5714
+ standalone: true,
5715
+ imports: [ButtonModule, TranslatePipe],
5716
+ template: `
5717
+ @if (report(); as data) {
5718
+ <div
5719
+ class="mb-4 rounded-border border border-orange-300 bg-orange-50 p-4 dark:border-orange-700 dark:bg-orange-950">
5720
+ <div class="flex flex-row items-start gap-3">
5721
+ <i class="pi pi-exclamation-triangle mt-1 text-xl text-orange-600 dark:text-orange-400"></i>
5722
+ <div class="flex flex-col gap-1">
5723
+ <span class="font-bold text-surface-900 dark:text-surface-0">
5724
+ {{ 'defaultSecretsBanner.title' | translate }}
5725
+ </span>
5726
+ <span class="text-surface-700 dark:text-surface-200">
5727
+ {{
5728
+ 'defaultSecretsBanner.description'
5729
+ | translate: { count: data.findings?.length ?? 0, checked: data.checkedCount ?? 0 }
5730
+ }}
5731
+ </span>
5732
+ </div>
5733
+ <div class="ml-auto flex flex-row gap-2">
5734
+ <p-button
5735
+ severity="secondary"
5736
+ size="small"
5737
+ [icon]="expanded() ? 'pi pi-chevron-up' : 'pi pi-chevron-down'"
5738
+ [label]="
5739
+ (expanded() ? 'defaultSecretsBanner.actions.hide' : 'defaultSecretsBanner.actions.details') | translate
5740
+ "
5741
+ [text]="true"
5742
+ (click)="expanded.set(!expanded())" />
5743
+ <p-button
5744
+ icon="pi pi-times"
5745
+ severity="secondary"
5746
+ size="small"
5747
+ [ariaLabel]="'defaultSecretsBanner.actions.dismiss' | translate"
5748
+ [text]="true"
5749
+ (click)="dismiss()" />
5750
+ </div>
5751
+ </div>
5752
+
5753
+ @if (expanded()) {
5754
+ <div class="mt-3 overflow-x-auto">
5755
+ <table class="w-full text-left text-sm">
5756
+ <thead>
5757
+ <tr class="text-surface-600 dark:text-surface-300">
5758
+ <th class="py-1 pr-4" scope="col">{{ 'defaultSecretsBanner.columns.configKey' | translate }}</th>
5759
+ <th class="py-1 pr-4" scope="col">{{ 'defaultSecretsBanner.columns.kind' | translate }}</th>
5760
+ <th class="py-1" scope="col">
5761
+ {{ 'defaultSecretsBanner.columns.environmentVariable' | translate }}
5762
+ </th>
5763
+ </tr>
5764
+ </thead>
5765
+ <tbody>
5766
+ @for (finding of data.findings; track finding.configKey) {
5767
+ <tr class="text-surface-900 dark:text-surface-0">
5768
+ <td class="py-1 pr-4 font-mono">{{ finding.configKey }}</td>
5769
+ <td class="py-1 pr-4">{{ kindLabel(finding) | translate }}</td>
5770
+ <td class="py-1 font-mono">{{ finding.environmentVariable }}</td>
5771
+ </tr>
5772
+ }
5773
+ </tbody>
5774
+ </table>
5775
+ </div>
5776
+ }
5777
+ </div>
5778
+ }
5779
+ `
5780
+ }]
5781
+ }] });
5782
+
5532
5783
  class AppLayoutComponent {
5533
5784
  constructor() {
5534
5785
  this.layoutService = inject(LayoutService);
@@ -5607,37 +5858,51 @@ class AppLayoutComponent {
5607
5858
  }
5608
5859
  }
5609
5860
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5610
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: AppLayoutComponent, isStandalone: true, selector: "app-layout", providers: [MenuService, MenuApi], viewQueries: [{ propertyName: "appSidebar", first: true, predicate: SidebarComponent, descendants: true }, { propertyName: "appTopBar", first: true, predicate: AppTopbar, descendants: true }], ngImport: i0, template: `
5861
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AppLayoutComponent, isStandalone: true, selector: "app-layout", providers: [MenuService, MenuApi], viewQueries: [{ propertyName: "appSidebar", first: true, predicate: SidebarComponent, descendants: true }, { propertyName: "appTopBar", first: true, predicate: AppTopbar, descendants: true }], ngImport: i0, template: `
5611
5862
  <div class="layout-wrapper" [ngClass]="containerClass">
5612
5863
  <app-topbar></app-topbar>
5613
5864
  <app-sidebar></app-sidebar>
5614
5865
  <div class="layout-main-container">
5866
+ <default-secrets-banner />
5615
5867
  <div class="layout-main">
5616
5868
  <router-outlet></router-outlet>
5617
5869
  </div>
5618
- <app-footer></app-footer>
5870
+ @if (layoutService.footerVisible()) {
5871
+ <app-footer></app-footer>
5872
+ }
5619
5873
  </div>
5620
5874
  <div class="layout-mask animate-fadein"></div>
5621
5875
  </div>
5622
5876
  <!-- Outside the wrapper on purpose: the blocker marks the wrapper inert while it is visible. -->
5623
5877
  <block-loader />
5624
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AppTopbar, selector: "app-topbar" }, { kind: "component", type: SidebarComponent, selector: "app-sidebar" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$5.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: FooterComponent, selector: "app-footer" }, { kind: "component", type: BlockLoaderComponent, selector: "block-loader" }] }); }
5878
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AppTopbar, selector: "app-topbar" }, { kind: "component", type: SidebarComponent, selector: "app-sidebar" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$5.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: FooterComponent, selector: "app-footer" }, { kind: "component", type: BlockLoaderComponent, selector: "block-loader" }, { kind: "component", type: DefaultSecretsBannerComponent, selector: "default-secrets-banner" }] }); }
5625
5879
  }
5626
5880
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppLayoutComponent, decorators: [{
5627
5881
  type: Component,
5628
5882
  args: [{
5629
5883
  selector: 'app-layout',
5630
5884
  standalone: true,
5631
- imports: [CommonModule, AppTopbar, SidebarComponent, RouterModule, FooterComponent, BlockLoaderComponent],
5885
+ imports: [
5886
+ CommonModule,
5887
+ AppTopbar,
5888
+ SidebarComponent,
5889
+ RouterModule,
5890
+ FooterComponent,
5891
+ BlockLoaderComponent,
5892
+ DefaultSecretsBannerComponent
5893
+ ],
5632
5894
  template: `
5633
5895
  <div class="layout-wrapper" [ngClass]="containerClass">
5634
5896
  <app-topbar></app-topbar>
5635
5897
  <app-sidebar></app-sidebar>
5636
5898
  <div class="layout-main-container">
5899
+ <default-secrets-banner />
5637
5900
  <div class="layout-main">
5638
5901
  <router-outlet></router-outlet>
5639
5902
  </div>
5640
- <app-footer></app-footer>
5903
+ @if (layoutService.footerVisible()) {
5904
+ <app-footer></app-footer>
5905
+ }
5641
5906
  </div>
5642
5907
  <div class="layout-mask animate-fadein"></div>
5643
5908
  </div>
@@ -6115,7 +6380,6 @@ var error_component = /*#__PURE__*/Object.freeze({
6115
6380
  var profileComponent$1 = {
6116
6381
  changePhoto: "Upload Photo",
6117
6382
  successfullyUploaded: "Uploaded successfully",
6118
- failedToLoadPhoto: "Failed to load user photo",
6119
6383
  deletePhoto: "Delete Photo",
6120
6384
  deletePhotoConfirmHeader: "Delete Photo",
6121
6385
  deletePhotoConfirmMessage: "Are you sure you want to delete your photo?",
@@ -6131,7 +6395,6 @@ var en$7 = {
6131
6395
  var profileComponent = {
6132
6396
  changePhoto: "Загрузить фото",
6133
6397
  successfullyUploaded: "Загружено",
6134
- failedToLoadPhoto: "Не удалось загрузить фото пользователя",
6135
6398
  deletePhoto: "Удалить фото",
6136
6399
  deletePhotoConfirmHeader: "Удаление фото",
6137
6400
  deletePhotoConfirmMessage: "Вы уверены, что хотите удалить своё фото?",
@@ -10680,5 +10943,5 @@ function provideOipRoutes(options = {}) {
10680
10943
  * Generated bundle index. Do not edit.
10681
10944
  */
10682
10945
 
10683
- export { APP_INFO_TOKEN, APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AccessComponent, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppInfoService, AppLayoutComponent, AppModulesComponent, AppTopbar, AppTopbarApplicationSwitcherComponent, ApplicationRegistryService, ApplicationsApi, ApplicationsComponent, AuthGuardService, BaseModuleComponent, BffSecurityService, BlockLoaderComponent, ConfigComponent, ContentType, CustomElementExtensionModuleHostComponent, DbMigrationComponent, DiscussionComponent, ErrorComponent, ExtensionLoaderService, ExtensionModuleHostComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, ModuleInstanceRightsService, ModuleLoadingService, MsgService, NoModulesComponent, NotfoundComponent, NotificationApi, NotificationService, OIP_EXTENSION_EVENTS, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, StartPageService, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserProfileComponent, UserService, convertToPrimeNgDateFormat, defaultTheme, emitOipContextChange, emitOipError, emitOipNavigate, emitOipNotify, emitOipSettingsChange, emitOipTitleChange, langIntercept, mergeWithDefaults, moduleAccessGuard, oipAccessRoute, oipApplicationsRoute, oipAuthGuard, oipConfigRoute, oipDbMigrationRoute, oipDiscussionRoute, oipErrorRoute, oipExtensionsRoute, oipIframeModuleRoute, oipModulesRoute, oipNoModulesRoute, oipProfileRoute, oipStartRedirectGuard, oipStartRoute, provideAppInfo, provideAppThemes, provideLogoComponent, provideOip, provideOipRoutes, provideTranslations, replaceDefaults };
10946
+ export { APP_INFO_TOKEN, APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AccessComponent, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppInfoService, AppLayoutComponent, AppModulesComponent, AppTopbar, AppTopbarApplicationSwitcherComponent, ApplicationRegistryService, ApplicationsApi, ApplicationsComponent, AuthGuardService, BaseModuleComponent, BffSecurityService, BlockLoaderComponent, ConfigComponent, ContentType, CustomElementExtensionModuleHostComponent, DbMigrationComponent, DefaultSecretsBannerComponent, DiscussionComponent, ErrorComponent, ExtensionLoaderService, ExtensionModuleHostComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, ModuleInstanceRightsService, ModuleLoadingService, MsgService, NoModulesComponent, NotfoundComponent, NotificationApi, NotificationService, OIP_EXTENSION_EVENTS, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, StartPageService, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserProfileComponent, UserService, convertToPrimeNgDateFormat, defaultTheme, emitOipContextChange, emitOipError, emitOipNavigate, emitOipNotify, emitOipSettingsChange, emitOipTitleChange, langIntercept, mergeWithDefaults, moduleAccessGuard, oipAccessRoute, oipApplicationsRoute, oipAuthGuard, oipConfigRoute, oipDbMigrationRoute, oipDiscussionRoute, oipErrorRoute, oipExtensionsRoute, oipIframeModuleRoute, oipModulesRoute, oipNoModulesRoute, oipProfileRoute, oipStartRedirectGuard, oipStartRoute, provideAppInfo, provideAppThemes, provideLogoComponent, provideOip, provideOipRoutes, provideTranslations, replaceDefaults };
10684
10947
  //# sourceMappingURL=oip-common.mjs.map