@ardimedia/angular-portal-azure 0.3.25 → 0.3.28

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/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@ardimedia/angular-portal-azure",
3
- "version": "0.3.25",
3
+ "version": "0.3.28",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.1.0",
6
- "@angular/core": "^21.1.0"
6
+ "@angular/core": "^21.1.0",
7
+ "@angular/forms": "^21.1.0"
7
8
  },
8
9
  "dependencies": {
9
10
  "tslib": "^2.3.0"
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { WritableSignal, Type, EnvironmentProviders } from '@angular/core';
2
+ import { WritableSignal, Type, EnvironmentProviders, InjectionToken, AfterContentInit, OnDestroy } from '@angular/core';
3
3
  import * as _ardimedia_angular_portal_azure from '@ardimedia/angular-portal-azure';
4
4
 
5
5
  /**
@@ -117,6 +117,7 @@ interface PortalLabels {
117
117
  settings: string;
118
118
  language: string;
119
119
  appearance: string;
120
+ unsavedChangesConfirm: string;
120
121
  }
121
122
  /** Language preset definition for the built-in language registry. */
122
123
  interface LanguagePreset {
@@ -186,6 +187,7 @@ interface BladeDataLifecycle<T> {
186
187
  onExecuted?: () => void;
187
188
  onExecuteError?: (ex: ApiException) => void;
188
189
  isFormValid?: () => boolean;
190
+ isDirty?: () => boolean;
189
191
  }
190
192
  /**
191
193
  * Extended blade definition for data-driven blades with CRUD operations.
@@ -374,10 +376,16 @@ declare function createPanorama(title: string): PanoramaDefinition;
374
376
  interface AvatarMenuItem {
375
377
  /** Display text */
376
378
  label: string;
377
- /** Navigation URL */
379
+ /** Navigation URL. Used when {@link action} is not set; ignored otherwise (use '#'). */
378
380
  href: string;
379
381
  /** Optional icon CSS class, e.g. 'ti ti-settings' */
380
382
  icon?: string;
383
+ /**
384
+ * Optional click handler. When set, the item performs this action instead of navigating to
385
+ * {@link href} (e.g. open a blade). The dropdown closes and the default link navigation is
386
+ * prevented.
387
+ */
388
+ action?: () => void;
381
389
  }
382
390
  /**
383
391
  * Avatar menu definition for the user menu in the portal header.
@@ -510,6 +518,31 @@ declare class PortalService {
510
518
  declare class BladeService {
511
519
  private readonly portal;
512
520
  private readonly registry;
521
+ /**
522
+ * Unsaved-changes guard registry: blade path -> predicate returning true when the blade has
523
+ * unsaved edits. Populated by apa-blade-detail (from the projected NgForm). Consulted before a
524
+ * blade is closed/replaced or the page is left, so the user can confirm discarding changes.
525
+ * Message can be localised via PortalLabels.unsavedChangesConfirm; the navigation flow is
526
+ * synchronous, so a synchronous window.confirm is used.
527
+ */
528
+ private readonly dirtyChecks;
529
+ /** Optional override for the confirmation message (defaults to the de-CH label). */
530
+ unsavedChangesMessage: string;
531
+ constructor();
532
+ /** Register a blade's unsaved-changes predicate (called by apa-blade-detail). */
533
+ registerDirtyCheck(path: string, isDirty: () => boolean): void;
534
+ /** Remove a blade's unsaved-changes predicate (called when the detail is destroyed). */
535
+ unregisterDirtyCheck(path: string): void;
536
+ private isPathDirty;
537
+ private anyDirty;
538
+ /**
539
+ * Returns true if it's OK to proceed with removing the given blade paths: none of them is dirty,
540
+ * or the user confirmed discarding the changes. Shows one confirmation regardless of how many
541
+ * dirty blades are affected.
542
+ */
543
+ private mayDiscard;
544
+ /** Drop dirty-check entries for paths that are no longer open. */
545
+ private pruneDirtyChecks;
513
546
  /**
514
547
  * Set the first blade (e.g., when opening a top-level item from a tile).
515
548
  * Clears all existing blades, hides panorama, and adds the new blade.
@@ -540,14 +573,14 @@ declare class BladeService {
540
573
  *
541
574
  * Ported from AreaBlades.clearPath() in v0.2.346.
542
575
  */
543
- clearPath(path: string): void;
576
+ clearPath(path: string): boolean;
544
577
  /**
545
578
  * Remove all blades AFTER a given path (keeps the blade itself).
546
579
  * Used for cascade close when a blade opens a child.
547
580
  *
548
581
  * Ported from AreaBlades.clearChild() in v0.2.346.
549
582
  */
550
- clearChild(path: string): void;
583
+ clearChild(path: string): boolean;
551
584
  /**
552
585
  * Remove blades at and beyond a specific 1-based level.
553
586
  * Ported from AreaBlades.clearLevel() in v0.2.346.
@@ -646,6 +679,7 @@ declare class BladeRouterService {
646
679
  private readonly portal;
647
680
  private readonly registry;
648
681
  private readonly destroyRef;
682
+ private readonly config;
649
683
  private _syncingFromUrl;
650
684
  private _initialRestoreDone;
651
685
  constructor();
@@ -688,6 +722,12 @@ declare class BladeRouterService {
688
722
  private extractLegacyBladesParam;
689
723
  /** Handle legacy ?blades= URL by redirecting to new path format */
690
724
  private handleLegacyUrl;
725
+ /**
726
+ * Return the effective route prefix. If a prefix was configured via
727
+ * `provideBladeRouter({ prefix })`, use it (including empty string).
728
+ * Otherwise fall back to dynamically reading the first URL segment.
729
+ */
730
+ private getEffectivePrefix;
691
731
  static ɵfac: i0.ɵɵFactoryDeclaration<BladeRouterService, never>;
692
732
  static ɵprov: i0.ɵɵInjectableDeclaration<BladeRouterService>;
693
733
  }
