@ecodev/natural 44.0.6 → 45.1.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 (34) hide show
  1. package/esm2020/lib/classes/abstract-detail.mjs +39 -40
  2. package/esm2020/lib/classes/abstract-navigable-list.mjs +6 -2
  3. package/esm2020/lib/classes/rxjs.mjs +2 -1
  4. package/esm2020/lib/classes/validators.mjs +2 -2
  5. package/esm2020/lib/modules/dropdown-components/type-date/type-date.component.mjs +1 -1
  6. package/esm2020/lib/modules/dropdown-components/type-date-range/type-date-range.component.mjs +1 -1
  7. package/esm2020/lib/modules/dropdown-components/type-number/type-number.component.mjs +7 -3
  8. package/esm2020/lib/modules/dropdown-components/type-select/type-select.component.mjs +8 -4
  9. package/esm2020/lib/modules/file/abstract-file.mjs +26 -29
  10. package/esm2020/lib/modules/file/utils.mjs +12 -1
  11. package/esm2020/lib/modules/fixed-button-detail/fixed-button-detail.component.mjs +22 -9
  12. package/esm2020/lib/modules/hierarchic-selector/hierarchic-selector/hierarchic-selector.component.mjs +3 -3
  13. package/esm2020/lib/modules/hierarchic-selector/hierarchic-selector/hierarchic-selector.service.mjs +3 -9
  14. package/esm2020/lib/services/abstract-model.service.mjs +8 -41
  15. package/esm2020/lib/services/debounce.service.mjs +128 -0
  16. package/esm2020/lib/services/swiss-parsing-date-adapter.service.mjs +21 -13
  17. package/esm2020/public-api.mjs +2 -1
  18. package/fesm2015/ecodev-natural.mjs +266 -141
  19. package/fesm2015/ecodev-natural.mjs.map +1 -1
  20. package/fesm2020/ecodev-natural.mjs +263 -139
  21. package/fesm2020/ecodev-natural.mjs.map +1 -1
  22. package/lib/modules/dropdown-components/type-date/type-date.component.d.ts +1 -1
  23. package/lib/modules/dropdown-components/type-date-range/type-date-range.component.d.ts +1 -1
  24. package/lib/modules/dropdown-components/type-number/type-number.component.d.ts +2 -1
  25. package/lib/modules/dropdown-components/type-select/type-select.component.d.ts +7 -3
  26. package/lib/modules/file/abstract-file.d.ts +0 -3
  27. package/lib/modules/file/utils.d.ts +1 -0
  28. package/lib/modules/fixed-button-detail/fixed-button-detail.component.d.ts +14 -6
  29. package/lib/modules/hierarchic-selector/hierarchic-selector/hierarchic-selector.component.d.ts +5 -6
  30. package/lib/modules/hierarchic-selector/hierarchic-selector/hierarchic-selector.service.d.ts +5 -14
  31. package/lib/services/abstract-model.service.d.ts +4 -6
  32. package/lib/services/debounce.service.d.ts +46 -0
  33. package/package.json +1 -1
  34. package/public-api.d.ts +1 -0
@@ -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, createEnvironmentInjector, createComponent, PLATFORM_ID, ErrorHandler } from '@angular/core';
4
- import { Subject, BehaviorSubject, of, timer, EMPTY, Observable, first as first$1, combineLatest, ReplaySubject, forkJoin, merge as merge$1, asyncScheduler, catchError } from 'rxjs';
4
+ import { Subject, BehaviorSubject, of, timer, switchMap as switchMap$1, endWith, last, EMPTY, Observable, first as first$1, combineLatest, ReplaySubject, debounceTime as debounceTime$1, raceWith, take as take$1, mergeMap, shareReplay as shareReplay$1, catchError, forkJoin, map as map$1, merge as merge$1, tap as tap$1, asyncScheduler } from 'rxjs';
5
5
  import * as i3 from '@angular/forms';
6
6
  import { FormGroup, FormArray, Validators, UntypedFormGroup, UntypedFormArray, UntypedFormControl, FormsModule, FormControl, FormControlDirective, FormControlName, ReactiveFormsModule } from '@angular/forms';
7
7
  import * as i2$1 from '@angular/router';
@@ -13,7 +13,7 @@ import * as i4 from '@angular/material/button';
13
13
  import { MatButtonModule } from '@angular/material/button';
14
14
  import * as i2 from '@angular/material/snack-bar';
15
15
  import { MatSnackBarModule } from '@angular/material/snack-bar';
16
- import { switchMap, map, first, filter, finalize, takeUntil, take, tap, takeWhile, debounceTime, shareReplay, mergeMap, startWith, distinctUntilChanged, throttleTime } from 'rxjs/operators';
16
+ import { switchMap, first, map, filter, finalize, takeUntil, take, tap, takeWhile, debounceTime, shareReplay, startWith, distinctUntilChanged, throttleTime } from 'rxjs/operators';
17
17
  import * as i7$2 from '@angular/material/table';
18
18
  import { MatTableDataSource, MatTableModule } from '@angular/material/table';
19
19
  import { DataSource, SelectionModel } from '@angular/cdk/collections';
@@ -2124,7 +2124,7 @@ function unique(fieldName, excludedId, modelService) {
2124
2124
  };
2125
2125
  const qvm = new NaturalQueryVariablesManager();
2126
2126
  qvm.set('variables', variables);
2127
- return timer(500).pipe(switchMap(() => modelService.count(qvm).pipe(map(count => (count > 0 ? { duplicateValue: count } : null)))));
2127
+ return timer(500).pipe(switchMap(() => modelService.count(qvm).pipe(first(), map(count => (count > 0 ? { duplicateValue: count } : null)))));
2128
2128
  };
2129
2129
  }
