@sumaris-net/ngx-components 1.21.0-beta9 → 1.21.2

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 (86) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +594 -1227
  2. package/bundles/sumaris-net.ngx-components.umd.js.map +1 -1
  3. package/bundles/sumaris-net.ngx-components.umd.min.js +2 -2
  4. package/bundles/sumaris-net.ngx-components.umd.min.js.map +1 -1
  5. package/doc/changelog.md +12 -0
  6. package/esm2015/public_api.js +3 -8
  7. package/esm2015/src/app/core/account/account.js +2 -2
  8. package/esm2015/src/app/core/auth/form/form-auth.js +4 -2
  9. package/esm2015/src/app/core/form/editor.class.js +64 -20
  10. package/esm2015/src/app/core/form/entity-editor-modal.class.js +20 -15
  11. package/esm2015/src/app/core/form/entity-editor.class.js +21 -12
  12. package/esm2015/src/app/core/form/form.class.js +68 -35
  13. package/esm2015/src/app/core/graphql/graphql.service.js +5 -3
  14. package/esm2015/src/app/core/icon/icon.component.js +2 -5
  15. package/esm2015/src/app/core/menu/menu.component.js +2 -2
  16. package/esm2015/src/app/core/services/local-settings.service.js +2 -2
  17. package/esm2015/src/app/core/table/table.class.js +26 -27
  18. package/esm2015/src/app/shared/functions.js +1 -60
  19. package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +5 -4
  20. package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +10 -7
  21. package/esm2015/src/app/shared/material/chips/material.chips.js +3 -2
  22. package/esm2015/src/app/shared/material/chips/testing/chips.test.js +3 -2
  23. package/esm2015/src/app/shared/material/datetime/material.date.js +3 -2
  24. package/esm2015/src/app/shared/material/datetime/material.datetime.js +3 -2
  25. package/esm2015/src/app/shared/observables.js +13 -7
  26. package/esm2015/src/app/shared/pipes/arrays.pipe.js +1 -1
  27. package/esm2015/src/app/shared/pipes/form.pipes.js +4 -6
  28. package/esm2015/src/app/shared/pipes/highlight.pipe.js +4 -4
  29. package/esm2015/src/app/shared/pipes/string.pipes.js +7 -18
  30. package/esm2015/src/app/shared/services/memory-entity-service.class.js +13 -1
  31. package/esm2015/src/app/shared/services.js +61 -0
  32. package/esm2015/src/app/shared/types.js +1 -1
  33. package/esm2015/src/app/social/social.errors.js +2 -5
  34. package/esm2015/src/app/social/social.module.js +15 -10
  35. package/esm2015/src/app/social/user-event/user-event.model.js +2 -58
  36. package/esm2015/src/app/social/user-event/user-event.service.js +167 -295
  37. package/esm2015/src/app/social/user-event/user-events.table.js +12 -17
  38. package/esm2015/sumaris-net.ngx-components.js +6 -8
  39. package/fesm2015/sumaris-net.ngx-components.js +479 -1015
  40. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  41. package/package.json +3 -2
  42. package/public_api.d.ts +2 -7
  43. package/src/app/core/auth/form/form-auth.d.ts +1 -1
  44. package/src/app/core/form/editor.class.d.ts +39 -12
  45. package/src/app/core/form/entity-editor-modal.class.d.ts +4 -3
  46. package/src/app/core/form/entity-editor.class.d.ts +10 -5
  47. package/src/app/core/form/form.class.d.ts +32 -19
  48. package/src/app/core/icon/icon.component.d.ts +4 -4
  49. package/src/app/core/table/table.class.d.ts +21 -14
  50. package/src/app/shared/functions.d.ts +0 -9
  51. package/src/app/shared/material/autocomplete/testing/autocomplete.test.d.ts +1 -2
  52. package/src/app/shared/material/badge/badge-icon.test.d.ts +1 -1
  53. package/src/app/shared/observables.d.ts +1 -0
  54. package/src/app/shared/pipes/form.pipes.d.ts +1 -2
  55. package/src/app/shared/services/memory-entity-service.class.d.ts +6 -0
  56. package/src/app/shared/services.d.ts +9 -0
  57. package/src/app/shared/types.d.ts +0 -4
  58. package/src/app/social/social.errors.d.ts +0 -3
  59. package/src/app/social/social.module.d.ts +0 -8
  60. package/src/app/social/user-event/user-event.model.d.ts +6 -51
  61. package/src/app/social/user-event/user-event.service.d.ts +51 -79
  62. package/src/app/social/user-event/user-events.table.d.ts +6 -6
  63. package/src/assets/i18n/en-US.json +2 -15
  64. package/src/assets/i18n/en.json +2 -15
  65. package/src/assets/i18n/fr.json +1 -14
  66. package/src/theme/_ngx-components.scss +0 -7
  67. package/sumaris-net.ngx-components.d.ts +5 -7
  68. package/sumaris-net.ngx-components.metadata.json +1 -1
  69. package/esm2015/src/app/social/job/job.model.js +0 -24
  70. package/esm2015/src/app/social/job/job.module.js +0 -25
  71. package/esm2015/src/app/social/job/job.service.js +0 -53
  72. package/esm2015/src/app/social/job/progression/job-progression.component.js +0 -192
  73. package/esm2015/src/app/social/job/progression/job-progression.list.js +0 -20
  74. package/esm2015/src/app/social/message/message.module.js +0 -25
  75. package/esm2015/src/app/social/user-event/notification/user-event-notification.component.js +0 -92
  76. package/esm2015/src/app/social/user-event/notification/user-event-notification.list.js +0 -39
  77. package/esm2015/src/app/social/user-event/user-event.module.js +0 -28
  78. package/src/app/social/job/job.model.d.ts +0 -32
  79. package/src/app/social/job/job.module.d.ts +0 -2
  80. package/src/app/social/job/job.service.d.ts +0 -23
  81. package/src/app/social/job/progression/job-progression.component.d.ts +0 -43
  82. package/src/app/social/job/progression/job-progression.list.d.ts +0 -12
  83. package/src/app/social/message/message.module.d.ts +0 -2
  84. package/src/app/social/user-event/notification/user-event-notification.component.d.ts +0 -25
  85. package/src/app/social/user-event/notification/user-event-notification.list.d.ts +0 -20
  86. package/src/app/social/user-event/user-event.module.d.ts +0 -2
@@ -241,64 +241,6 @@ function changeCaseToUnderscore(value) {
241
241
  function removeDiacritics(text) {
242
242
  return text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
243
243
  }
244
- function suggestFromArray(items, value, opts) {
245
- if (isNotNil(value) && typeof value === 'object')
246
- return { data: [value] };
247
- value = (typeof value === 'string' && value !== '*') && value.toUpperCase() || undefined;
248
- const keys = opts && (opts.searchAttribute && [opts.searchAttribute] || opts.searchAttributes) || ['label'];
249
- if (!items) {
250
- return { data: [], total: 0 };
251
- }
252
- // Filter items
253
- let filteredItems = items;
254
- if (isNotNilOrBlank(value)) {
255
- // If wildcard, search using regexp
256
- if (value.indexOf('*') !== -1) {
257
- value = value.replace(/[*]+/g, '.*');
258
- filteredItems = filteredItems.filter(v => keys.findIndex(key => matchUpperCase(getPropertyByPathAsString(v, key), value)) !== -1);
259
- }
260
- // Else (no wildcard), search using startsWith
261
- else {
262
- filteredItems = filteredItems.filter(v => keys.findIndex(key => startsWithUpperCase(getPropertyByPathAsString(v, key), value)) !== -1);
263
- }
264
- }
265
- // Exclude ids
266
- if (isNotEmptyArray(opts === null || opts === void 0 ? void 0 : opts.excludedIds)) {
267
- filteredItems = filteredItems.filter(v => !opts.excludedIds.includes(+v['id']));
268
- }
269
- // Sort
270
- if (!opts || opts.skipSort !== true) {
271
- // Make to copy input items, before sorting (if not yet already done)
272
- if (filteredItems === items)
273
- filteredItems = filteredItems.slice();
274
- // Sort by keys
275
- filteredItems.sort(propertiesPathComparator(keys));
276
- }
277
- const total = filteredItems.length || 0;
278
- // Pagination (truncate if need)
279
- let pageData = filteredItems;
280
- if (opts) {
281
- if ((opts.offset || 0) > 0) {
282
- pageData = pageData.slice(opts.offset);
283
- }
284
- if (isNotNil(opts.size) && pageData.length > opts.size) {
285
- pageData = pageData.slice(0, opts.size);
286
- }
287
- }
288
- const result = {
289
- data: pageData,
290
- total
291
- };
292
- // Add fetch more capability, if total was fetched
293
- const nextOffset = (opts && opts.offset || 0) + pageData.length;
294
- if (nextOffset < total) {
295
- result.fetchMore = (_) => __awaiter(this, void 0, void 0, function* () {
296
- return suggestFromArray(filteredItems, undefined /*OPTIMISATION: already applied*/, Object.assign(Object.assign({}, opts), { offset: nextOffset, skipSort: true, excludedIds: undefined // OPTIMISATION: already filtered
297
- }));
298
- });
299
- }
300
- return result;
301
- }
302
244
  function suggestFromStringArray(values, value, options) {
303
245
  value = (typeof value === 'string' && value !== '*') && value.toUpperCase() || undefined;
304
246
  if (isNilOrBlank(value))
@@ -843,11 +785,11 @@ function chainPromises(defers) {
843
785
  }, null);
844
786
  }
845
787
  function firstTrue(obs) {
846
- return obs.pipe(first((v) => v === true), map(_ => { }) // Convert to void
788
+ return obs.pipe(first(value => value === true), map(_ => { }) // Convert to void
847
789
  );
848
790
  }
849
791
  function firstFalse(obs) {
850
- return obs.pipe(first((v) => v === false), map(_ => { }) // Convert to void
792
+ return obs.pipe(first(value => value === false), map(_ => { }) // Convert to void
851
793
  );
852
794
  }
853
795
  /**
@@ -879,12 +821,11 @@ function waitFor(predicate, opts) {
879
821
  }
880
822
  function waitForTrue(observable, opts) {
881
823
  return __awaiter(this, void 0, void 0, function* () {
882
- const firstTrueObservable = firstTrue(observable);
883
824
  // Timeout (+ dueTime)
884
825
  if (opts && opts.timeout > 0) {
885
826
  const $timeout = timer(opts.timeout);
886
827
  return merge(timer(opts.dueTime || 0)
887
- .pipe(switchMap(() => firstTrueObservable), takeUntil($timeout)), $timeout
828
+ .pipe(switchMap(() => firstTrue(observable)), takeUntil($timeout)), $timeout
888
829
  .pipe(map(() => {
889
830
  throw new Error(`Timeout ready() - after ${opts.timeout}ms`);
890
831
  })))
@@ -893,10 +834,17 @@ function waitForTrue(observable, opts) {
893
834
  // dueTime (without timeout)
894
835
  if (opts && opts.dueTime > 0) {
895
836
  return timer(opts.dueTime)
896
- .pipe(switchMap(() => firstTrueObservable))
837
+ .pipe(switchMap(() => firstTrue(observable)))
897
838
  .toPromise();
898
839
  }
899
- return firstTrueObservable.toPromise();
840
+ return firstTrue(observable).toPromise();
841
+ });
842
+ }
843
+ function waitForFalse(observable, opts) {
844
+ return __awaiter(this, void 0, void 0, function* () {
845
+ return waitForTrue(
846
+ // Inverse the logic
847
+ observable.pipe(map(v => v === false)), opts);
900
848
  });
901
849
  }
902
850
 
@@ -1100,6 +1048,65 @@ const isMobile = (win) => {
1100
1048
  return _cache.mobile;
1101
1049
  };
1102
1050
 
1051
+ function suggestFromArray(items, value, opts) {
1052
+ if (isNotNil(value) && typeof value === 'object')
1053
+ return { data: [value] };
1054
+ value = (typeof value === 'string' && value !== '*') && value.toUpperCase() || undefined;
1055
+ const keys = opts && (opts.searchAttribute && [opts.searchAttribute] || opts.searchAttributes) || ['label'];
1056
+ if (!items) {
1057
+ return { data: [], total: 0 };
1058
+ }
1059
+ // Filter items
1060
+ let filteredItems = items;
1061
+ if (isNotNilOrBlank(value)) {
1062
+ // If wildcard, search using regexp
1063
+ if (value.indexOf('*') !== -1) {
1064
+ value = value.replace(/[*]+/g, '.*');
1065
+ filteredItems = filteredItems.filter(v => keys.findIndex(key => matchUpperCase(getPropertyByPathAsString(v, key), value)) !== -1);
1066
+ }
1067
+ // Else (no wildcard), search using startsWith
1068
+ else {
1069
+ filteredItems = filteredItems.filter(v => keys.findIndex(key => startsWithUpperCase(getPropertyByPathAsString(v, key), value)) !== -1);
1070
+ }
1071
+ }
1072
+ // Exclude ids
1073
+ if (isNotEmptyArray(opts === null || opts === void 0 ? void 0 : opts.excludedIds)) {
1074
+ filteredItems = filteredItems.filter(v => !opts.excludedIds.includes(+v['id']));
1075
+ }
1076
+ // Sort
1077
+ if (!opts || opts.skipSort !== true) {
1078
+ // Make to copy input items, before sorting (if not yet already done)
1079
+ if (filteredItems === items)
1080
+ filteredItems = filteredItems.slice();
1081
+ // Sort by keys
1082
+ filteredItems.sort(propertiesPathComparator(keys));
1083
+ }
1084
+ const total = filteredItems.length || 0;
1085
+ // Pagination (truncate if need)
1086
+ let pageData = filteredItems;
1087
+ if (opts) {
1088
+ if ((opts.offset || 0) > 0) {
1089
+ pageData = pageData.slice(opts.offset);
1090
+ }
1091
+ if (isNotNil(opts.size) && pageData.length > opts.size) {
1092
+ pageData = pageData.slice(0, opts.size);
1093
+ }
1094
+ }
1095
+ const result = {
1096
+ data: pageData,
1097
+ total
1098
+ };
1099
+ // Add fetch more capability, if total was fetched
1100
+ const nextOffset = (opts && opts.offset || 0) + pageData.length;
1101
+ if (nextOffset < total) {
1102
+ result.fetchMore = (_) => __awaiter(this, void 0, void 0, function* () {
1103
+ return suggestFromArray(filteredItems, undefined /*OPTIMISATION: already applied*/, Object.assign(Object.assign({}, opts), { offset: nextOffset, skipSort: true, excludedIds: undefined // OPTIMISATION: already filtered
1104
+ }));
1105
+ });
1106
+ }
1107
+ return result;
1108
+ }
1109
+
1103
1110
  class MatAutocompleteConfigHolder {
1104
1111
  constructor(options) {
1105
1112
  this.options = options;
@@ -1360,11 +1367,11 @@ class MatAutocompleteField {
1360
1367
  // Search text (no distinctUntilChanged() because of the debounceTime() pipe)
1361
1368
  this.formControl.valueChanges
1362
1369
  .pipe(filter(value => this.enabled && isNotNilString(value)),
1363
- // Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
1370
+ // Mark as loading (to show loading spinner) - as soon as possible, and before debounceTime
1364
1371
  tap(_ => this.showLoadingSpinner && this.markAsLoading()),
1365
1372
  // Filter if not enough character
1366
1373
  filter(value => {
1367
- if (value.length <= this.suggestLengthThreshold) {
1374
+ if (((value === null || value === void 0 ? void 0 : value.length) || 0) < this.suggestLengthThreshold) {
1368
1375
  // Update display value, to enable the message "not enough characters"
1369
1376
  this.displayValue = value;
1370
1377
  return false;
@@ -2328,9 +2335,9 @@ class HighlightPipe {
2328
2335
  const cleanedSearchText = removeDiacritics(searchRegexp).toUpperCase();
2329
2336
  const index = removeDiacritics(value.toUpperCase()).indexOf(cleanedSearchText);
2330
2337
  if (index !== -1) {
2331
- return value.substr(0, index - 1) +
2332
- '<b>' + value.substr(index, cleanedSearchText.length) + '</b>' +
2333
- value.substr(index + cleanedSearchText.length);
2338
+ return value.substring(0, index - 1) +
2339
+ '<b>' + value.substring(index, cleanedSearchText.length) + '</b>' +
2340
+ value.substring(index + cleanedSearchText.length);
2334
2341
  }
2335
2342
  return value;
2336
2343
  }
@@ -2728,60 +2735,50 @@ class IsNotNilOrBlankPipe {
2728
2735
  return isNotNilOrBlank(value);
2729
2736
  }
2730
2737
  }
2731
- IsNotNilOrBlankPipe.ɵprov = ɵɵdefineInjectable({ factory: function IsNotNilOrBlankPipe_Factory() { return new IsNotNilOrBlankPipe(); }, token: IsNotNilOrBlankPipe, providedIn: "root" });
2732
2738
  IsNotNilOrBlankPipe.decorators = [
2733
2739
  { type: Pipe, args: [{
2734
2740
  name: 'isNotNilOrBlank'
2735
- },] },
2736
- { type: Injectable, args: [{ providedIn: 'root' },] }
2741
+ },] }
2737
2742
  ];
2738
2743
  class IsNilOrBlankPipe {
2739
2744
  transform(value) {
2740
2745
  return isNilOrBlank(value);
2741
2746
  }
2742
2747
  }
2743
- IsNilOrBlankPipe.ɵprov = ɵɵdefineInjectable({ factory: function IsNilOrBlankPipe_Factory() { return new IsNilOrBlankPipe(); }, token: IsNilOrBlankPipe, providedIn: "root" });
2744
2748
  IsNilOrBlankPipe.decorators = [
2745
2749
  { type: Pipe, args: [{
2746
2750
  name: 'isNilOrBlank'
2747
- },] },
2748
- { type: Injectable, args: [{ providedIn: 'root' },] }
2751
+ },] }
2749
2752
  ];
2750
2753
  class ToStringPipe {
2751
2754
  transform(value) {
2752
2755
  return (value !== null && value !== undefined) ? value.toString() : '';
2753
2756
  }
2754
2757
  }
2755
- ToStringPipe.ɵprov = ɵɵdefineInjectable({ factory: function ToStringPipe_Factory() { return new ToStringPipe(); }, token: ToStringPipe, providedIn: "root" });
2756
2758
  ToStringPipe.decorators = [
2757
2759
  { type: Pipe, args: [{
2758
2760
  name: 'toString'
2759
- },] },
2760
- { type: Injectable, args: [{ providedIn: 'root' },] }
2761
+ },] }
2761
2762
  ];