@@ -712,6 +752,19 @@ declare class BladeRouterService {
712
752
  */
713
753
  declare function providePortalAzure(config: PortalConfig): EnvironmentProviders;
714
754
 
755
+ /** Configuration for `provideBladeRouter()`. */
756
+ interface BladeRouterConfig {
757
+ /**
758
+ * Fixed URL prefix for blade path segments.
759
+ *
760
+ * - When omitted, the prefix is read dynamically from the first URL segment (default).
761
+ * - When set to a non-empty string (e.g. `'app'`), that string is used as the fixed prefix.
762
+ * - When set to `''` (empty string), blade paths are encoded directly at the URL root with no prefix.
763
+ */
764
+ prefix?: string;
765
+ }
766
+ /** @internal */
767
+ declare const BLADE_ROUTER_CONFIG: InjectionToken<BladeRouterConfig>;
715
768
  /**
716
769
  * Enables opt-in URL synchronization for the blade stack.
717
770
  *
@@ -726,12 +779,15 @@ declare function providePortalAzure(config: PortalConfig): EnvironmentProviders;
726
779
  * };
727
780
  * ```
728
781
  *
729
- * When enabled, blade paths sync to the URL as a query parameter:
730
- * `?blades=customers,customers/list,customers/1`
782
+ * Optionally pass a config to set a fixed route prefix:
783
+ * ```typescript
784
+ * provideBladeRouter({ prefix: 'app' }) // → /app/customers/list
785
+ * provideBladeRouter({ prefix: '' }) // → /customers/list (no prefix)
786
+ * ```
731
787
  *
732
788
  * Without this provider, blade navigation remains purely in-memory.
733
789
  */
734
- declare function provideBladeRouter(): EnvironmentProviders;
790
+ declare function provideBladeRouter(config?: BladeRouterConfig): EnvironmentProviders;
735
791
 
736
792
  /**
737
793
  * Individual dashboard tile.
@@ -809,6 +865,11 @@ declare class PortalLayoutComponent {
809
865
  code: string;
810
866
  displayName: string;
811
867
  }[];
868
+ /**
869
+ * Handle an avatar dropdown item click. If the item defines an action (e.g. open a blade), run it
870
+ * and suppress the default link navigation; otherwise let the href navigate normally.
871
+ */
872
+ protected onAvatarItemClick(item: AvatarMenuItem, event: Event): void;
812
873
  constructor();
813
874
  protected toggleDarkMode(): void;
814
875
  protected switchLanguage(code: string): void;
@@ -878,15 +939,21 @@ declare class BladeComponent {
878
939
  *
879
940
  * Usage:
880
941
  * ```html
942
+ * <!-- Default: each component is wrapped in <apa-blade> -->
881
943
  * <apa-blade-host />
944
+ *
945
+ * <!-- No wrapper: components render directly (they manage their own blade chrome) -->
946
+ * <apa-blade-host [wrapBlade]="false" />
882
947
  * ```
883
948
  */
884
949
  declare class BladeHostComponent {
950
+ /** Whether to wrap each component in an `<apa-blade>` element. Default: true. */
951
+ readonly wrapBlade: i0.InputSignal<boolean>;
885
952
  protected readonly portal: PortalService;
886
953
  private readonly registry;
887
954
  getComponent(path: string): i0.Type<unknown> | null;
888
955
  static ɵfac: i0.ɵɵFactoryDeclaration<BladeHostComponent, never>;
889
- static ɵcmp: i0.ɵɵComponentDeclaration<BladeHostComponent, "apa-blade-host", never, {}, {}, never, never, true, never>;
956
+ static ɵcmp: i0.ɵɵComponentDeclaration<BladeHostComponent, "apa-blade-host", never, { "wrapBlade": { "alias": "wrapBlade"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
890
957
  }
891
958
 
892
959
  /**
@@ -973,10 +1040,15 @@ declare class BladeGridComponent {
973
1040
  * </apa-blade>
974
1041
  * ```
975
1042
  */
976
- declare class BladeDetailComponent {
1043
+ declare class BladeDetailComponent implements AfterContentInit, OnDestroy {
977
1044
  readonly blade: i0.InputSignal<BladeDataDefinition<any>>;
1045
+ private readonly bladeService;
1046
+ /** The template-driven form projected into this detail, if any (auto-discovered). */
1047
+ private readonly form;
1048
+ ngAfterContentInit(): void;
1049
+ ngOnDestroy(): void;
978
1050
  static ɵfac: i0.ɵɵFactoryDeclaration<BladeDetailComponent, never>;
979
- static ɵcmp: i0.ɵɵComponentDeclaration<BladeDetailComponent, "apa-blade-detail", never, { "blade": { "alias": "blade"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
1051
+ static ɵcmp: i0.ɵɵComponentDeclaration<BladeDetailComponent, "apa-blade-detail", never, { "blade": { "alias": "blade"; "required": true; "isSignal": true; }; }, {}, ["form"], ["*"], true, never>;
980
1052
  }
981
1053
  /**
982
1054
  * Create standard detail blade commands (new, save, delete, cancel).
@@ -1057,5 +1129,5 @@ declare class SidebarComponent {
1057
1129
  static ɵcmp: i0.ɵɵComponentDeclaration<SidebarComponent, "apa-sidebar", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "collapsedWidth": { "alias": "collapsedWidth"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1058
1130
  }
1059
1131
 
1060
- export { AvatarMenuComponent, BladeComponent, BladeDetailComponent, BladeGridComponent, BladeHostComponent, BladeNavComponent, BladeRegistry, BladeRouterService, BladeService, CommandBarComponent, DEFAULT_LABELS, LABELS_DE_CH, LABELS_DE_DE, LABELS_EN, LABELS_ES, LABELS_FR, LABELS_IT, LANGUAGE_PRESETS, NotificationPanelComponent, PanoramaComponent, PortalLayoutComponent, PortalService, SidebarComponent, TILE_DIMENSIONS, TileComponent, TileSize, clearStatusBar, createAvatarMenu, createBlade, createCommand, createDataBlade, createDetailCommands, createNavItem, createNotificationPanel, createPanorama, createTile, executeDeleteItem, executeLoadItem, executeLoadItems, executeSaveItem, filterItems, getUserDisplayName, layoutTiles, nextBladeUid, provideBladeRouter, providePortalAzure, registerLanguagePreset, statusBarError, statusBarInfo, statusBarSuccess };
1061
- export type { AddBladeEventArgs, ApiException, AvatarMenuDefinition, AvatarMenuItem, BladeCommand, BladeDataDefinition, BladeDataLifecycle, BladeDefinition, BladeNavItem, BladeParameter, BladeRegistryEntry, LanguagePreset, NotificationDefinition, NotificationLifecycle, PanoramaDefinition, PortalConfig, PortalLabels, PositionedTile, StandardCommandKey, StatusBarState, StatusBarStyle, TileDefinition, UserAccount };
1132
+ export { AvatarMenuComponent, BLADE_ROUTER_CONFIG, BladeComponent, BladeDetailComponent, BladeGridComponent, BladeHostComponent, BladeNavComponent, BladeRegistry, BladeRouterService, BladeService, CommandBarComponent, DEFAULT_LABELS, LABELS_DE_CH, LABELS_DE_DE, LABELS_EN, LABELS_ES, LABELS_FR, LABELS_IT, LANGUAGE_PRESETS, NotificationPanelComponent, PanoramaComponent, PortalLayoutComponent, PortalService, SidebarComponent, TILE_DIMENSIONS, TileComponent, TileSize, clearStatusBar, createAvatarMenu, createBlade, createCommand, createDataBlade, createDetailCommands, createNavItem, createNotificationPanel, createPanorama, createTile, executeDeleteItem, executeLoadItem, executeLoadItems, executeSaveItem, filterItems, getUserDisplayName, layoutTiles, nextBladeUid, provideBladeRouter, providePortalAzure, registerLanguagePreset, statusBarError, statusBarInfo, statusBarSuccess };
1133
+ export type { AddBladeEventArgs, ApiException, AvatarMenuDefinition, AvatarMenuItem, BladeCommand, BladeDataDefinition, BladeDataLifecycle, BladeDefinition, BladeNavItem, BladeParameter, BladeRegistryEntry, BladeRouterConfig, LanguagePreset, NotificationDefinition, NotificationLifecycle, PanoramaDefinition, PortalConfig, PortalLabels, PositionedTile, StandardCommandKey, StatusBarState, StatusBarStyle, TileDefinition, UserAccount };