2130
2130
  /**
@@ -2349,53 +2349,52 @@ class NaturalAbstractDetail extends NaturalAbstractPanel {
2349
2349
  this.form.disable();
2350
2350
  this.service
2351
2351
  .create(this.data.model)
2352
- .pipe(finalize(() => this.form.enable()))
2353
- .subscribe(model => {
2352
+ .pipe(switchMap$1(model => {
2354
2353
  this.alertService.info($localize `Créé`);
2355
2354
  this.form.patchValue(model);
2356
- this.postCreate(model).subscribe({
2357
- complete: () => {
2358
- var _a;
2359
- if (redirect) {
2360
- if (this.isPanel) {
2361
- const oldUrl = this.router.url;
2362
- const nextUrl = (_a = this.panelData) === null || _a === void 0 ? void 0 : _a.config.params.nextRoute;
2363
- const newUrl = oldUrl.replace('/new', '/' + model.id) + (nextUrl ? '/' + nextUrl : '');
2364
- this.router.navigateByUrl(newUrl); // replace /new by /123
2365
- }
2366
- else {
2367
- this.router.navigate(['..', model.id], { relativeTo: this.route });
2368
- }
2369
- }
2370
- },
2371
- });
2372
- });
2355
+ return this.postCreate(model).pipe(endWith(model), last());
2356
+ }), switchMap$1(model => {
2357
+ var _a;
2358
+ if (redirect) {
2359
+ if (this.isPanel) {
2360
+ const oldUrl = this.router.url;
2361
+ const nextUrl = (_a = this.panelData) === null || _a === void 0 ? void 0 : _a.config.params.nextRoute;
2362
+ const newUrl = oldUrl.replace('/new', '/' + model.id) + (nextUrl ? '/' + nextUrl : '');
2363
+ return this.router.navigateByUrl(newUrl); // replace /new by /123
2364
+ }
2365
+ else {
2366
+ return this.router.navigate(['..', model.id], { relativeTo: this.route });
2367
+ }
2368
+ }
2369
+ return EMPTY;
2370
+ }), finalize(() => this.form.enable()))
2371
+ .subscribe();
2373
2372
  }
2374
2373
  delete(redirectionRoute) {
2374
+ this.form.disable();
2375
2375
  this.alertService
2376
2376
  .confirm($localize `Suppression`, $localize `Voulez-vous supprimer définitivement cet élément ?`, $localize `Supprimer définitivement`)
2377
- .subscribe(confirmed => {
2378
- if (confirmed) {
2379
- this.preDelete(this.data.model);
2380
- this.form.disable();
2381
- this.service
2382
- .delete([this.data.model])
2383
- .pipe(finalize(() => this.form.enable()))
2384
- .subscribe(() => {
2385
- var _a;
2386
- this.alertService.info($localize `Supprimé`);
2387
- if (!this.isPanel) {
2388
- const defaultRoute = ['../../' + kebabCase(this.key)];
2389
- this.router.navigate(redirectionRoute ? redirectionRoute : defaultRoute, {
2390
- relativeTo: this.route,
2391
- });
2392
- }
2393
- else {
2394
- (_a = this.panelService) === null || _a === void 0 ? void 0 : _a.goToPenultimatePanel();
2395
- }
2396
- });
2377
+ .pipe(switchMap$1(confirmed => {
2378
+ if (!confirmed) {
2379
+ return EMPTY;
2397
2380
  }
2398
- });
2381
+ this.preDelete(this.data.model);
2382
+ return this.service.delete([this.data.model]).pipe(switchMap$1(() => {
2383
+ var _a;
2384
+ this.alertService.info($localize `Supprimé`);
2385
+ if (this.isPanel) {
2386
+ (_a = this.panelService) === null || _a === void 0 ? void 0 : _a.goToPenultimatePanel();
2387
+ return EMPTY;
2388
+ }
2389
+ else {
2390
+ const defaultRoute = ['../../' + kebabCase(this.key)];
2391
+ return this.router.navigate(redirectionRoute ? redirectionRoute : defaultRoute, {
2392
+ relativeTo: this.route,
2393
+ });
2394
+ }
2395
+ }));
2396
+ }), finalize(() => this.form.enable()))
2397
+ .subscribe();
2399
2398
  }
2400
2399
  postUpdate(model) { }
2401
2400
  /**
@@ -3433,7 +3432,10 @@ class NaturalAbstractNavigableList extends NaturalAbstractList {
3433
3432
  const variables = { filter: { groups: [{ conditions: [condition] }] } };
3434
3433
  const qvm = new NaturalQueryVariablesManager();
3435
3434
  qvm.set('variables', variables);
3436
- this.service.count(qvm).subscribe(count => (navigableItem.hasNavigation = count > 0));
3435
+ this.service
3436
+ .count(qvm)
3437
+ .pipe(first$1())
3438
+ .subscribe(count => (navigableItem.hasNavigation = count > 0));
3437
3439
  return navigableItem;
3438
3440
  });
3439
3441
  const navigableResult = Object.assign(Object.assign({}, result), { items: navigableItems });
@@ -3559,6 +3561,7 @@ function cancellableTimeout(canceller, milliSeconds = 0) {
3559
3561
  function debug(debugName) {
3560
3562
  return tap({
3561
3563
  subscribe: () => console.log('SUBSCRIBE', debugName),
3564
+ unsubscribe: () => console.log('UNSUBSCRIBE', debugName),
3562
3565
  next: value => console.log('NEXT', debugName, value),
3563
3566
  error: error => console.log('ERROR', debugName, error),
3564
3567
  complete: () => console.log('COMPLETE', debugName),
@@ -3566,18 +3569,15 @@ function debug(debugName) {
3566
3569
  }
3567
3570
 
3568
3571
  class NaturalAbstractModelService {
3569
- constructor(apollo, name, oneQuery, allQuery, createMutation, updateMutation, deleteMutation) {
3572
+ constructor(apollo, naturalDebounceService, name, oneQuery, allQuery, createMutation, updateMutation, deleteMutation) {
3570
3573
  this.apollo = apollo;
3574
+ this.naturalDebounceService = naturalDebounceService;
3571
3575
  this.name = name;
3572
3576
  this.oneQuery = oneQuery;
3573
3577
  this.allQuery = allQuery;
3574
3578
  this.createMutation = createMutation;
3575
3579
  this.updateMutation = updateMutation;
3576
3580
  this.deleteMutation = deleteMutation;
3577
- /**
3578
- * Stores the debounced update function
3579
- */
3580
- this.debouncedUpdateCache = new Map();
3581
3581
  /**
3582
3582
  * Store the creation mutations that are pending
3583
3583
  */
