@ecodev/natural 42.4.0 → 43.0.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.
Files changed (28) hide show
  1. package/esm2020/lib/classes/query-variable-manager.mjs +2 -2
  2. package/esm2020/lib/classes/rxjs.mjs +2 -1
  3. package/esm2020/lib/modules/columns-picker/columns-picker-column.directive.mjs +6 -2
  4. package/esm2020/lib/modules/common/directives/linkable-tab.directive.mjs +2 -2
  5. package/esm2020/lib/modules/logger/error-handler.mjs +26 -11
  6. package/esm2020/lib/modules/logger/public-api.mjs +3 -3
  7. package/esm2020/lib/modules/relations/relations.component.mjs +9 -4
  8. package/esm2020/lib/modules/search/dropdown-container/dropdown-container.component.mjs +3 -3
  9. package/esm2020/lib/modules/search/dropdown-container/dropdown.service.mjs +1 -1
  10. package/esm2020/lib/modules/search/input/input.component.mjs +3 -1
  11. package/esm2020/lib/modules/sidenav/sidenav-container/sidenav-container.component.mjs +4 -5
  12. package/esm2020/lib/modules/table-button/table-button.component.mjs +21 -6
  13. package/esm2020/lib/services/abstract-model.service.mjs +45 -39
  14. package/fesm2015/ecodev-natural.mjs +112 -63
  15. package/fesm2015/ecodev-natural.mjs.map +1 -1
  16. package/fesm2020/ecodev-natural.mjs +109 -62
  17. package/fesm2020/ecodev-natural.mjs.map +1 -1
  18. package/lib/modules/columns-picker/columns-picker-column.directive.d.ts +1 -1
  19. package/lib/modules/logger/error-handler.d.ts +19 -3
  20. package/lib/modules/logger/public-api.d.ts +2 -2
  21. package/lib/modules/relations/relations.component.d.ts +1 -0
  22. package/lib/modules/search/dropdown-container/dropdown-container.component.d.ts +1 -1
  23. package/lib/modules/search/dropdown-container/dropdown.service.d.ts +1 -1
  24. package/lib/modules/search/input/input.component.d.ts +2 -2
  25. package/lib/modules/sidenav/sidenav-container/sidenav-container.component.d.ts +2 -3
  26. package/lib/modules/table-button/table-button.component.d.ts +9 -6
  27. package/lib/services/abstract-model.service.d.ts +2 -2
  28. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import '@angular/localize/init';
2
2
  import * as i0 from '@angular/core';
3
3
  import { Directive, Component, Inject, Injectable, HostBinding, HostListener, InjectionToken, Input, NgModule, EventEmitter, ChangeDetectionStrategy, Output, ContentChildren, Pipe, TemplateRef, ViewEncapsulation, ViewChild, Injector, Optional, Self, ContentChild, PLATFORM_ID, ErrorHandler } from '@angular/core';
4
- import { Subject, BehaviorSubject, of, timer, EMPTY, Observable, ReplaySubject, forkJoin, merge as merge$1, asyncScheduler, catchError } from 'rxjs';
4
+ import { Subject, BehaviorSubject, of, timer, EMPTY, Observable, first as first$1, combineLatest, ReplaySubject, forkJoin, merge as merge$1, asyncScheduler, catchError } from 'rxjs';
5
5
  import * as i5 from '@angular/forms';
6
6
  import { FormGroup, FormArray, Validators, FormControl, FormsModule, FormControlDirective, FormControlName, ReactiveFormsModule } from '@angular/forms';
7
7
  import * as i2$1 from '@angular/router';