2762
2763
  class StrLengthPipe {
2763
2764
  transform(value) {
2764
2765
  return value && value.length || 0;
2765
2766
  }
2766
2767
  }
2767
- StrLengthPipe.ɵprov = ɵɵdefineInjectable({ factory: function StrLengthPipe_Factory() { return new StrLengthPipe(); }, token: StrLengthPipe, providedIn: "root" });
2768
2768
  StrLengthPipe.decorators = [
2769
2769
  { type: Pipe, args: [{
2770
2770
  name: 'strLength'
2771
- },] },
2772
- { type: Injectable, args: [{ providedIn: 'root' },] }
2771
+ },] }
2773
2772
  ];
2774
2773
  class StrIncludesPipe {
2775
2774
  transform(value, searchString, position) {
2776
2775
  return (value === null || value === void 0 ? void 0 : value.includes(searchString, position)) || false;
2777
2776
  }
2778
2777
  }
2779
- StrIncludesPipe.ɵprov = ɵɵdefineInjectable({ factory: function StrIncludesPipe_Factory() { return new StrIncludesPipe(); }, token: StrIncludesPipe, providedIn: "root" });
2780
2778
  StrIncludesPipe.decorators = [
2781
2779
  { type: Pipe, args: [{
2782
2780
  name: 'strIncludes'
2783
- },] },
2784
- { type: Injectable, args: [{ providedIn: 'root' },] }
2781
+ },] }
2785
2782
  ];
2786
2783
 
2787
2784
  class TranslateContextService {
@@ -4203,7 +4200,7 @@ FormGetPipe.decorators = [
4203
4200
  ];
4204
4201
  class FormGetControlPipe {
4205
4202
  transform(form, path) {
4206
- return (form && path && form.get(path) || form);
4203
+ return (form && isNotNil(path) && form.get(path) || form);
4207
4204
  }
4208
4205
  }
4209
4206
  FormGetControlPipe.decorators = [
@@ -4232,8 +4229,7 @@ FormGetGroupPipe.decorators = [
4232
4229
  },] }
4233
4230
  ];
4234
4231
  class FormGetValuePipe {
4235
- constructor(adapter, _ref) {
4236
- this.adapter = adapter;
4232
+ constructor(_ref) {
4237
4233
  this._ref = _ref;
4238
4234
  this.value = undefined;
4239
4235
  this._lastControl = null;
@@ -4298,7 +4294,6 @@ FormGetValuePipe.decorators = [
4298
4294
  },] }
4299
4295
  ];
4300
4296
  FormGetValuePipe.ctorParameters = () => [
4301
- { type: FormErrorTranslator },
4302
4297
  { type: ChangeDetectorRef }
4303
4298
  ];
4304
4299
 
