@sumaris-net/ngx-components 0.25.17 → 0.26.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 (30) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +108 -68
  2. package/bundles/sumaris-net.ngx-components.umd.js.map +1 -1
  3. package/bundles/sumaris-net.ngx-components.umd.min.js +1 -1
  4. package/bundles/sumaris-net.ngx-components.umd.min.js.map +1 -1
  5. package/doc/changelog.md +6 -0
  6. package/esm2015/src/app/core/account/account.js +5 -7
  7. package/esm2015/src/app/core/auth/form/form-auth.js +6 -7
  8. package/esm2015/src/app/core/form/entity-editor.class.js +16 -6
  9. package/esm2015/src/app/core/form/form.class.js +29 -12
  10. package/esm2015/src/app/core/form/list.form.js +2 -2
  11. package/esm2015/src/app/core/form/properties.form.js +2 -3
  12. package/esm2015/src/app/core/settings/settings.page.js +5 -7
  13. package/esm2015/src/app/core/table/entities-table-datasource.class.js +5 -7
  14. package/esm2015/src/app/core/table/table.class.js +25 -19
  15. package/esm2015/src/app/shared/pipes/form.pipes.js +1 -1
  16. package/esm2015/src/app/shared/validator/form-error-adapter.class.js +3 -3
  17. package/esm2015/src/app/shared/validator/validators.js +8 -9
  18. package/fesm2015/sumaris-net.ngx-components.js +88 -64
  19. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/app/core/account/account.d.ts +2 -5
  22. package/src/app/core/auth/form/form-auth.d.ts +2 -4
  23. package/src/app/core/form/entity-editor.class.d.ts +10 -2
  24. package/src/app/core/form/form.class.d.ts +15 -12
  25. package/src/app/core/form/properties.form.d.ts +0 -1
  26. package/src/app/core/settings/settings.page.d.ts +2 -5
  27. package/src/app/core/table/table.class.d.ts +5 -7
  28. package/src/app/shared/pipes/form.pipes.d.ts +2 -2
  29. package/src/app/shared/validator/form-error-adapter.class.d.ts +6 -6
  30. package/sumaris-net.ngx-components.metadata.json +1 -1
@@ -2700,23 +2700,22 @@ class SharedFormGroupValidators {
2700
2700
  };
2701
2701
  }
2702
2702
  static dateMaxDuration(startDateField, endDateField, maxDuration, durationUnit) {
2703
+ const maxDurationError = { dateMaxDuration: true };
2703
2704
  return (group) => {
2704
- const endField = group.get(endDateField);
2705
2705
  const startDate = fromDateISOString(group.get(startDateField).value);
2706
+ const endField = group.get(endDateField);
2706
2707
  const endDate = fromDateISOString(endField.value);
2707
2708
  if (isNotNil(startDate) && isNotNil(endDate) && Math.abs(startDate.diff(endDate, durationUnit)) > maxDuration) {
2709
+ console.log('TODO error !');
2708
2710
  // Update end field
2709
- const endFieldErrors = endField.errors || {};
2710
- endFieldErrors['dateMaxDuration'] = true;
2711
- endField.setErrors(endFieldErrors);
2712
2711
  endField.markAsTouched({ onlySelf: true });
2712
+ endField.markAsPending();
2713
+ endField.setErrors(Object.assign(Object.assign({}, endField.errors), maxDurationError));
2713
2714
  // Return the error (should be apply to the parent form)
2714
- return { dateMaxDuration: true };
2715
+ return maxDurationError;
2715
2716
  }
2716
2717
  // OK: remove the existing on the end field
2717
- else {
2718
- SharedValidators.clearError(endField, 'dateMaxDuration');
2719
- }
2718
+ SharedValidators.clearError(endField, 'dateMaxDuration');
2720
2719
  return null;
2721
2720
  };
2722
2721
  }
@@ -3504,8 +3503,8 @@ class FormErrorAdapter {
3504
3503
  }, "");
3505
3504
  }
