@quadrel-enterprise-ui/framework 20.6.2 → 20.7.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.
@@ -3,7 +3,7 @@ import { inject, ElementRef, Directive, InjectionToken, HostBinding, Input, View
3
3
  import { Dialog, DialogRef, DialogModule } from '@angular/cdk/dialog';
4
4
  import * as i1 from '@angular/common';
5
5
  import { CommonModule, NgFor, NgIf, NgClass, NgTemplateOutlet, AsyncPipe } from '@angular/common';
6
- import { BehaviorSubject, pairwise, from, switchMap, map as map$1, Subject, throwError, of, ReplaySubject, merge, fromEvent, isObservable, NEVER, Observable, EMPTY, shareReplay, Subscription, distinctUntilChanged as distinctUntilChanged$1, debounce, timer, startWith as startWith$1, debounceTime as debounceTime$1, takeUntil as takeUntil$1, firstValueFrom, combineLatest, concat, take as take$1, delay, tap as tap$1, first, scan, queueScheduler, combineLatestWith, forkJoin, delayWhen, withLatestFrom, async, filter as filter$1 } from 'rxjs';
6
+ import { BehaviorSubject, pairwise, from, switchMap, map as map$1, Subject, throwError, of, ReplaySubject, merge, fromEvent, isObservable, NEVER, Observable, EMPTY, shareReplay, Subscription, distinctUntilChanged as distinctUntilChanged$1, debounce, timer, startWith as startWith$1, debounceTime as debounceTime$1, takeUntil as takeUntil$1, firstValueFrom, combineLatest, concat, take as take$1, delay, tap as tap$1, first, scan, queueScheduler, filter as filter$1, concatMap as concatMap$1, exhaustMap, finalize, combineLatestWith, forkJoin, delayWhen, withLatestFrom, async } from 'rxjs';
7
7
  import { map, takeUntil, take, filter, catchError, debounceTime, startWith, distinctUntilChanged, concatMap, tap, skip, observeOn, switchMap as switchMap$1, pairwise as pairwise$1, mergeMap, delay as delay$1 } from 'rxjs/operators';
8
8
  import { v4 } from 'uuid';
9
9
  import * as i3 from '@ngx-translate/core';
@@ -1161,6 +1161,7 @@ class QdConfirmationDialogOpenerService {
1161
1161
  open(component, config) {
1162
1162
  config.panelClass = 'qd-custom-panel';
1163
1163
  config.width = config.dialogSize || QdDialogSize.Default;
1164
+ config.disableClose = true;
1164
1165
  return this.dialog.open(component, config);
1165
1166
  }
1166
1167
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdConfirmationDialogOpenerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -1222,8 +1223,8 @@ class QdDialogService {
1222
1223
  open(component, config) {
1223
1224
  config.panelClass = 'qd-custom-panel';
1224
1225
  config.width = config.dialogSize || QdDialogSize.Default;
1226
+ config.disableClose = true;
1225
1227
  if (config.dialogSize === QdDialogSize.FullWidth) {
1226
- config.disableClose = true;
1227
1228
  config.maxWidth = '100vw';
1228
1229
  config.width = '100vw';
1229
1230
  config.maxHeight = '100vh';
@@ -1435,8 +1436,7 @@ class QdDialogComponent {
1435
1436
  this.dialogService.pageDialogCanClose$.pipe(takeUntil(this._destroyed$)).subscribe(entry => {
1436
1437
  this._pageDialogCanCloseFn = entry?.owner === this.dialogRef ? entry.fn : null;
1437
1438
  });
1438
- if (this.isFullWidth)
1439
- this.bindEscToClose();
1439
+ this.bindEscToClose();
1440
1440
  }
1441
1441
  ngAfterContentChecked() {
1442
1442
  const children = Array.from(this.body?.nativeElement?.children ?? []);
@@ -27203,18 +27203,24 @@ class QdFormGroupManagerService {
27203
27203
  const snapshot = this._formGroupsSnapshot.get(key);
27204
27204
  if (!snapshot)
27205
27205
  return;
27206
- Object.entries(fg.controls).forEach(([ctrlKey, ctrl]) => {
27207
- const newValue = snapshot[ctrlKey];
27208
- if (ctrl instanceof FormArray && Array.isArray(newValue)) {
27209
- this.resetFormArrayToValues(ctrl, newValue);
27210
- }
27211
- else {
27212
- ctrl.reset(newValue);
27213
- }
27214
- });
27206
+ this.restoreFormGroup(fg, snapshot);
27215
27207
  });
27216
27208
  this.cancelPendingAsyncValidation();
27217
27209
  }
27210
+ restoreFormGroup(fg, snapshot) {
27211
+ Object.entries(fg.controls).forEach(([ctrlKey, ctrl]) => {
27212
+ const newValue = snapshot[ctrlKey];
27213
+ if (ctrl instanceof FormArray && Array.isArray(newValue)) {
27214
+ this.resetFormArrayToValues(ctrl, newValue);
27215
+ }
27216
+ else if (ctrl instanceof FormGroup && newValue && typeof newValue === 'object') {
27217
+ this.restoreFormGroup(ctrl, newValue);
27218
+ }
27219
+ else {
27220
+ ctrl.reset(newValue);
27221
+ }
27222
+ });
27223
+ }
27218
27224
  /**
27219
27225
  * Cancels any in-flight async validators on all registered form groups.
27220
27226
  *
@@ -28581,6 +28587,121 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
28581
28587
  type: Output
28582
28588
  }] } });
28583
28589
 
28590
+ /**
28591
+ * Intercepts router navigation when unsaved form changes exist on a QdPage.
28592
+ *
28593
+ * Provided per `QdPageComponent`. Activated automatically when the page enters an editable state
28594
+ * (create pages or inspect pages in edit mode). Deactivated when the page returns to view mode.
28595
+ *
28596
+ * #### When navigation is intercepted
28597
+ *
28598
+ * - The user has unsaved form changes (tracked via `QdFormGroupManagerService`).
28599
+ * - A `NavigationStart` event occurs (browser back, shell back button, or programmatic navigation).
28600
+ *
28601
+ * The current navigation is cancelled, and a confirmation dialog is shown. The user can either
28602
+ * discard changes and proceed or cancel and stay on the page.
28603
+ *
28604
+ * #### When navigation is allowed
28605
+ *
28606
+ * - No unsaved changes exist — navigation proceeds silently.
28607
+ * - A framework action (Submit, SaveDraft) wraps its handler via `executeWithBypass()`.
28608
+ * - A confirmed discard sets `allowNextNavigation()` before the cancel handler navigates.
28609
+ * - The page switches to view mode via `deactivate()`.
28610
+ *
28611
+ * Custom actions defined by the application are not bypassed. If a custom action navigates away
28612
+ * while unsaved changes exist, the confirmation dialog is shown.
28613
+ */
28614
+ class QdPageNavigationInterceptorService {
28615
+ router = inject(Router);
28616
+ formGroupManager = inject(QdFormGroupManagerService);
28617
+ confirmationDialog = inject(QdConfirmationDialogOpenerService);
28618
+ _destroy$ = new Subject();
28619
+ _deactivate$ = new Subject();
28620
+ _bypassInterception = false;
28621
+ _allowedTargetUrls = new Set();
28622
+ _confirmationMessage;
28623
+ ngOnDestroy() {
28624
+ this._allowedTargetUrls.clear();
28625
+ this._destroy$.next();
28626
+ this._destroy$.complete();
28627
+ this._deactivate$.complete();
28628
+ }
28629
+ /**
28630
+ * Starts intercepting navigation events. Replaces any previously active listener.
28631
+ */
28632
+ activate(confirmationMessage) {
28633
+ this._confirmationMessage = confirmationMessage;
28634
+ this._deactivate$.next();
28635
+ this.listenForUnsavedNavigationAttempts();
28636
+ }
28637
+ /**
28638
+ * Stops intercepting and clears all pending URL bypasses.
28639
+ */
28640
+ deactivate() {
28641
+ this._deactivate$.next();
28642
+ this._allowedTargetUrls.clear();
28643
+ }
28644
+ /**
28645
+ * Whitelists the next navigation so it bypasses interception.
28646
+ * Without a URL, any next navigation is bypassed (wildcard). With a URL, only that
28647
+ * specific navigation is bypassed — non-matching navigations are still intercepted.
28648
+ */
28649
+ allowNextNavigation(targetUrl) {
28650
+ this._allowedTargetUrls.add(targetUrl ?? '*');
28651
+ }
28652
+ /**
28653
+ * Executes the callback with interception temporarily disabled.
28654
+ * The callback must navigate synchronously — async navigation after the callback returns
28655
+ * will not be bypassed. This works because Angular's router emits NavigationStart
28656
+ * synchronously within the navigateByUrl() / navigate() call.
28657
+ */
28658
+ executeWithBypass(fn) {
28659
+ this._bypassInterception = true;
28660
+ try {
28661
+ fn();
28662
+ }
28663
+ finally {
28664
+ this._bypassInterception = false;
28665
+ }
28666
+ }
28667
+ listenForUnsavedNavigationAttempts() {
28668
+ this.router.events
28669
+ .pipe(filter$1((event) => event instanceof NavigationStart), filter$1(() => !this._bypassInterception), filter$1(event => this.shouldIntercept(event)), concatMap$1(event => this.checkForPendingChanges(event)), filter$1(({ hasChanges }) => hasChanges), exhaustMap(({ event }) => this.cancelNavigationAndConfirm(event)), filter$1(({ confirmed }) => confirmed), takeUntil$1(this._deactivate$), takeUntil$1(this._destroy$))
28670
+ .subscribe(({ targetUrl }) => this.navigateToConfirmedTarget(targetUrl));
28671
+ }
28672
+ shouldIntercept(event) {
28673
+ if (this._allowedTargetUrls.has('*')) {
28674
+ this._allowedTargetUrls.clear();
28675
+ return false;
28676
+ }
28677
+ if (this._allowedTargetUrls.has(event.url)) {
28678
+ this._allowedTargetUrls.delete(event.url);
28679
+ return false;
28680
+ }
28681
+ return true;
28682
+ }
28683
+ checkForPendingChanges(event) {
28684
+ return this.formGroupManager.$hasValuesChanged().pipe(take$1(1), map$1(hasChanges => ({ event, hasChanges })));
28685
+ }
28686
+ cancelNavigationAndConfirm(event) {
28687
+ this._bypassInterception = true;
28688
+ void this.router.navigateByUrl(this.router.url, { skipLocationChange: true });
28689
+ return this.confirmationDialog
28690
+ .showCancelConfirmation({ cancel: { confirmationMessage: this._confirmationMessage } })
28691
+ .pipe(map$1(confirmed => ({ confirmed, targetUrl: event.url })), finalize(() => (this._bypassInterception = false)));
28692
+ }
28693
+ navigateToConfirmedTarget(targetUrl) {
28694
+ this._bypassInterception = false;
28695
+ this._allowedTargetUrls.add(targetUrl);
28696
+ void this.router.navigateByUrl(targetUrl);
28697
+ }
28698
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageNavigationInterceptorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
28699
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageNavigationInterceptorService });
28700
+ }
28701
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageNavigationInterceptorService, decorators: [{
28702
+ type: Injectable
28703
+ }] });
28704
+
28584
28705
  class QdPageSubmitActionService {
28585
28706
  footerService = inject(QdPageFooterService);
28586
28707
  formGroupManagerService = inject(QdFormGroupManagerService);
@@ -29042,6 +29163,7 @@ class QdPageComponent {
29042
29163
  dialog = inject(QdDialogService);
29043
29164
  bottomOffset$ = inject(QD_SAFE_BOTTOM_OFFSET, { optional: true });
29044
29165
  dialogRef = inject(DialogRef, { optional: true });
29166
+ navigationInterceptor = inject(QdPageNavigationInterceptorService);
29045
29167
  /**
29046
29168
  * This property defines the configuration for the QdPage component, including the page type,
29047
29169
  * title, and specific configurations for each type of page.
@@ -29109,8 +29231,10 @@ class QdPageComponent {
29109
29231
  ]);
29110
29232
  }
29111
29233
  ngAfterViewInit() {
29112
- if (this.config.pageType === 'create')
29234
+ if (this.config.pageType === 'create') {
29113
29235
  this.setupCreatePageFooterActions();
29236
+ this.navigationInterceptor.activate(this.config.pageTypeConfig?.cancel?.confirmationMessage);
29237
+ }
29114
29238
  if (this.config.pageType === 'create' && this.config?.pageTypeConfig?.cancel !== undefined)
29115
29239
  this.handleCancelActionWithFormChanges();
29116
29240
  if (this.config.pageType === 'create' && this.config?.pageTypeConfig?.saveDraft !== undefined)
@@ -29160,8 +29284,12 @@ class QdPageComponent {
29160
29284
  actionKey: 'cancel',
29161
29285
  partialAction: {
29162
29286
  handler: hasChanged
29163
- ? () => this.setupSubmitActionValidation()
29164
- : () => this.config?.pageTypeConfig?.cancel?.handler()
29287
+ ? () => this.setupCancelConfirmation()
29288
+ : () => {
29289
+ this.navigationInterceptor.executeWithBypass(() => {
29290
+ this.config?.pageTypeConfig?.cancel?.handler();
29291
+ });
29292
+ }
29165
29293
  }
29166
29294
  }
29167
29295
  ]);
@@ -29175,7 +29303,7 @@ class QdPageComponent {
29175
29303
  action: {
29176
29304
  titleI18n: pageTypeConfig.saveDraft?.label?.i18n ?? 'i18n.qd.page.footer.saveDraft',
29177
29305
  type: QdFooterActionType.Secondary,
29178
- handler: () => pageTypeConfig?.saveDraft?.handler(),
29306
+ handler: this.generateFooterActionHandler(pageTypeConfig?.saveDraft?.handler),
29179
29307
  isVisible: true,
29180
29308
  isDisabled: false
29181
29309
  }
@@ -29183,6 +29311,12 @@ class QdPageComponent {
29183
29311
  ]);
29184
29312
  }
29185
29313
  updateInspectPageOperationMode(pageTypeConfig, mode) {
29314
+ if (mode === 'edit') {
29315
+ this.navigationInterceptor.activate(pageTypeConfig?.cancel?.confirmationMessage);
29316
+ }
29317
+ else {
29318
+ this.navigationInterceptor.deactivate();
29319
+ }
29186
29320
  if (mode === 'view') {
29187
29321
  this.formGroupManagerService.cancelPendingAsyncValidation();
29188
29322
  setTimeout(() => this.formGroupManagerService.cancelPendingAsyncValidation());
@@ -29200,18 +29334,19 @@ class QdPageComponent {
29200
29334
  return (...args) => {
29201
29335
  if (!handler)
29202
29336
  return;
29203
- handler(this.formGroupManagerService.hasFormGroups() ? this.formGroupManagerService.getAllValues() : args);
29337
+ const values = this.formGroupManagerService.hasFormGroups() ? this.formGroupManagerService.getAllValues() : args;
29338
+ this.navigationInterceptor.executeWithBypass(() => handler(values));
29204
29339
  };
29205
29340
  }
29206
- setupSubmitActionValidation() {
29341
+ setupCancelConfirmation() {
29207
29342
  this.dialog
29208
29343
  .open(QdPageCancelConfirmationDialogComponent, {
29209
29344
  title: { i18n: 'i18n.qd.page.cancel.confirmation.dialog.title' },
29210
29345
  dialogSize: QdDialogSize.Small,
29211
29346
  data: this.config.pageTypeConfig
29212
29347
  })
29213
- .closed.pipe(takeUntil(this._destroyed$))
29214
- .subscribe();
29348
+ .closed.pipe(filter$1(result => !!result), takeUntil(this._destroyed$))
29349
+ .subscribe(() => this.navigationInterceptor.allowNextNavigation());
29215
29350
  }
29216
29351
  initSubmitValidation() {
29217
29352
  this._cancelSubmitValidation$.next();
@@ -29248,11 +29383,23 @@ class QdPageComponent {
29248
29383
  }))), this.dialogRef);
29249
29384
  }
29250
29385
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29251
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdPageComponent, isStandalone: false, selector: "qd-page", inputs: { config: "config", testId: ["data-test-id", "testId"] }, outputs: { operationModeChanged: "operationModeChanged" }, host: { properties: { "class.has-control-panel": "isControlPanelVisible", "class.control-panel-broad": "isControlPanelBroad", "class.has-footer": "this.footerVisible", "class.has-info-banners": "this.hasInfoBanners" } }, providers: [QdPageFooterService, QdFormGroupManagerService, QdPageSubmitActionService, QdResolverTriggerService], queries: [{ propertyName: "controlPanel", first: true, predicate: QdPageControlPanelComponent, descendants: true }, { propertyName: "stepperComponent", first: true, predicate: QdPageStepperComponent, descendants: true }, { propertyName: "tabsComponent", first: true, predicate: QdPageTabsComponent, descendants: true }, { propertyName: "stepperAdapterDirective", first: true, predicate: QdPageStepperAdapterDirective, descendants: true }, { propertyName: "tabsAdapterDirective", first: true, predicate: QdPageTabsAdapterDirective, descendants: true }, { propertyName: "sections", predicate: QdSectionComponent }, { propertyName: "infoBanners", predicate: QdPageInfoBannerComponent }], usesOnChanges: true, ngImport: i0, template: "<main qdSnackbarListener>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: QdProjectionGuardComponent, selector: "qd-projection-guard", inputs: ["isDisabled", "warningMessage"] }, { kind: "component", type: QdPageFooterComponent, selector: "qd-page-footer" }, { kind: "component", type: QdPageObjectHeaderComponent, selector: "qd-page-object-header", inputs: ["config", "hasNavigation", "data-test-id"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] });
29386
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdPageComponent, isStandalone: false, selector: "qd-page", inputs: { config: "config", testId: ["data-test-id", "testId"] }, outputs: { operationModeChanged: "operationModeChanged" }, host: { properties: { "class.has-control-panel": "isControlPanelVisible", "class.control-panel-broad": "isControlPanelBroad", "class.has-footer": "this.footerVisible", "class.has-info-banners": "this.hasInfoBanners" } }, providers: [
29387
+ QdPageFooterService,
29388
+ QdFormGroupManagerService,
29389
+ QdPageSubmitActionService,
29390
+ QdResolverTriggerService,
29391
+ QdPageNavigationInterceptorService
29392
+ ], queries: [{ propertyName: "controlPanel", first: true, predicate: QdPageControlPanelComponent, descendants: true }, { propertyName: "stepperComponent", first: true, predicate: QdPageStepperComponent, descendants: true }, { propertyName: "tabsComponent", first: true, predicate: QdPageTabsComponent, descendants: true }, { propertyName: "stepperAdapterDirective", first: true, predicate: QdPageStepperAdapterDirective, descendants: true }, { propertyName: "tabsAdapterDirective", first: true, predicate: QdPageTabsAdapterDirective, descendants: true }, { propertyName: "sections", predicate: QdSectionComponent }, { propertyName: "infoBanners", predicate: QdPageInfoBannerComponent }], usesOnChanges: true, ngImport: i0, template: "<main qdSnackbarListener>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: QdProjectionGuardComponent, selector: "qd-projection-guard", inputs: ["isDisabled", "warningMessage"] }, { kind: "component", type: QdPageFooterComponent, selector: "qd-page-footer" }, { kind: "component", type: QdPageObjectHeaderComponent, selector: "qd-page-object-header", inputs: ["config", "hasNavigation", "data-test-id"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] });
29252
29393
  }
29253
29394
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageComponent, decorators: [{
29254
29395
  type: Component,
29255
- args: [{ selector: 'qd-page', providers: [QdPageFooterService, QdFormGroupManagerService, QdPageSubmitActionService, QdResolverTriggerService], host: { '[class.has-control-panel]': 'isControlPanelVisible', '[class.control-panel-broad]': 'isControlPanelBroad' }, standalone: false, template: "<main qdSnackbarListener>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"] }]
29396
+ args: [{ selector: 'qd-page', providers: [
29397
+ QdPageFooterService,
29398
+ QdFormGroupManagerService,
29399
+ QdPageSubmitActionService,
29400
+ QdResolverTriggerService,
29401
+ QdPageNavigationInterceptorService
29402
+ ], host: { '[class.has-control-panel]': 'isControlPanelVisible', '[class.control-panel-broad]': 'isControlPanelBroad' }, standalone: false, template: "<main qdSnackbarListener>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"] }]
29256
29403
  }], ctorParameters: () => [], propDecorators: { config: [{
29257
29404
  type: Input,
29258
29405
  args: [{ required: true }]