@@ -5169,7 +5164,8 @@ class MatDate {
5169
5164
  set tabindex(value) {
5170
5165
  if (this._tabindex !== value) {
5171
5166
  this._tabindex = value;
5172
- setTimeout(() => this.updateTabIndex());
5167
+ if (!this._writing)
5168
+ this.updateTabIndex();
5173
5169
  }
5174
5170
  }
5175
5171
  get tabindex() {
@@ -5528,7 +5524,8 @@ class MatDateTime {
5528
5524
  set tabindex(value) {
5529
5525
  if (this._tabindex !== value) {
5530
5526
  this._tabindex = value;
5531
- setTimeout(() => this.updateTabIndex());
5527
+ if (!this._writing)
5528
+ this.updateTabIndex();
5532
5529
  }
5533
5530
  }
5534
5531
  get tabindex() {
@@ -10707,7 +10704,7 @@ class LocalSettingsService extends StartableService {
10707
10704
  }
10708
10705
  get usageMode() {
10709
10706
  var _a;
10710
- if (isNil((_a = this._data) === null || _a === void 0 ? void 0 : _a.mobile)) {
10707
+ if (isNil((_a = this._data) === null || _a === void 0 ? void 0 : _a.usageMode)) {
10711
10708
  console.warn("[settings] Accessing to property 'usageMode' BEFORE service started! Please use ready()");
10712
10709
  return isCordova(window) ? 'FIELD' : 'DESK';
10713
10710
  }
@@ -13307,7 +13304,8 @@ class GraphqlService extends StartableService {
13307
13304
  console.debug('[graphql] Apply token authentication to headers');
13308
13305
  this.connectionParams.authToken = token;
13309
13306
  }
13310
- else {
13307
+ // Clean auth token
13308
+ else if (this.connectionParams.authToken) {
13311
13309
  console.debug('[graphql] Remove token authentication from headers');
13312
13310
  delete this.connectionParams.authToken;
13313
13311
  // Clear cache
@@ -13319,7 +13317,8 @@ class GraphqlService extends StartableService {
13319
13317
  console.debug('[graphql] Apply basic authentication to headers');
13320
13318
  this.connectionParams.authBasic = basic;
13321
13319
  }
13322
- else {
13320
+ // Clean auth basic
13321
+ else if (this.connectionParams.authBasic) {
13323
13322
  console.debug('[graphql] Remove basic authentication from headers');
13324
13323
  delete this.connectionParams.authBasic;
13325
13324
  // Clear cache
@@ -17425,12 +17424,12 @@ class FormFieldValuesHolder {
17425
17424
  // eslint-disable-next-line @angular-eslint/directive-class-suffix
17426
17425
  class AppForm {
17427
17426
  constructor(injector, form) {
17428
- this.error = null;
17427
+ this._subscription = new Subscription();
17429
17428
  this._enable = false;
17430
- this._$ready = new BehaviorSubject(false);
17431
- this._$loading = new BehaviorSubject(true);
17432
17429
  this.i18nFieldPrefix = null;
17433
- this._subscription = new Subscription();
17430
+ this.readySubject = new BehaviorSubject(false);
17431
+ this.loadingSubject = new BehaviorSubject(true);
17432
+ this.errorSubject = new BehaviorSubject(undefined);
17434
17433
  this.debug = false;
17435
17434
  this.onCancel = new EventEmitter();
17436
17435
  this.onSubmit = new EventEmitter();
@@ -17448,16 +17447,37 @@ class AppForm {
17448
17447
  * @deprecated
17449
17448
  */
17450
17449
  set _loading(value) {
17451
- this._$loading.next(value);
17450
+ this.loadingSubject.next(value);
17452
17451
  }
17453
17452
  /**
17454
17453
  * @deprecated
17455
17454
  */
17456
17455
  get _loading() {
17457
- return this._$loading.value;
17456
+ return this.loadingSubject.value;
17457
+ }
17458
+ /**
17459
+ * @deprecated
17460
+ */
17461
+ get _$ready() {
17462
+ return this.readySubject;
17463
+ }
17464
+ /**
17465
+ * @deprecated
17466
+ */
17467
+ get _$loading() {
17468
+ return this.loadingSubject;
17469
+ }
17470
+ get error() {
17471
+ return this.errorSubject.value;
17472
+ }
17473
+ set error(error) {
17474
+ this.setError(error);
17458
17475
  }
17459
17476
  get loading() {
17460
- return this._$loading.value;
17477
+ return this.loadingSubject.value;
17478
+ }
17479
+ get loaded() {
17480
+ return !this.loadingSubject.value;
17461
17481
  }
17462
17482
  get value() {
17463
17483
  return this.form.value;
@@ -17466,7 +17486,8 @@ class AppForm {
17466
17486
  this.setValue(data);
17467
17487
  }
17468
17488
  get dirty() {
17469
- return this.form && this.form.dirty;
17489
+ var _a;
17490
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.dirty) || false;
17470
17491
  }
17471
17492
  get invalid() {
17472
17493
  return !this.form || this.form.invalid;
@@ -17475,7 +17496,8 @@ class AppForm {
17475
17496
  return !this.form || (this.form.dirty && this.form.pending);
17476
17497
  }
17477
17498
  get valid() {
17478
- return this.form && this.form.valid;
17499
+ var _a;
17500
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
17479
17501
  }
17480
17502
  get empty() {
17481
17503
  return !this.form || (!this.form.dirty && !this.form.touched);
@@ -17521,17 +17543,16 @@ class AppForm {
17521
17543
  }
17522
17544
  ngOnDestroy() {
17523
17545
  this._subscription.unsubscribe();
17524
- this.onCancel.complete();
17546
+ this.readySubject.unsubscribe();
17547
+ this.loadingSubject.unsubscribe();
17548
+ this.errorSubject.unsubscribe();
17525
17549
  this.onCancel.unsubscribe();
17526
- this.onSubmit.complete();
17527
17550
  this.onSubmit.unsubscribe();
17528
- this._$ready.complete();
17529
- this._$ready.unsubscribe();
17530
- this._$loading.complete();
17531
- this._$loading.unsubscribe();
17532
17551
  }
17533
17552
  cancel() {
17534
- this.onCancel.emit();
17553
+ return __awaiter(this, void 0, void 0, function* () {
17554
+ this.onCancel.emit();
17555
+ });
17535
17556
  }
17536
17557
  /**
17537
17558
  *
@@ -17626,22 +17647,14 @@ class AppForm {
17626
17647
  this.markForCheck();
17627
17648
  }
17628
17649
  markAsLoading(opts) {
17629
- if (this._$loading.value !== true) {
17630
- this._$loading.next(true);
17631
- if (!opts || opts.emitEvent !== false)
17632
- this.markForCheck();
17633
- }
17650
+ this.setLoading(true, opts);
17634
17651
  }
17635
17652
  markAsLoaded(opts) {
17636
- if (this._$loading.value !== false) {
17637
- this._$loading.next(false);
17638
- if (!opts || opts.emitEvent !== false)
17639
- this.markForCheck();
17640
- }
17653
+ this.setLoading(false, opts);
17641
17654
  }
17642
17655
  markAsReady(opts) {
17643
- if (this._$ready.value !== true) {
17644
- this._$ready.next(true);
17656
+ if (this.readySubject.value !== true) {
17657
+ this.readySubject.next(true);
17645
17658
  // If subclasses implements OnReady
17646
17659
  if (typeof this['ngOnReady'] === 'function') {
17647
17660
  this.ngOnReady();
@@ -17653,16 +17666,18 @@ class AppForm {
17653
17666
  * @param opts
17654
17667
  */
17655
17668
  ready(opts) {
17656
- return waitForTrue(this._$ready, opts);
17669
+ if (this.readySubject.value)
17670
+ return Promise.resolve();
17671
+ return waitForTrue(this.readySubject, opts);
17657
17672
  }
17658
17673
  /**
17659
- * Wait form is idle (not loading)
17674
+ * Wait form is not busy (=loaded)
17660
17675
  * @param opts
17661
17676
  */
17662
17677
  waitIdle(opts) {
17663
- return __awaiter(this, void 0, void 0, function* () {
17664
- return AppFormUtils.waitIdle(this, opts);
17665
- });
17678
+ if (!this.loadingSubject.value)
17679
+ return Promise.resolve();
17680
+ return waitForFalse(this.loadingSubject, opts);
17666
17681
  }
17667
17682
  updateValueAndValidity(opts) {
17668
17683
  AppFormUtils.updateValueAndValidity(this.form, opts);
@@ -17692,10 +17707,27 @@ class AppForm {
17692
17707
  registerAutocompleteField(fieldName, opts) {
17693
17708
  return this.autocompleteHelper.add(fieldName, opts);
17694
17709
  }
17710
+ setError(value, opts) {
17711
+ if (this.errorSubject.value !== value) {
17712
+ this.errorSubject.next(value);
17713
+ if (!opts || opts.emitEvent !== false) {
17714
+ this.markForCheck();
17715
+ }
17716
+ }
17717
+ }
17695
17718
  markForCheck() {
17696
17719
  // Should be overwritten by subclasses
17697
17720
  console.warn('markForCheck() has been called, but is not overwritten by component ' + this.constructor.name);
17698
17721
  }
17722
+ /* -- private function -- */
17723
+ setLoading(value, opts) {
17724
+ if (this.loadingSubject.value !== value) {
17725
+ this.loadingSubject.next(value);
17726
+ if (!opts || opts.emitEvent !== false) {
17727
+ this.markForCheck();
17728
+ }
17729
+ }
17730
+ }
17699
17731
  }
17700
17732
  AppForm.decorators = [
17701
17733
  { type: Directive }
@@ -18213,6 +18245,18 @@ class InMemoryEntitiesService extends EntitiesService {
18213
18245
  return this._equalsFn(d1, d2);
18214
18246
  return d1 && d1.equals ? d1.equals(d2) : EntityUtils.equals(d1, d2, 'id');
18215
18247
  }
18248
+ /**
18249
+ * Count data stored by the service (without hidden data).
18250
+ * @param opts
18251
+ */
18252
+ get count() {
18253
+ var _a;
18254
+ return (((_a = this.data) === null || _a === void 0 ? void 0 : _a.length) || 0);
18255
+ }
18256
+ get hiddenCount() {
18257
+ var _a;
18258
+ return ((_a = this._hiddenData) === null || _a === void 0 ? void 0 : _a.length) || 0;
18259
+ }
18216
18260
  /* -- protected methods -- */
18217
18261
  filter(data, _filter, hiddenData) {
18218
18262
  // if filter is DataFilter instance, use its test function
@@ -18766,7 +18810,9 @@ class AuthForm extends AppForm {
18766
18810
  }
18767
18811
  }
18768
18812
  cancel() {
18769
- this.onCancel.emit();
18813
+ return __awaiter(this, void 0, void 0, function* () {
18814
+ this.onCancel.emit();
18815
+ });
18770
18816
  }
18771
18817
  doSubmit(event) {
18772
18818
  return __awaiter(this, void 0, void 0, function* () {
@@ -19623,7 +19669,7 @@ class AccountPage extends AppForm {
19623
19669
  cancel: { get: () => super.cancel }
19624
19670
  });
19625
19671
  return __awaiter(this, void 0, void 0, function* () {
19626
- _super.cancel.call(this);
19672
+ yield _super.cancel.call(this);
19627
19673
  });
19628
19674
  }
19629
19675
  markForCheck() {
@@ -21431,7 +21477,7 @@ class MenuComponent {
21431
21477
  MenuComponent.decorators = [
21432
21478
  { type: Component, args: [{
21433
21479
  selector: 'app-menu',
21434
- template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n<!-- todo ajouter ici les 2 composants du module social -->\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
21480
+ template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
21435
21481
  animations: [fadeInAnimation],
21436
21482
  changeDetection: ChangeDetectionStrategy.OnPush,
21437
21483
  styles: ["ion-menu{--ion-item-background:transparent;--ion-item-divider-background:transparent;--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint);--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-text-color-selected:var(--ion-color-primary);--ion-item-icon-color-selected:var(--ion-color-primary);--ion-item-text-color-disable:var(--ion-color-medium);--ion-item-icon-color-disable:var(--ion-color-medium)}ion-menu ion-header ion-text{color:var(--ion-color-primary)}ion-menu ion-header .user-avatar{background-size:cover;background-repeat:no-repeat;background-position:50%;background-color:var(--ion-color-secondary);border:1px solid var(--ion-color-primary);overflow:hidden!important;font-size:var(--avatar-size,60px)!important;line-height:var(--avatar-size,60px);height:var(--avatar-size,60px)!important;width:var(--avatar-size,60px)!important;border-radius:50%;display:inline-block}ion-menu ion-header .user-logo{text-align:right}ion-menu ion-header .user-logo img{max-width:120px;max-height:var(--avatar-size,60px);width:auto}ion-menu ion-header .username{padding-top:0;margin-top:0;margin-bottom:0;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-menu ion-header button[mat-button]{padding:0;text-align:start!important;width:100%}ion-menu .scroll-content{margin-top:79px!important}ion-menu .has-user-header .scroll-content{margin-top:188px!important}ion-menu ion-content.has-profile-header{--offset-top:188px}ion-menu ion-content.no-profile-header{--offset-top:79px}ion-menu ion-content ion-list{min-height:100%;display:flex;flex-direction:column;justify-content:flex-start}ion-menu ion-content ion-list ion-menu-toggle.flex-spacer{flex:1 1 auto;display:flex;flex-direction:column;justify-content:flex-end}ion-menu ion-content ion-list ion-item.primary{--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint)}ion-menu ion-content ion-list ion-item.secondary{--ion-item-icon-color:var(--ion-color-secondary-tint);--ion-item-text-color:var(--ion-color-secondary-tint)}ion-menu ion-content ion-list ion-item.tertiary{--ion-item-icon-color:var(--ion-color-tertiary-tint);--ion-item-text-color:var(--ion-color-tertiary-tint)}ion-menu ion-content ion-list ion-item.danger{--ion-item-icon-color:var(--ion-color-danger-tint);--ion-item-text-color:var(--ion-color-danger-tint)}ion-menu ion-content ion-list ion-item.medium{--ion-item-icon-color:var(--ion-color-medium-shade);--ion-item-text-color:var(--ion-color-medium-shade)}ion-menu ion-content ion-list ion-item.dark{--ion-item-icon-color:var(--ion-color-dark-tint);--ion-item-text-color:var(--ion-color-dark-tint)}ion-menu ion-content ion-list ion-item ion-icon,ion-menu ion-content ion-list ion-item mat-icon{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item ion-label,ion-menu ion-content ion-list ion-item ion-text{color:var(--ion-item-text-color)!important}ion-menu ion-content ion-list ion-item.selected{background-color:var(--ion-item-background-selected)!important;--color-hover:var(--ion-item-background-selected)!important}ion-menu ion-content ion-list ion-item.selected ion-icon,ion-menu ion-content ion-list ion-item.selected mat-icon{color:var(--ion-item-icon-color-selected)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item.selected ion-label,ion-menu ion-content ion-list ion-item.selected ion-text{color:var(--ion-item-text-color-selected)!important}ion-menu ion-content ion-list ion-item.selected:hover{--color-hover:var(--ion-item-background-selected)!important;--ion-item-icon-color-selected:var(--ion-item-icon-color)!important;--ion-item-text-color-selected:var(--ion-item-text-color)!important}ion-menu ion-footer{display:block!important}ion-menu ion-footer ion-toolbar ion-title{cursor:pointer;font-size:12pt;font-weight:400;text-align:center;padding:0 8px}ion-menu ion-footer ion-toolbar ion-button{--width:40px}@media screen and (max-width:767px){ion-menu ion-footer{display:none!important;visibility:hidden!important}}@media screen and (min-width:768px){ion-menu ion-scroll{overflow-y:auto!important}ion-menu .user-avatar{font-size:var(--avatar-size,80px)!important;line-height:var(--avatar-size,80px);height:var(--avatar-size,80px)!important;width:var(--avatar-size,80px)!important}ion-menu .user-logo img{max-height:var(--avatar-size,80px)}}"]
@@ -21495,14 +21541,13 @@ class AppIconComponent {
21495
21541
  this.icon = value.icon;
21496
21542
  this.matIcon = value.matIcon;
21497
21543
  this.matSvgIcon = value.matSvgIcon;
21498
- this.color = value.color;
21499
21544
  }
21500
21545
  ;
21501
21546
  }
21502
21547
  AppIconComponent.decorators = [
21503
21548
  { type: Component, args: [{
21504
21549
  selector: 'app-icon',
21505
- template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n [style.font-size.px]=\"height || width\"\n >{{matIcon}}</mat-icon>\n</ng-template>\n\n"
21550
+ template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\">{{matIcon}}</mat-icon>\n</ng-template>\n\n"
21506
21551
  },] }
21507
21552
  ];
21508
21553
  AppIconComponent.propDecorators = {
@@ -21510,8 +21555,6 @@ AppIconComponent.propDecorators = {
21510
21555
  matIcon: [{ type: Input }],
21511
21556
  matSvgIcon: [{ type: Input }],
21512
21557
  color: [{ type: Input }],
21513
- height: [{ type: Input }],
21514
- width: [{ type: Input }],
21515
21558
  ref: [{ type: Input }]
21516
21559
  };
21517
21560
 
@@ -22583,19 +22626,24 @@ class AppTable {
22583
22626
  get error() {
22584
22627
  return this.errorSubject.value;
22585
22628
  }
22586
- get error$() {
22587
- return this.errorSubject.asObservable();
22588
- }
22589
22629
  /**
22590
22630
  * @deprecated
22591
- * @param error
22592
22631
  */
22632
+ get error$() {
22633
+ return this.errorSubject.asObservable();
22634
+ }
22593
22635
  set error(error) {
22594
22636
  this.setError(error);
22595
22637
  }
22638
+ /**
22639
+ * @deprecated
22640
+ */
22596
22641
  get loading$() {
22597
22642
  return this.loadingSubject.asObservable();
22598
22643
  }
22644
+ /**
22645
+ * @deprecated
22646
+ */
22599
22647
  get saving$() {
22600
22648
  return this.savingSubject.asObservable();
22601
22649
  }
@@ -22718,17 +22766,15 @@ class AppTable {
22718
22766
  if (this.savingSubject.value !== true) {
22719
22767
  this.focusColumn = undefined; // unselect focus column
22720
22768
  this.savingSubject.next(true);
22721
- if (!opts || opts.emitEvent !== false) {
22769
+ if (!opts || opts.emitEvent !== false)
22722
22770
  this.markForCheck();
22723
- }
22724
22771
  }
22725
22772
  }
22726
22773
  markAsSaved(opts) {
22727
22774
  if (this.savingSubject.value !== false) {
22728
22775
  this.savingSubject.next(false);
22729
- if (!opts || opts.emitEvent !== false) {
22776
+ if (!opts || opts.emitEvent !== false)
22730
22777
  this.markForCheck();
22731
- }
22732
22778
  }
22733
22779
  }
22734
22780
  markAsLoading(opts) {
@@ -23013,7 +23059,7 @@ class AppTable {
23013
23059
  .then(() => this.editRowById(event, row.id, { focusColumn: this.lastUserColumn }));
23014
23060
  return true;
23015
23061
  }
23016
- // Edit next row
23062
+ // Edit previous row
23017
23063
  this.editRow(event, row, { focusColumn: this.lastUserColumn });
23018
23064
  return true;
23019
23065
  }
@@ -23036,8 +23082,7 @@ class AppTable {
23036
23082
  if (id < 0)
23037
23083
  return;
23038
23084
  if (id >= this.visibleRowCount) {
23039
- this.focusColumn = opts && opts.focusColumn || this.firstUserColumn;
23040
- this.addRow(event);
23085
+ this.addRow(event, undefined, opts);
23041
23086
  }
23042
23087
  else {
23043
23088
  const row = yield this.dataSource.getRow(id);
@@ -23110,7 +23155,7 @@ class AppTable {
23110
23155
  this.cancelExistingRow(event, row, opts);
23111
23156
  }
23112
23157
  }
23113
- addRow(event, insertAt) {
23158
+ addRow(event, insertAt, opts) {
23114
23159
  if (this.debug)
23115
23160
  console.debug('[table] Asking for new row...');
23116
23161
  if (!this._enabled)
@@ -23125,7 +23170,7 @@ class AppTable {
23125
23170
  return false;
23126
23171
  }
23127
23172
  // Add new row
23128
- this.addRowToTable(insertAt);
23173
+ this.addRowToTable(insertAt, opts);
23129
23174
  return true;
23130
23175
  }
23131
23176
  save(opts) {
@@ -23240,7 +23285,7 @@ class AppTable {
23240
23285
  * @param event
23241
23286
  * @param row
23242
23287
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
23243
- * Use skipIfLoading=false to force deletion even if table is busy
23288
+ * And to force deletion even if table is busy
23244
23289
  */
23245
23290
  deleteRow(event, row, opts) {
23246
23291
  return __awaiter(this, void 0, void 0, function* () {
@@ -23253,7 +23298,7 @@ class AppTable {
23253
23298
  * @param event
23254
23299
  * @param rows
23255
23300
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
23256
- * Use skipIfLoading=false to force deletion even if table is busy
23301
+ * And to force deletion even if table is busy
23257
23302
  */
23258
23303
  deleteRows(event, rows, opts) {
23259
23304
  var _a;
@@ -23266,8 +23311,8 @@ class AppTable {
23266
23311
  event === null || event === void 0 ? void 0 : event.preventDefault();
23267
23312
  if (!this._enabled || isEmptyArray(rows))
23268
23313
  return 0; // Skip is disabled, or no rows to delete
23269
- if (this.loading && (!opts || opts.skipIfLoading !== false)) {
23270
- console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.skipLoading = false to force deletion');
23314
+ if (this.loading && (!opts || opts.interactive !== false)) {
23315
+ console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.interactive = false to force deletion');
23271
23316
  return 0; // Skip if loading
23272
23317
  }
23273
23318
  // Make sure to keep newly created row
@@ -23404,15 +23449,11 @@ class AppTable {
23404
23449
  moveRow(id, direction) {
23405
23450
  this.dataSource.move(id, direction);
23406
23451
  }
23407
- ready() {
23408
- return __awaiter(this, void 0, void 0, function* () {
23409
- yield firstTruePromise(this.readySubject);
23410
- });
23452
+ ready(opts) {
23453
+ return waitForTrue(this.readySubject, opts);
23411
23454
  }
23412
23455
  waitIdle(opts) {
23413
- return __awaiter(this, void 0, void 0, function* () {
23414
- yield firstFalsePromise(this.loadingSubject);
23415
- });
23456
+ return waitForFalse(this.loadingSubject, opts);
23416
23457
  }
23417
23458
  openSelectColumnsModal(event) {
23418
23459
  return __awaiter(this, void 0, void 0, function* () {
@@ -23790,9 +23831,10 @@ class AppTable {
23790
23831
  //if (this.debug) console.debug("[table] id = " + id);
23791
23832
  return id;
23792
23833
  }
23793
- addRowToTable(insertAt) {
23834
+ addRowToTable(insertAt, opts) {
23794
23835
  return __awaiter(this, void 0, void 0, function* () {
23795
23836
  this.focusFirstColumn = true;
23837
+ this.focusColumn = (opts === null || opts === void 0 ? void 0 : opts.focusColumn) || this.firstUserColumn;
23796
23838
  yield this._dataSource.asyncCreateNew(insertAt);
23797
23839
  this.editedRow = this._dataSource.getRow(-1);
23798
23840
  // Emit start editing event
@@ -24139,8 +24181,9 @@ class AppEditor {
24139
24181
  this._subscription = new Subscription();
24140
24182
  this._enabled = false;
24141
24183
  this._dirty = false;
24142
- this._$ready = new BehaviorSubject(false);
24143
- this._$loading = new BehaviorSubject(true);
24184
+ this.readySubject = new BehaviorSubject(false);
24185
+ this.loadingSubject = new BehaviorSubject(true);
24186
+ this.errorSubject = new BehaviorSubject(undefined);
24144
24187
  this.debug = false;
24145
24188
  this.submitted = false;
24146
24189
  this.toolbar = null;
@@ -24150,18 +24193,36 @@ class AppEditor {
24150
24193
  * @deprecated
24151
24194
  */
24152
24195
  set _loading(value) {
24153
- this._$loading.next(value);
24196
+ this.loadingSubject.next(value);
24154
24197
  }
24155
24198
  /**
24156
24199
  * @deprecated
24157
24200
  */
24158
24201
  get _loading() {
24159
- return this._$loading.value;
24202
+ return this.loadingSubject.value;
24160
24203
  }
24161
- get tables() {
24162
- return this._children && this._children.filter(c => c instanceof AppTable);
24204
+ /**
24205
+ * @deprecated
24206
+ */
24207
+ get _$ready() {
24208
+ return this.readySubject;
24163
24209
  }
24164
- get forms() {
24210
+ /**
24211
+ * @deprecated
24212
+ */
24213
+ get _$loading() {
24214
+ return this.loadingSubject;
24215
+ }
24216
+ get error() {
24217
+ return this.errorSubject.value;
24218
+ }
24219
+ set error(error) {
24220
+ this.setError(error);
24221
+ }
24222
+ get tables() {
24223
+ return this._children && this._children.filter(c => c instanceof AppTable);
24224
+ }
24225
+ get forms() {
24165
24226
  return this._children && this._children.filter(c => c instanceof AppForm);
24166
24227
  }
24167
24228
  get dirty() {
@@ -24185,7 +24246,7 @@ class AppEditor {
24185
24246
  }
24186
24247
  get loading() {
24187
24248
  var _a;
24188
- return this._$loading.value || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
24249
+ return this.loadingSubject.value || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
24189
24250
  }
24190
24251
  get enabled() {
24191
24252
  return this._enabled;
@@ -24209,10 +24270,9 @@ class AppEditor {
24209
24270
  }
24210
24271
  ngOnDestroy() {
24211
24272
  this._subscription.unsubscribe();
24212
- this._$ready.complete();
24213
- this._$ready.unsubscribe();
24214
- this._$loading.complete();
24215
- this._$loading.unsubscribe();
24273
+ this.readySubject.unsubscribe();
24274
+ this.loadingSubject.unsubscribe();
24275
+ this.errorSubject.unsubscribe();
24216
24276
  }
24217
24277
  addChildForm(form) {
24218
24278
  if (!form)
@@ -24281,16 +24341,16 @@ class AppEditor {
24281
24341
  this.markForCheck();
24282
24342
  }
24283
24343
  markAsLoading(opts) {
24284
- if (!this._loading) {
24285
- this._loading = true;
24344
+ if (!this.loadingSubject.value) {
24345
+ this.loadingSubject.next(true);
24286
24346
  if (!opts || opts.emitEvent !== false)
24287
24347
  this.markForCheck();
24288
24348
  }
24289
24349
  }
24290
24350
  markAsLoaded(opts) {
24291
24351
  var _a;
24292
- if (this._loading) {
24293
- this._loading = false;
24352
+ if (this.loadingSubject.value) {
24353
+ this.loadingSubject.next(false);
24294
24354
  if (!opts || opts.onlySelf !== true) {
24295
24355
  // Emit to children forms
24296
24356
  // Tables should be changed by parent
@@ -24304,15 +24364,17 @@ class AppEditor {
24304
24364
  markAsReady(opts) {
24305
24365
  var _a;
24306
24366
  (_a = this._children) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markAsReady(opts));
24307
- this._$ready.next(true);
24367
+ this.readySubject.next(true);
24308
24368
  }
24309
24369
  ready(opts) {
24310
- return __awaiter(this, void 0, void 0, function* () {
24311
- return waitForTrue(this._$ready, opts);
24312
- });
24370
+ if (this.readySubject.value)
24371
+ return Promise.resolve();
24372
+ return waitForTrue(this.readySubject, opts);
24313
24373
  }
24314
24374
  waitIdle(opts) {
24315
- return AppFormUtils.waitIdle(this, opts);
24375
+ if (!this.loadingSubject.value)
24376
+ return Promise.resolve();
24377
+ return waitForFalse(this.loadingSubject, opts);
24316
24378
  }
24317
24379
  cancel(event) {
24318
24380
  return __awaiter(this, void 0, void 0, function* () {
@@ -24515,6 +24577,14 @@ class AppEditor {
24515
24577
  console.warn(`${prefix} Unknown children sub-form: `, c);
24516
24578
  }
24517
24579
  }
24580
+ setError(value, opts) {
24581
+ if (this.errorSubject.value !== value) {
24582
+ this.errorSubject.next(value);
24583
+ if (!opts || opts.emitEvent !== false) {
24584
+ this.markForCheck();
24585
+ }
24586
+ }
24587
+ }
24518
24588
  markForCheck() {
24519
24589
  // Should be override by subclasses, if change detection is Push
24520
24590
  }
@@ -24579,6 +24649,8 @@ class AppTabEditor extends AppEditor {
24579
24649
  ngOnDestroy() {
24580
24650
  super.ngOnDestroy();
24581
24651
  this.selectedTabIndexChange.complete();
24652
+ this.loadingSubject.unsubscribe();
24653
+ this.errorSubject.unsubscribe();
24582
24654
  }
24583
24655
  setSelectedTabIndex(value, opts) {
24584
24656
  // Fix value
@@ -24601,6 +24673,10 @@ class AppTabEditor extends AppEditor {
24601
24673
  this.markForCheck();
24602
24674
  }
24603
24675
  }
24676
+ realignInkBar() {
24677
+ var _a;
24678
+ (_a = this.tabGroup) === null || _a === void 0 ? void 0 : _a.realignInkBar();
24679
+ }
24604
24680
  onTabChange(event, queryTabIndexParamName) {
24605
24681
  queryTabIndexParamName = queryTabIndexParamName || this.queryTabIndexParamName;
24606
24682
  if (!queryTabIndexParamName || !this.route)
@@ -24670,6 +24746,16 @@ class AppTabEditor extends AppEditor {
24670
24746
  yield _super.unload.call(this, opts);
24671
24747
  });
24672
24748
  }
24749
+ saveDirtyTables() {
24750
+ return __awaiter(this, void 0, void 0, function* () {
24751
+ // Save all dirty tables
24752
+ const results = yield Promise.all((this.tables || [])
24753
+ .filter(c => c.dirty)
24754
+ .map(c => c.save()));
24755
+ const saved = results.findIndex(result => result !== true) === -1;
24756
+ return saved;
24757
+ });
24758
+ }
24673
24759
  }
24674
24760
  AppTabEditor.decorators = [
24675
24761
  { type: Directive }
@@ -24698,7 +24784,7 @@ class AppEntityEditor extends AppTabEditor {
24698
24784
  super(injector.get(ActivatedRoute), injector.get(Router), injector.get(AlertController), injector.get(TranslateService), options);
24699
24785
  this.dataType = dataType;
24700
24786
  this.dataService = dataService;
24701
- this.saving = false;
24787
+ this.savingSubject = new BehaviorSubject(false);
24702
24788
  this.$title = new Subject();
24703
24789
  this.onUpdateView = new EventEmitter();
24704
24790
  this.environement = injector.get(ENVIRONMENT);
@@ -24741,21 +24827,24 @@ class AppEntityEditor extends AppTabEditor {
24741
24827
  return isNil((_a = this.data) === null || _a === void 0 ? void 0 : _a.id);
24742
24828
  }
24743
24829
  get loading() {
24744
- return this._loading;
24830
+ return this.loadingSubject.value;
24831
+ }
24832
+ get saving() {
24833
+ return this.savingSubject.value;
24745
24834
  }
24746
24835
  get service() {
24747
24836
  return this.dataService;
24748
24837
  }
24749
24838
  markAsSaving(opts) {
24750
- if (!this.saving) {
24751
- this.saving = true;
24839
+ if (this.savingSubject.value !== true) {
24840
+ this.savingSubject.next(true);
24752
24841
  if (!opts || opts.emitEvent !== false)
24753
24842
  this.markForCheck();
24754
24843
  }
24755
24844
  }
24756
24845
  markAsSaved(opts) {
24757
- if (this.saving) {
24758
- this.saving = false;
24846
+ if (this.savingSubject.value !== false) {
24847
+ this.savingSubject.next(false);
24759
24848
  if (!opts || opts.emitEvent !== false)
24760
24849
  this.markForCheck();
24761
24850
  }
@@ -24784,11 +24873,12 @@ class AppEntityEditor extends AppTabEditor {
24784
24873
  this.$title.unsubscribe();
24785
24874
  this.onUpdateView.complete();
24786
24875
  this.onUpdateView.unsubscribe();
24876
+ this.savingSubject.unsubscribe();
24787
24877
  }
24788
24878
  waitIdle(opts) {
24789
24879
  // Wait end of saving
24790
24880
  if (this.saving)
24791
- return waitFor(() => this.saving !== true);
24881
+ return waitForFalse(this.savingSubject);
24792
24882
  return super.waitIdle(opts);
24793
24883
  }
24794
24884
  /**
@@ -25033,9 +25123,10 @@ class AppEntityEditor extends AppTabEditor {
25033
25123
  yield this.waitWhilePending();
25034
25124
  // If invalid
25035
25125
  if (this.invalid) {
25036
- this.markAllAsTouched();
25037
25126
  this.logFormErrors();
25038
25127
  this.openFirstInvalidTab();
25128
+ this.scrollToTop();
25129
+ this.markAllAsTouched();
25039
25130
  this.submitted = true;
25040
25131
  return false;
25041
25132
  }
@@ -25046,6 +25137,10 @@ class AppEntityEditor extends AppTabEditor {
25046
25137
  try {
25047
25138
  // Compute next tab index (if enable)
25048
25139
  const nextTabIndex = this._autoOpenNextTab && isNil(this.previousDataId) && this.computeNextTabIndex();
25140
+ // Save all dirty tables
25141
+ const saved = yield this.saveDirtyTables();
25142
+ if (!saved)
25143
+ return false;
25049
25144
  // Get data
25050
25145
  const data = yield this.getValue();
25051
25146
  this.disable();
@@ -25159,7 +25254,7 @@ class AppEntityEditor extends AppTabEditor {
25159
25254
  this.registerForms();
25160
25255
  this._dirty = false;
25161
25256
  this.data = null;
25162
- this.saving = false;
25257
+ this.savingSubject.next(false);
25163
25258
  });
25164
25259
  }
25165
25260
  goBack(event) {
@@ -25369,7 +25464,7 @@ class AppEntityEditorModal extends AppTabEditor {
25369
25464
  constructor(injector, dataType, options) {
25370
25465
  super(null, injector.get(Router), injector.get(AlertController), injector.get(TranslateService), options);
25371
25466
  this.dataType = dataType;
25372
- this.saving = false;
25467
+ this.savingSubject = new BehaviorSubject(false);
25373
25468
  this.$title = new Subject();
25374
25469
  this.i18nSuffix = null;
25375
25470
  this.environement = injector.get(ENVIRONMENT);
@@ -25405,16 +25500,19 @@ class AppEntityEditorModal extends AppTabEditor {
25405
25500
  get isOnFieldMode() {
25406
25501
  return this.settings.isOnFieldMode(this._usageMode);
25407
25502
  }
25503
+ get saving() {
25504
+ return this.savingSubject.value;
25505
+ }
25408
25506
  markAsSaving(opts) {
25409
- if (!this.saving) {
25410
- this.saving = true;
25507
+ if (this.savingSubject.value !== true) {
25508
+ this.savingSubject.next(true);
25411
25509
  if (!opts || opts.emitEvent !== false)
25412
25510
  this.markForCheck();
25413
25511
  }
25414
25512
  }
25415
25513
  markAsSaved(opts) {
25416
- if (this.saving) {
25417
- this.saving = false;
25514
+ if (this.savingSubject.value !== false) {
25515
+ this.savingSubject.next(false);
25418
25516
  if (!opts || opts.emitEvent !== false)
25419
25517
  this.markForCheck();
25420
25518
  }
@@ -25458,11 +25556,12 @@ class AppEntityEditorModal extends AppTabEditor {
25458
25556
  super.ngOnDestroy();
25459
25557
  this.$title.complete();
25460
25558
  this.$title.unsubscribe();
25559
+ this.savingSubject.unsubscribe();
25461
25560
  }
25462
25561
  waitIdle(opts) {
25463
25562
  // Wait end of saving
25464
25563
  if (this.saving)
25465
- return waitFor(() => this.saving !== true);
25564
+ return waitForFalse(this.savingSubject);
25466
25565
  return super.waitIdle(opts);
25467
25566
  }
25468
25567
  load() {
@@ -25568,9 +25667,9 @@ class AppEntityEditorModal extends AppTabEditor {
25568
25667
  if (this.invalid) {
25569
25668
  this.logFormErrors();
25570
25669
  this.setError('COMMON.FORM.HAS_ERROR');
25571
- this.markAllAsTouched();
25572
25670
  this.openFirstInvalidTab();
25573
25671
  this.scrollToTop();
25672
+ this.markAllAsTouched();
25574
25673
  this.submitted = true;
25575
25674
  return false;
25576
25675
  }
@@ -25580,13 +25679,14 @@ class AppEntityEditorModal extends AppTabEditor {
25580
25679
  console.debug(this._logPrefix + 'Saving data...');
25581
25680
  try {
25582
25681
  // Save all dirty tables
25583
- const saved = Promise.all((this.tables || [])
25584
- .filter(c => c.dirty)
25585
- .map(c => c.save()))
25586
- .then(res => res.findIndex(r => r !== true) === -1);
25682
+ const saved = yield this.saveDirtyTables();
25683
+ if (!saved)
25684
+ return false;
25685
+ // Fill data
25587
25686
  this.data = yield this.getValue();
25687
+ // Mark as submitted
25588
25688
  this.submitted = true;
25589
- return saved;
25689
+ return true;
25590
25690
  }
25591
25691
  catch (err) {
25592
25692
  this.submitted = true;
@@ -25823,10 +25923,7 @@ AppInMemoryTable.propDecorators = {
25823
25923
  const SocialErrorCodes = {
25824
25924
  LOAD_USER_EVENTS_ERROR: 50000,
25825
25925
  SAVE_USER_EVENT_ERROR: 50001,
25826
- COUNT_USER_EVENT_ERROR: 50002,
25827
- SEND_MESSAGE_ERROR: 50003,
25828
- SUBSCRIBE_USER_EVENTS_ERROR: 50005,
25829
- SUBSCRIBE_JOB_PROGRESSION_ERROR: 50010
25926
+ SEND_MESSAGE_ERROR: 50003
25830
25927
  };
25831
25928
 
25832
25929
  var UserEvent_1;
@@ -25841,23 +25938,16 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25841
25938
  }
25842
25939
  asObject(opts) {
25843
25940
  const target = super.asObject(opts);
25844
- target.creationDate = toDateISOString(this.creationDate);
25845
- target.readDate = toDateISOString(this.readDate);
25846
25941
  // Serialize content
25847
25942
  if (typeof target.content === 'object') {
25848
25943
  target.content = JSON.stringify(target.content);
25849
25944
  }
25850
- delete target.avatar;
25851
- delete target.avatarIcon;
25852
- delete target.icon;
25853
- delete target.actions;
25854
25945
  return target;
25855
25946
  }
25856
25947
  fromObject(source) {
25857
25948
  Object.assign(this, source); // Copy all properties
25858
25949
  super.fromObject(source);
25859
25950
  this.creationDate = fromDateISOString(source.creationDate);
25860
- this.readDate = fromDateISOString(source.readDate);
25861
25951
  try {
25862
25952
  // Deserialize content
25863
25953
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -25876,52 +25966,6 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25876
25966
  UserEvent = UserEvent_1 = __decorate([
25877
25967
  EntityClass({ typename: 'UserEventVO' })
25878
25968
  ], UserEvent);
25879
- // @dynamic
25880
- let UserEventFilter = class UserEventFilter extends EntityFilter {
25881
- constructor() {
25882
- super(...arguments);
25883
- this.types = [];
25884
- this.levels = [];
25885
- this.issuers = [];
25886
- this.recipients = [];
25887
- this.startDate = null;
25888
- this.excludeRead = false;
25889
- }
25890
- fromObject(source, opts) {
25891
- super.fromObject(source, opts);
25892
- this.types = source.types || [];
25893
- this.levels = source.levels || [];
25894
- this.issuers = source.issuers || [];
25895
- this.recipients = source.recipients || [];
25896
- this.startDate = fromDateISOString(source.startDate);
25897
- this.excludeRead = source.excludeRead || false;
25898
- }
25899
- buildFilter() {
25900
- const filterFns = super.buildFilter();
25901
- if (isNotEmptyArray(this.types)) {
25902
- filterFns.push(t => this.types.includes(t.type));
25903
- }
25904
- if (isNotEmptyArray(this.levels)) {
25905
- filterFns.push(t => this.levels.includes(t.level));
25906
- }
25907
- if (isNotEmptyArray(this.issuers)) {
25908
- filterFns.push(t => this.issuers.includes(t.issuer));
25909
- }
25910
- if (isNotEmptyArray(this.recipients)) {
25911
- filterFns.push(t => this.recipients.includes(t.recipient));
25912
- }
25913
- if (isNotNil(this.startDate)) {
25914
- filterFns.push(t => this.startDate.isSameOrBefore(t.creationDate));
25915
- }
25916
- if (this.excludeRead === true) {
25917
- filterFns.push(t => isNil(t.readSignature)); // todo or t.signature ?
25918
- }
25919
- return filterFns;
25920
- }
25921
- };
25922
- UserEventFilter = __decorate([
25923
- EntityClass({ typename: 'UserEventFilterVO' })
25924
- ], UserEventFilter);
25925
25969
 
25926
25970
  const UserEventFragments = {
25927
25971
  userEvent: gql `fragment UserEventFragment on UserEventVO {
@@ -25949,190 +25993,134 @@ const UserEventFragments = {
25949
25993
  }`
25950
25994
  };
25951
25995
 
25952
- const moment$6 = momentImported;
25953
- const UserEventServiceToken = new InjectionToken('UserEventService');
25954
- class AbstractUserEventService extends BaseGraphqlService {
25955
- constructor(graphql, accountService, network, translate, queries, mutations, subscriptions, environment) {
25996
+ // @dynamic
25997
+ let UserEventFilter = class UserEventFilter extends EntityFilter {
25998
+ constructor() {
25999
+ super(...arguments);
26000
+ this.issuer = null;
26001
+ this.recipient = null;
26002
+ }
26003
+ fromObject(source, opts) {
26004
+ super.fromObject(source, opts);
26005
+ this.issuer = source.issuer;
26006
+ this.recipient = source.recipient;
26007
+ }
26008
+ buildFilter() {
26009
+ const filterFns = super.buildFilter();
26010
+ // issuer
26011
+ if (this.issuer) {
26012
+ filterFns.push(t => (t.issuer === this.issuer));
26013
+ }
26014
+ if (this.recipient) {
26015
+ filterFns.push(t => (t.recipient === this.recipient));
26016
+ }
26017
+ return filterFns;
26018
+ }
26019
+ };
26020
+ UserEventFilter = __decorate([
26021
+ EntityClass({ typename: 'UserEventFilterVO' })
26022
+ ], UserEventFilter);
26023
+ const SaveQuery = gql `
26024
+ mutation SaveUserEvent($data: UserEventVOInput){
26025
+ data: saveUserEvent(userEvent: $data){
26026
+ ...UserEventFragment
26027
+ }
26028
+ }
26029
+ ${UserEventFragments.userEvent}
26030
+ `;
26031
+ const LoadAllQuery = gql `
26032
+ query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26033
+ data: userEvents(filter: $filter, page: $page){
26034
+ ...LightUserEventFragment
26035
+ }
26036
+ }
26037
+ ${UserEventFragments.lightUserEvent}
26038
+ `;
26039
+ const DeleteByIdsMutation = gql `
26040
+ mutation DeleteUserEvents($ids:[Int]){
26041
+ deleteUserEvents(ids: $ids)
26042
+ }
26043
+ `;
26044
+ const LoadAllWithContentQuery = gql `
26045
+ query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26046
+ data: userEvents(filter: $filter, page: $page){
26047
+ ...UserEventFragment
26048
+ }
26049
+ }
26050
+ ${UserEventFragments.userEvent}
26051
+ `;
26052
+ class UserEventService extends BaseGraphqlService {
26053
+ constructor(graphql, accountService, network, translate, toastController, environment) {
25956
26054
  super(graphql, environment);
25957
26055
  this.graphql = graphql;
25958
26056
  this.accountService = accountService;
25959
26057
  this.network = network;
25960
26058
  this.translate = translate;
25961
- this.queries = queries;
25962
- this.mutations = mutations;
25963
- this.subscriptions = subscriptions;
26059
+ this.toastController = toastController;
25964
26060
  this.environment = environment;
25965
- this._count$ = new BehaviorSubject(0);
25966
- this._subscriptions = new Subscription();
25967
- this.listeners = [];
25968
- this._logPrefix = '[user-event-service] ';
26061
+ this._userEventActions = [];
25969
26062
  // For DEV only
25970
- this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
25971
- // listen login/logout
25972
- this._subscriptions.add(accountService.onLogin.subscribe(() => __awaiter(this, void 0, void 0, function* () {
25973
- const count = yield this.count(this.defaultFilter());
25974
- if (count && this._debug) {
25975
- console.debug(`${this._logPrefix}Received ${count} unread notifications`);
25976
- }
25977
- this._count$.next(count);
25978
- })));
25979
- }
25980
- get userEventCount() {
25981
- return this._count$.asObservable();
25982
- }
25983
- ngOnDestroy() {
25984
- this._subscriptions.unsubscribe();
26063
+ this._debug = environment && !environment.production;
25985
26064
  }
26065
+ /**
26066
+ *
26067
+ * @param offset
26068
+ * @param size
26069
+ * @param sortBy
26070
+ * @param sortDirection
26071
+ * @param filter
26072
+ * @param options
26073
+ * @deprecated use watchPage() instead
26074
+ */
25986
26075
  watchAll(offset, size, sortBy, sortDirection, filter, options) {
25987
26076
  return this.watchPage({ offset, size, sortBy, sortDirection }, filter, options);
25988
26077
  }
25989
26078
  watchPage(page, filter, options) {
25990
- var _a;
25991
26079
  let now = this._debug && Date.now();
25992
26080
  //if (this._debug)
25993
- console.debug(`${this._logPrefix}Loading user events...`, filter);
26081
+ console.debug('[user-event-service] Loading user events...', filter);
25994
26082
  filter = this.asFilter(filter);
25995
26083
  // Force recipient to current issuer, if not admin and not specified
25996
- if (isEmptyArray(filter === null || filter === void 0 ? void 0 : filter.recipients) || !this.accountService.isAdmin()) {
25997
- const recipient = this.defaultRecipient();
25998
- if (!((_a = filter === null || filter === void 0 ? void 0 : filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
26084
+ if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
26085
+ const recipient = this.accountService.account.pubkey;
26086
+ if (recipient !== filter.recipient) {
25999
26087
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
26000
- filter.recipients = [recipient];
26088
+ filter.recipient = recipient;
26001
26089
  }
26002
26090
  }
26003
- const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26091
+ const withContent = options && options.withContent === true;
26004
26092
  return this.mutableWatchQuery({
26005
26093
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
26006
- query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26094
+ query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
26007
26095
  variables: {
26008
- page: Object.assign(Object.assign({ sortBy: 'creationDate' }, page), {
26009
- // @ts-ignore
26010
- sortDirection: (page.sortDirection || 'desc').toUpperCase() }),
26096
+ page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
26011
26097
  filter: filter && filter.asPodObject()
26012
26098
  },
26013
26099
  arrayFieldName: 'data',
26014
26100
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
26015
- fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || "cache-first"
26101
+ fetchPolicy: options && options.fetchPolicy || undefined
26016
26102
  })
26017
26103
  .pipe(map(res => {
26018
- const data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(this.processUserEvent);
26104
+ const data = res && (res.data || []).map(UserEvent.fromObject);
26019
26105
  if (now) {
26020
- console.debug(`${this._logPrefix}${data.length} user events loaded in ${Date.now() - now}ms`);
26106
+ console.debug(`[user-event-service] ${data.length} user events loaded in ${Date.now() - now}ms`);
26021
26107
  now = null;
26022
26108
  }
26023
- const unreadCount = this.unreadEvents(data);
26024
26109
  return {
26025
26110
  data,
26026
- total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
26111
+ total: res && toNumber(res.total, data.length)
26027
26112
  };
26028
26113
  }));
26029
26114
  }
26030
- add(entity) {
26031
- // TODO set an id !!!!!!!!!!!!!!!!!!!!!!!!!
26032
- entity = this.processUserEvent(entity);
26033
- const withContent = !!entity.content;
26034
- // Add user event locally
26035
- this.insertIntoMutableCachedQueries(this.graphql.cache, {
26036
- query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26037
- data: entity
26038
- });
26039
- // Update count
26040
- this._count$.next(this._count$.value + 1);
26041
- }
26042
- count(filter, options) {
26043
- var _a;
26044
- return __awaiter(this, void 0, void 0, function* () {
26045
- if (!((_a = this.queries) === null || _a === void 0 ? void 0 : _a.count)) {
26046
- console.warn(`${this._logPrefix}Query 'count' not provided, skip.`);
26047
- return undefined;
26048
- }
26049
- if (!filter)
26050
- throw new Error(`Missing argument 'filter'`);
26051
- filter = this.asFilter(filter);
26052
- if (this._debug)
26053
- console.debug(`${this._logPrefix}Counting user events with filter:`, filter);
26054
- const res = yield this.graphql.query({
26055
- query: this.queries.count,
26056
- variables: {
26057
- filter: filter.asPodObject()
26058
- },
26059
- error: { code: SocialErrorCodes.COUNT_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.COUNT_USER_EVENT_ERROR' },
26060
- fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'network-only'
26061
- });
26062
- return res.total;
26063
- });
26064
- }
26065
- listenChanges(filter, options) {
26066
- var _a;
26067
- if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
26068
- console.warn(`${this._logPrefix}Subscription query 'listenChanges' not provided, skip.`);
26069
- return of();
26070
- }
26071
- if (!filter)
26072
- throw new Error(`Missing argument 'filter'`);
26073
- filter = this.asFilter(filter);
26074
- const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26075
- if (this._debug)
26076
- console.debug(`${this._logPrefix}[WS] Listening changes for user events with filter:`, filter);
26077
- return this.graphql.subscribe({
26078
- query: this.subscriptions.listenChanges,
26079
- fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
26080
- variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
26081
- error: {
26082
- code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
26083
- message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
26084
- }
26085
- }).pipe(map(({ data }) => {
26086
- if (data && this._debug)
26087
- console.debug(`${this._logPrefix}Received new user events:`, data);
26088
- const updatedData = data === null || data === void 0 ? void 0 : data.map(this.processUserEvent);
26089
- // Update cache
26090
- this.insertIntoMutableCachedQueries(this.graphql.cache, {
26091
- query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26092
- data: updatedData
26093
- });
26094
- // update count
26095
- this._count$.next(this.unreadEvents(updatedData));
26096
- return updatedData;
26097
- }));
26098
- }
26099
- delete(entity) {
26100
- return __awaiter(this, void 0, void 0, function* () {
26101
- if (!entity)
26102
- return; // skip
26103
- yield this.deleteAll([entity]);
26104
- });
26105
- }
26106
- deleteAll(entities, opts) {
26107
- return __awaiter(this, void 0, void 0, function* () {
26108
- const ids = entities && entities
26109
- .map(t => t.id);
26110
- if (isEmptyArray(ids))
26111
- return; // stop, if nothing else to do
26112
- const now = Date.now();
26113
- if (this._debug)
26114
- console.debug(`${this._logPrefix}Deleting events... ids:`, ids);
26115
- yield this.graphql.mutate({
26116
- mutation: this.mutations.deleteByIds,
26117
- variables: {
26118
- ids
26119
- },
26120
- update: (proxy) => {
26121
- // Remove from caches
26122
- this.removeFromMutableCachedQueriesByIds(proxy, {
26123
- query: this.queries.loadAll,
26124
- ids
26125
- });
26126
- this.removeFromMutableCachedQueriesByIds(proxy, {
26127
- query: this.queries.loadAllWithContent,
26128
- ids
26129
- });
26130
- if (this._debug)
26131
- console.debug(`${this._logPrefix}Events deleted in ${Date.now() - now}ms`);
26132
- }
26133
- });
26134
- });
26115
+ saveAll(data, options) {
26116
+ return Promise.all(data
26117
+ .map(entity => this.save(entity, options)));
26135
26118
  }
26119
+ /**
26120
+ * Save a userEvent entity
26121
+ *
26122
+ * @param entity
26123
+ */
26136
26124
  save(entity, options) {
26137
26125
  return __awaiter(this, void 0, void 0, function* () {
26138
26126
  this.fillDefaultProperties(entity);
@@ -26141,9 +26129,9 @@ class AbstractUserEventService extends BaseGraphqlService {
26141
26129
  const json = entity.asObject();
26142
26130
  const now = Date.now();
26143
26131
  if (this._debug)
26144
- console.debug(`${this._logPrefix}Saving user event...`, json);
26132
+ console.debug(`[user-event-service] Saving user event...`, json);
26145
26133
  yield this.graphql.mutate({
26146
- mutation: this.mutations.save,
26134
+ mutation: SaveQuery,
26147
26135
  variables: {
26148
26136
  data: json
26149
26137
  },
@@ -26153,16 +26141,16 @@ class AbstractUserEventService extends BaseGraphqlService {
26153
26141
  const savedEntity = data && data.data;
26154
26142
  if (savedEntity) {
26155
26143
  if (this._debug)
26156
- console.debug(`${this._logPrefix}User event saved in ${Date.now() - now}ms`, entity);
26144
+ console.debug(`[user-event-service] User event saved in ${Date.now() - now}ms`, entity);
26157
26145
  this.copyIdAndUpdateDate(savedEntity, entity);
26158
26146
  // Add to cache
26159
26147
  if (isNew) {
26160
26148
  this.insertIntoMutableCachedQueries(proxy, {
26161
- query: this.queries.loadAll,
26149
+ query: LoadAllQuery,
26162
26150
  data: Object.assign(Object.assign({}, savedEntity), { content: null })
26163
26151
  });
26164
26152
  this.insertIntoMutableCachedQueries(proxy, {
26165
- query: this.queries.loadAllWithContent,
26153
+ query: LoadAllWithContentQuery,
26166
26154
  data: savedEntity
26167
26155
  });
26168
26156
  }
@@ -26172,144 +26160,63 @@ class AbstractUserEventService extends BaseGraphqlService {
26172
26160
  return entity;
26173
26161
  });
26174
26162
  }
26175
- saveAll(data, opts) {
26176
- return Promise.all(data
26177
- .map(entity => this.save(entity, opts)));
26178
- }
26179
- markAsRead(entity) {
26163
+ /**
26164
+ * Save many trips
26165
+ *
26166
+ * @param entities
26167
+ * @param opts
26168
+ */
26169
+ deleteAll(entities, opts) {
26180
26170
  return __awaiter(this, void 0, void 0, function* () {
26181
- // Get onRead listeners
26182
- const onReadListeners = (this.listeners || []).filter(listener => !!listener.onRead).filter(listener => listener.accept(entity));
26183
- if (onReadListeners.length) {
26184
- for (const listener of onReadListeners) {
26185
- yield listener.onRead(entity);
26171
+ const ids = entities && entities
26172
+ .map(t => t.id);
26173
+ if (isEmptyArray(ids))
26174
+ return; // stop, if nothing else to do
26175
+ const now = Date.now();
26176
+ if (this._debug)
26177
+ console.debug('[user-event-service] Deleting events... ids:', ids);
26178
+ yield this.graphql.mutate({
26179
+ mutation: DeleteByIdsMutation,
26180
+ variables: {
26181
+ ids
26182
+ },
26183
+ update: (proxy) => {
26184
+ // Remove from caches
26185
+ this.removeFromMutableCachedQueriesByIds(proxy, {
26186
+ query: LoadAllQuery,
26187
+ ids
26188
+ });
26189
+ this.removeFromMutableCachedQueriesByIds(proxy, {
26190
+ query: LoadAllWithContentQuery,
26191
+ ids
26192
+ });
26193
+ if (this._debug)
26194
+ console.debug(`[user-event-service] Events deleted in ${Date.now() - now}ms`);
26186
26195
  }
26187
- }
26188
- else {
26189
- // Use default
26190
- yield this.defaultMarkAsRead(entity);
26191
- }
26196
+ });
26192
26197
  });
26193
26198
  }
26194
- registerListener(listener) {
26195
- if (!this.listeners)
26196
- this.listeners = [];
26197
- this.listeners.push(listener);
26198
- }
26199
- /* -- protected methods -- */
26200
- processUserEvent(source) {
26201
- // Convert json source to IUserEvent
26202
- let target = this.fromObject(source);
26203
- // Get listeners
26204
- const listeners = (this.listeners || []).filter(listener => listener.onReceived).filter(listener => listener.accept(target));
26205
- for (const listener of listeners) {
26206
- if (target) {
26207
- target = listener.onReceived(target);
26208
- }
26209
- else {
26210
- if (this._debug)
26211
- console.debug(`${this._logPrefix}Event has been rejected by a listener`, source);
26212
- break;
26213
- }
26214
- }
26215
- return target;
26216
- }
26217
- defaultMarkAsRead(userEvent) {
26199
+ /**
26200
+ * Delete userEvent entities
26201
+ */
26202
+ delete(data) {
26218
26203
  return __awaiter(this, void 0, void 0, function* () {
26219
- if (!userEvent)
26220
- throw new Error(`${this._logPrefix}Invalid event to save`);
26221
- // set read date
26222
- userEvent.readDate = moment$6();
26223
- if (!userEvent.id || userEvent.id < 0) {
26224
- if (this._debug)
26225
- console.debug(`${this._logPrefix}Save local user event`);
26226
- // TODO !!!!!!!!!!!!!
26227
- }
26228
- else {
26229
- yield this.save(userEvent);
26230
- }
26204
+ if (!data)
26205
+ return; // skip
26206
+ yield this.deleteAll([data]);
26231
26207
  });
26232
26208
  }
26233
- defaultFilter() {
26234
- // By default
26235
- return {
26236
- recipients: [this.defaultRecipient()]
26237
- };
26238
- }
26239
- defaultRecipient() {
26240
- return this.accountService.person.pubkey;
26241
- }
26242
- fillDefaultProperties(entity) {
26209
+ listenChanges(id, options) {
26210
+ // TODO
26211
+ console.warn('TODO: implement listen changes on user events');
26212
+ return of();
26243
26213
  }
26244
- unreadEvents(events) {
26245
- // default calculation on unread events from a list
26246
- if (isEmptyArray(events))
26247
- return undefined;
26248
- const lastReadDate = events
26249
- .filter(event => isNotNil(event.readDate))
26250
- .reduce((lastDate, event) => DateUtils.max(lastDate, event.readDate), undefined);
26251
- return events
26252
- .filter(event => event.creationDate.isSameOrAfter(lastReadDate)).length;
26214
+ registerAction(definition) {
26215
+ console.info(`[user-event-service] Registering action ${definition.name} for ${definition.__typename}`);
26216
+ this._userEventActions.push(definition);
26253
26217
  }
26254
- copyIdAndUpdateDate(source, target) {
26255
- EntityUtils.copyIdAndUpdateDate(source, target);
26256
- }
26257
- }
26258
- AbstractUserEventService.decorators = [
26259
- { type: Directive }
26260
- ];
26261
- AbstractUserEventService.ctorParameters = () => [
26262
- { type: GraphqlService },
26263
- { type: AccountService },
26264
- { type: NetworkService },
26265
- { type: TranslateService },
26266
- { type: undefined },
26267
- { type: undefined },
26268
- { type: undefined },
26269
- { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
26270
- ];
26271
- const userEventQueries = {
26272
- loadAll: gql `
26273
- query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26274
- data: userEvents(filter: $filter, page: $page){
26275
- ...LightUserEventFragment
26276
- }
26277
- }
26278
- ${UserEventFragments.lightUserEvent}
26279
- `,
26280
- loadAllWithContent: gql `
26281
- query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26282
- data: userEvents(filter: $filter, page: $page){
26283
- ...UserEventFragment
26284
- }
26285
- }
26286
- ${UserEventFragments.userEvent}
26287
- `
26288
- };
26289
- const userEventMutations = {
26290
- deleteByIds: gql `
26291
- mutation DeleteUserEvents($ids:[Int]){
26292
- deleteUserEvents(ids: $ids)
26293
- }
26294
- `,
26295
- save: gql `
26296
- mutation SaveUserEvent($data: UserEventVOInput){
26297
- data: saveUserEvent(userEvent: $data){
26298
- ...UserEventFragment
26299
- }
26300
- }
26301
- ${UserEventFragments.userEvent}
26302
- `
26303
- };
26304
- class UserEventService extends AbstractUserEventService {
26305
- constructor(graphql, accountService, network, translate, toastController, environment) {
26306
- super(graphql, accountService, network, translate, userEventQueries, userEventMutations, undefined, environment);
26307
- this.graphql = graphql;
26308
- this.accountService = accountService;
26309
- this.network = network;
26310
- this.translate = translate;
26311
- this.toastController = toastController;
26312
- this.environment = environment;
26218
+ getActionsByTypename(typename) {
26219
+ return this._userEventActions.filter(def => def.__typename === typename);
26313
26220
  }
26314
26221
  showToastErrorWithContext(opts) {
26315
26222
  return __awaiter(this, void 0, void 0, function* () {
@@ -26373,16 +26280,13 @@ class UserEventService extends AbstractUserEventService {
26373
26280
  }
26374
26281
  sendDataForDebug(data) {
26375
26282
  const userEvent = new UserEvent();
26376
- userEvent.type = UserEventTypes.DEBUG_DATA;
26283
+ userEvent.eventType = UserEventTypes.DEBUG_DATA;
26377
26284
  userEvent.content = this.convertObjectToString(data);
26378
26285
  return this.save(userEvent);
26379
26286
  }
26380
26287
  asFilter(filter) {
26381
26288
  return UserEventFilter.fromObject(filter);
26382
26289
  }
26383
- fromObject(source) {
26384
- return UserEvent.fromObject(source);
26385
- }
26386
26290
  /* -- protected methods -- */
26387
26291
  convertObjectToString(data) {
26388
26292
  if (typeof data === 'string') {
@@ -26411,9 +26315,13 @@ class UserEventService extends AbstractUserEventService {
26411
26315
  // TODO: compute sign
26412
26316
  console.warn('TODO: sign user event before sending');
26413
26317
  }
26318
+ copyIdAndUpdateDate(source, target) {
26319
+ EntityUtils.copyIdAndUpdateDate(source, target);
26320
+ }
26414
26321
  }
26322
+ UserEventService.ɵprov = ɵɵdefineInjectable({ factory: function UserEventService_Factory() { return new UserEventService(ɵɵinject(GraphqlService), ɵɵinject(AccountService), ɵɵinject(NetworkService), ɵɵinject(TranslateService), ɵɵinject(ToastController), ɵɵinject(ENVIRONMENT, 8)); }, token: UserEventService, providedIn: "root" });
26415
26323
  UserEventService.decorators = [
26416
- { type: Injectable }
26324
+ { type: Injectable, args: [{ providedIn: 'root' },] }
26417
26325
  ];
26418
26326
  UserEventService.ctorParameters = () => [
26419
26327
  { type: GraphqlService },
@@ -26426,7 +26334,7 @@ UserEventService.ctorParameters = () => [
26426
26334
 
26427
26335
  const ICONS_MAP = {
26428
26336
  DEBUG_DATA: { matIcon: 'bug_report' },
26429
- INBOX_MESSAGE: { matIcon: 'mail' }
26337
+ INBOX_MESSAGE: { matIcon: 'mail' },
26430
26338
  };
26431
26339
  // TODO: refactor with a registration done by data service:
26432
26340
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -26492,7 +26400,7 @@ class UserEventsTable extends AppTable {
26492
26400
  }
26493
26401
  }));
26494
26402
  const filter = this.filter || new UserEventFilter();
26495
- filter.recipients = [this.recipient];
26403
+ filter.recipient = this.recipient;
26496
26404
  this.setFilter(filter, { emitEvent: true });
26497
26405
  }
26498
26406
  start() {
@@ -26505,17 +26413,17 @@ class UserEventsTable extends AppTable {
26505
26413
  });
26506
26414
  }
26507
26415
  getIcon(source) {
26508
- return ICONS_MAP[source.type];
26416
+ return ICONS_MAP[source.eventType];
26509
26417
  }
26510
26418
  getDetail(source) {
26511
26419
  if (!source)
26512
26420
  return undefined;
26513
- if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
26421
+ if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
26514
26422
  const context = source.content.context;
26515
26423
  if (context && context.__typename) {
26516
- // const actions = this.service.getActionsByTypename(context.__typename);
26424
+ const actions = this.service.getActionsByTypename(context.__typename);
26517
26425
  return {
26518
- // actions,
26426
+ actions,
26519
26427
  title: source.content.error && source.content.error.message || source.content.message,
26520
26428
  description: source.content.error && source.content.error.details || undefined
26521
26429
  };
@@ -26527,11 +26435,11 @@ class UserEventsTable extends AppTable {
26527
26435
  doAction(action, row) {
26528
26436
  return __awaiter(this, void 0, void 0, function* () {
26529
26437
  const event = row.currentData;
26530
- // const context = event.content && event.content.context;
26438
+ const context = event.content && event.content.context;
26531
26439
  this.markAsLoading();
26532
26440
  if (action && typeof action.executeAction === 'function') {
26533
26441
  try {
26534
- let res = action.executeAction(event /*, context*/);
26442
+ let res = action.executeAction(event, context);
26535
26443
  res = (res instanceof Promise) ? yield res : res;
26536
26444
  }
26537
26445
  catch (err) {
@@ -26550,18 +26458,13 @@ UserEventsTable.decorators = [
26550
26458
  selector: 'app-user-events-table',
26551
26459
  template: "\n<!-- Type = options menu -->\n<mat-menu #optionsMenu=\"matMenu\" xPosition=\"after\">\n\n <!-- display columns -->\n <button mat-menu-item\n (click)=\"openSelectColumnsModal($event)\">\n <mat-icon>view_column</mat-icon>\n <ion-label translate>COMMON.DISPLAYED_COLUMNS_DOTS</ion-label>\n </button>\n\n</mat-menu>\n\n<!-- top header -->\n<mat-toolbar>\n\n <ng-container *ngIf=\"!selection.hasValue(); else hasSelection\">\n\n <button mat-icon-button [title]=\"'COMMON.BTN_REFRESH'|translate\" (click)=\"onRefresh.emit()\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n </ng-container>\n\n <!-- if row selection -->\n <ng-template #hasSelection>\n\n <!-- delete -->\n <button mat-icon-button class=\"hidden-xs hidden-sm\" *ngIf=\"canDelete\"\n [title]=\"'COMMON.BTN_DELETE'|translate\" (click)=\"deleteSelection($event)\">\n <mat-icon>delete</mat-icon>\n </button>\n </ng-template>\n\n <!-- error -->\n <ion-item *ngIf=\"error\" hidden-xs hidden-sm hidden-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <div class=\"toolbar-spacer\"></div>\n\n <button mat-icon-button\n [title]=\"'COMMON.BTN_OPTIONS'|translate\"\n [matMenuTriggerFor]=\"optionsMenu\">\n <mat-icon>more_vert</mat-icon>\n </button>\n</mat-toolbar>\n\n\n<mat-table [dataSource]=\"dataSource\" matSort\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n matSortDisableClear [trackBy]=\"trackByFn\">\n\n <!-- select -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(row) : null\" [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <!-- id -->\n <ng-container matColumnDef=\"id\">\n <mat-header-cell *matHeaderCellDef mat-sort-header [class.cdk-visually-hidden]=\"!isAdmin\">\n <app-loading-spinner [loading]=\"loadingSubject|async\"><ion-label>#</ion-label></app-loading-spinner>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!isAdmin\">{{ row.currentData.id | mathAbs }}</mat-cell>\n </ng-container>\n\n <!-- creationDate -->\n <ng-container matColumnDef=\"creationDate\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>SOCIAL.USER_EVENT.CREATION_DATE</ion-label>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <ion-text>\n {{row.currentData.creationDate | dateFromNow }}<br/>\n <ion-text color=\"medium\"><small>{{row.currentData.creationDate | dateFormat: {time: true} }}</small></ion-text>\n </ion-text>\n </mat-cell>\n </ng-container>\n\n <!-- icon -->\n <ng-container matColumnDef=\"icon\">\n <mat-header-cell *matHeaderCellDef>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row;\">\n <ng-container *ngIf=\"getIcon(row.currentData); let details\">\n <ion-icon slot=\"start\" *ngIf=\"details.icon\" [name]=\"details.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"details.matIcon\">{{details.matIcon}}</mat-icon>\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <!-- event type -->\n <ng-container matColumnDef=\"eventType\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>SOCIAL.USER_EVENT.EVENT_TYPE</ion-label>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row;\">\n <span>{{'SOCIAL.USER_EVENT.TYPE_ENUM.' + row.currentData.eventType | translate}}</span>\n </mat-cell>\n </ng-container>\n\n <!-- message -->\n <ng-container matColumnDef=\"message\">\n <mat-header-cell *matHeaderCellDef>\n <ion-label translate>SOCIAL.USER_EVENT.MESSAGE</ion-label>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row;\">\n <ng-container *ngIf=\"getDetail(row.currentData); let details\">\n <ion-text [innerHTML]=\"details.title|translate\">\n </ion-text>\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <!-- Actions buttons column -->\n <ng-container matColumnDef=\"actions\">\n <mat-header-cell *matHeaderCellDef>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\"getDetail(row.currentData); let details\">\n <button mat-icon-button color=\"light\"\n *ngFor=\"let action of details.actions\"\n [title]=\"action.title |translate\"\n [color]=\"action.color\"\n (click)=\"doAction(action, row)\">\n <ion-icon slot=\"start\" *ngIf=\"action.icon\" [name]=\"action.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"action.matIcon\">{{action.matIcon}}</mat-icon>\n </button>\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns;\"\n class=\"mat-row-disabled\"\n (click)=\"clickRow($event, row)\"></mat-row>\n\n</mat-table>\n\n<ion-row class=\"ion-no-padding\">\n <ion-col></ion-col>\n <ion-col class=\"ion-no-padding\" size=\"auto\">\n <mat-paginator [length]=\"totalRowCount\" [pageSize]=\"defaultPageSize\" [pageSizeOptions]=\"defaultPageSizeOptions\" showFirstLastButtons>\n </mat-paginator>\n </ion-col>\n</ion-row>\n",
26552
26460
  changeDetection: ChangeDetectionStrategy.OnPush,
26553
- providers: [
26554
- {
26555
- provide: UserEventServiceToken, useClass: UserEventService
26556
- }
26557
- ],
26558
26461
  styles: [".mat-header-row .mat-column-icon,.mat-row .mat-column-icon{max-width:40px;padding-left:0}.mat-header-row .mat-column-icon ion-icon,.mat-header-row .mat-column-icon mat-icon,.mat-row .mat-column-icon ion-icon,.mat-row .mat-column-icon mat-icon{font-size:1.2em;height:1.2em;width:1.2em}.mat-header-row .mat-column-creationDate,.mat-row .mat-column-creationDate{min-width:100px;max-width:120px}"]
26559
26462
  },] }
26560
26463
  ];
26561
26464
  UserEventsTable.ctorParameters = () => [
26562
26465
  { type: Injector },
26563
26466
  { type: AccountService },
26564
- { type: undefined, decorators: [{ type: Inject, args: [UserEventServiceToken,] }] },
26467
+ { type: UserEventService },
26565
26468
  { type: EntitiesStorage },
26566
26469
  { type: ChangeDetectorRef },
26567
26470
  { type: undefined, decorators: [{ type: Inject, args: [ENVIRONMENT,] }] }
@@ -26573,147 +26476,6 @@ UserEventsTable.propDecorators = {
26573
26476
  defaultSortDirection: [{ type: Input }]
26574
26477
  };
26575
26478
 
26576
- class UserEventNotificationList {
26577
- constructor(popoverController) {
26578
- this.popoverController = popoverController;
26579
- }
26580
- ngOnInit() {
26581
- }
26582
- read($event, userEvent) {
26583
- var _a;
26584
- if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
26585
- return;
26586
- (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
26587
- }
26588
- executeAction(action, userEvent) {
26589
- // Execute then close popover
26590
- action.executeAction(userEvent);
26591
- this.dismiss();
26592
- }
26593
- dismiss() {
26594
- this.popoverController.dismiss();
26595
- }
26596
- }
26597
- UserEventNotificationList.decorators = [
26598
- { type: Component, args: [{
26599
- selector: 'app-user-event-notification-list',
26600
- template: "\n<ion-list class=\"ion-list-popover\">\n\n <ion-row class=\"ion-list-header column\">\n <ion-col>\n <ion-label>{{titleI18n | translate}}</ion-label>\n </ion-col>\n </ion-row>\n\n <ion-item *ngIf=\"!(userEvents | async)?.length\">\n {{'SOCIAL.USER_EVENT.NOTIFICATION.EMPTY' | translate}}\n </ion-item>\n <ion-item\n *ngFor=\"let userEvent of userEvents | async\"\n (click)=\"read($event, userEvent)\"\n >\n\n <ion-avatar slot=\"start\">\n\n <img *ngIf=\"userEvent.avatar; else avatarIcon\" src=\"{{ userEvent.avatar }}\">\n\n <ng-template #avatarIcon>\n <app-icon\n *ngIf=\"userEvent.avatarIcon\"\n [ref]=\"userEvent.avatarIcon\"\n height=\"40\"\n width=\"40\"\n ></app-icon>\n </ng-template>\n\n </ion-avatar>\n\n <ion-grid class=\"ion-no-margin ion-no-padding\">\n <ion-row>\n <ion-col>\n <p [class.unread]=\"!userEvent.readDate\">\n {{userEvent.message}}\n </p>\n </ion-col>\n </ion-row>\n <ion-row *ngIf=\"userEvent.actions?.length\">\n <ion-col>\n <p>\n <span *ngFor=\"let action of userEvent.actions\">\n <a\n [style.margin-right.px]=\"8\"\n [style.cursor]=\"'pointer'\"\n (click)=\"executeAction(action, userEvent)\"\n >\n {{ '&#10142;&nbsp;' + action.name}}\n </a>\n </span>\n </p>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <app-icon\n *ngIf=\"userEvent.icon\"\n [ref]=\"userEvent.icon\"\n height=\"16\"\n width=\"16\"\n [style.vertical-align]=\"'sub'\"\n ></app-icon>\n <small>\n <span>{{userEvent.creationDate|dateFromNow}}</span>\n <span [style.color]=\"'gray'\">{{ ' | ' + (userEvent.creationDate|dateFormat:{time:true}) }}</span>\n </small>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-item>\n\n</ion-list>\n",
26601
- styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}"]
26602
- },] }
26603
- ];
26604
- UserEventNotificationList.ctorParameters = () => [
26605
- { type: PopoverController }
26606
- ];
26607
- UserEventNotificationList.propDecorators = {
26608
- titleI18n: [{ type: Input }],
26609
- userEvents: [{ type: Input }],
26610
- readEvent: [{ type: Output }]
26611
- };
26612
-
26613
- class UserEventNotificationComponent {
26614
- constructor(userEventService, accountService, popoverController, cd) {
26615
- this.userEventService = userEventService;
26616
- this.accountService = accountService;
26617
- this.popoverController = popoverController;
26618
- this.cd = cd;
26619
- this.debug = false;
26620
- this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
26621
- this.disabled = false;
26622
- this.userEventsSubject = new BehaviorSubject(undefined);
26623
- this._subscriptions = new Subscription();
26624
- this._logPrefix = '[user-event-notification] ';
26625
- this._readEvent = new EventEmitter();
26626
- }
26627
- get count() {
26628
- var _a;
26629
- return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(map(value => value === 0 ? undefined : value));
26630
- }
26631
- ngOnInit() {
26632
- if (isNil(this.userEventService)) {
26633
- console.warn(`${this._logPrefix}No service injected`);
26634
- this.disabled = true;
26635
- return;
26636
- }
26637
- this._subscriptions.add(this.userEventService.watchAll(0, 10, 'creationDate', "desc").subscribe(value => {
26638
- const data = value.data;
26639
- if (this.debug) {
26640
- console.debug(`${this._logPrefix}Receiving user events`, data);
26641
- }
26642
- this.userEventsSubject.next(data);
26643
- }));
26644
- this._readEvent.subscribe(value => {
26645
- this.userEventService.markAsRead(value);
26646
- });
26647
- }
26648
- showList(event) {
26649
- return __awaiter(this, void 0, void 0, function* () {
26650
- const popover = yield this.popoverController.create({
26651
- component: UserEventNotificationList,
26652
- componentProps: {
26653
- titleI18n: this.titleI18n,
26654
- userEvents: this.userEventsSubject,
26655
- readEvent: this._readEvent
26656
- },
26657
- backdropDismiss: true,
26658
- keyboardClose: true,
26659
- event,
26660
- translucent: true,
26661
- cssClass: 'popover-large'
26662
- });
26663
- yield popover.present();
26664
- });
26665
- }
26666
- markForCheck() {
26667
- this.cd.markForCheck();
26668
- }
26669
- ngOnDestroy() {
26670
- if (this.debug) {
26671
- console.debug(`${this._logPrefix}Destroying`);
26672
- }
26673
- this._subscriptions.unsubscribe();
26674
- }
26675
- }
26676
- UserEventNotificationComponent.decorators = [
26677
- { type: Component, args: [{
26678
- selector: 'app-user-event-notification-component',
26679
- template: "<button\n #button\n mat-icon-button\n [title]=\"titleI18n | translate\"\n [disabled]=\"disabled\"\n (click)=\"showList($event)\"\n>\n <mat-icon\n [matBadge]=\"count | async\"\n matBadgeColor=\"accent\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n >notifications\n </mat-icon>\n</button>\n\n",
26680
- changeDetection: ChangeDetectionStrategy.OnPush,
26681
- styles: [""]
26682
- },] }
26683
- ];
26684
- UserEventNotificationComponent.ctorParameters = () => [
26685
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [UserEventServiceToken,] }] },
26686
- { type: AccountService },
26687
- { type: PopoverController },
26688
- { type: ChangeDetectorRef }
26689
- ];
26690
- UserEventNotificationComponent.propDecorators = {
26691
- debug: [{ type: Input }],
26692
- titleI18n: [{ type: Input }],
26693
- disabled: [{ type: Input }]
26694
- };
26695
-
26696
- class UserEventModule {
26697
- }
26698
- UserEventModule.decorators = [
26699
- { type: NgModule, args: [{
26700
- imports: [
26701
- CommonModule,
26702
- CoreModule,
26703
- SharedModule
26704
- ],
26705
- declarations: [
26706
- UserEventsTable,
26707
- UserEventNotificationComponent,
26708
- UserEventNotificationList,
26709
- ],
26710
- exports: [
26711
- UserEventsTable,
26712
- UserEventNotificationComponent
26713
- ]
26714
- },] }
26715
- ];
26716
-
26717
26479
  const MessageTypes = {
26718
26480
  INBOX_MESSAGE: 'INBOX_MESSAGE',
26719
26481
  EMAIL: 'EMAIL',
@@ -26925,9 +26687,9 @@ MessageForm.propDecorators = {
26925
26687
  canSelectType: [{ type: Input }]
26926
26688
  };
26927
26689
 
26928
- class MessageModule {
26690
+ class SocialModule {
26929
26691
  }
26930
- MessageModule.decorators = [
26692
+ SocialModule.decorators = [
26931
26693
  { type: NgModule, args: [{
26932
26694
  imports: [
26933
26695
  CommonModule,
@@ -26935,317 +26697,17 @@ MessageModule.decorators = [
26935
26697
  SharedModule
26936
26698
  ],
26937
26699
  declarations: [
26700
+ UserEventsTable,
26938
26701
  MessageModal,
26939
26702
  MessageForm
26940
26703
  ],
26941
26704
  exports: [
26705
+ UserEventsTable,
26942
26706
  MessageModal
26943
26707
  ]
26944
26708
  },] }
26945
26709
  ];
26946
26710
 
26947
- var JobProgression_1;
26948
- // todo use entity
26949
- class Job {
26950
- }
26951
- // @dynamic
26952
- let JobProgression = JobProgression_1 = class JobProgression extends Entity {
26953
- constructor() {
26954
- super(JobProgression_1.TYPENAME);
26955
- }
26956
- fromObject(source) {
26957
- super.fromObject(source);
26958
- this.message = source.message;
26959
- this.current = source.current;
26960
- this.total = source.total;
26961
- }
26962
- };
26963
- JobProgression = JobProgression_1 = __decorate([
26964
- EntityClass({ typename: 'JobProgressionVO' })
26965
- ], JobProgression);
26966
-
26967
- const JobProgressionServiceToken = new InjectionToken('JobProgressionService');
26968
- const jobProgressionSubscription = gql `subscription UpdateJobProgression($id: Int!, $interval: Int){
26969
- data: updateJobProgression(id: $id, interval: $interval) {
26970
- id
26971
- message
26972
- current
26973
- total
26974
- }
26975
- }`;
26976
- class JobProgressionService extends BaseGraphqlService {
26977
- constructor(graphql, environment) {
26978
- super(graphql, environment);
26979
- this.graphql = graphql;
26980
- this.environment = environment;
26981
- this._logPrefix = '[job-progression-service] ';
26982
- // For DEV only
26983
- this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
26984
- }
26985
- listenChanges(id, options) {
26986
- if (isNil(id))
26987
- throw new Error(`${this._logPrefix}Missing argument 'id'`);
26988
- if (this._debug)
26989
- console.debug(`${this._logPrefix}[WS] Listening changes for job progression {${id}}...`);
26990
- return this.graphql.subscribe({
26991
- query: jobProgressionSubscription,
26992
- fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
26993
- variables: { id, interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
26994
- error: { code: SocialErrorCodes.SUBSCRIBE_JOB_PROGRESSION_ERROR, message: 'SOCIAL.ERROR.SUBSCRIBE_JOB_PROGRESSION_ERROR' }
26995
- }).pipe(map(({ data }) => {
26996
- const progression = data && JobProgression.fromObject(data);
26997
- if (progression && this._debug)
26998
- console.debug(`${this._logPrefix}Job progression ${id} updated on server`, progression);
26999
- return progression;
27000
- }));
27001
- }
27002
- }
27003
- JobProgressionService.decorators = [
27004
- { type: Injectable }
27005
- ];
27006
- JobProgressionService.ctorParameters = () => [
27007
- { type: GraphqlService },
27008
- { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
27009
- ];
27010
-
27011
- class JobProgressionList {
27012
- constructor() {
27013
- }
27014
- ngOnInit() {
27015
- }
27016
- }
27017
- JobProgressionList.decorators = [
27018
- { type: Component, args: [{
27019
- selector: 'app-job-progression-list',
27020
- template: "<ion-list class=\"ion-list-popover\">\n\n <ion-row class=\"ion-list-header column\">\n <ion-col>\n <ion-label>{{titleI18n | translate}}</ion-label>\n </ion-col>\n </ion-row>\n\n <ion-item *ngIf=\"!jobProgressions?.length\">\n {{'SOCIAL.JOB.PROGRESSION.EMPTY' | translate}}\n </ion-item>\n <ion-item *ngFor=\"let jobProgression of jobProgressions\">\n <ion-grid class=\"ion-no-margin\">\n <ion-row>\n <ion-col>\n {{jobProgression.message}}\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <ion-progress-bar\n [value]=\"jobProgression.total > 0 ? jobProgression.current / jobProgression.total : undefined\"\n [type]=\"jobProgression.total > 0 ? 'determinate' : 'indeterminate'\">\n </ion-progress-bar>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-item>\n\n</ion-list>\n",
27021
- styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}"]
27022
- },] }
27023
- ];
27024
- JobProgressionList.ctorParameters = () => [];
27025
- JobProgressionList.propDecorators = {
27026
- titleI18n: [{ type: Input }],
27027
- jobProgressions: [{ type: Input }]
27028
- };
27029
-
27030
- class JobProgressionComponent {
27031
- constructor(jobProgressionService, popoverController, cd) {
27032
- this.jobProgressionService = jobProgressionService;
27033
- this.popoverController = popoverController;
27034
- this.cd = cd;
27035
- this.debug = false;
27036
- this.titleI18n = 'SOCIAL.JOB.PROGRESSION.TITLE';
27037
- this.jobFinished = new EventEmitter();
27038
- this.disabled = true;
27039
- this.color = 'accent';
27040
- this.mode = 'determinate';
27041
- this.value = 0;
27042
- this.jobProgressions = [];
27043
- this._subscriptions = new Subscription();
27044
- this._subscriptionsById = {};
27045
- this._logPrefix = '[job-progression] ';
27046
- }
27047
- ngOnInit() {
27048
- var _a, _b, _c, _d;
27049
- if (isNil(this.jobProgressionService)) {
27050
- console.warn(`${this._logPrefix}No service injected`);
27051
- }
27052
- // parse options
27053
- this.autoHide = toBoolean((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoHide, false);
27054
- this.visible = !this.autoHide;
27055
- this.autoHideDelay = toNumber((_b = this.options) === null || _b === void 0 ? void 0 : _b.autoHideDelay, 1000);
27056
- this.autoRemove = toBoolean((_c = this.options) === null || _c === void 0 ? void 0 : _c.autoRemove, true);
27057
- this.autoRemoveDelay = toNumber((_d = this.options) === null || _d === void 0 ? void 0 : _d.autoRemoveDelay, 1000);
27058
- }
27059
- addJob(id) {
27060
- if (isNil(this.jobProgressionService)) {
27061
- console.warn(`${this._logPrefix}No service injected. Can't add a job`);
27062
- return;
27063
- }
27064
- if (this.debug) {
27065
- console.debug(`${this._logPrefix}Add job id=${id}`);
27066
- }
27067
- if (!!this.getProgression(id)) {
27068
- console.warn(`${this._logPrefix}Job (id=${id}) already present`);
27069
- return;
27070
- }
27071
- this.disabled = false;
27072
- const sub = this.jobProgressionService.listenChanges(id)
27073
- .pipe(filter(progression => {
27074
- if (id !== progression.id) {
27075
- console.error(`${this._logPrefix}Job progression (id=${progression.id}) doesn't match expected job (id=${id})`);
27076
- return false;
27077
- }
27078
- return true;
27079
- }), map(progression => {
27080
- // Ensure visible
27081
- this.visible = true;
27082
- // Get current progression object
27083
- const currentProgression = this.getProgression(id);
27084
- if (!currentProgression) {
27085
- // add it
27086
- this.jobProgressions.push(progression);
27087
- if (this.debug) {
27088
- console.debug(`${this._logPrefix}Progression added id=${id}`, progression);
27089
- }
27090
- }
27091
- else {
27092
- // update current
27093
- Object.assign(currentProgression, progression);
27094
- if (this.debug) {
27095
- console.debug(`${this._logPrefix}Progression updated id=${id}`, progression);
27096
- }
27097
- }
27098
- return progression;
27099
- }))
27100
- .subscribe(progression => {
27101
- // update value
27102
- this.updateValue();
27103
- // job finished
27104
- if (progression.total > 0 && progression.current == progression.total) {
27105
- if (this.debug) {
27106
- console.debug(`${this._logPrefix}Finished job id=${progression.id}`);
27107
- }
27108
- // emit event
27109
- this.jobFinished.emit(progression.id);
27110
- if (this.autoRemove) {
27111
- setTimeout(() => {
27112
- var _a;
27113
- this.removeJob(progression.id);
27114
- // If last job
27115
- if (this.autoHide && !((_a = this.jobProgressions) === null || _a === void 0 ? void 0 : _a.length)) {
27116
- setTimeout(() => {
27117
- this.visible = false;
27118
- this.markForCheck();
27119
- }, this.autoHideDelay);
27120
- }
27121
- }, this.autoRemoveDelay);
27122
- }
27123
- }
27124
- });
27125
- this._subscriptionsById[id] = sub;
27126
- this._subscriptions.add(sub);
27127
- }
27128
- removeJob(id) {
27129
- if (this.debug) {
27130
- console.debug(`${this._logPrefix}Remove job id=${id}`);
27131
- }
27132
- const sub = this._subscriptionsById[id];
27133
- if (sub) {
27134
- this._subscriptions.remove(sub);
27135
- sub.unsubscribe();
27136
- }
27137
- const progression = this.getProgression(id);
27138
- if (progression) {
27139
- this.jobProgressions.splice(this.jobProgressions.indexOf(progression), 1);
27140
- }
27141
- this.updateValue();
27142
- }
27143
- getProgression(id) {
27144
- return this.jobProgressions.find(progression => progression.id === id);
27145
- }
27146
- updateValue() {
27147
- if (this.debug) {
27148
- console.debug(`${this._logPrefix}Updating value`);
27149
- }
27150
- let value = 0;
27151
- const nbProgression = arraySize(this.jobProgressions);
27152
- let allIndeterminate = nbProgression > 0;
27153
- this.jobProgressions.forEach(progression => {
27154
- const indeterminate = progression.total === 0;
27155
- allIndeterminate = allIndeterminate && indeterminate;
27156
- if (!indeterminate) {
27157
- value = value + progression.current * 100 / progression.total;
27158
- }
27159
- });
27160
- this.value = nbProgression > 0 ? value / nbProgression : 0;
27161
- this.mode = allIndeterminate ? 'indeterminate' : 'determinate';
27162
- if (this.debug) {
27163
- console.debug(`${this._logPrefix}Setting value=${this.value}, mode=${this.mode}`);
27164
- }
27165
- this.markForCheck();
27166
- }
27167
- showList(event) {
27168
- return __awaiter(this, void 0, void 0, function* () {
27169
- const popover = yield this.popoverController.create({
27170
- component: JobProgressionList,
27171
- componentProps: {
27172
- titleI18n: this.titleI18n,
27173
- jobProgressions: this.jobProgressions
27174
- },
27175
- backdropDismiss: true,
27176
- keyboardClose: true,
27177
- event,
27178
- translucent: true,
27179
- cssClass: 'popover-large'
27180
- });
27181
- yield popover.present();
27182
- });
27183
- }
27184
- markForCheck() {
27185
- this.cd.markForCheck();
27186
- }
27187
- ngOnDestroy() {
27188
- if (this.debug) {
27189
- console.debug(`${this._logPrefix}Destroying`);
27190
- }
27191
- this._subscriptions.unsubscribe();
27192
- }
27193
- }
27194
- JobProgressionComponent.decorators = [
27195
- { type: Component, args: [{
27196
- selector: 'app-job-progression',
27197
- template: "<button\n #button\n mat-icon-button\n [title]=\"titleI18n | translate\"\n [disabled]=\"disabled\"\n *ngIf=\"visible\"\n (click)=\"showList($event)\"\n>\n <mat-icon\n [matBadge]=\"jobProgressions?.length\"\n [matBadgeHidden]=\"!jobProgressions?.length\"\n matBadgeColor=\"accent\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n >{{ disabled || jobProgressions?.length ? 'schedule' : 'task_alt' }}\n </mat-icon>\n <mat-spinner\n #spinner\n *ngIf=\"jobProgressions?.length\"\n class=\"floating-spinner\"\n [color]=\"color\"\n [mode]=\"mode\"\n [value]=\"value\"\n diameter=\"30\"\n strokeWidth=\"3\"\n ></mat-spinner>\n</button>\n\n",
27198
- changeDetection: ChangeDetectionStrategy.OnPush,
27199
- styles: [".floating-spinner{position:absolute;top:6px;left:5px}"]
27200
- },] }
27201
- ];
27202
- JobProgressionComponent.ctorParameters = () => [
27203
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [JobProgressionServiceToken,] }] },
27204
- { type: PopoverController },
27205
- { type: ChangeDetectorRef }
27206
- ];
27207
- JobProgressionComponent.propDecorators = {
27208
- debug: [{ type: Input }],
27209
- titleI18n: [{ type: Input }],
27210
- options: [{ type: Input }],
27211
- jobFinished: [{ type: Output }]
27212
- };
27213
-
27214
- class JobModule {
27215
- }
27216
- JobModule.decorators = [
27217
- { type: NgModule, args: [{
27218
- imports: [
27219
- CommonModule,
27220
- SharedModule,
27221
- TranslateModule.forChild(),
27222
- ],
27223
- declarations: [
27224
- JobProgressionComponent,
27225
- JobProgressionList
27226
- ],
27227
- exports: [
27228
- JobProgressionComponent
27229
- ]
27230
- },] }
27231
- ];
27232
-
27233
- const SocialModuleOptionsToken = new InjectionToken("SocialModuleOptions");
27234
- class SocialModule {
27235
- }
27236
- SocialModule.decorators = [
27237
- { type: NgModule, args: [{
27238
- imports: [
27239
- CommonModule,
27240
- CoreModule,
27241
- SharedModule,
27242
- UserEventModule,
27243
- JobModule,
27244
- MessageModule,
27245
- ],
27246
- },] }
27247
- ];
27248
-
27249
26711
  const Mutations = {
27250
26712
  send: gql `mutation SendMessage($data: MessageVOInput){
27251
26713
  done: sendMessage(message: $data)
@@ -27891,10 +27353,12 @@ class AutocompleteTestPage {
27891
27353
  });
27892
27354
  }
27893
27355
  ngAfterViewInit() {
27894
- setTimeout(() => {
27895
- this.farEntityField.suggestLengthThreshold = 2;
27896
- this.farEntityField.reloadItems();
27897
- }, 2000);
27356
+ if (this.farEntityField) {
27357
+ setTimeout(() => {
27358
+ this.farEntityField.suggestLengthThreshold = 2;
27359
+ this.farEntityField.reloadItems();
27360
+ }, 2000);
27361
+ }
27898
27362
  setTimeout(() => this.loadData(), 1000);
27899
27363
  }
27900
27364
  // Load the form with data
@@ -27982,7 +27446,7 @@ class AutocompleteTestPage {
27982
27446
  AutocompleteTestPage.decorators = [
27983
27447
  { type: Component, args: [{
27984
27448
  selector: 'app-autocomplete-test',
27985
- template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Autocomplete field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <!-- Tab nav - mobile/desktop mode -->\n <nav mat-tab-nav-bar>\n <a mat-tab-link\n [active]=\"mode==='mobile'\"\n (click)=\"toggleMode('mobile')\">\n <mat-label>Mobile</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='desktop'\"\n (click)=\"toggleMode('desktop')\">\n <mat-label>Desktop</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='memory'\"\n (click)=\"toggleMode('memory')\">\n <mat-label>Memory leak debug</mat-label>\n </a>\n <a mat-tab-link\n [active]=\"mode==='temp'\"\n (click)=\"toggleMode('temp')\">\n <mat-label>Temporary</mat-label>\n </a>\n </nav>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!--<ion-grid *ngIf=\"mode === 'temp'\">\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>items: Observable&lt;any[]&gt;</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n </ion-row>\n\n\n </ion-grid>-->\n\n\n <ion-grid *ngIf=\"mode === 'memory'\">\n\n <!-- debugging memory leak -->\n <ion-row>\n <ion-col>\n <ion-text><h4>Debug memory leak</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Items type\">\n <mat-select (selectionChange)=\"memoryAutocompleteFieldName=$event.value\" [value]=\"memoryAutocompleteFieldName\">\n <mat-option value=\"entity-$items\">Observable</mat-option>\n <mat-option value=\"entity-suggestFn\">Suggest function</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"1\" class=\"ion-no-padding\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Mobile ?\">\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [checked]=\"memoryMobile\">\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\" color=\"tertiary\">Start</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\" color=\"tertiary\">Stop</ion-button>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n *ngIf=\"!memoryHide && memoryAutocompleteFieldName\"\n [config]=\"autocompleteFields.get(memoryAutocompleteFieldName)\"\n [mobile]=\"memoryMobile\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-memory-leak]'\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n <!-- Mobile mode -->\n <ion-grid *ngIf=\"mode === 'mobile'\">\n\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Entity far in the list (not in first page)\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre style=\"white-space: normal !important;\">value: {{stringify(form.controls.farEntity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"farEntity\" #farEntityField\n [config]=\"autocompleteFields.get('entity-far')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-far]'\"\n [debug]=\"true\"\n [required]=\"true\"\n [clearable]=\"true\"\n placeholder=\"Far entity (in the list)\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) =&gt; any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-1]'\"\n [required]=\"true\"\n placeholder=\"Suggest field\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Items is an Observable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-observable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [clearable]=\"true\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-mobile-suggestLengthThreshold]'\"\n required\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"true\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Change filter\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-button (click)=\"updateFilter(filterChangeField, 'entity-items-filter')\">Filter on: {{autocompleteFields.get('entity-items-filter').filter?.searchAttribute }}</ion-button>\n </ion-col>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\" #filterChangeField\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-filter]'\"\n ></mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"min-width-large\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"true\"\n class=\"min-width-large\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Fullscreen\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-mobile-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Desktop mode -->\n <ion-grid *ngIf=\"mode === 'desktop'\">\n <ion-row>\n <ion-col>\n <ion-text><h4>Desktop mode</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n items from suggest function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [clearable]=\"true\"\n [logPrefix]=\"'[combo-desktop-suggest]'\">\n </mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-desktop-suggestLengthThreshold]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an array\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: [], value: {{stringify(form.controls.entity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [logPrefix]=\"'[combo-desktop-array-1]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"false\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-missing]'\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size panel\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-disable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"mat-autocomplete-panel-full-size\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n class=\"mat-autocomplete-panel-full-size\"\n panelWidth=\"100vw\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>panelWidth: string</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox #showIcons [checked]=\"false\">\n Icons ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n <mat-icon matPrefix *ngIf=\"showIcons.checked\">keyboard_arrow_right</mat-icon>\n <mat-icon matSuffix *ngIf=\"showIcons.checked\">keyboard_arrow_left</mat-icon>\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
27449
+ template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Autocomplete field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <!-- Tab nav - mobile/desktop mode -->\n <nav mat-tab-nav-bar>\n <a mat-tab-link\n [active]=\"mode==='mobile'\"\n (click)=\"toggleMode('mobile')\">\n <mat-label>Mobile</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='desktop'\"\n (click)=\"toggleMode('desktop')\">\n <mat-label>Desktop</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='memory'\"\n (click)=\"toggleMode('memory')\">\n <mat-label>Memory leak debug</mat-label>\n </a>\n <a mat-tab-link\n [active]=\"mode==='temp'\"\n (click)=\"toggleMode('temp')\">\n <mat-label>Temporary</mat-label>\n </a>\n </nav>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!--<ion-grid *ngIf=\"mode === 'temp'\">\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>items: Observable&lt;any[]&gt;</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n </ion-row>\n\n\n </ion-grid>-->\n\n\n <ion-grid *ngIf=\"mode === 'memory'\">\n\n <!-- debugging memory leak -->\n <ion-row>\n <ion-col>\n <ion-text><h4>Debug memory leak</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Items type\">\n <mat-select (selectionChange)=\"memoryAutocompleteFieldName=$event.value\" [value]=\"memoryAutocompleteFieldName\">\n <mat-option value=\"entity-$items\">Observable</mat-option>\n <mat-option value=\"entity-suggestFn\">Suggest function</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"1\" class=\"ion-no-padding\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Mobile ?\">\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [checked]=\"memoryMobile\">\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\" color=\"tertiary\">Start</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\" color=\"tertiary\">Stop</ion-button>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n *ngIf=\"!memoryHide && memoryAutocompleteFieldName\"\n [config]=\"autocompleteFields.get(memoryAutocompleteFieldName)\"\n [mobile]=\"memoryMobile\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-memory-leak]'\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n <!-- Mobile mode -->\n <ion-grid *ngIf=\"mode === 'mobile'\">\n\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Entity far in the list (not in first page)\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre style=\"white-space: normal !important;\">value: {{stringify(form.controls.farEntity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"farEntity\" #farEntityField\n [config]=\"autocompleteFields.get('entity-far')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-far]'\"\n [debug]=\"true\"\n [required]=\"true\"\n [clearable]=\"true\"\n placeholder=\"Far entity (in the list)\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) =&gt; any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-1]'\"\n [required]=\"true\"\n placeholder=\"Suggest field\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Items is an Observable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-observable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [clearable]=\"true\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-mobile-suggestLengthThreshold]'\"\n required\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"true\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Change filter\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-button (click)=\"updateFilter(filterChangeField, 'entity-items-filter')\">Filter on: {{autocompleteFields.get('entity-items-filter').filter?.searchAttribute }}</ion-button>\n </ion-col>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\" #filterChangeField\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-filter]'\"\n ></mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"min-width-large\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"true\"\n class=\"min-width-large\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Fullscreen\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-mobile-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Desktop mode -->\n <ion-grid *ngIf=\"mode === 'desktop'\">\n <ion-row>\n <ion-col>\n <ion-text><h4>Desktop mode</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n items from suggest function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [clearable]=\"true\"\n [logPrefix]=\"'[combo-desktop-suggest]'\"\n [debug]=\"true\">\n </mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-desktop-suggestLengthThreshold]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an array\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: [], value: {{stringify(form.controls.entity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [logPrefix]=\"'[combo-desktop-array-1]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"false\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-missing]'\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size panel\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-disable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"mat-autocomplete-panel-full-size\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n class=\"mat-autocomplete-panel-full-size\"\n panelWidth=\"100vw\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>panelWidth: string</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox #showIcons [checked]=\"false\">\n Icons ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n <mat-icon matPrefix *ngIf=\"showIcons.checked\">keyboard_arrow_right</mat-icon>\n <mat-icon matSuffix *ngIf=\"showIcons.checked\">keyboard_arrow_left</mat-icon>\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
27986
27450
  },] }
27987
27451
  ];
27988
27452
  AutocompleteTestPage.ctorParameters = () => [
@@ -28058,13 +27522,13 @@ LatLongTestPage.ctorParameters = () => [
28058
27522
  { type: FormBuilder }
28059
27523
  ];
28060
27524
 
28061
- const moment$7 = momentImported;
27525
+ const moment$6 = momentImported;
28062
27526
  class SwipeTestPage {
28063
27527
  constructor(formBuilder, dateFormatPipe) {
28064
27528
  this.formBuilder = formBuilder;
28065
27529
  this.dateFormatPipe = dateFormatPipe;
28066
27530
  this.$dates = new BehaviorSubject(undefined);
28067
- this._today = moment$7().startOf('day');
27531
+ this._today = moment$6().startOf('day');
28068
27532
  this.form = formBuilder.group({
28069
27533
  empty: [null, Validators.required],
28070
27534
  date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
@@ -28077,7 +27541,7 @@ class SwipeTestPage {
28077
27541
  ngOnInit() {
28078
27542
  const dates = [];
28079
27543
  for (let d = 0; d < 7; d++) {
28080
- dates[d] = moment$7(this._today).add(d - 3, 'day');
27544
+ dates[d] = moment$6(this._today).add(d - 3, 'day');
28081
27545
  }
28082
27546
  this.$dates.next(dates);
28083
27547
  this.loadData();
@@ -28118,7 +27582,7 @@ SwipeTestPage.ctorParameters = () => [
28118
27582
  { type: DateFormatPipe }
28119
27583
  ];
28120
27584
 
28121
- const moment$8 = momentImported;
27585
+ const moment$7 = momentImported;
28122
27586
  class DateTimeTestPage {
28123
27587
  constructor(platform, formBuilder, cd) {
28124
27588
  this.platform = platform;
@@ -28150,7 +27614,7 @@ class DateTimeTestPage {
28150
27614
  // Load the form with data
28151
27615
  loadData() {
28152
27616
  return __awaiter(this, void 0, void 0, function* () {
28153
- const now = moment$8();
27617
+ const now = moment$7();
28154
27618
  const data = {
28155
27619
  empty: null,
28156
27620
  emptyRequired: null,
@@ -28396,7 +27860,7 @@ NumpadTestPage.ctorParameters = () => [
28396
27860
  { type: FormBuilder }
28397
27861
  ];
28398
27862
 
28399
- const moment$9 = momentImported;
27863
+ const moment$8 = momentImported;
28400
27864
  class DateTestPage {
28401
27865
  constructor(formBuilder, cd) {
28402
27866
  this.formBuilder = formBuilder;
@@ -28429,7 +27893,7 @@ class DateTestPage {
28429
27893
  // Load the form with data
28430
27894
  loadData() {
28431
27895
  return __awaiter(this, void 0, void 0, function* () {
28432
- const now = moment$9();
27896
+ const now = moment$8();
28433
27897
  const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
28434
27898
  const data = {
28435
27899
  empty: null,
@@ -29175,5 +28639,5 @@ CoreTestingModule.decorators = [
29175
28639
  * Generated bundle index. Do not edit.
29176
28640
  */
29177
28641
 
29178
- export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, Job, JobModule, JobProgression, JobProgressionComponent, JobProgressionService, JobProgressionServiceToken, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, ResizableComponent, ResizableDirective, ResizableModule, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEvent, UserEventFilter, UserEventFragments, UserEventModule, UserEventNotificationComponent, UserEventService, UserEventServiceToken, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moment$5 as moment, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, tz, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh, AppUpdateOfflineModeCard as ɵi, AppIconComponent as ɵj, UserEventNotificationList as ɵk, JobProgressionList as ɵl, DateTestPage as ɵm, NumpadTestPage as ɵn, MatBadgeIconTestPage as ɵo, ToastTestingModule as ɵp, ToastTestingPage as ɵq };
28642
+ export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, ResizableComponent, ResizableDirective, ResizableModule, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEvent, UserEventFilter, UserEventFragments, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moment$5 as moment, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, tz, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh, AppUpdateOfflineModeCard as ɵi, AppIconComponent as ɵj, DateTestPage as ɵk, NumpadTestPage as ɵl, MatBadgeIconTestPage as ɵm, ToastTestingModule as ɵn, ToastTestingPage as ɵo };
29179
28643
  //# sourceMappingURL=sumaris-net.ngx-components.js.map