@@ -3809,36 +3809,7 @@ class NaturalAbstractModelService {
3809
3809
  this.throwIfNotQuery(this.updateMutation);
3810
3810
  // Keep a single instance of the debounced update function
3811
3811
  const id = object.id;
3812
- let debounced = this.debouncedUpdateCache.get(id);
3813
- if (!debounced) {
3814
- const source = new ReplaySubject(1);
3815
- let wasCancelled = false;
3816
- const canceller = new Subject();
3817
- canceller.subscribe(() => {
3818
- wasCancelled = true;
3819
- source.complete();
3820
- canceller.complete();
3821
- });
3822
- // Create debounced update function
3823
- const result = source.pipe(debounceTime(2000), // Wait 2sec.
3824
- take(1), mergeMap(() => {
3825
- this.debouncedUpdateCache.delete(id);
3826
- if (wasCancelled) {
3827
- return EMPTY;
3828
- }
3829
- return this.updateNow(object);
3830
- }), shareReplay());
3831
- debounced = {
3832
- source,
3833
- canceller,
3834
- result,
3835
- };
3836
- this.debouncedUpdateCache.set(id, debounced);
3837
- }
3838
- // Notify our debounced update each time we ask to update
3839
- debounced.source.next();
3840
- // Return and observable that is updated when mutation is done
3841
- return debounced.result;
3812
+ return this.naturalDebounceService.debounce(this, id, this.updateNow(object));
3842
3813
  }
3843
3814
  /**
3844
3815
  * Update an object immediately when subscribing
@@ -3890,8 +3861,7 @@ class NaturalAbstractModelService {
3890
3861
  this.throwIfNotQuery(this.deleteMutation);
3891
3862
  const ids = objects.map(o => {
3892
3863
  // Cancel pending update
3893
- const debounced = this.debouncedUpdateCache.get(o.id);
3894
- debounced === null || debounced === void 0 ? void 0 : debounced.canceller.next();
3864
+ this.naturalDebounceService.cancel(this, o.id);
3895
3865
  return o.id;
3896
3866
  });
3897
3867
  const variables = merge({
@@ -3939,7 +3909,7 @@ class NaturalAbstractModelService {
3939
3909
  return input;
3940
3910
  }
3941
3911
  /**
3942
- * Return the number of objects matching the query
3912
+ * Return the number of objects matching the query. It may never complete.
3943
3913
  *
3944
3914
  * This is used for the unique validator
3945
3915
  */
@@ -4072,6 +4042,132 @@ class NaturalAbstractModelService {
4072
4042
  }
4073
4043
  }
4074
4044
 