3506
3505
  translateControlPath(path, opts) {
3507
- if (opts === null || opts === void 0 ? void 0 : opts.pathTranslateService) {
3508
- return opts === null || opts === void 0 ? void 0 : opts.pathTranslateService.translateControlPath(path);
3506
+ if (opts === null || opts === void 0 ? void 0 : opts.controlPathTranslator) {
3507
+ return opts === null || opts === void 0 ? void 0 : opts.controlPathTranslator.translateControlPath(path);
3509
3508
  }
3510
3509
  const i18nKey = (opts && opts.i18nPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
3511
3510
  return this.translate.instant(i18nKey);
@@ -16464,20 +16463,21 @@ RegisterModal.propDecorators = {
16464
16463
 
16465
16464
  // eslint-disable-next-line @angular-eslint/directive-class-suffix
16466
16465
  class AppForm {
16467
- constructor(dateAdapter, form, settings) {
16468
- this.dateAdapter = dateAdapter;
16469
- this.settings = settings;
16470
- this._subscription = new Subscription();
16466
+ constructor(injector, form) {
16467
+ this.error = null;
16471
16468
  this._enable = false;
16472
16469
  this._loading = true;
16473
- this.error = null;
16470
+ this.i18nFieldPrefix = null;
16471
+ this._subscription = new Subscription();
16474
16472
  this.debug = false;
16475
16473
  this.onCancel = new EventEmitter();
16476
16474
  this.onSubmit = new EventEmitter();
16477
16475
  if (form)
16478
16476
  this.setForm(form);
16479
- this.autocompleteHelper = new MatAutocompleteConfigHolder(settings && {
16480
- getUserAttributes: (a, b) => settings.getFieldDisplayAttributes(a, b)
16477
+ this.settings = injector.get(LocalSettingsService);
16478
+ this.errorTranslator = injector.get(FormErrorAdapter);
16479
+ this.autocompleteHelper = new MatAutocompleteConfigHolder(this.settings && {
16480
+ getUserAttributes: (a, b) => this.settings.getFieldDisplayAttributes(a, b)
16481
16481
  });
16482
16482
  this.autocompleteFields = this.autocompleteHelper.fields;
16483
16483
  }
@@ -16537,6 +16537,9 @@ class AppForm {
16537
16537
  }
16538
16538
  ngOnInit() {
16539
16539
  this._enable ? this.enable() : this.disable();
16540
+ this.errorTranslatorOptions = this.errorTranslatorOptions || {
16541
+ controlPathTranslator: this
16542
+ };
16540
16543
  }
16541
16544
  ngOnDestroy() {
16542
16545
  this._subscription.unsubscribe();
@@ -16645,7 +16648,18 @@ class AppForm {
16645
16648
  if (!opts || opts.emitEvent !== false)
16646
16649
  this.markForCheck();
16647
16650
  }
16651
+ translateControlPath(path) {
16652
+ return this.getFieldName(path);
16653
+ }
16648
16654
  /* -- protected methods -- */
16655
+ getFormError(form, opts) {
16656
+ if (!form || !this.errorTranslator)
16657
+ return undefined;
16658
+ return this.errorTranslator.translateErrors(this.form, Object.assign({ controlPathTranslator: this }, opts));
16659
+ }
16660
+ getFieldName(path) {
16661
+ return (this.i18nFieldPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
16662
+ }
16649
16663
  registerSubscription(sub) {
16650
16664
  return this._subscription.add(sub);
16651
16665
  }
@@ -16661,25 +16675,25 @@ AppForm.decorators = [
16661
16675
  { type: Directive }
16662
16676
  ];
16663
16677
  AppForm.ctorParameters = () => [
16664
- { type: undefined },
16665
- { type: FormGroup },
16666
- { type: LocalSettingsService }
16678
+ { type: Injector },
16679
+ { type: FormGroup }
16667
16680
  ];
16668
16681
  AppForm.propDecorators = {
16669
16682
  debug: [{ type: Input }],
16670
16683
  tabindex: [{ type: Input }],
16684
+ errorTranslatorOptions: [{ type: Input }],
16671
16685
  form: [{ type: Input }],
16672
16686
  onCancel: [{ type: Output }],
16673
16687
  onSubmit: [{ type: Output }]
16674
16688
  };
16675
16689
 
16676
16690
  class AuthForm extends AppForm {
16677
- constructor(platform, dateAdapter, formBuilder, settings, configService, modalCtrl, network, cd, environment) {
16678
- super(dateAdapter, formBuilder.group({
16691
+ constructor(injector, platform, formBuilder, settings, configService, modalCtrl, network, cd, environment) {
16692
+ super(injector, formBuilder.group({
16679
16693
  username: [null, Validators.required],
16680
16694
  password: [null, Validators.required],
16681
16695
  offline: [network.offline]
16682
- }), settings);
16696
+ }));
16683
16697
  this.configService = configService;
16684
16698
  this.modalCtrl = modalCtrl;
16685
16699
  this.network = network;
@@ -16771,8 +16785,8 @@ AuthForm.decorators = [
16771
16785
  },] }
16772
16786
  ];
16773
16787
  AuthForm.ctorParameters = () => [
16788
+ { type: Injector },
16774
16789
  { type: PlatformService },
16775
- { type: DateAdapter },
16776
16790
  { type: FormBuilder },
16777
16791
  { type: LocalSettingsService },
16778
16792
  { type: ConfigService },
@@ -17368,9 +17382,8 @@ AccountValidatorService.ctorParameters = () => [
17368
17382
  ];
17369
17383
 
17370
17384
  class AccountPage extends AppForm {
17371
- constructor(dateAdapter, router, formBuilder, accountService, validatorService, settingsValidatorService, translate, settings, cd, locales) {
17372
- super(dateAdapter, validatorService.getFormGroup(accountService.account), settings);
17373
- this.dateAdapter = dateAdapter;
17385
+ constructor(injector, router, formBuilder, accountService, validatorService, settingsValidatorService, translate, settings, cd, locales) {
17386
+ super(injector, validatorService.getFormGroup(accountService.account));
17374
17387
  this.router = router;
17375
17388
  this.formBuilder = formBuilder;
17376
17389
  this.accountService = accountService;
@@ -17535,7 +17548,7 @@ AccountPage.decorators = [
17535
17548
  },] }
17536
17549
  ];
17537
17550
  AccountPage.ctorParameters = () => [
17538
- { type: DateAdapter },
17551
+ { type: Injector },
17539
17552
  { type: Router },
17540
17553
  { type: FormBuilder },
17541
17554
  { type: AccountService },
@@ -17902,9 +17915,8 @@ LocalSettingsValidatorService.ctorParameters = () => [
17902
17915
  ];
17903
17916
 
17904
17917
  class SettingsPage extends AppForm {
17905
- constructor(dateAdapter, platform, router, validatorService, alertCtrl, translate, formBuilder, accountService, settings, cd, network, locales) {
17906
- super(dateAdapter, validatorService.getFormGroup(), settings);
17907
- this.dateAdapter = dateAdapter;
17918
+ constructor(injector, platform, router, validatorService, alertCtrl, translate, formBuilder, accountService, settings, cd, network, locales) {
17919
+ super(injector, validatorService.getFormGroup());
17908
17920
  this.platform = platform;
17909
17921
  this.router = router;
17910
17922
  this.validatorService = validatorService;
@@ -18170,7 +18182,7 @@ SettingsPage.decorators = [
18170
18182
  },] }
18171
18183
  ];
18172
18184
  SettingsPage.ctorParameters = () => [
18173
- { type: DateAdapter },
18185
+ { type: Injector },
18174
18186
  { type: PlatformService },
18175
18187
  { type: Router },
18176
18188
  { type: LocalSettingsValidatorService },
@@ -18186,8 +18198,7 @@ SettingsPage.ctorParameters = () => [
18186
18198
 
18187
18199
  class AppPropertiesForm extends AppForm {
18188
18200
  constructor(injector, formBuilder, dateAdapter, settings, cd, formGroupDir) {
18189
- super(dateAdapter, null, settings);
18190
- this.injector = injector;
18201
+ super(injector, null);
18191
18202
  this.formBuilder = formBuilder;
18192
18203
  this.dateAdapter = dateAdapter;
18193
18204
  this.settings = settings;
@@ -18299,7 +18310,7 @@ AppPropertiesForm.propDecorators = {
18299
18310
 
18300
18311
  class AppListForm extends AppForm {
18301
18312
  constructor(injector, formBuilder, dateAdapter, settings, cd, formGroupDir) {
18302
- super(dateAdapter, null, settings);
18313
+ super(injector, null);
18303
18314
  this.injector = injector;
18304
18315
  this.formBuilder = formBuilder;
18305
18316
  this.dateAdapter = dateAdapter;
@@ -20058,12 +20069,10 @@ class EntitiesTableDataSource extends TableDataSource {
20058
20069
  this._stopWatching$.next();
20059
20070
  }
20060
20071
  waitIdle(debounceTimeMs) {
20061
- return __awaiter(this, void 0, void 0, function* () {
20062
- return firstFalsePromise(this.loadingSubject
20063
- .asObservable()
20064
- .pipe(debounceTime(debounceTimeMs || 100) // if not started yet, wait
20065
- ));
20066
- });
20072
+ return firstFalsePromise(this.loadingSubject
20073
+ .asObservable()
20074
+ .pipe(debounceTime(debounceTimeMs || 100) // if not started yet, wait
20075
+ ));
20067
20076
  }
20068
20077
  confirmCreate(row) {
20069
20078
  if (!super.confirmCreate(row))
@@ -20492,7 +20501,7 @@ class AppTable {
20492
20501
  this.saveBeforeSort = toBoolean(this.saveBeforeSort, !this.readOnly); // force to false when readonly
20493
20502
  this.saveBeforeFilter = toBoolean(this.saveBeforeFilter, !this.readOnly); // force to false when readonly
20494
20503
  this.keepEditedRowOnSave = toBoolean(this.keepEditedRowOnSave, this.inlineEdition);
20495
- this.translateErrorOptions = this.translateErrorOptions || { separator: ', ', pathTranslateService: this }; // Can be override in subclasses constructors
20504
+ this.errorTranslatorOptions = this.errorTranslatorOptions || { separator: ', ', controlPathTranslator: this }; // Can be override in subclasses constructors
20496
20505
  // Check ask user confirmation is possible
20497
20506
  if (this.confirmBeforeDelete && !this.alertCtrl)
20498
20507
  throw Error('Missing \'alertCtrl\' or \'injector\' in component\'s constructor.');
@@ -20698,7 +20707,7 @@ class AppTable {
20698
20707
  if (previousRow && (previousRow.id === -1) && ((_a = previousRow.validator) === null || _a === void 0 ? void 0 : _a.invalid) && !((_b = previousRow.validator) === null || _b === void 0 ? void 0 : _b.dirty)) {
20699
20708
  this.deleteNewRow(event, previousRow);
20700
20709
  // Wait deletion is done, then edit previous row (by id, because of reloading)
20701
- firstFalsePromise(this.loadingSubject)
20710
+ this.waitIdle()
20702
20711
  .then(() => this.editRowById(event, row.id, { focusColumn: this.lastUserColumn }));
20703
20712
  return true;
20704
20713
  }
@@ -20985,31 +20994,34 @@ class AppTable {
20985
20994
  });
20986
20995
  }
20987
20996
  selectRowById(id) {
20988
- if (id === undefined)
20989
- return Promise.resolve(false);
20990
- return this.dataSource.waitIdle()
20991
- .then(() => this.dataSource.getRow(id))
20992
- .then(row => row && this.clickRow(null, row));
20997
+ return __awaiter(this, void 0, void 0, function* () {
20998
+ if (id === undefined)
20999
+ return false;
21000
+ yield this.waitIdle();
21001
+ const row = this.dataSource.getRow(id);
21002
+ return this.clickRow(null, row);
21003
+ });
20993
21004
  }
20994
21005
  /**
20995
21006
  * Try to select row by data. Will use dataEquals() (that call EntityUtils.equals()) to find same row's data
20996
21007
  * @param data
20997
21008
  */
20998
21009
  selectRowByData(data) {
20999
- if (data === undefined)
21000
- return Promise.resolve(false);
21001
- return this.dataSource.waitIdle()
21002
- .then(() => this.dataSource.getRows())
21003
- .then(rows => rows.find(row => this.equals(row.currentData, data)))
21004
- .then(row => row && this.clickRow(null, row));
21010
+ return __awaiter(this, void 0, void 0, function* () {
21011
+ if (data === undefined)
21012
+ return Promise.resolve(false);
21013
+ yield this.waitIdle();
21014
+ const row = ((yield this.dataSource.getRows()) || [])
21015
+ .find(row => this.equals(row.currentData, data));
21016
+ return row && this.clickRow(null, row);
21017
+ });
21005
21018
  }
21006
21019
  clickRow(event, row) {
21007
- var _a;
21008
21020
  if (this.loading) {
21009
21021
  // Wait while loading, and loop
21010
21022
  if (this.debug)
21011
21023
  console.debug("[table] Waiting before apply clickRow() (datasource is busy)...");
21012
- (_a = this.dataSource) === null || _a === void 0 ? void 0 : _a.waitIdle().then(() => this.clickRow(event, row));
21024
+ this.waitIdle().then(() => this.clickRow(event, row));
21013
21025
  return false;
21014
21026
  }
21015
21027
  // DEBUG
@@ -21035,6 +21047,9 @@ class AppTable {
21035
21047
  moveRow(id, direction) {
21036
21048
  this.dataSource.move(id, direction);
21037
21049
  }
21050
+ waitIdle() {
21051
+ return firstFalsePromise(this.loadingSubject);
21052
+ }
21038
21053
  openSelectColumnsModal(event) {
21039
21054
  return __awaiter(this, void 0, void 0, function* () {
21040
21055
  // Copy current columns (deep copy)
@@ -21067,7 +21082,7 @@ class AppTable {
21067
21082
  // When target wait for a complete (e.g. IonRefresher)
21068
21083
  if ((event === null || event === void 0 ? void 0 : event.target) && event.target.complete) {
21069
21084
  setTimeout(() => __awaiter(this, void 0, void 0, function* () {
21070
- yield firstFalsePromise(this.loadingSubject);
21085
+ yield this.waitIdle();
21071
21086
  event.target.complete();
21072
21087
  }));
21073
21088
  }
@@ -21391,7 +21406,7 @@ class AppTable {
21391
21406
  return this._autocompleteConfigHolder.add(fieldName, options);
21392
21407
  }
21393
21408
  getI18nColumnName(columnName) {
21394
- return this.i18nColumnPrefix + changeCaseToUnderscore(columnName).toUpperCase();
21409
+ return (this.i18nColumnPrefix || '') + changeCaseToUnderscore(columnName).toUpperCase();
21395
21410
  }
21396
21411
  generateTableId() {
21397
21412
  return this.location.path(true).replace(/[?].*$/g, '').replace(/\/[\d]+/g, '_id') + '_' + this.constructor.name;
@@ -21494,7 +21509,7 @@ class AppTable {
21494
21509
  row = row || this.editedRow;
21495
21510
  if (!row || !this.formErrorAdapter)
21496
21511
  return undefined;
21497
- return this.formErrorAdapter.translateErrors(row.validator, Object.assign(Object.assign({}, this.translateErrorOptions), opts));
21512
+ return this.formErrorAdapter.translateErrors(row.validator, Object.assign(Object.assign({}, this.errorTranslatorOptions), opts));
21498
21513
  }
21499
21514
  setError(value, opts) {
21500
21515
  if (this.errorSubject.value !== value) {
@@ -22215,6 +22230,7 @@ class AppEntityEditor extends AppTabEditor {
22215
22230
  // Default options
22216
22231
  enableListenChanges: (injector.get(ENVIRONMENT).listenRemoteChanges === true), pathIdAttribute: 'id', autoLoad: true, autoUpdateRoute: true, i18nPrefix: '' }, options);
22217
22232
  this.settings = injector.get(LocalSettingsService);
22233
+ this.formErrorAdapter = injector.get(FormErrorAdapter);
22218
22234
  this.cd = injector.get(ChangeDetectorRef);
22219
22235
  this.dateFormat = injector.get(DateFormatPipe);
22220
22236
  this.toastController = injector.get(ToastController);
@@ -22294,7 +22310,6 @@ class AppEntityEditor extends AppTabEditor {
22294
22310
  /**
22295
22311
  * Load data from the snapshot route
22296
22312
  *
22297
- * @param route
22298
22313
  * @protected
22299
22314
  */
22300
22315
  loadFromRoute() {
@@ -22383,7 +22398,7 @@ class AppEntityEditor extends AppTabEditor {
22383
22398
  const idChanged = isNotNil(data.id)
22384
22399
  && this.previousDataId !== undefined // Ignore if first loading (=undefined)
22385
22400
  && this.previousDataId !== data.id;
22386
- opts = Object.assign({ updateRoute: this._autoUpdateRoute && idChanged && !this.loading, openTabIndex: this._autoOpenNextTab && idChanged && isNil(this.previousDataId) && this.selectedTabIndex + 1 < this.tabCount ? this.selectedTabIndex + 1 : undefined }, opts);
22401
+ opts = Object.assign({ updateRoute: this._autoUpdateRoute && idChanged && !this.loading, openTabIndex: this._autoOpenNextTab && idChanged && this.computeNextTabIndex() }, opts);
22387
22402
  this.data = data;
22388
22403
  this.previousDataId = data.id || null;
22389
22404
  const promiseOrVoid = this.setValue(data);
@@ -22482,7 +22497,13 @@ class AppEntityEditor extends AppTabEditor {
22482
22497
  return this.goBack();
22483
22498
  });
22484
22499
  }
22485
- save(event, options) {
22500
+ /**
22501
+ * Save the editor, by calling the dataService.save().
22502
+ * Ensure that editor if valid. If not, display an error
22503
+ * @param event
22504
+ * @param opts
22505
+ */
22506
+ save(event, opts) {
22486
22507
  return __awaiter(this, void 0, void 0, function* () {
22487
22508
  if (this.loading || this.saving) {
22488
22509
  console.debug('[data-editor] Skip save: editor is busy (loading or saving)');
@@ -22511,10 +22532,10 @@ class AppEntityEditor extends AppTabEditor {
22511
22532
  const data = yield this.getValue();
22512
22533
  this.disable();
22513
22534
  // Save form
22514
- const updatedData = yield this.dataService.save(data, options);
22535
+ const updatedData = yield this.dataService.save(data, opts);
22515
22536
  yield this.onEntitySaved(updatedData);
22516
22537
  // Update the view (e.g metadata)
22517
- yield this.updateView(updatedData, options);
22538
+ yield this.updateView(updatedData, opts);
22518
22539
  // Subscribe to remote changes
22519
22540
  if (!this.hasRemoteListener)
22520
22541
  this.startListenRemoteChanges();
@@ -22639,6 +22660,9 @@ class AppEntityEditor extends AppTabEditor {
22639
22660
  this.error = userMessage;
22640
22661
  }
22641
22662
  /* -- protected methods -- */
22663
+ computeNextTabIndex() {
22664
+ return this.selectedTabIndex + 1 < this.tabCount ? this.selectedTabIndex + 1 : undefined;
22665
+ }
22642
22666
  unload() {
22643
22667
  return __awaiter(this, void 0, void 0, function* () {
22644
22668
  this.form.reset();