@@ -525,7 +525,7 @@ class NaturalQueryVariablesManager {
525
525
  */
526
526
  updateVariables() {
527
527
  const merged = {};
528
- this.channels.forEach((channelVariables) => {
528
+ this.channels.forEach(channelVariables => {
529
529
  if (channelVariables.filter) {
530
530
  // Merge filter's groups first
531
531
  const groups = this.mergeGroupList(merged.filter && merged.filter.groups ? merged.filter.groups : [], channelVariables.filter.groups || []);
@@ -3560,6 +3560,7 @@ function cancellableTimeout(canceller, milliSeconds = 0) {
3560
3560
  */
3561
3561
  function debug(debugName) {
3562
3562
  return tap({
3563
+ subscribe: () => console.log('SUBSCRIBE', debugName),
3563
3564
  next: value => console.log('NEXT', debugName, value),
3564
3565
  error: error => console.log('ERROR', debugName, error),
3565
3566
  complete: () => console.log('COMPLETE', debugName),
@@ -3677,13 +3678,15 @@ class NaturalAbstractModelService {
3677
3678
  getOne(id) {
3678
3679
  this.throwIfObservable(id);
3679
3680
  this.throwIfNotQuery(this.oneQuery);
3680
- const queryRef = this.apollo.watchQuery({
3681
- query: this.oneQuery,
3682
- variables: this.getVariablesForOne(id),
3683
- fetchPolicy: 'cache-and-network',
3684
- nextFetchPolicy: 'cache-only',
3685
- });
3686
- return queryRef.valueChanges.pipe(filter(result => !!result.data), takeWhile(result => result.networkStatus !== NetworkStatus.ready, true), map(result => result.data[this.name]));
3681
+ return this.getVariablesForOne(id).pipe(switchMap(variables => {
3682
+ this.throwIfNotQuery(this.oneQuery);
3683
+ return this.apollo.watchQuery({
3684
+ query: this.oneQuery,
3685
+ variables: variables,
3686
+ fetchPolicy: 'cache-and-network',
3687
+ nextFetchPolicy: 'cache-only',
3688
+ }).valueChanges;
3689
+ }), filter(result => !!result.data), takeWhile(result => result.networkStatus !== NetworkStatus.ready, true), map(result => result.data[this.name]));
3687
3690
  }
3688
3691
  /**
3689
3692
  * Get a collection of objects
@@ -3693,16 +3696,17 @@ class NaturalAbstractModelService {
3693
3696
  */
3694
3697
  getAll(queryVariablesManager) {
3695
3698
  this.throwIfNotQuery(this.allQuery);
3696
- // Copy manager to prevent to apply internal variables to external QueryVariablesManager
3697
- const manager = new NaturalQueryVariablesManager(queryVariablesManager);
3698
- manager.merge('partial-variables', this.getPartialVariablesForAll());
3699
- return this.apollo
3700
- .query({
3701
- query: this.allQuery,
3702
- variables: manager.variables.value,
3703
- fetchPolicy: 'network-only',
3704
- })
3705
- .pipe(this.mapAll());
3699
+ return this.getPartialVariablesForAll().pipe(first$1(), switchMap(partialVariables => {
3700
+ this.throwIfNotQuery(this.allQuery);
3701
+ // Copy manager to prevent to apply internal variables to external QueryVariablesManager
3702
+ const manager = new NaturalQueryVariablesManager(queryVariablesManager);
3703
+ manager.merge('partial-variables', partialVariables);
3704
+ return this.apollo.query({
3705
+ query: this.allQuery,
3706
+ variables: manager.variables.value,
3707
+ fetchPolicy: 'network-only',
3708
+ });
3709
+ }), this.mapAll());
3706
3710
  }
3707
3711
  /**
3708
3712
  * Get a collection of objects
@@ -3716,16 +3720,19 @@ class NaturalAbstractModelService {
3716
3720
  */
3717
3721
  watchAll(queryVariablesManager, fetchPolicy = 'cache-and-network') {
3718
3722
  this.throwIfNotQuery(this.allQuery);
3719
- return queryVariablesManager.variables.pipe(
3720
- // Ignore very fast variable changes
3721
- debounceTime(20),
3722
- // Wait for variables to be defined to prevent duplicate query: with and without variables
3723
- // Null is accepted value for "no variables"
3724
- filter(variables => typeof variables !== 'undefined'), switchMap(() => {
3723
+ return combineLatest({
3724
+ variables: queryVariablesManager.variables.pipe(
3725
+ // Ignore very fast variable changes
3726
+ debounceTime(20),
3727
+ // Wait for variables to be defined to prevent duplicate query: with and without variables
3728
+ // Null is accepted value for "no variables"
3729
+ filter(variables => typeof variables !== 'undefined')),
3730
+ partialVariables: this.getPartialVariablesForAll(),
3731
+ }).pipe(switchMap(result => {
3725
3732
  // Apply partial variables from service
3726
3733
  // Copy manager to prevent to apply internal variables to external QueryVariablesManager
3727
3734
  const manager = new NaturalQueryVariablesManager(queryVariablesManager);
3728
- manager.merge('partial-variables', this.getPartialVariablesForAll());
3735
+ manager.merge('partial-variables', result.partialVariables);
3729
3736
  this.throwIfNotQuery(this.allQuery);
3730
3737
  return this.apollo
3731
3738
  .watchQuery({
@@ -3942,22 +3949,22 @@ class NaturalAbstractModelService {
3942
3949
  const plural = makePlural(this.name);
3943
3950
  const queryName = 'Count' + upperCaseFirstLetter(plural);
3944
3951
  const filterType = upperCaseFirstLetter(this.name) + 'Filter';
3945
- // Copy manager to prevent to apply internal variables to external QueryVariablesManager
3946
- const manager = new NaturalQueryVariablesManager(queryVariablesManager);
3947
- manager.merge('partial-variables', this.getPartialVariablesForAll());
3948
3952
  const query = gql `
3949
3953
  query ${queryName} ($filter: ${filterType}) {
3950
3954
  count: ${plural} (filter: $filter, pagination: {pageSize: 0, pageIndex: 0}) {
3951
3955
  length
3952
3956
  }
3953
3957
  }`;
3954
- return this.apollo
3955
- .query({
3956
- query: query,
3957
- variables: manager.variables.value,
3958
- fetchPolicy: 'network-only',
3959
- })
3960
- .pipe(map(result => result.data.count.length));
3958
+ return this.getPartialVariablesForAll().pipe(switchMap(partialVariables => {
3959
+ // Copy manager to prevent to apply internal variables to external QueryVariablesManager
3960
+ const manager = new NaturalQueryVariablesManager(queryVariablesManager);
3961
+ manager.merge('partial-variables', partialVariables);
3962
+ return this.apollo.query({
3963
+ query: query,
3964
+ variables: manager.variables.value,
3965
+ fetchPolicy: 'network-only',
3966
+ });
3967
+ }), map(result => result.data.count.length));
3961
3968
  }
3962
3969
  /**
3963
3970
  * Return empty object with some default values from server perspective
@@ -4009,7 +4016,7 @@ class NaturalAbstractModelService {
4009
4016
  * This is typically a site or state ID, and is needed to get appropriate access rights
4010
4017
  */
4011
4018
  getPartialVariablesForOne() {
4012
- return {};
4019
+ return of({});
4013
4020
  }
4014
4021
  /**
4015
4022
  * Returns additional variables to be used when getting multiple objects
@@ -4017,7 +4024,7 @@ class NaturalAbstractModelService {
4017
4024
  * This is typically a site or state ID, but it could be something else to further filter the query
4018
4025
  */
4019
4026
  getPartialVariablesForAll() {
4020
- return {};
4027
+ return of({});
4021
4028
  }
4022
4029
  /**
4023
4030
  * Returns additional variables to be used when creating an object
@@ -4055,7 +4062,7 @@ class NaturalAbstractModelService {
4055
4062
  * Merge given ID with additional partial variables if there is any
4056
4063
  */
4057
4064
  getVariablesForOne(id) {
4058
- return merge({}, { id: id }, this.getPartialVariablesForOne());
4065
+ return this.getPartialVariablesForOne().pipe(map(partialVariables => merge({}, { id: id }, partialVariables)));
4059
4066
  }
4060
4067
  /**
4061
4068
  * Throw exception to prevent executing null queries
@@ -4355,6 +4362,10 @@ class NaturalColumnsPickerColumnDirective {
4355
4362
  * Initial visibility state
4356
4363
  */
4357
4364
  this.hidden = false;
4365
+ /**
4366
+ * Localized label of column, if absent default to key
4367
+ */
4368
+ this.label = '';
4358
4369
  }
4359
4370
  /**
4360
4371
  * This must be the column key as defined in matColumnDef
@@ -4367,7 +4378,8 @@ class NaturalColumnsPickerColumnDirective {
4367
4378
  this.label = this.key;
4368
4379
  }
4369
4380
  ngAfterViewInit() {
4370
- this.label = this.elementRef.nativeElement.textContent;
4381
+ var _a;
4382
+ this.label = (_a = this.elementRef.nativeElement.textContent) !== null && _a !== void 0 ? _a : '';
4371
4383
  }
4372
4384
  }
4373
4385
  NaturalColumnsPickerColumnDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalColumnsPickerColumnDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
@@ -4704,7 +4716,7 @@ class NaturalLinkableTabDirective extends NaturalAbstractController {
4704
4716
  }
4705
4717
  });
4706
4718
  // When mat-tab-groups selected tab change, update url
4707
- this.component.selectedTabChange.pipe(takeUntil(this.ngUnsubscribe)).subscribe((event) => {
4719
+ this.component.selectedTabChange.pipe(takeUntil(this.ngUnsubscribe)).subscribe(event => {
4708
4720
  const activatedTabName = getTabId(event.tab);
4709
4721
  const segments = this.route.snapshot.url;
4710
4722
  if (!segments.length) {
@@ -5211,10 +5223,10 @@ class NaturalDropdownContainerComponent extends BasePortalOutlet {
5211
5223
  }
5212
5224
  }
5213
5225
  NaturalDropdownContainerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalDropdownContainerComponent, deps: [{ token: i0.ElementRef }, { token: i1$6.ConfigurableFocusTrapFactory }, { token: NATURAL_DROPDOWN_CONTAINER_DATA }], target: i0.ɵɵFactoryTarget.Component });
5214
- NaturalDropdownContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.0", type: NaturalDropdownContainerComponent, selector: "ng-component", viewQueries: [{ propertyName: "portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }, { propertyName: "templateRef", first: true, predicate: TemplateRef, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div\n (@transformMenu.done)=\"onAnimationDone($event)\"\n [@transformMenu]=\"panelAnimationState\"\n class=\"natural-dropdown-container mat-elevation-z2\"\n role=\"menu\"\n tabindex=\"-1\"\n>\n <div class=\"natural-dropdown-container-content\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n\n <div *ngIf=\"data.showValidateButton\" class=\"natural-dropdown-validate-button\">\n <button (click)=\"close()\" color=\"primary\" mat-raised-button>Valider</button>\n </div>\n</div>\n", styles: [".natural-dropdown-container{display:flex;flex-direction:column;border-radius:2px;height:100%}.natural-dropdown-container-content{flex:1;padding:5px;overflow:auto}.natural-dropdown-container .natural-dropdown-validate-button{flex:none;display:flex;flex-direction:row;justify-content:flex-end;margin:5px}\n"], components: [{ type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [naturalDropdownAnimations.transformMenu, naturalDropdownAnimations.fadeInItems], encapsulation: i0.ViewEncapsulation.None });
5226
+ NaturalDropdownContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.0", type: NaturalDropdownContainerComponent, selector: "ng-component", viewQueries: [{ propertyName: "portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }, { propertyName: "templateRef", first: true, predicate: TemplateRef, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div\n (@transformMenu.done)=\"onAnimationDone($event)\"\n [@transformMenu]=\"panelAnimationState\"\n class=\"natural-dropdown-container mat-elevation-z2\"\n role=\"menu\"\n tabindex=\"-1\"\n>\n <div class=\"natural-dropdown-container-content\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n\n <div *ngIf=\"data.showValidateButton\" class=\"natural-dropdown-validate-button\">\n <button (click)=\"close()\" color=\"primary\" mat-raised-button i18n>Valider</button>\n </div>\n</div>\n", styles: [".natural-dropdown-container{display:flex;flex-direction:column;border-radius:2px;height:100%}.natural-dropdown-container-content{flex:1;padding:5px;overflow:auto}.natural-dropdown-container .natural-dropdown-validate-button{flex:none;display:flex;flex-direction:row;justify-content:flex-end;margin:5px}\n"], components: [{ type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [naturalDropdownAnimations.transformMenu, naturalDropdownAnimations.fadeInItems], encapsulation: i0.ViewEncapsulation.None });
5215
5227
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalDropdownContainerComponent, decorators: [{
5216
5228
  type: Component,
5217
- args: [{ encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, animations: [naturalDropdownAnimations.transformMenu, naturalDropdownAnimations.fadeInItems], template: "<div\n (@transformMenu.done)=\"onAnimationDone($event)\"\n [@transformMenu]=\"panelAnimationState\"\n class=\"natural-dropdown-container mat-elevation-z2\"\n role=\"menu\"\n tabindex=\"-1\"\n>\n <div class=\"natural-dropdown-container-content\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n\n <div *ngIf=\"data.showValidateButton\" class=\"natural-dropdown-validate-button\">\n <button (click)=\"close()\" color=\"primary\" mat-raised-button>Valider</button>\n </div>\n</div>\n", styles: [".natural-dropdown-container{display:flex;flex-direction:column;border-radius:2px;height:100%}.natural-dropdown-container-content{flex:1;padding:5px;overflow:auto}.natural-dropdown-container .natural-dropdown-validate-button{flex:none;display:flex;flex-direction:row;justify-content:flex-end;margin:5px}\n"] }]
5229
+ args: [{ encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, animations: [naturalDropdownAnimations.transformMenu, naturalDropdownAnimations.fadeInItems], template: "<div\n (@transformMenu.done)=\"onAnimationDone($event)\"\n [@transformMenu]=\"panelAnimationState\"\n class=\"natural-dropdown-container mat-elevation-z2\"\n role=\"menu\"\n tabindex=\"-1\"\n>\n <div class=\"natural-dropdown-container-content\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n\n <div *ngIf=\"data.showValidateButton\" class=\"natural-dropdown-validate-button\">\n <button (click)=\"close()\" color=\"primary\" mat-raised-button i18n>Valider</button>\n </div>\n</div>\n", styles: [".natural-dropdown-container{display:flex;flex-direction:column;border-radius:2px;height:100%}.natural-dropdown-container-content{flex:1;padding:5px;overflow:auto}.natural-dropdown-container .natural-dropdown-validate-button{flex:none;display:flex;flex-direction:row;justify-content:flex-end;margin:5px}\n"] }]
5218
5230
  }], ctorParameters: function () {
5219
5231
  return [{ type: i0.ElementRef }, { type: i1$6.ConfigurableFocusTrapFactory }, { type: undefined, decorators: [{
5220
5232
  type: Inject,
@@ -6672,6 +6684,8 @@ class NaturalInputComponent {
6672
6684
  configuration: facet.configuration,
6673
6685
  };
6674
6686
  const injector = Injector.create({ providers: this.createProviders(data), parent: this.injector });
6687
+ // TODO replace by this when https://github.com/angular/angular/commit/d1e83e1b30f2cea9f2ed16bff2d3b969335072ab is released
6688
+ // this.dropdownComponentRef = createComponent(facet.component, {environmentInjector: injector});
6675
6689
  const factory = this.componentFactoryResolver.resolveComponentFactory(facet.component);
6676
6690
  this.dropdownComponentRef = factory.create(injector);
6677
6691
  return this.dropdownComponentRef.instance;
@@ -9307,6 +9321,7 @@ class NaturalRelationsComponent extends NaturalAbstractController {
9307
9321
  * Observable variables/options for listing service usage and apollo watchQuery
9308
9322
  */
9309
9323
  this.variablesManager = new NaturalQueryVariablesManager();
9324
+ this.removing = new Set();
9310
9325
  }
9311
9326
  /**
9312
9327
  * The filter used to filter relations
@@ -9340,7 +9355,11 @@ class NaturalRelationsComponent extends NaturalAbstractController {
9340
9355
  * Refetch result to display it in table
9341
9356
  */
9342
9357
  removeRelation(relation) {
9343
- this.linkMutationService.unlink(this.main, relation, this.otherName).subscribe();
9358
+ this.removing.add(relation);
9359
+ this.linkMutationService
9360
+ .unlink(this.main, relation, this.otherName)
9361
+ .pipe(finalize(() => this.removing.delete(relation)))
9362
+ .subscribe(() => { var _a; return (_a = this.dataSource) === null || _a === void 0 ? void 0 : _a.remove(relation); });
9344
9363
  }
9345
9364
  /**
9346
9365
  * Link action
@@ -9417,10 +9436,10 @@ class NaturalRelationsComponent extends NaturalAbstractController {
9417
9436
  }
9418
9437
  }
9419
9438
  NaturalRelationsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalRelationsComponent, deps: [{ token: NaturalLinkMutationService }, { token: NaturalHierarchicSelectorDialogService }], target: i0.ɵɵFactoryTarget.Component });
9420
- NaturalRelationsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.0", type: NaturalRelationsComponent, selector: "natural-relations", inputs: { service: "service", placeholder: "placeholder", autocompleteSelectorFilter: "autocompleteSelectorFilter", displayWith: "displayWith", disabled: "disabled", main: "main", hierarchicSelectorFilters: "hierarchicSelectorFilters", hierarchicSelectorConfig: "hierarchicSelectorConfig", otherName: "otherName", filter: "filter" }, outputs: { selectionChange: "selectionChange" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "select", first: true, predicate: NaturalSelectComponent, descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"body\">\n <ng-template #defaultNameCell let-item=\"item\">\n {{ getDisplayFn()(item) }}\n </ng-template>\n\n <table *ngIf=\"dataSource\" [dataSource]=\"dataSource\" class=\"natural-row-click\" mat-table>\n <tr *matHeaderRowDef=\"displayedColumns\" mat-header-row style=\"display: none\"></tr>\n <tr *matRowDef=\"let row; columns: displayedColumns\" mat-row></tr>\n\n <ng-container matColumnDef=\"name\">\n <th *matHeaderCellDef i18n mat-header-cell>Titre</th>\n <td *matCellDef=\"let item\" mat-cell>\n <ng-template\n [ngTemplateOutletContext]=\"{item: item}\"\n [ngTemplateOutlet]=\"itemTemplate ? itemTemplate : defaultNameCell\"\n ></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"unlink\">\n <th *matHeaderCellDef mat-header-cell></th>\n <td *matCellDef=\"let element\" mat-cell>\n <button\n *ngIf=\"!disabled\"\n (click)=\"removeRelation(element)\"\n color=\"warn\"\n mat-icon-button\n i18n-matTooltip\n matTooltip=\"Dissocier\"\n >\n <natural-icon name=\"link_off\"></natural-icon>\n </button>\n </td>\n </ng-container>\n </table>\n\n <mat-paginator\n (page)=\"pagination($event)\"\n *ngIf=\"dataSource?.data && (dataSource?.data?.length || 0) > (dataSource?.data?.pageSize || 0)\"\n [length]=\"dataSource?.data?.length || 0\"\n [pageIndex]=\"dataSource?.data?.pageIndex || 0\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSize]=\"dataSource?.data?.pageSize || 0\"\n ></mat-paginator>\n\n <div *ngIf=\"!loading && dataSource?.data?.length === 0\" class=\"margin-v mat-body\">\n <span i18n>Aucun r\u00E9sultat</span>\n </div>\n\n <mat-progress-spinner *ngIf=\"loading\" [diameter]=\"40\" class=\"loading\" mode=\"indeterminate\"></mat-progress-spinner>\n</div>\n\n<natural-select\n #select\n (selectionChange)=\"addRelations([$any($event)])\"\n *ngIf=\"!hierarchicSelectorConfig && service && !disabled\"\n [displayWith]=\"getDisplayFn()\"\n [filter]=\"autocompleteSelectorFilter\"\n [placeholder]=\"placeholder\"\n [service]=\"service\"\n [showIcon]=\"false\"\n></natural-select>\n\n<div *ngIf=\"hierarchicSelectorConfig && !disabled\">\n <button (click)=\"openNaturalHierarchicSelector()\" color=\"primary\" mat-flat-button>{{ placeholder }}</button>\n</div>\n", styles: [":host{display:flex;flex-direction:column}:host>*:not(:last-child){margin-bottom:20px}:host .body{display:flex;flex-direction:column}:host .loading{margin:20px auto}:host .mat-column-unlink{width:2.5em}\n"], components: [{ type: i3$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i3$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i3$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: NaturalIconComponent, selector: "natural-icon", inputs: ["label", "labelColor", "labelPosition", "name", "size"] }, { type: i6$1.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { type: i5$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }, { type: NaturalSelectComponent, selector: "natural-select", inputs: ["service", "optionRequired", "searchField", "filter", "disabled"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i3$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { type: i3$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i3$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i3$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i3$2.MatCellDef, selector: "[matCellDef]" }, { type: i3$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i10.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
9439
+ NaturalRelationsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.0", type: NaturalRelationsComponent, selector: "natural-relations", inputs: { service: "service", placeholder: "placeholder", autocompleteSelectorFilter: "autocompleteSelectorFilter", displayWith: "displayWith", disabled: "disabled", main: "main", hierarchicSelectorFilters: "hierarchicSelectorFilters", hierarchicSelectorConfig: "hierarchicSelectorConfig", otherName: "otherName", filter: "filter" }, outputs: { selectionChange: "selectionChange" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "select", first: true, predicate: NaturalSelectComponent, descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"body\">\n <ng-template #defaultNameCell let-item=\"item\">\n {{ getDisplayFn()(item) }}\n </ng-template>\n\n <table *ngIf=\"dataSource\" [dataSource]=\"dataSource\" class=\"natural-row-click\" mat-table>\n <tr *matHeaderRowDef=\"displayedColumns\" mat-header-row style=\"display: none\"></tr>\n <tr *matRowDef=\"let row; columns: displayedColumns\" mat-row></tr>\n\n <ng-container matColumnDef=\"name\">\n <th *matHeaderCellDef i18n mat-header-cell>Titre</th>\n <td *matCellDef=\"let item\" mat-cell>\n <ng-template\n [ngTemplateOutletContext]=\"{item: item}\"\n [ngTemplateOutlet]=\"itemTemplate ? itemTemplate : defaultNameCell\"\n ></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"unlink\">\n <th *matHeaderCellDef mat-header-cell></th>\n <td *matCellDef=\"let element\" mat-cell>\n <button\n *ngIf=\"!disabled\"\n (click)=\"removeRelation(element)\"\n [disabled]=\"removing.has(element)\"\n color=\"warn\"\n mat-icon-button\n i18n-matTooltip\n matTooltip=\"Dissocier\"\n >\n <natural-icon name=\"link_off\"></natural-icon>\n </button>\n </td>\n </ng-container>\n </table>\n\n <mat-paginator\n (page)=\"pagination($event)\"\n *ngIf=\"dataSource?.data && (dataSource?.data?.length || 0) > (dataSource?.data?.pageSize || 0)\"\n [length]=\"dataSource?.data?.length || 0\"\n [pageIndex]=\"dataSource?.data?.pageIndex || 0\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSize]=\"dataSource?.data?.pageSize || 0\"\n ></mat-paginator>\n\n <div *ngIf=\"!loading && dataSource?.data?.length === 0\" class=\"margin-v mat-body\">\n <span i18n>Aucun r\u00E9sultat</span>\n </div>\n\n <mat-progress-spinner *ngIf=\"loading\" [diameter]=\"40\" class=\"loading\" mode=\"indeterminate\"></mat-progress-spinner>\n</div>\n\n<natural-select\n #select\n (selectionChange)=\"addRelations([$any($event)])\"\n *ngIf=\"!hierarchicSelectorConfig && service && !disabled\"\n [displayWith]=\"getDisplayFn()\"\n [filter]=\"autocompleteSelectorFilter\"\n [placeholder]=\"placeholder\"\n [service]=\"service\"\n [showIcon]=\"false\"\n></natural-select>\n\n<div *ngIf=\"hierarchicSelectorConfig && !disabled\">\n <button (click)=\"openNaturalHierarchicSelector()\" color=\"primary\" mat-flat-button>{{ placeholder }}</button>\n</div>\n", styles: [":host{display:flex;flex-direction:column}:host>*:not(:last-child){margin-bottom:20px}:host .body{display:flex;flex-direction:column}:host .loading{margin:20px auto}:host .mat-column-unlink{width:2.5em}\n"], components: [{ type: i3$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i3$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i3$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: NaturalIconComponent, selector: "natural-icon", inputs: ["label", "labelColor", "labelPosition", "name", "size"] }, { type: i6$1.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { type: i5$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }, { type: NaturalSelectComponent, selector: "natural-select", inputs: ["service", "optionRequired", "searchField", "filter", "disabled"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i3$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { type: i3$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i3$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i3$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i3$2.MatCellDef, selector: "[matCellDef]" }, { type: i3$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i10.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
9421
9440
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalRelationsComponent, decorators: [{
9422
9441
  type: Component,
9423
- args: [{ selector: 'natural-relations', template: "<div class=\"body\">\n <ng-template #defaultNameCell let-item=\"item\">\n {{ getDisplayFn()(item) }}\n </ng-template>\n\n <table *ngIf=\"dataSource\" [dataSource]=\"dataSource\" class=\"natural-row-click\" mat-table>\n <tr *matHeaderRowDef=\"displayedColumns\" mat-header-row style=\"display: none\"></tr>\n <tr *matRowDef=\"let row; columns: displayedColumns\" mat-row></tr>\n\n <ng-container matColumnDef=\"name\">\n <th *matHeaderCellDef i18n mat-header-cell>Titre</th>\n <td *matCellDef=\"let item\" mat-cell>\n <ng-template\n [ngTemplateOutletContext]=\"{item: item}\"\n [ngTemplateOutlet]=\"itemTemplate ? itemTemplate : defaultNameCell\"\n ></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"unlink\">\n <th *matHeaderCellDef mat-header-cell></th>\n <td *matCellDef=\"let element\" mat-cell>\n <button\n *ngIf=\"!disabled\"\n (click)=\"removeRelation(element)\"\n color=\"warn\"\n mat-icon-button\n i18n-matTooltip\n matTooltip=\"Dissocier\"\n >\n <natural-icon name=\"link_off\"></natural-icon>\n </button>\n </td>\n </ng-container>\n </table>\n\n <mat-paginator\n (page)=\"pagination($event)\"\n *ngIf=\"dataSource?.data && (dataSource?.data?.length || 0) > (dataSource?.data?.pageSize || 0)\"\n [length]=\"dataSource?.data?.length || 0\"\n [pageIndex]=\"dataSource?.data?.pageIndex || 0\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSize]=\"dataSource?.data?.pageSize || 0\"\n ></mat-paginator>\n\n <div *ngIf=\"!loading && dataSource?.data?.length === 0\" class=\"margin-v mat-body\">\n <span i18n>Aucun r\u00E9sultat</span>\n </div>\n\n <mat-progress-spinner *ngIf=\"loading\" [diameter]=\"40\" class=\"loading\" mode=\"indeterminate\"></mat-progress-spinner>\n</div>\n\n<natural-select\n #select\n (selectionChange)=\"addRelations([$any($event)])\"\n *ngIf=\"!hierarchicSelectorConfig && service && !disabled\"\n [displayWith]=\"getDisplayFn()\"\n [filter]=\"autocompleteSelectorFilter\"\n [placeholder]=\"placeholder\"\n [service]=\"service\"\n [showIcon]=\"false\"\n></natural-select>\n\n<div *ngIf=\"hierarchicSelectorConfig && !disabled\">\n <button (click)=\"openNaturalHierarchicSelector()\" color=\"primary\" mat-flat-button>{{ placeholder }}</button>\n</div>\n", styles: [":host{display:flex;flex-direction:column}:host>*:not(:last-child){margin-bottom:20px}:host .body{display:flex;flex-direction:column}:host .loading{margin:20px auto}:host .mat-column-unlink{width:2.5em}\n"] }]
9442
+ args: [{ selector: 'natural-relations', template: "<div class=\"body\">\n <ng-template #defaultNameCell let-item=\"item\">\n {{ getDisplayFn()(item) }}\n </ng-template>\n\n <table *ngIf=\"dataSource\" [dataSource]=\"dataSource\" class=\"natural-row-click\" mat-table>\n <tr *matHeaderRowDef=\"displayedColumns\" mat-header-row style=\"display: none\"></tr>\n <tr *matRowDef=\"let row; columns: displayedColumns\" mat-row></tr>\n\n <ng-container matColumnDef=\"name\">\n <th *matHeaderCellDef i18n mat-header-cell>Titre</th>\n <td *matCellDef=\"let item\" mat-cell>\n <ng-template\n [ngTemplateOutletContext]=\"{item: item}\"\n [ngTemplateOutlet]=\"itemTemplate ? itemTemplate : defaultNameCell\"\n ></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"unlink\">\n <th *matHeaderCellDef mat-header-cell></th>\n <td *matCellDef=\"let element\" mat-cell>\n <button\n *ngIf=\"!disabled\"\n (click)=\"removeRelation(element)\"\n [disabled]=\"removing.has(element)\"\n color=\"warn\"\n mat-icon-button\n i18n-matTooltip\n matTooltip=\"Dissocier\"\n >\n <natural-icon name=\"link_off\"></natural-icon>\n </button>\n </td>\n </ng-container>\n </table>\n\n <mat-paginator\n (page)=\"pagination($event)\"\n *ngIf=\"dataSource?.data && (dataSource?.data?.length || 0) > (dataSource?.data?.pageSize || 0)\"\n [length]=\"dataSource?.data?.length || 0\"\n [pageIndex]=\"dataSource?.data?.pageIndex || 0\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSize]=\"dataSource?.data?.pageSize || 0\"\n ></mat-paginator>\n\n <div *ngIf=\"!loading && dataSource?.data?.length === 0\" class=\"margin-v mat-body\">\n <span i18n>Aucun r\u00E9sultat</span>\n </div>\n\n <mat-progress-spinner *ngIf=\"loading\" [diameter]=\"40\" class=\"loading\" mode=\"indeterminate\"></mat-progress-spinner>\n</div>\n\n<natural-select\n #select\n (selectionChange)=\"addRelations([$any($event)])\"\n *ngIf=\"!hierarchicSelectorConfig && service && !disabled\"\n [displayWith]=\"getDisplayFn()\"\n [filter]=\"autocompleteSelectorFilter\"\n [placeholder]=\"placeholder\"\n [service]=\"service\"\n [showIcon]=\"false\"\n></natural-select>\n\n<div *ngIf=\"hierarchicSelectorConfig && !disabled\">\n <button (click)=\"openNaturalHierarchicSelector()\" color=\"primary\" mat-flat-button>{{ placeholder }}</button>\n</div>\n", styles: [":host{display:flex;flex-direction:column}:host>*:not(:last-child){margin-bottom:20px}:host .body{display:flex;flex-direction:column}:host .loading{margin:20px auto}:host .mat-column-unlink{width:2.5em}\n"] }]
9424
9443
  }], ctorParameters: function () { return [{ type: NaturalLinkMutationService }, { type: NaturalHierarchicSelectorDialogService }]; }, propDecorators: { select: [{
9425
9444
  type: ViewChild,
9426
9445
  args: [NaturalSelectComponent]
@@ -9800,9 +9819,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImpor
9800
9819
  } });
9801
9820
 
9802
9821
  class NaturalSidenavContainerComponent {
9803
- constructor(sidenavService, element) {
9822
+ constructor(sidenavService) {
9804
9823
  this.sidenavService = sidenavService;
9805
- this.element = element;
9806
9824
  /**
9807
9825
  * The side that the drawer is attached to
9808
9826
  */
@@ -9853,12 +9871,12 @@ class NaturalSidenavContainerComponent {
9853
9871
  this.sidenavService.toggleMinimized();
9854
9872
  }
9855
9873
  }
9856
- NaturalSidenavContainerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalSidenavContainerComponent, deps: [{ token: NaturalSidenavService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
9874
+ NaturalSidenavContainerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalSidenavContainerComponent, deps: [{ token: NaturalSidenavService }], target: i0.ɵɵFactoryTarget.Component });
9857
9875
  NaturalSidenavContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.0", type: NaturalSidenavContainerComponent, selector: "natural-sidenav-container", inputs: { name: "name", position: "position", mobileAutoClose: "mobileAutoClose", minimizedWidth: "minimizedWidth", noScroll: "noScroll" }, host: { properties: { "attr.no-scroll": "this.noScroll" } }, providers: [NaturalSidenavService], viewQueries: [{ propertyName: "menuContainer", first: true, predicate: MatSidenavContainer, descendants: true, static: true }, { propertyName: "menuSidenav", first: true, predicate: MatSidenav, descendants: true, static: true }], ngImport: i0, template: "<mat-sidenav-container (backdropClick)=\"sidenavService.setOpened(false)\">\n <mat-sidenav\n [mode]=\"sidenavService.activeMode\"\n [ngClass]=\"sidenavService.isMinimized ? 'menuMinimized' : ''\"\n [opened]=\"sidenavService.isOpened\"\n [style.min-width.px]=\"sidenavService.isMinimized && minimizedWidth ? minimizedWidth : null\"\n [style.width.px]=\"sidenavService.isMinimized && minimizedWidth ? minimizedWidth : null\"\n [position]=\"position\"\n >\n <ng-content select=\"natural-sidenav\"></ng-content>\n </mat-sidenav>\n\n <mat-sidenav-content>\n <div>\n <ng-content select=\"natural-sidenav-content\"></ng-content>\n </div>\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{display:flex;flex-direction:column}:host mat-sidenav-container{display:flex;flex-direction:column;flex:1}:host mat-sidenav-content>div{overflow:auto}:host .menuMinimized{overflow-x:hidden}:host .buttons{display:flex;flex-direction:row;justify-content:flex-end}\n"], components: [{ type: i2$6.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { type: i2$6.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { type: i2$6.MatSidenavContent, selector: "mat-sidenav-content" }], directives: [{ type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
9858
9876
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalSidenavContainerComponent, decorators: [{
9859
9877
  type: Component,
9860
9878
  args: [{ selector: 'natural-sidenav-container', providers: [NaturalSidenavService], template: "<mat-sidenav-container (backdropClick)=\"sidenavService.setOpened(false)\">\n <mat-sidenav\n [mode]=\"sidenavService.activeMode\"\n [ngClass]=\"sidenavService.isMinimized ? 'menuMinimized' : ''\"\n [opened]=\"sidenavService.isOpened\"\n [style.min-width.px]=\"sidenavService.isMinimized && minimizedWidth ? minimizedWidth : null\"\n [style.width.px]=\"sidenavService.isMinimized && minimizedWidth ? minimizedWidth : null\"\n [position]=\"position\"\n >\n <ng-content select=\"natural-sidenav\"></ng-content>\n </mat-sidenav>\n\n <mat-sidenav-content>\n <div>\n <ng-content select=\"natural-sidenav-content\"></ng-content>\n </div>\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{display:flex;flex-direction:column}:host mat-sidenav-container{display:flex;flex-direction:column;flex:1}:host mat-sidenav-content>div{overflow:auto}:host .menuMinimized{overflow-x:hidden}:host .buttons{display:flex;flex-direction:row;justify-content:flex-end}\n"] }]
9861
- }], ctorParameters: function () { return [{ type: NaturalSidenavService }, { type: i0.ElementRef }]; }, propDecorators: { name: [{
9879
+ }], ctorParameters: function () { return [{ type: NaturalSidenavService }]; }, propDecorators: { name: [{
9862
9880
  type: Input
9863
9881
  }], position: [{
9864
9882
  type: Input
@@ -9954,6 +9972,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImpor
9954
9972
  * Button that fits well in a `<mat-table>` and support either
9955
9973
  * route navigation via `navigate` or external URL via `href`.
9956
9974
  *
9975
+ * If neither `navigate` nor `href` has a meaningful value, then
9976
+ * it will show the icon and/or label in `<span>` instead of a button
9977
+ *
9957
9978
  * External URL will always be opened in new tab.
9958
9979
  */
9959
9980
  class NaturalTableButtonComponent {
@@ -9963,14 +9984,27 @@ class NaturalTableButtonComponent {
9963
9984
  this.navigate = [];
9964
9985
  this.preserveFragment = false;
9965
9986
  this.raised = false;
9987
+ this.type = 'none';
9988
+ }
9989
+ ngOnChanges(changes) {
9990
+ var _a;
9991
+ if (((_a = this.navigate) === null || _a === void 0 ? void 0 : _a.length) || Object.keys(this.queryParams).length) {
9992
+ this.type = 'routerLink';
9993
+ }
9994
+ else if (this.href) {
9995
+ this.type = 'href';
9996
+ }
9997
+ else {
9998
+ this.type = 'none';
9999
+ }
9966
10000
  }
9967
10001
  }
9968
10002
  NaturalTableButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalTableButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9969
- NaturalTableButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.0", type: NaturalTableButtonComponent, selector: "natural-table-button", inputs: { queryParams: "queryParams", queryParamsHandling: "queryParamsHandling", label: "label", icon: "icon", href: "href", navigate: "navigate", fragment: "fragment", preserveFragment: "preserveFragment", raised: "raised", color: "color" }, ngImport: i0, template: "<!-- Because directives can't be applied conditionally (routerLink, mat-button and mat-icon-button), we have to use different elements -->\n\n<ng-container *ngIf=\"!raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"!href && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"!href && !label\"\n [color]=\"color\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"href && label\" [attr.href]=\"href\" [color]=\"color\" mat-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a *ngIf=\"href && !label\" [attr.href]=\"href\" [color]=\"color\" mat-icon-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n\n<ng-container *ngIf=\"raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"!href && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"!href && !label\"\n [color]=\"color\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"href && label\" [attr.href]=\"href\" [color]=\"color\" mat-raised-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a *ngIf=\"href && !label\" [attr.href]=\"href\" [color]=\"color\" mat-icon-button mat-raised-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n", styles: ["natural-table-button{flex:1;display:flex;flex-direction:row;justify-content:flex-start;align-items:center}natural-table-button a.mat-button{flex:1;display:flex;flex-direction:row;align-items:center;justify-content:flex-start}natural-table-button a.mat-button .mat-button-wrapper{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>*{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>:not(:last-child){margin-right:5px}\n"], components: [{ type: i1.MatAnchor, selector: "a[mat-button], a[mat-raised-button], a[mat-icon-button], a[mat-fab], a[mat-mini-fab], a[mat-stroked-button], a[mat-flat-button]", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matButton", "matAnchor"] }, { type: NaturalIconComponent, selector: "natural-icon", inputs: ["label", "labelColor", "labelPosition", "name", "size"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "preserveFragment", "skipLocationChange", "replaceUrl", "state", "relativeTo", "routerLink"] }], encapsulation: i0.ViewEncapsulation.None });
10003
+ NaturalTableButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.0", type: NaturalTableButtonComponent, selector: "natural-table-button", inputs: { queryParams: "queryParams", queryParamsHandling: "queryParamsHandling", label: "label", icon: "icon", href: "href", navigate: "navigate", fragment: "fragment", preserveFragment: "preserveFragment", raised: "raised", color: "color" }, usesOnChanges: true, ngImport: i0, template: "<!-- Because directives can't be applied conditionally (routerLink, mat-button and mat-icon-button), we have to use different elements -->\n\n<!-- Edge case of a button without any kind of link at all -->\n<span *ngIf=\"type === 'none'\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span *ngIf=\"label\">{{ label }}</span>\n</span>\n\n<ng-container *ngIf=\"!raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"type === 'routerLink' && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"type === 'routerLink' && !label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"type === 'href' && label\" [attr.href]=\"href\" [color]=\"color\" mat-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a *ngIf=\"type === 'href' && !label\" [attr.href]=\"href\" [color]=\"color\" mat-icon-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n\n<ng-container *ngIf=\"raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"type === 'routerLink' && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"type === 'routerLink' && !label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"type === 'href' && label\" [attr.href]=\"href\" [color]=\"color\" mat-raised-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"type === 'href' && !label\"\n [attr.href]=\"href\"\n [color]=\"color\"\n mat-icon-button\n mat-raised-button\n target=\"_blank\"\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n", styles: ["natural-table-button{flex:1;display:flex;flex-direction:row;justify-content:flex-start;align-items:center}natural-table-button a.mat-button{flex:1;display:flex;flex-direction:row;align-items:center;justify-content:flex-start}natural-table-button a.mat-button .mat-button-wrapper{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>*{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>:not(:last-child){margin-right:5px}natural-table-button>span{padding:0 16px}\n"], components: [{ type: NaturalIconComponent, selector: "natural-icon", inputs: ["label", "labelColor", "labelPosition", "name", "size"] }, { type: i1.MatAnchor, selector: "a[mat-button], a[mat-raised-button], a[mat-icon-button], a[mat-fab], a[mat-mini-fab], a[mat-stroked-button], a[mat-flat-button]", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matButton", "matAnchor"] }], directives: [{ type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "preserveFragment", "skipLocationChange", "replaceUrl", "state", "relativeTo", "routerLink"] }], encapsulation: i0.ViewEncapsulation.None });
9970
10004
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImport: i0, type: NaturalTableButtonComponent, decorators: [{
9971
10005
  type: Component,
9972
- args: [{ selector: 'natural-table-button', encapsulation: ViewEncapsulation.None, template: "<!-- Because directives can't be applied conditionally (routerLink, mat-button and mat-icon-button), we have to use different elements -->\n\n<ng-container *ngIf=\"!raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"!href && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"!href && !label\"\n [color]=\"color\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"href && label\" [attr.href]=\"href\" [color]=\"color\" mat-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a *ngIf=\"href && !label\" [attr.href]=\"href\" [color]=\"color\" mat-icon-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n\n<ng-container *ngIf=\"raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"!href && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"!href && !label\"\n [color]=\"color\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [queryParams]=\"queryParams\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"href && label\" [attr.href]=\"href\" [color]=\"color\" mat-raised-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a *ngIf=\"href && !label\" [attr.href]=\"href\" [color]=\"color\" mat-icon-button mat-raised-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n", styles: ["natural-table-button{flex:1;display:flex;flex-direction:row;justify-content:flex-start;align-items:center}natural-table-button a.mat-button{flex:1;display:flex;flex-direction:row;align-items:center;justify-content:flex-start}natural-table-button a.mat-button .mat-button-wrapper{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>*{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>:not(:last-child){margin-right:5px}\n"] }]
9973
- }], ctorParameters: function () { return []; }, propDecorators: { queryParams: [{
10006
+ args: [{ selector: 'natural-table-button', encapsulation: ViewEncapsulation.None, template: "<!-- Because directives can't be applied conditionally (routerLink, mat-button and mat-icon-button), we have to use different elements -->\n\n<!-- Edge case of a button without any kind of link at all -->\n<span *ngIf=\"type === 'none'\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span *ngIf=\"label\">{{ label }}</span>\n</span>\n\n<ng-container *ngIf=\"!raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"type === 'routerLink' && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"type === 'routerLink' && !label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"type === 'href' && label\" [attr.href]=\"href\" [color]=\"color\" mat-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a *ngIf=\"type === 'href' && !label\" [attr.href]=\"href\" [color]=\"color\" mat-icon-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n\n<ng-container *ngIf=\"raised\">\n <!-- App routed link with label... -->\n <a\n *ngIf=\"type === 'routerLink' && label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"type === 'routerLink' && !label\"\n [color]=\"color\"\n [queryParams]=\"queryParams\"\n [queryParamsHandling]=\"queryParamsHandling\"\n [routerLink]=\"navigate\"\n [fragment]=\"fragment\"\n [preserveFragment]=\"preserveFragment\"\n mat-icon-button\n mat-raised-button\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n\n <!-- External link with label... -->\n <a *ngIf=\"type === 'href' && label\" [attr.href]=\"href\" [color]=\"color\" mat-raised-button target=\"_blank\">\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n <span>{{ label }}</span>\n </a>\n\n <!-- ... and without label -->\n <a\n *ngIf=\"type === 'href' && !label\"\n [attr.href]=\"href\"\n [color]=\"color\"\n mat-icon-button\n mat-raised-button\n target=\"_blank\"\n >\n <natural-icon *ngIf=\"icon\" [name]=\"icon\"></natural-icon>\n </a>\n</ng-container>\n", styles: ["natural-table-button{flex:1;display:flex;flex-direction:row;justify-content:flex-start;align-items:center}natural-table-button a.mat-button{flex:1;display:flex;flex-direction:row;align-items:center;justify-content:flex-start}natural-table-button a.mat-button .mat-button-wrapper{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>*{display:flex;flex-direction:row;align-items:center}natural-table-button a.mat-button .mat-button-wrapper>:not(:last-child){margin-right:5px}natural-table-button>span{padding:0 16px}\n"] }]
10007
+ }], propDecorators: { queryParams: [{
9974
10008
  type: Input
9975
10009
  }], queryParamsHandling: [{
9976
10010
  type: Input
@@ -10556,8 +10590,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.0", ngImpor
10556
10590
  * Public API Surface of natural
10557
10591
  */
10558
10592
 
10559
- const NaturalLoggerConfigUrl = new InjectionToken('NaturalLoggerConfigUrl');
10560
- const NaturalLoggerConfigExtra = new InjectionToken('NaturalLoggerConfigExtra');
10593
+ const NaturalLoggerConfigUrl = new InjectionToken('Absolute URL of the log server');
10594
+ const NaturalLoggerConfigExtra = new InjectionToken('Class that may provide extra data to log');
10595
+ /**
10596
+ * Replace Angular's error handler to also send the log to a remote server via HTTP POST.
10597
+ *
10598
+ * Usage is automatic as soon we import the module via:
10599
+ *
10600
+ * ```ts
10601
+ * NaturalErrorModule.forRoot('http://example.com', ExtraService),
10602
+ * ```
10603
+ */
10561
10604
  class NaturalErrorHandler extends ErrorHandler {
10562
10605
  constructor(http, document, url, loggerExtra) {
10563
10606
  super();
@@ -10567,21 +10610,16 @@ class NaturalErrorHandler extends ErrorHandler {
10567
10610
  this.loggerExtra = loggerExtra;
10568
10611
  }
10569
10612
  handleError(error) {
10570
- var _a, _b, _c, _d, _e;
10613
+ var _a, _b, _c, _d;
10571
10614
  console.error(error);
10572
10615
  const params = {
10616
+ message: this.toMessage(error),
10573
10617
  href: (_a = this.document.defaultView) === null || _a === void 0 ? void 0 : _a.window.location.href,
10574
10618
  host: (_b = this.document.defaultView) === null || _b === void 0 ? void 0 : _b.window.location.hostname,
10575
10619
  path: (_c = this.document.defaultView) === null || _c === void 0 ? void 0 : _c.window.location.pathname,
10576
10620
  agent: (_d = this.document.defaultView) === null || _d === void 0 ? void 0 : _d.window.navigator.userAgent,
10577
10621
  level: 'error',
10578
10622
  };
10579
- if (error === null || error === void 0 ? void 0 : error.message) {
10580
- params.message = error.message;
10581
- }
10582
- else {
10583
- params.message = error;
10584
- }
10585
10623
  if (error === null || error === void 0 ? void 0 : error.stack) {
10586
10624
  params.stacktrace = error.stack;
10587
10625
  }
@@ -10595,7 +10633,10 @@ class NaturalErrorHandler extends ErrorHandler {
10595
10633
  params.url = error.url;
10596
10634
  }
10597
10635
  if (this.loggerExtra) {
10598
- (_e = this.loggerExtra) === null || _e === void 0 ? void 0 : _e.getExtras(error).subscribe(result => {
10636
+ this.loggerExtra
10637
+ .getExtras(error)
10638
+ .pipe(catchError(e => of({ getExtrasErrorMessage: this.toMessage(e) })), first$1())
10639
+ .subscribe(result => {
10599
10640
  this.postLog(Object.assign(params, result));
10600
10641
  });
10601
10642
  }
@@ -10603,6 +10644,14 @@ class NaturalErrorHandler extends ErrorHandler {
10603
10644
  this.postLog(params);
10604
10645
  }
10605
10646
  }
10647
+ toMessage(error) {
10648
+ if (error && typeof error === 'object' && 'message' in error) {
10649
+ return '' + error.message;
10650
+ }
10651
+ else {
10652
+ return '' + error;
10653
+ }
10654
+ }
10606
10655
  /**
10607
10656
  * Send parameters to remote log
10608
10657
  */