4045
+ /**
4046
+ * Debounce subscriptions to observable, with possibility to cancel one, or flush all of them. Typically,
4047
+ * observables are object updates, so `NaturalAbstractModelService.updateNow()`.
4048
+ *
4049
+ * `key` must be an instance of `NaturalAbstractModelService` to separate objects by their types. So User with ID 1 is
4050
+ * not confused with Product with ID 1. It has no other purpose.
4051
+ *
4052
+ * `id` should be the ID of the object that will be updated.
4053
+ */
4054
+ class NaturalDebounceService {
4055
+ constructor() {
4056
+ this.flusher = new Subject();
4057
+ /**
4058
+ * Stores the debounced update function
4059
+ */
4060
+ this.allDebouncedUpdateCache = new Map();
4061
+ }
4062
+ /**
4063
+ * Debounce the given source observable for a short time. If called multiple times with the same key and id,
4064
+ * it will postpone the subscription to the source observable.
4065
+ *
4066
+ * Giving the same key and id but a different source observable will replace the original observable, but
4067
+ * keep the same debouncing timeline.
4068
+ */
4069
+ debounce(key, id, source) {
4070
+ const debouncedUpdateCache = this.getMap(key);
4071
+ let debounced = debouncedUpdateCache.get(id);
4072
+ if (debounced) {
4073
+ debounced.source = source;
4074
+ }
4075
+ else {
4076
+ const debouncer = new ReplaySubject(1);
4077
+ let wasCancelled = false;
4078
+ const canceller = new Subject();
4079
+ canceller.subscribe(() => {
4080
+ wasCancelled = true;
4081
+ debouncer.complete();
4082
+ canceller.complete();
4083
+ this.delete(key, id);
4084
+ });
4085
+ debounced = {
4086
+ debouncer,
4087
+ canceller,
4088
+ source,
4089
+ result: debouncer.pipe(debounceTime$1(2000), // Wait 2 seconds...
4090
+ raceWith(this.flusher), // ...unless flusher is triggered
4091
+ take$1(1), mergeMap(() => {
4092
+ this.delete(key, id);
4093
+ if (wasCancelled || !debounced) {
4094
+ return EMPTY;
4095
+ }
4096
+ return debounced.source;
4097
+ }), shareReplay$1()),
4098
+ };
4099
+ debouncedUpdateCache.set(id, debounced);
4100
+ }
4101
+ // Notify our debounced update each time we ask to update
4102
+ debounced.debouncer.next();
4103
+ // Return and observable that is updated when mutation is done
4104
+ return debounced.result;
4105
+ }
4106
+ cancel(key, id) {
4107
+ var _a;
4108
+ const debounced = (_a = this.allDebouncedUpdateCache.get(key)) === null || _a === void 0 ? void 0 : _a.get(id);
4109
+ debounced === null || debounced === void 0 ? void 0 : debounced.canceller.next();
4110
+ }
4111
+ /**
4112
+ * Immediately execute all pending updates.
4113
+ *
4114
+ * It should typically be called before login out.
4115
+ *
4116
+ * The returned observable will complete when all updates complete, even if some of them error.
4117
+ */
4118
+ flush() {
4119
+ const all = [];
4120
+ this.allDebouncedUpdateCache.forEach(map => map.forEach(debounced => {
4121
+ all.push(debounced.result.pipe(catchError(() => of(undefined))));
4122
+ }));
4123
+ if (!all.length) {
4124
+ all.push(of(undefined));
4125
+ }
4126
+ return new Observable(subscriber => {
4127
+ const subscription = forkJoin(all)
4128
+ .pipe(map$1(() => undefined))
4129
+ .subscribe(subscriber);
4130
+ // Flush only after subscription process is finished
4131
+ this.flusher.next();
4132
+ return subscription;
4133
+ });
4134
+ }
4135
+ /**
4136
+ * Count of pending updates
4137
+ */
4138
+ get count() {
4139
+ let count = 0;
4140
+ this.allDebouncedUpdateCache.forEach(map => (count += map.size));
4141
+ return count;
4142
+ }
4143
+ getMap(key) {
4144
+ let debouncedUpdateCache = this.allDebouncedUpdateCache.get(key);
4145
+ if (!debouncedUpdateCache) {
4146
+ debouncedUpdateCache = new Map();
4147
+ this.allDebouncedUpdateCache.set(key, debouncedUpdateCache);
4148
+ }
4149
+ return debouncedUpdateCache;
4150
+ }
4151
+ delete(key, id) {
4152
+ const map = this.allDebouncedUpdateCache.get(key);
4153
+ if (!map) {
4154
+ return;
4155
+ }
4156
+ map.delete(id);
4157
+ if (!map.size) {
4158
+ this.allDebouncedUpdateCache.delete(key);
4159
+ }
4160
+ }
4161
+ }
4162
+ NaturalDebounceService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4163
+ NaturalDebounceService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, providedIn: 'root' });
4164
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, decorators: [{
4165
+ type: Injectable,
4166
+ args: [{
4167
+ providedIn: 'root',
4168
+ }]
4169
+ }] });
4170
+
4075
4171
  const enumTypeQuery = gql `
4076
4172
  query EnumType($name: String!) {
4077
4173
  __type(name: $name) {
@@ -4280,6 +4376,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
4280
4376
  }]
4281
4377
  }], ctorParameters: function () { return [{ type: i1$1.Apollo }]; } });
4282
4378
 
4379
+ const patterns = [
4380
+ /^(?<day>\d{1,2})\.(?<month>\d{1,2})\.(?<year>\d{4}|\d{2})$/,
4381
+ /^(?<day>\d{1,2})-(?<month>\d{1,2})-(?<year>\d{4}|\d{2})$/,
4382
+ /^(?<day>\d{1,2})\/(?<month>\d{1,2})\/(?<year>\d{4}|\d{2})$/,
4383
+ /^(?<day>\d{1,2})\\(?<month>\d{1,2})\\(?<year>\d{4}|\d{2})$/,
4384
+ // strict ISO format
4385
+ /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/,
4386
+ ];
4283
4387
  class NaturalSwissParsingDateAdapter extends NativeDateAdapter {
4284
4388
  /**
4285
4389
  * Parse commonly accepted swiss format, such as:
@@ -4293,24 +4397,24 @@ class NaturalSwissParsingDateAdapter extends NativeDateAdapter {
4293
4397
  return new Date(value);
4294
4398
  }
4295
4399
  if (typeof value === 'string') {
4296
- let m = value.match(/(\d{1,2})\.(\d{1,2})\.(\d{4}|\d{2})/);
4297
- if (m) {
4298
- let year = +m[3];
4299
- // Assume year 2000 if only two digits
4300
- if (year < 100) {
4301
- year += 2000;
4400
+ const trimmed = value.trim();
4401
+ for (const pattern of patterns) {
4402
+ const m = trimmed.match(pattern);
4403
+ if (m === null || m === void 0 ? void 0 : m.groups) {
4404
+ const year = +m.groups.year;
4405
+ const month = +m.groups.month;
4406
+ const day = +m.groups.day;
4407
+ return this.createDateIfValid(year, month, day);
4302
4408
  }
4303
- return this.createDateIfValid(year, +m[2], +m[1]);
4304
- }
4305
- // Attempt strict ISO format
4306
- m = value.match(/(\d{4})-(\d{2})-(\d{2})/);
4307
- if (m) {
4308
- return this.createDateIfValid(+m[1], +m[2], +m[3]);
4309
4409
  }
4310
4410
  }
4311
4411
  return null;
4312
4412
  }
4313
4413
  createDateIfValid(year, month, date) {
4414
+ // Assume year 2000 if only two digits
4415
+ if (year < 100) {
4416
+ year += 2000;
4417
+ }
4314
4418
  month = month - 1;
4315
4419
  if (month >= 0 && month <= 11 && date >= 1 && date <= 31) {
4316
4420
  return this.createDate(year, month, date);
@@ -5397,6 +5501,7 @@ class TypeSelectComponent extends NaturalAbstractController {
5397
5501
  this.defaults = {
5398
5502
  items: [],
5399
5503
  multiple: true,
5504
+ operators: true,
5400
5505
  };
5401
5506
  this.configuration = Object.assign(Object.assign({}, this.defaults), data.configuration);
5402
5507
  // Immediately initValidators and everytime the operator change later
@@ -5445,7 +5550,7 @@ class TypeSelectComponent extends NaturalAbstractController {
5445
5550
  this.valueCtrl.updateValueAndValidity();
5446
5551
  }
5447
5552
  isMultiple() {
5448
- return !!this.configuration.multiple;
5553
+ return this.configuration.multiple;
5449
5554
  }
5450
5555
  getItemById(id) {
5451
5556
  return this.items.find(item => this.getId(item) === id);
@@ -5493,6 +5598,9 @@ class TypeSelectComponent extends NaturalAbstractController {
5493
5598
  return [operator.label, selection].filter(v => v).join(' ');
5494
5599
  }
5495
5600
  conditionToOperatorKey(condition) {
5601
+ if (!this.configuration.operators) {
5602
+ return 'is';
5603
+ }
5496
5604
  if (condition.in && !condition.in.not) {
5497
5605
  return 'is';
5498
5606
  }
@@ -5523,10 +5631,10 @@ class TypeSelectComponent extends NaturalAbstractController {
5523
5631
  }
5524
5632
  }
5525
5633
  TypeSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: TypeSelectComponent, deps: [{ token: NATURAL_DROPDOWN_DATA }], target: i0.ɵɵFactoryTarget.Component });
5526
- TypeSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: TypeSelectComponent, selector: "ng-component", viewQueries: [{ propertyName: "list", first: true, predicate: MatSelectionList, descendants: true }], usesInheritance: true, ngImport: i0, template: "<form [formGroup]=\"form\">\n <mat-form-field style=\"max-width: 7em; margin-right: 1em\">\n <mat-label i18n=\"Mathematical operator < > =\">Op\u00E9rateur</mat-label>\n <mat-select [formControl]=\"operatorCtrl\" [required]=\"true\">\n <mat-option *ngFor=\"let item of operators\" [value]=\"item.key\">\n {{ item.label }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-selection-list *ngIf=\"requireValueCtrl\" [formControl]=\"valueCtrl\">\n <mat-list-option *ngFor=\"let item of items\" [value]=\"getId(item)\" checkboxPosition=\"before\">\n {{ getDisplay(item) }}\n </mat-list-option>\n </mat-selection-list>\n</form>\n", dependencies: [{ kind: "directive", type: i1$3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "component", type: i4$2.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4$3.MatSelectionList, selector: "mat-selection-list", inputs: ["disableRipple", "color", "compareWith", "disabled", "multiple"], outputs: ["selectionChange"], exportAs: ["matSelectionList"] }, { kind: "component", type: i4$3.MatListOption, selector: "mat-list-option", inputs: ["disableRipple", "checkboxPosition", "color", "value", "disabled", "selected"], outputs: ["selectedChange"], exportAs: ["matListOption"] }, { kind: "component", type: i4$4.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { kind: "component", type: i1$7.MatOption, selector: "mat-option", exportAs: ["matOption"] }] });
5634
+ TypeSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: TypeSelectComponent, selector: "ng-component", viewQueries: [{ propertyName: "list", first: true, predicate: MatSelectionList, descendants: true }], usesInheritance: true, ngImport: i0, template: "<form [formGroup]=\"form\">\n <mat-form-field style=\"max-width: 7em; margin-right: 1em\" *ngIf=\"configuration.operators\">\n <mat-label i18n=\"Mathematical operator < > =\">Op\u00E9rateur</mat-label>\n <mat-select [formControl]=\"operatorCtrl\" [required]=\"true\">\n <mat-option *ngFor=\"let item of operators\" [value]=\"item.key\">\n {{ item.label }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-selection-list *ngIf=\"requireValueCtrl\" [formControl]=\"valueCtrl\">\n <mat-list-option *ngFor=\"let item of items\" [value]=\"getId(item)\" checkboxPosition=\"before\">\n {{ getDisplay(item) }}\n </mat-list-option>\n </mat-selection-list>\n</form>\n", dependencies: [{ kind: "directive", type: i1$3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "component", type: i4$2.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4$3.MatSelectionList, selector: "mat-selection-list", inputs: ["disableRipple", "color", "compareWith", "disabled", "multiple"], outputs: ["selectionChange"], exportAs: ["matSelectionList"] }, { kind: "component", type: i4$3.MatListOption, selector: "mat-list-option", inputs: ["disableRipple", "checkboxPosition", "color", "value", "disabled", "selected"], outputs: ["selectedChange"], exportAs: ["matListOption"] }, { kind: "component", type: i4$4.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { kind: "component", type: i1$7.MatOption, selector: "mat-option", exportAs: ["matOption"] }] });
5527
5635
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: TypeSelectComponent, decorators: [{
5528
5636
  type: Component,
5529
- args: [{ template: "<form [formGroup]=\"form\">\n <mat-form-field style=\"max-width: 7em; margin-right: 1em\">\n <mat-label i18n=\"Mathematical operator < > =\">Op\u00E9rateur</mat-label>\n <mat-select [formControl]=\"operatorCtrl\" [required]=\"true\">\n <mat-option *ngFor=\"let item of operators\" [value]=\"item.key\">\n {{ item.label }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-selection-list *ngIf=\"requireValueCtrl\" [formControl]=\"valueCtrl\">\n <mat-list-option *ngFor=\"let item of items\" [value]=\"getId(item)\" checkboxPosition=\"before\">\n {{ getDisplay(item) }}\n </mat-list-option>\n </mat-selection-list>\n</form>\n" }]
5637
+ args: [{ template: "<form [formGroup]=\"form\">\n <mat-form-field style=\"max-width: 7em; margin-right: 1em\" *ngIf=\"configuration.operators\">\n <mat-label i18n=\"Mathematical operator < > =\">Op\u00E9rateur</mat-label>\n <mat-select [formControl]=\"operatorCtrl\" [required]=\"true\">\n <mat-option *ngFor=\"let item of operators\" [value]=\"item.key\">\n {{ item.label }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-selection-list *ngIf=\"requireValueCtrl\" [formControl]=\"valueCtrl\">\n <mat-list-option *ngFor=\"let item of items\" [value]=\"getId(item)\" checkboxPosition=\"before\">\n {{ getDisplay(item) }}\n </mat-list-option>\n </mat-selection-list>\n</form>\n" }]
5530
5638
  }], ctorParameters: function () {
5531
5639
  return [{ type: undefined, decorators: [{
5532
5640
  type: Inject,
@@ -6090,7 +6198,6 @@ class TypeNumberComponent {
6090
6198
  constructor(data, dropdownRef) {
6091
6199
  this.dropdownRef = dropdownRef;
6092
6200
  this.renderedValue = new BehaviorSubject('');
6093
- this.configuration = {};
6094
6201
  this.operatorCtrl = new FormControl('equal', { nonNullable: true });
6095
6202
  this.valueCtrl = new FormControl();
6096
6203
  this.matcher = new InvalidWithValueStateMatcher$1();
@@ -6099,7 +6206,12 @@ class TypeNumberComponent {
6099
6206
  value: this.valueCtrl,
6100
6207
  });
6101
6208
  this.operators = possibleComparableOperators;
6102
- this.configuration = data.configuration || {};
6209
+ this.defaults = {
6210
+ min: null,
6211
+ max: null,
6212
+ step: null,
6213
+ };
6214
+ this.configuration = Object.assign(Object.assign({}, this.defaults), data.configuration);
6103
6215
  merge$1(this.operatorCtrl.valueChanges, this.valueCtrl.valueChanges).subscribe(() => {
6104
6216
  const rendered = this.getRenderedValue();
6105
6217
  this.renderedValue.next(rendered);
@@ -6272,7 +6384,7 @@ class NaturalHierarchicSelectorService {
6272
6384
  }
6273
6385
  countItems(node, contextFilters = null) {
6274
6386
  const configurations = this.getContextualizedConfigs(node, contextFilters, null);
6275
- const observables = configurations.map(c => c.configuration.injectedService.count(c.variablesManager));
6387
+ const observables = configurations.map(c => c.configuration.injectedService.count(c.variablesManager).pipe(first$1()));
6276
6388
  forkJoin(observables).subscribe(results => {
6277
6389
  const totalItems = results.reduce((total, length) => total + length, 0);
6278
6390
  node.expandable = totalItems > 0;
@@ -6309,12 +6421,6 @@ class NaturalHierarchicSelectorService {
6309
6421
  }
6310
6422
  return configsAndServices;
6311
6423
  }
6312
- /**
6313
- * Check configuration to return a boolean that allows or denies the selection for the given element
6314
- */
6315
- isSelectable(node) {
6316
- return !!node.node.config.selectableAtKey;
6317
- }
6318
6424
  /**
6319
6425
  * Return models matching given FlatNodes
6320
6426
  * Returns a Literal of models grouped by their configuration attribute "selectableAtKey"
@@ -7015,7 +7121,7 @@ class NaturalHierarchicSelectorComponent extends NaturalAbstractController {
7015
7121
  }
7016
7122
  else if (!this.multiple) {
7017
7123
  if (this.flatNodesSelection.isSelected(flatNode)) {
7018
- this.unselectSingleFlatNode(flatNode);
7124
+ this.unselectSingleFlatNode();
7019
7125
  }
7020
7126
  else {
7021
7127
  // If not multiple, and we want to select an element, unselect everything before to keep a single selection
@@ -7186,7 +7292,7 @@ class NaturalHierarchicSelectorComponent extends NaturalAbstractController {
7186
7292
  /**
7187
7293
  * Clear all selected and select the given node
7188
7294
  */
7189
- unselectSingleFlatNode(flatNode) {
7295
+ unselectSingleFlatNode() {
7190
7296
  this.flatNodesSelection.clear();
7191
7297
  this.selectedNodes = [];
7192
7298
  this.updateSelection(this.selectedNodes);
@@ -8125,6 +8231,17 @@ function createFileInput(document) {
8125
8231
  fileElem.type = 'file';
8126
8232
  return fileElem;
8127
8233
  }
8234
+ function isDirectory(file) {
8235
+ return file
8236
+ .slice(0, 1)
8237
+ .text()
8238
+ .then(text => {
8239
+ // Firefox will return empty string for a folder, so we must check that special case.
8240
+ // That means that any empty file will incorrectly be interpreted as a folder on all
8241
+ // browsers, but that's tolerable because there is no real use-case to upload an empty file.
8242
+ return text !== '';
8243
+ }, () => false);
8244
+ }
8128
8245
  function stopEvent(event) {
8129
8246
  event.preventDefault();
8130
8247
  event.stopPropagation();
@@ -8223,10 +8340,6 @@ class NaturalAbstractFile extends NaturalAbstractController {
8223
8340
  this.element = element;
8224
8341
  this.naturalFileService = naturalFileService;
8225
8342
  this.document = document;
8226
- this.validators = [
8227
- { name: 'accept', fn: this.acceptValidator },
8228
- { name: 'fileSize', fn: this.fileSizeValidator },
8229
- ];
8230
8343
  /**
8231
8344
  * Whether we should accept a single file or multiple files
8232
8345
  */
@@ -8323,8 +8436,7 @@ class NaturalAbstractFile extends NaturalAbstractController {
8323
8436
  valid: [],
8324
8437
  invalid: [],
8325
8438
  };
8326
- for (const file of files) {
8327
- const error = this.validate(file);
8439
+ forkJoin(files.map(file => this.validate(file).pipe(tap$1(error => {
8328
8440
  if (error) {
8329
8441
  selection.invalid.push({
8330
8442
  file: file,
@@ -8334,17 +8446,18 @@ class NaturalAbstractFile extends NaturalAbstractController {
8334
8446
  else {
8335
8447
  selection.valid.push(file);
8336
8448
  }
8337
- }
8338
- if (selection.valid.length) {
8339
- this.fileChange.emit(selection.valid[0]);
8340
- }
8341
- if (selection.valid.length || selection.invalid.length) {
8342
- this.filesChange.emit(selection);
8343
- if (this.broadcast) {
8344
- this.naturalFileService.filesChanged.next(selection);
8449
+ })))).subscribe(() => {
8450
+ if (selection.valid.length) {
8451
+ this.fileChange.emit(selection.valid[0]);
8345
8452
  }
8346
- }
8347
- this.getFileElement().value = '';
8453
+ if (selection.valid.length || selection.invalid.length) {
8454
+ this.filesChange.emit(selection);
8455
+ if (this.broadcast) {
8456
+ this.naturalFileService.filesChanged.next(selection);
8457
+ }
8458
+ }
8459
+ this.getFileElement().value = '';
8460
+ });
8348
8461
  }
8349
8462
  /**
8350
8463
  * Called when input has files
@@ -8391,18 +8504,18 @@ class NaturalAbstractFile extends NaturalAbstractController {
8391
8504
  this.handleFiles(files);
8392
8505
  }
8393
8506
  validate(file) {
8394
- for (const validator of this.validators) {
8395
- if (!validator.fn.call(this, file)) {
8396
- return validator.name;
8507
+ return forkJoin({
8508
+ accept: of(acceptType(this.accept, file.type, file.name)),
8509
+ fileSize: of(!(this.maxSize && file.size > this.maxSize)),
8510
+ directory: isDirectory(file),
8511
+ }).pipe(map$1(result => {
8512
+ for (const [key, value] of Object.entries(result)) {
8513
+ if (!value) {
8514
+ return key;
8515
+ }
8397
8516
  }
8398
- }
8399
- return null;
8400
- }
8401
- acceptValidator(item) {
8402
- return acceptType(this.accept, item.type, item.name);
8403
- }
8404
- fileSizeValidator(item) {
8405
- return !(this.maxSize && item.size > this.maxSize);
8517
+ return null;
8518
+ }));
8406
8519
  }
8407
8520
  }
8408
8521
  NaturalAbstractFile.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalAbstractFile, deps: [{ token: i0.ElementRef }, { token: NaturalFileService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
@@ -8760,9 +8873,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
8760
8873
  */
8761
8874
 
8762
8875
  class NaturalFixedButtonDetailComponent {
8763
- constructor() {
8876
+ constructor(route) {
8877
+ this.canChange = true;
8878
+ this.isCreation = false;
8764
8879
  this.create = new EventEmitter();
8765
8880
  this.delete = new EventEmitter();
8881
+ route.params.subscribe(() => (this.canChange = true));
8882
+ }
8883
+ get model() {
8884
+ return this._model;
8885
+ }
8886
+ set model(value) {
8887
+ this._model = value;
8888
+ if (this.canChange) {
8889
+ this.isCreation = !this._model.id;
8890
+ }
8766
8891
  }
8767
8892
  clickCreate() {
8768
8893
  if (this.form.enabled) {
@@ -8775,12 +8900,12 @@ class NaturalFixedButtonDetailComponent {
8775
8900
  }
8776
8901
  }
8777
8902
  }
8778
- NaturalFixedButtonDetailComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8779
- NaturalFixedButtonDetailComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: NaturalFixedButtonDetailComponent, selector: "natural-fixed-button-detail", inputs: { model: "model", form: "form" }, outputs: { create: "create", delete: "delete" }, ngImport: i0, template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"!model.id\"\n [disabled]=\"form.disabled\"\n [color]=\"form.valid ? 'accent' : 'warn'\"\n class=\"detail-speed-dial\"\n icon=\"save\"\n></natural-fixed-button>\n\n<natural-fixed-button\n (click)=\"clickDelete()\"\n *ngIf=\"model.id && (!model.permissions || model.permissions.delete)\"\n [disabled]=\"form.disabled\"\n class=\"detail-speed-dial\"\n color=\"warn\"\n icon=\"delete_forever\"\n i18n-matTooltip\n matTooltip=\"Supprimer d\u00E9finitivement\"\n matTooltipPosition=\"left\"\n></natural-fixed-button>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: NaturalFixedButtonComponent, selector: "natural-fixed-button", inputs: ["icon", "link", "color", "disabled"] }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
8903
+ NaturalFixedButtonDetailComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, deps: [{ token: i2$1.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
8904
+ NaturalFixedButtonDetailComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: NaturalFixedButtonDetailComponent, selector: "natural-fixed-button-detail", inputs: { model: "model", form: "form" }, outputs: { create: "create", delete: "delete" }, ngImport: i0, template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"isCreation\"\n [disabled]=\"form.disabled\"\n [color]=\"form.valid ? 'accent' : 'warn'\"\n class=\"detail-speed-dial\"\n icon=\"save\"\n></natural-fixed-button>\n\n<natural-fixed-button\n (click)=\"clickDelete()\"\n *ngIf=\"!isCreation && (!model.permissions || model.permissions.delete)\"\n [disabled]=\"form.disabled\"\n class=\"detail-speed-dial\"\n color=\"warn\"\n icon=\"delete_forever\"\n i18n-matTooltip\n matTooltip=\"Supprimer d\u00E9finitivement\"\n matTooltipPosition=\"left\"\n></natural-fixed-button>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: NaturalFixedButtonComponent, selector: "natural-fixed-button", inputs: ["icon", "link", "color", "disabled"] }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
8780
8905
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, decorators: [{
8781
8906
  type: Component,
8782
- args: [{ selector: 'natural-fixed-button-detail', template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"!model.id\"\n [disabled]=\"form.disabled\"\n [color]=\"form.valid ? 'accent' : 'warn'\"\n class=\"detail-speed-dial\"\n icon=\"save\"\n></natural-fixed-button>\n\n<natural-fixed-button\n (click)=\"clickDelete()\"\n *ngIf=\"model.id && (!model.permissions || model.permissions.delete)\"\n [disabled]=\"form.disabled\"\n class=\"detail-speed-dial\"\n color=\"warn\"\n icon=\"delete_forever\"\n i18n-matTooltip\n matTooltip=\"Supprimer d\u00E9finitivement\"\n matTooltipPosition=\"left\"\n></natural-fixed-button>\n" }]
8783
- }], propDecorators: { model: [{
8907
+ args: [{ selector: 'natural-fixed-button-detail', template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"isCreation\"\n [disabled]=\"form.disabled\"\n [color]=\"form.valid ? 'accent' : 'warn'\"\n class=\"detail-speed-dial\"\n icon=\"save\"\n></natural-fixed-button>\n\n<natural-fixed-button\n (click)=\"clickDelete()\"\n *ngIf=\"!isCreation && (!model.permissions || model.permissions.delete)\"\n [disabled]=\"form.disabled\"\n class=\"detail-speed-dial\"\n color=\"warn\"\n icon=\"delete_forever\"\n i18n-matTooltip\n matTooltip=\"Supprimer d\u00E9finitivement\"\n matTooltipPosition=\"left\"\n></natural-fixed-button>\n" }]
8908
+ }], ctorParameters: function () { return [{ type: i2$1.ActivatedRoute }]; }, propDecorators: { model: [{
8784
8909
  type: Input
8785
8910
  }], form: [{
8786
8911
  type: Input
@@ -10916,5 +11041,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
10916
11041
  * Generated bundle index. Do not edit.
10917
11042
  */
10918
11043
 
10919
- export { AvatarComponent, AvatarService, FileComponent, IconsConfigService, LOCAL_STORAGE, NATURAL_DROPDOWN_DATA, NATURAL_SEO_CONFIG, NaturalAbstractController, NaturalAbstractDetail, NaturalAbstractEditableList, NaturalAbstractList, NaturalAbstractModelService, NaturalAbstractNavigableList, NaturalAbstractPanel, NaturalAlertModule, NaturalAlertService, NaturalAvatarModule, NaturalCapitalizePipe, NaturalColumnsPickerColumnDirective, NaturalColumnsPickerComponent, NaturalColumnsPickerModule, NaturalCommonModule, NaturalConfirmComponent, NaturalDataSource, NaturalDetailHeaderComponent, NaturalDetailHeaderModule, NaturalDialogTriggerComponent, NaturalDialogTriggerModule, NaturalDropdownComponentsModule, NaturalDropdownRef, NaturalEllipsisPipe, NaturalEnumPipe, NaturalEnumService, NaturalErrorHandler, NaturalErrorModule, NaturalFileDropDirective, NaturalFileModule, NaturalFileSelectDirective, NaturalFileService, NaturalFixedButtonComponent, NaturalFixedButtonDetailComponent, NaturalFixedButtonDetailModule, NaturalFixedButtonModule, NaturalHierarchicSelectorComponent, NaturalHierarchicSelectorDialogComponent, NaturalHierarchicSelectorDialogService, NaturalHierarchicSelectorModule, NaturalHierarchicSelectorService, NaturalHttpPrefixDirective, NaturalIconComponent, NaturalIconModule, NaturalLinkMutationService, NaturalLinkableTabDirective, NaturalLoggerConfigExtra, NaturalLoggerConfigUrl, NaturalMatomoModule, NaturalMatomoService, NaturalMemoryStorage, NaturalPanelsComponent, NaturalPanelsModule, NaturalPanelsService, NaturalPersistenceService, NaturalQueryVariablesManager, NaturalRelationsComponent, NaturalRelationsModule, NaturalSearchComponent, NaturalSearchModule, NaturalSelectComponent, NaturalSelectEnumComponent, NaturalSelectHierarchicComponent, NaturalSelectModule, NaturalSeoService, NaturalSidenavComponent, NaturalSidenavContainerComponent, NaturalSidenavContentComponent, NaturalSidenavModule, NaturalSidenavService, NaturalSidenavStackService, NaturalSrcDensityDirective, NaturalStampComponent, NaturalStampModule, NaturalSwissDatePipe, NaturalSwissParsingDateAdapter, NaturalTableButtonComponent, NaturalTableButtonModule, PanelsHooksConfig, SESSION_STORAGE, SortingOrder, TypeDateComponent, TypeDateRangeComponent, TypeHierarchicSelectorComponent, TypeNaturalSelectComponent, TypeNumberComponent, TypeSelectComponent, TypeTextComponent, available, cancellableTimeout, cleanSameValues, collectErrors, copyToClipboard, debug, decimal, deepFreeze, deliverableEmail, ensureHttpPrefix, fallbackIfNoOpenedPanels, formatIsoDate, formatIsoDateTime, fromUrl, getForegroundColor, hasFilesAndProcessDate, ifValid, integer, localStorageFactory, localStorageProvider, lowerCaseFirstLetter, makePlural, memoryLocalStorageProvider, memorySessionStorageProvider, mergeOverrideArray, money, naturalPanelsUrlMatcher, relationsToIds, replaceObjectKeepingReference, replaceOperatorByField, replaceOperatorByName, sessionStorageFactory, sessionStorageProvider, toGraphQLDoctrineFilter, toNavigationParameters, toUrl, unique, upperCaseFirstLetter, urlValidator, validTlds, validateAllFormControls, wrapLike };
11044
+ export { AvatarComponent, AvatarService, FileComponent, IconsConfigService, LOCAL_STORAGE, NATURAL_DROPDOWN_DATA, NATURAL_SEO_CONFIG, NaturalAbstractController, NaturalAbstractDetail, NaturalAbstractEditableList, NaturalAbstractList, NaturalAbstractModelService, NaturalAbstractNavigableList, NaturalAbstractPanel, NaturalAlertModule, NaturalAlertService, NaturalAvatarModule, NaturalCapitalizePipe, NaturalColumnsPickerColumnDirective, NaturalColumnsPickerComponent, NaturalColumnsPickerModule, NaturalCommonModule, NaturalConfirmComponent, NaturalDataSource, NaturalDebounceService, NaturalDetailHeaderComponent, NaturalDetailHeaderModule, NaturalDialogTriggerComponent, NaturalDialogTriggerModule, NaturalDropdownComponentsModule, NaturalDropdownRef, NaturalEllipsisPipe, NaturalEnumPipe, NaturalEnumService, NaturalErrorHandler, NaturalErrorModule, NaturalFileDropDirective, NaturalFileModule, NaturalFileSelectDirective, NaturalFileService, NaturalFixedButtonComponent, NaturalFixedButtonDetailComponent, NaturalFixedButtonDetailModule, NaturalFixedButtonModule, NaturalHierarchicSelectorComponent, NaturalHierarchicSelectorDialogComponent, NaturalHierarchicSelectorDialogService, NaturalHierarchicSelectorModule, NaturalHierarchicSelectorService, NaturalHttpPrefixDirective, NaturalIconComponent, NaturalIconModule, NaturalLinkMutationService, NaturalLinkableTabDirective, NaturalLoggerConfigExtra, NaturalLoggerConfigUrl, NaturalMatomoModule, NaturalMatomoService, NaturalMemoryStorage, NaturalPanelsComponent, NaturalPanelsModule, NaturalPanelsService, NaturalPersistenceService, NaturalQueryVariablesManager, NaturalRelationsComponent, NaturalRelationsModule, NaturalSearchComponent, NaturalSearchModule, NaturalSelectComponent, NaturalSelectEnumComponent, NaturalSelectHierarchicComponent, NaturalSelectModule, NaturalSeoService, NaturalSidenavComponent, NaturalSidenavContainerComponent, NaturalSidenavContentComponent, NaturalSidenavModule, NaturalSidenavService, NaturalSidenavStackService, NaturalSrcDensityDirective, NaturalStampComponent, NaturalStampModule, NaturalSwissDatePipe, NaturalSwissParsingDateAdapter, NaturalTableButtonComponent, NaturalTableButtonModule, PanelsHooksConfig, SESSION_STORAGE, SortingOrder, TypeDateComponent, TypeDateRangeComponent, TypeHierarchicSelectorComponent, TypeNaturalSelectComponent, TypeNumberComponent, TypeSelectComponent, TypeTextComponent, available, cancellableTimeout, cleanSameValues, collectErrors, copyToClipboard, debug, decimal, deepFreeze, deliverableEmail, ensureHttpPrefix, fallbackIfNoOpenedPanels, formatIsoDate, formatIsoDateTime, fromUrl, getForegroundColor, hasFilesAndProcessDate, ifValid, integer, localStorageFactory, localStorageProvider, lowerCaseFirstLetter, makePlural, memoryLocalStorageProvider, memorySessionStorageProvider, mergeOverrideArray, money, naturalPanelsUrlMatcher, relationsToIds, replaceObjectKeepingReference, replaceOperatorByField, replaceOperatorByName, sessionStorageFactory, sessionStorageProvider, toGraphQLDoctrineFilter, toNavigationParameters, toUrl, unique, upperCaseFirstLetter, urlValidator, validTlds, validateAllFormControls, wrapLike };
10920
11045
  //# sourceMappingURL=ecodev-natural.mjs.map