@sumaris-net/ngx-components 1.21.0-beta7 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +475 -1171
  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 +9 -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 +7 -1
  10. package/esm2015/src/app/core/form/entity-editor-modal.class.js +17 -6
  11. package/esm2015/src/app/core/form/entity-editor.class.js +1 -1
  12. package/esm2015/src/app/core/form/form.class.js +62 -33
  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 +18 -23
  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 -293
  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 +387 -970
  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 +14 -1
  45. package/src/app/core/form/entity-editor-modal.class.d.ts +1 -0
  46. package/src/app/core/form/entity-editor.class.d.ts +6 -2
  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 +15 -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();
@@ -17456,8 +17455,29 @@ class AppForm {
17456
17455
  get _loading() {
17457
17456
  return this._$loading.value;
17458
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);
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,14 @@ class AppForm {
17653
17666
  * @param opts
17654
17667
  */
17655
17668
  ready(opts) {
17656
- return waitForTrue(this._$ready, opts);
17669
+ return waitForTrue(this.readySubject, opts);
17657
17670
  }
17658
17671
  /**
17659
- * Wait form is idle (not loading)
17672
+ * Wait form is not busy (=loaded)
17660
17673
  * @param opts
17661
17674
  */
17662
17675
  waitIdle(opts) {
17663
- return __awaiter(this, void 0, void 0, function* () {
17664
- return AppFormUtils.waitIdle(this, opts);
17665
- });
17676
+ return waitForFalse(this.loadingSubject, opts);
17666
17677
  }
17667
17678
  updateValueAndValidity(opts) {
17668
17679
  AppFormUtils.updateValueAndValidity(this.form, opts);
@@ -17692,10 +17703,27 @@ class AppForm {
17692
17703
  registerAutocompleteField(fieldName, opts) {
17693
17704
  return this.autocompleteHelper.add(fieldName, opts);
17694
17705
  }
17706
+ setError(value, opts) {
17707
+ if (this.errorSubject.value !== value) {
17708
+ this.errorSubject.next(value);
17709
+ if (!opts || opts.emitEvent !== false) {
17710
+ this.markForCheck();
17711
+ }
17712
+ }
17713
+ }
17695
17714
  markForCheck() {
17696
17715
  // Should be overwritten by subclasses
17697
17716
  console.warn('markForCheck() has been called, but is not overwritten by component ' + this.constructor.name);
17698
17717
  }
17718
+ /* -- private function -- */
17719
+ setLoading(value, opts) {
17720
+ if (this.loadingSubject.value !== value) {
17721
+ this.loadingSubject.next(value);
17722
+ if (!opts || opts.emitEvent !== false) {
17723
+ this.markForCheck();
17724
+ }
17725
+ }
17726
+ }
17699
17727
  }
17700
17728
  AppForm.decorators = [
17701
17729
  { type: Directive }
@@ -18213,6 +18241,18 @@ class InMemoryEntitiesService extends EntitiesService {
18213
18241
  return this._equalsFn(d1, d2);
18214
18242
  return d1 && d1.equals ? d1.equals(d2) : EntityUtils.equals(d1, d2, 'id');
18215
18243
  }
18244
+ /**
18245
+ * Count data stored by the service (without hidden data).
18246
+ * @param opts
18247
+ */
18248
+ get count() {
18249
+ var _a;
18250
+ return (((_a = this.data) === null || _a === void 0 ? void 0 : _a.length) || 0);
18251
+ }
18252
+ get hiddenCount() {
18253
+ var _a;
18254
+ return ((_a = this._hiddenData) === null || _a === void 0 ? void 0 : _a.length) || 0;
18255
+ }
18216
18256
  /* -- protected methods -- */
18217
18257
  filter(data, _filter, hiddenData) {
18218
18258
  // if filter is DataFilter instance, use its test function
@@ -18766,7 +18806,9 @@ class AuthForm extends AppForm {
18766
18806
  }
18767
18807
  }
18768
18808
  cancel() {
18769
- this.onCancel.emit();
18809
+ return __awaiter(this, void 0, void 0, function* () {
18810
+ this.onCancel.emit();
18811
+ });
18770
18812
  }
18771
18813
  doSubmit(event) {
18772
18814
  return __awaiter(this, void 0, void 0, function* () {
@@ -19623,7 +19665,7 @@ class AccountPage extends AppForm {
19623
19665
  cancel: { get: () => super.cancel }
19624
19666
  });
19625
19667
  return __awaiter(this, void 0, void 0, function* () {
19626
- _super.cancel.call(this);
19668
+ yield _super.cancel.call(this);
19627
19669
  });
19628
19670
  }
19629
19671
  markForCheck() {
@@ -21431,7 +21473,7 @@ class MenuComponent {
21431
21473
  MenuComponent.decorators = [
21432
21474
  { type: Component, args: [{
21433
21475
  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",
21476
+ 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
21477
  animations: [fadeInAnimation],
21436
21478
  changeDetection: ChangeDetectionStrategy.OnPush,
21437
21479
  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 +21537,13 @@ class AppIconComponent {
21495
21537
  this.icon = value.icon;
21496
21538
  this.matIcon = value.matIcon;
21497
21539
  this.matSvgIcon = value.matSvgIcon;
21498
- this.color = value.color;
21499
21540
  }
21500
21541
  ;
21501
21542
  }
21502
21543
  AppIconComponent.decorators = [
21503
21544
  { type: Component, args: [{
21504
21545
  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"
21546
+ 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
21547
  },] }
21507
21548
  ];
21508
21549
  AppIconComponent.propDecorators = {
@@ -21510,8 +21551,6 @@ AppIconComponent.propDecorators = {
21510
21551
  matIcon: [{ type: Input }],
21511
21552
  matSvgIcon: [{ type: Input }],
21512
21553
  color: [{ type: Input }],
21513
- height: [{ type: Input }],
21514
- width: [{ type: Input }],
21515
21554
  ref: [{ type: Input }]
21516
21555
  };
21517
21556
 
@@ -22583,13 +22622,12 @@ class AppTable {
22583
22622
  get error() {
22584
22623
  return this.errorSubject.value;
22585
22624
  }
22586
- get error$() {
22587
- return this.errorSubject.asObservable();
22588
- }
22589
22625
  /**
22590
22626
  * @deprecated
22591
- * @param error
22592
22627
  */
22628
+ get error$() {
22629
+ return this.errorSubject.asObservable();
22630
+ }
22593
22631
  set error(error) {
22594
22632
  this.setError(error);
22595
22633
  }
@@ -23013,7 +23051,7 @@ class AppTable {
23013
23051
  .then(() => this.editRowById(event, row.id, { focusColumn: this.lastUserColumn }));
23014
23052
  return true;
23015
23053
  }
23016
- // Edit next row
23054
+ // Edit previous row
23017
23055
  this.editRow(event, row, { focusColumn: this.lastUserColumn });
23018
23056
  return true;
23019
23057
  }
@@ -23036,8 +23074,7 @@ class AppTable {
23036
23074
  if (id < 0)
23037
23075
  return;
23038
23076
  if (id >= this.visibleRowCount) {
23039
- this.focusColumn = opts && opts.focusColumn || this.firstUserColumn;
23040
- this.addRow(event);
23077
+ this.addRow(event, undefined, opts);
23041
23078
  }
23042
23079
  else {
23043
23080
  const row = yield this.dataSource.getRow(id);
@@ -23110,7 +23147,7 @@ class AppTable {
23110
23147
  this.cancelExistingRow(event, row, opts);
23111
23148
  }
23112
23149
  }
23113
- addRow(event, insertAt) {
23150
+ addRow(event, insertAt, opts) {
23114
23151
  if (this.debug)
23115
23152
  console.debug('[table] Asking for new row...');
23116
23153
  if (!this._enabled)
@@ -23125,7 +23162,7 @@ class AppTable {
23125
23162
  return false;
23126
23163
  }
23127
23164
  // Add new row
23128
- this.addRowToTable(insertAt);
23165
+ this.addRowToTable(insertAt, opts);
23129
23166
  return true;
23130
23167
  }
23131
23168
  save(opts) {
@@ -23240,7 +23277,7 @@ class AppTable {
23240
23277
  * @param event
23241
23278
  * @param row
23242
23279
  * @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
23280
+ * And to force deletion even if table is busy
23244
23281
  */
23245
23282
  deleteRow(event, row, opts) {
23246
23283
  return __awaiter(this, void 0, void 0, function* () {
@@ -23253,7 +23290,7 @@ class AppTable {
23253
23290
  * @param event
23254
23291
  * @param rows
23255
23292
  * @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
23293
+ * And to force deletion even if table is busy
23257
23294
  */
23258
23295
  deleteRows(event, rows, opts) {
23259
23296
  var _a;
@@ -23266,8 +23303,8 @@ class AppTable {
23266
23303
  event === null || event === void 0 ? void 0 : event.preventDefault();
23267
23304
  if (!this._enabled || isEmptyArray(rows))
23268
23305
  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');
23306
+ if (this.loading && (!opts || opts.interactive !== false)) {
23307
+ console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.interactive = false to force deletion');
23271
23308
  return 0; // Skip if loading
23272
23309
  }
23273
23310
  // Make sure to keep newly created row
@@ -23404,15 +23441,11 @@ class AppTable {
23404
23441
  moveRow(id, direction) {
23405
23442
  this.dataSource.move(id, direction);
23406
23443
  }
23407
- ready() {
23408
- return __awaiter(this, void 0, void 0, function* () {
23409
- yield firstTruePromise(this.readySubject);
23410
- });
23444
+ ready(opts) {
23445
+ return waitForTrue(this.readySubject, opts);
23411
23446
  }
23412
23447
  waitIdle(opts) {
23413
- return __awaiter(this, void 0, void 0, function* () {
23414
- yield firstFalsePromise(this.loadingSubject);
23415
- });
23448
+ return waitForFalse(this.loadingSubject, opts);
23416
23449
  }
23417
23450
  openSelectColumnsModal(event) {
23418
23451
  return __awaiter(this, void 0, void 0, function* () {
@@ -23790,9 +23823,10 @@ class AppTable {
23790
23823
  //if (this.debug) console.debug("[table] id = " + id);
23791
23824
  return id;
23792
23825
  }
23793
- addRowToTable(insertAt) {
23826
+ addRowToTable(insertAt, opts) {
23794
23827
  return __awaiter(this, void 0, void 0, function* () {
23795
23828
  this.focusFirstColumn = true;
23829
+ this.focusColumn = (opts === null || opts === void 0 ? void 0 : opts.focusColumn) || this.firstUserColumn;
23796
23830
  yield this._dataSource.asyncCreateNew(insertAt);
23797
23831
  this.editedRow = this._dataSource.getRow(-1);
23798
23832
  // Emit start editing event
@@ -24308,6 +24342,8 @@ class AppEditor {
24308
24342
  }
24309
24343
  ready(opts) {
24310
24344
  return __awaiter(this, void 0, void 0, function* () {
24345
+ if (this._$ready.value)
24346
+ return;
24311
24347
  return waitForTrue(this._$ready, opts);
24312
24348
  });
24313
24349
  }
@@ -24601,6 +24637,10 @@ class AppTabEditor extends AppEditor {
24601
24637
  this.markForCheck();
24602
24638
  }
24603
24639
  }
24640
+ realignInkBar() {
24641
+ var _a;
24642
+ (_a = this.tabGroup) === null || _a === void 0 ? void 0 : _a.realignInkBar();
24643
+ }
24604
24644
  onTabChange(event, queryTabIndexParamName) {
24605
24645
  queryTabIndexParamName = queryTabIndexParamName || this.queryTabIndexParamName;
24606
24646
  if (!queryTabIndexParamName || !this.route)
@@ -25580,13 +25620,14 @@ class AppEntityEditorModal extends AppTabEditor {
25580
25620
  console.debug(this._logPrefix + 'Saving data...');
25581
25621
  try {
25582
25622
  // 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);
25623
+ const saved = yield this.saveDirtyTables();
25624
+ if (!saved)
25625
+ return false;
25626
+ // Fill data
25587
25627
  this.data = yield this.getValue();
25628
+ // Mark as submitted
25588
25629
  this.submitted = true;
25589
- return saved;
25630
+ return true;
25590
25631
  }
25591
25632
  catch (err) {
25592
25633
  this.submitted = true;
@@ -25698,6 +25739,16 @@ class AppEntityEditorModal extends AppTabEditor {
25698
25739
  this.markForCheck();
25699
25740
  }
25700
25741
  /* -- protected methods -- */
25742
+ saveDirtyTables() {
25743
+ return __awaiter(this, void 0, void 0, function* () {
25744
+ // Save all dirty tables
25745
+ const results = yield Promise.all((this.tables || [])
25746
+ .filter(c => c.dirty)
25747
+ .map(c => c.save()));
25748
+ const saved = results.findIndex(result => result !== true) === -1;
25749
+ return saved;
25750
+ });
25751
+ }
25701
25752
  waitWhilePending(opts) {
25702
25753
  return AppFormUtils.waitWhilePending(this, opts);
25703
25754
  }
@@ -25823,10 +25874,7 @@ AppInMemoryTable.propDecorators = {
25823
25874
  const SocialErrorCodes = {
25824
25875
  LOAD_USER_EVENTS_ERROR: 50000,
25825
25876
  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
25877
+ SEND_MESSAGE_ERROR: 50003
25830
25878
  };
25831
25879
 
25832
25880
  var UserEvent_1;
@@ -25841,23 +25889,16 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25841
25889
  }
25842
25890
  asObject(opts) {
25843
25891
  const target = super.asObject(opts);
25844
- target.creationDate = toDateISOString(this.creationDate);
25845
- target.readDate = toDateISOString(this.readDate);
25846
25892
  // Serialize content
25847
25893
  if (typeof target.content === 'object') {
25848
25894
  target.content = JSON.stringify(target.content);
25849
25895
  }
25850
- delete target.avatar;
25851
- delete target.avatarIcon;
25852
- delete target.icon;
25853
- delete target.actions;
25854
25896
  return target;
25855
25897
  }
25856
25898
  fromObject(source) {
25857
25899
  Object.assign(this, source); // Copy all properties
25858
25900
  super.fromObject(source);
25859
25901
  this.creationDate = fromDateISOString(source.creationDate);
25860
- this.readDate = fromDateISOString(source.readDate);
25861
25902
  try {
25862
25903
  // Deserialize content
25863
25904
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -25876,52 +25917,6 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25876
25917
  UserEvent = UserEvent_1 = __decorate([
25877
25918
  EntityClass({ typename: 'UserEventVO' })
25878
25919
  ], 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
25920
 
25926
25921
  const UserEventFragments = {
25927
25922
  userEvent: gql `fragment UserEventFragment on UserEventVO {
@@ -25949,188 +25944,134 @@ const UserEventFragments = {
25949
25944
  }`
25950
25945
  };
25951
25946
 
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) {
25947
+ // @dynamic
25948
+ let UserEventFilter = class UserEventFilter extends EntityFilter {
25949
+ constructor() {
25950
+ super(...arguments);
25951
+ this.issuer = null;
25952
+ this.recipient = null;
25953
+ }
25954
+ fromObject(source, opts) {
25955
+ super.fromObject(source, opts);
25956
+ this.issuer = source.issuer;
25957
+ this.recipient = source.recipient;
25958
+ }
25959
+ buildFilter() {
25960
+ const filterFns = super.buildFilter();
25961
+ // issuer
25962
+ if (this.issuer) {
25963
+ filterFns.push(t => (t.issuer === this.issuer));
25964
+ }
25965
+ if (this.recipient) {
25966
+ filterFns.push(t => (t.recipient === this.recipient));
25967
+ }
25968
+ return filterFns;
25969
+ }
25970
+ };
25971
+ UserEventFilter = __decorate([
25972
+ EntityClass({ typename: 'UserEventFilterVO' })
25973
+ ], UserEventFilter);
25974
+ const SaveQuery = gql `
25975
+ mutation SaveUserEvent($data: UserEventVOInput){
25976
+ data: saveUserEvent(userEvent: $data){
25977
+ ...UserEventFragment
25978
+ }
25979
+ }
25980
+ ${UserEventFragments.userEvent}
25981
+ `;
25982
+ const LoadAllQuery = gql `
25983
+ query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
25984
+ data: userEvents(filter: $filter, page: $page){
25985
+ ...LightUserEventFragment
25986
+ }
25987
+ }
25988
+ ${UserEventFragments.lightUserEvent}
25989
+ `;
25990
+ const DeleteByIdsMutation = gql `
25991
+ mutation DeleteUserEvents($ids:[Int]){
25992
+ deleteUserEvents(ids: $ids)
25993
+ }
25994
+ `;
25995
+ const LoadAllWithContentQuery = gql `
25996
+ query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
25997
+ data: userEvents(filter: $filter, page: $page){
25998
+ ...UserEventFragment
25999
+ }
26000
+ }
26001
+ ${UserEventFragments.userEvent}
26002
+ `;
26003
+ class UserEventService extends BaseGraphqlService {
26004
+ constructor(graphql, accountService, network, translate, toastController, environment) {
25956
26005
  super(graphql, environment);
25957
26006
  this.graphql = graphql;
25958
26007
  this.accountService = accountService;
25959
26008
  this.network = network;
25960
26009
  this.translate = translate;
25961
- this.queries = queries;
25962
- this.mutations = mutations;
25963
- this.subscriptions = subscriptions;
26010
+ this.toastController = toastController;
25964
26011
  this.environment = environment;
25965
- this._count$ = new BehaviorSubject(0);
25966
- this._subscriptions = new Subscription();
25967
- this.listeners = [];
25968
- this._logPrefix = '[user-event-service] ';
26012
+ this._userEventActions = [];
25969
26013
  // 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();
26014
+ this._debug = environment && !environment.production;
25985
26015
  }
26016
+ /**
26017
+ *
26018
+ * @param offset
26019
+ * @param size
26020
+ * @param sortBy
26021
+ * @param sortDirection
26022
+ * @param filter
26023
+ * @param options
26024
+ * @deprecated use watchPage() instead
26025
+ */
25986
26026
  watchAll(offset, size, sortBy, sortDirection, filter, options) {
25987
26027
  return this.watchPage({ offset, size, sortBy, sortDirection }, filter, options);
25988
26028
  }
25989
26029
  watchPage(page, filter, options) {
25990
- var _a;
25991
26030
  let now = this._debug && Date.now();
25992
26031
  //if (this._debug)
25993
- console.debug(`${this._logPrefix}Loading user events...`, filter);
26032
+ console.debug('[user-event-service] Loading user events...', filter);
25994
26033
  filter = this.asFilter(filter);
25995
26034
  // Force recipient to current issuer, if not admin and not specified
25996
- if (isEmptyArray(filter.recipients) || !this.accountService.isAdmin()) {
25997
- const recipient = this.defaultRecipient();
25998
- if (!((_a = filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
26035
+ if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
26036
+ const recipient = this.accountService.account.pubkey;
26037
+ if (recipient !== filter.recipient) {
25999
26038
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
26000
- filter.recipients = [recipient];
26039
+ filter.recipient = recipient;
26001
26040
  }
26002
26041
  }
26003
- const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26042
+ const withContent = options && options.withContent === true;
26004
26043
  return this.mutableWatchQuery({
26005
26044
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
26006
- query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26045
+ query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
26007
26046
  variables: {
26008
- page: Object.assign({ sortBy: 'updateDate', sortDirection: 'desc' }, page),
26047
+ page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
26009
26048
  filter: filter && filter.asPodObject()
26010
26049
  },
26011
26050
  arrayFieldName: 'data',
26012
26051
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
26013
- fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || "cache-first"
26052
+ fetchPolicy: options && options.fetchPolicy || undefined
26014
26053
  })
26015
26054
  .pipe(map(res => {
26016
- const data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(this.processUserEvent);
26055
+ const data = res && (res.data || []).map(UserEvent.fromObject);
26017
26056
  if (now) {
26018
- console.debug(`${this._logPrefix}${data.length} user events loaded in ${Date.now() - now}ms`);
26057
+ console.debug(`[user-event-service] ${data.length} user events loaded in ${Date.now() - now}ms`);
26019
26058
  now = null;
26020
26059
  }
26021
- const unreadCount = this.unreadEvents(data);
26022
26060
  return {
26023
26061
  data,
26024
- total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
26062
+ total: res && toNumber(res.total, data.length)
26025
26063
  };
26026
26064
  }));
26027
26065
  }
26028
- add(entity) {
26029
- // TODO set an id !!!!!!!!!!!!!!!!!!!!!!!!!
26030
- entity = this.processUserEvent(entity);
26031
- const withContent = !!entity.content;
26032
- // Add user event locally
26033
- this.insertIntoMutableCachedQueries(this.graphql.cache, {
26034
- query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26035
- data: entity
26036
- });
26037
- // Update count
26038
- this._count$.next(this._count$.value + 1);
26039
- }
26040
- count(filter, options) {
26041
- var _a;
26042
- return __awaiter(this, void 0, void 0, function* () {
26043
- if (!((_a = this.queries) === null || _a === void 0 ? void 0 : _a.count)) {
26044
- console.warn(`${this._logPrefix}Query 'count' not provided, skip.`);
26045
- return undefined;
26046
- }
26047
- if (!filter)
26048
- throw new Error(`Missing argument 'filter'`);
26049
- filter = this.asFilter(filter);
26050
- if (this._debug)
26051
- console.debug(`${this._logPrefix}Counting user events with filter:`, filter);
26052
- const res = yield this.graphql.query({
26053
- query: this.queries.count,
26054
- variables: {
26055
- filter: filter.asPodObject()
26056
- },
26057
- error: { code: SocialErrorCodes.COUNT_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.COUNT_USER_EVENT_ERROR' },
26058
- fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'network-only'
26059
- });
26060
- return res.total;
26061
- });
26062
- }
26063
- listenChanges(filter, options) {
26064
- var _a;
26065
- if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
26066
- console.warn(`${this._logPrefix}Subscription query 'listenChanges' not provided, skip.`);
26067
- return of();
26068
- }
26069
- if (!filter)
26070
- throw new Error(`Missing argument 'filter'`);
26071
- filter = this.asFilter(filter);
26072
- const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26073
- if (this._debug)
26074
- console.debug(`${this._logPrefix}[WS] Listening changes for user events with filter:`, filter);
26075
- return this.graphql.subscribe({
26076
- query: this.subscriptions.listenChanges,
26077
- fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
26078
- variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
26079
- error: {
26080
- code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
26081
- message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
26082
- }
26083
- }).pipe(map(({ data }) => {
26084
- if (data && this._debug)
26085
- console.debug(`${this._logPrefix}Received new user events:`, data);
26086
- const updatedData = data === null || data === void 0 ? void 0 : data.map(this.processUserEvent);
26087
- // Update cache
26088
- this.insertIntoMutableCachedQueries(this.graphql.cache, {
26089
- query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26090
- data: updatedData
26091
- });
26092
- // update count
26093
- this._count$.next(this.unreadEvents(updatedData));
26094
- return updatedData;
26095
- }));
26096
- }
26097
- delete(entity) {
26098
- return __awaiter(this, void 0, void 0, function* () {
26099
- if (!entity)
26100
- return; // skip
26101
- yield this.deleteAll([entity]);
26102
- });
26103
- }
26104
- deleteAll(entities, opts) {
26105
- return __awaiter(this, void 0, void 0, function* () {
26106
- const ids = entities && entities
26107
- .map(t => t.id);
26108
- if (isEmptyArray(ids))
26109
- return; // stop, if nothing else to do
26110
- const now = Date.now();
26111
- if (this._debug)
26112
- console.debug(`${this._logPrefix}Deleting events... ids:`, ids);
26113
- yield this.graphql.mutate({
26114
- mutation: this.mutations.deleteByIds,
26115
- variables: {
26116
- ids
26117
- },
26118
- update: (proxy) => {
26119
- // Remove from caches
26120
- this.removeFromMutableCachedQueriesByIds(proxy, {
26121
- query: this.queries.loadAll,
26122
- ids
26123
- });
26124
- this.removeFromMutableCachedQueriesByIds(proxy, {
26125
- query: this.queries.loadAllWithContent,
26126
- ids
26127
- });
26128
- if (this._debug)
26129
- console.debug(`${this._logPrefix}Events deleted in ${Date.now() - now}ms`);
26130
- }
26131
- });
26132
- });
26066
+ saveAll(data, options) {
26067
+ return Promise.all(data
26068
+ .map(entity => this.save(entity, options)));
26133
26069
  }
26070
+ /**
26071
+ * Save a userEvent entity
26072
+ *
26073
+ * @param entity
26074
+ */
26134
26075
  save(entity, options) {
26135
26076
  return __awaiter(this, void 0, void 0, function* () {
26136
26077
  this.fillDefaultProperties(entity);
@@ -26139,9 +26080,9 @@ class AbstractUserEventService extends BaseGraphqlService {
26139
26080
  const json = entity.asObject();
26140
26081
  const now = Date.now();
26141
26082
  if (this._debug)
26142
- console.debug(`${this._logPrefix}Saving user event...`, json);
26083
+ console.debug(`[user-event-service] Saving user event...`, json);
26143
26084
  yield this.graphql.mutate({
26144
- mutation: this.mutations.save,
26085
+ mutation: SaveQuery,
26145
26086
  variables: {
26146
26087
  data: json
26147
26088
  },
@@ -26151,16 +26092,16 @@ class AbstractUserEventService extends BaseGraphqlService {
26151
26092
  const savedEntity = data && data.data;
26152
26093
  if (savedEntity) {
26153
26094
  if (this._debug)
26154
- console.debug(`${this._logPrefix}User event saved in ${Date.now() - now}ms`, entity);
26095
+ console.debug(`[user-event-service] User event saved in ${Date.now() - now}ms`, entity);
26155
26096
  this.copyIdAndUpdateDate(savedEntity, entity);
26156
26097
  // Add to cache
26157
26098
  if (isNew) {
26158
26099
  this.insertIntoMutableCachedQueries(proxy, {
26159
- query: this.queries.loadAll,
26100
+ query: LoadAllQuery,
26160
26101
  data: Object.assign(Object.assign({}, savedEntity), { content: null })
26161
26102
  });
26162
26103
  this.insertIntoMutableCachedQueries(proxy, {
26163
- query: this.queries.loadAllWithContent,
26104
+ query: LoadAllWithContentQuery,
26164
26105
  data: savedEntity
26165
26106
  });
26166
26107
  }
@@ -26170,144 +26111,63 @@ class AbstractUserEventService extends BaseGraphqlService {
26170
26111
  return entity;
26171
26112
  });
26172
26113
  }
26173
- saveAll(data, opts) {
26174
- return Promise.all(data
26175
- .map(entity => this.save(entity, opts)));
26176
- }
26177
- markAsRead(entity) {
26114
+ /**
26115
+ * Save many trips
26116
+ *
26117
+ * @param entities
26118
+ * @param opts
26119
+ */
26120
+ deleteAll(entities, opts) {
26178
26121
  return __awaiter(this, void 0, void 0, function* () {
26179
- // Get onRead listeners
26180
- const onReadListeners = (this.listeners || []).filter(listener => !!listener.onRead).filter(listener => listener.accept(entity));
26181
- if (onReadListeners.length) {
26182
- for (const listener of onReadListeners) {
26183
- yield listener.onRead(entity);
26122
+ const ids = entities && entities
26123
+ .map(t => t.id);
26124
+ if (isEmptyArray(ids))
26125
+ return; // stop, if nothing else to do
26126
+ const now = Date.now();
26127
+ if (this._debug)
26128
+ console.debug('[user-event-service] Deleting events... ids:', ids);
26129
+ yield this.graphql.mutate({
26130
+ mutation: DeleteByIdsMutation,
26131
+ variables: {
26132
+ ids
26133
+ },
26134
+ update: (proxy) => {
26135
+ // Remove from caches
26136
+ this.removeFromMutableCachedQueriesByIds(proxy, {
26137
+ query: LoadAllQuery,
26138
+ ids
26139
+ });
26140
+ this.removeFromMutableCachedQueriesByIds(proxy, {
26141
+ query: LoadAllWithContentQuery,
26142
+ ids
26143
+ });
26144
+ if (this._debug)
26145
+ console.debug(`[user-event-service] Events deleted in ${Date.now() - now}ms`);
26184
26146
  }
26185
- }
26186
- else {
26187
- // Use default
26188
- yield this.defaultMarkAsRead(entity);
26189
- }
26147
+ });
26190
26148
  });
26191
26149
  }
26192
- registerListener(listener) {
26193
- if (!this.listeners)
26194
- this.listeners = [];
26195
- this.listeners.push(listener);
26196
- }
26197
- /* -- protected methods -- */
26198
- processUserEvent(source) {
26199
- // Convert json source to IUserEvent
26200
- let target = this.fromObject(source);
26201
- // Get listeners
26202
- const listeners = (this.listeners || []).filter(listener => listener.onReceived).filter(listener => listener.accept(target));
26203
- for (const listener of listeners) {
26204
- if (target) {
26205
- target = listener.onReceived(target);
26206
- }
26207
- else {
26208
- if (this._debug)
26209
- console.debug(`${this._logPrefix}Event has been rejected by a listener`, source);
26210
- break;
26211
- }
26212
- }
26213
- return target;
26214
- }
26215
- defaultMarkAsRead(userEvent) {
26150
+ /**
26151
+ * Delete userEvent entities
26152
+ */
26153
+ delete(data) {
26216
26154
  return __awaiter(this, void 0, void 0, function* () {
26217
- if (!userEvent)
26218
- throw new Error(`${this._logPrefix}Invalid event to save`);
26219
- // set read date
26220
- userEvent.readDate = moment$6();
26221
- if (!userEvent.id || userEvent.id < 0) {
26222
- if (this._debug)
26223
- console.debug(`${this._logPrefix}Save local user event`);
26224
- // TODO !!!!!!!!!!!!!
26225
- }
26226
- else {
26227
- yield this.save(userEvent);
26228
- }
26155
+ if (!data)
26156
+ return; // skip
26157
+ yield this.deleteAll([data]);
26229
26158
  });
26230
26159
  }
26231
- defaultFilter() {
26232
- // By default
26233
- return {
26234
- recipients: [this.defaultRecipient()]
26235
- };
26236
- }
26237
- defaultRecipient() {
26238
- return this.accountService.person.pubkey;
26239
- }
26240
- fillDefaultProperties(entity) {
26241
- }
26242
- unreadEvents(events) {
26243
- // default calculation on unread events from a list
26244
- if (isEmptyArray(events))
26245
- return undefined;
26246
- const lastReadDate = events
26247
- .filter(event => isNotNil(event.readDate))
26248
- .reduce((lastDate, event) => DateUtils.max(lastDate, event.readDate), undefined);
26249
- return events
26250
- .filter(event => event.creationDate.isSameOrAfter(lastReadDate)).length;
26251
- }
26252
- copyIdAndUpdateDate(source, target) {
26253
- EntityUtils.copyIdAndUpdateDate(source, target);
26254
- }
26255
- }
26256
- AbstractUserEventService.decorators = [
26257
- { type: Directive }
26258
- ];
26259
- AbstractUserEventService.ctorParameters = () => [
26260
- { type: GraphqlService },
26261
- { type: AccountService },
26262
- { type: NetworkService },
26263
- { type: TranslateService },
26264
- { type: undefined },
26265
- { type: undefined },
26266
- { type: undefined },
26267
- { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
26268
- ];
26269
- const userEventQueries = {
26270
- loadAll: gql `
26271
- query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26272
- data: userEvents(filter: $filter, page: $page){
26273
- ...LightUserEventFragment
26274
- }
26275
- }
26276
- ${UserEventFragments.lightUserEvent}
26277
- `,
26278
- loadAllWithContent: gql `
26279
- query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26280
- data: userEvents(filter: $filter, page: $page){
26281
- ...UserEventFragment
26282
- }
26160
+ listenChanges(id, options) {
26161
+ // TODO
26162
+ console.warn('TODO: implement listen changes on user events');
26163
+ return of();
26283
26164
  }
26284
- ${UserEventFragments.userEvent}
26285
- `
26286
- };
26287
- const userEventMutations = {
26288
- deleteByIds: gql `
26289
- mutation DeleteUserEvents($ids:[Int]){
26290
- deleteUserEvents(ids: $ids)
26291
- }
26292
- `,
26293
- save: gql `
26294
- mutation SaveUserEvent($data: UserEventVOInput){
26295
- data: saveUserEvent(userEvent: $data){
26296
- ...UserEventFragment
26297
- }
26165
+ registerAction(definition) {
26166
+ console.info(`[user-event-service] Registering action ${definition.name} for ${definition.__typename}`);
26167
+ this._userEventActions.push(definition);
26298
26168
  }
26299
- ${UserEventFragments.userEvent}
26300
- `
26301
- };
26302
- class UserEventService extends AbstractUserEventService {
26303
- constructor(graphql, accountService, network, translate, toastController, environment) {
26304
- super(graphql, accountService, network, translate, userEventQueries, userEventMutations, undefined, environment);
26305
- this.graphql = graphql;
26306
- this.accountService = accountService;
26307
- this.network = network;
26308
- this.translate = translate;
26309
- this.toastController = toastController;
26310
- this.environment = environment;
26169
+ getActionsByTypename(typename) {
26170
+ return this._userEventActions.filter(def => def.__typename === typename);
26311
26171
  }
26312
26172
  showToastErrorWithContext(opts) {
26313
26173
  return __awaiter(this, void 0, void 0, function* () {
@@ -26371,16 +26231,13 @@ class UserEventService extends AbstractUserEventService {
26371
26231
  }
26372
26232
  sendDataForDebug(data) {
26373
26233
  const userEvent = new UserEvent();
26374
- userEvent.type = UserEventTypes.DEBUG_DATA;
26234
+ userEvent.eventType = UserEventTypes.DEBUG_DATA;
26375
26235
  userEvent.content = this.convertObjectToString(data);
26376
26236
  return this.save(userEvent);
26377
26237
  }
26378
26238
  asFilter(filter) {
26379
26239
  return UserEventFilter.fromObject(filter);
26380
26240
  }
26381
- fromObject(source) {
26382
- return UserEvent.fromObject(source);
26383
- }
26384
26241
  /* -- protected methods -- */
26385
26242
  convertObjectToString(data) {
26386
26243
  if (typeof data === 'string') {
@@ -26409,9 +26266,13 @@ class UserEventService extends AbstractUserEventService {
26409
26266
  // TODO: compute sign
26410
26267
  console.warn('TODO: sign user event before sending');
26411
26268
  }
26269
+ copyIdAndUpdateDate(source, target) {
26270
+ EntityUtils.copyIdAndUpdateDate(source, target);
26271
+ }
26412
26272
  }
26273
+ 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" });
26413
26274
  UserEventService.decorators = [
26414
- { type: Injectable }
26275
+ { type: Injectable, args: [{ providedIn: 'root' },] }
26415
26276
  ];
26416
26277
  UserEventService.ctorParameters = () => [
26417
26278
  { type: GraphqlService },
@@ -26424,7 +26285,7 @@ UserEventService.ctorParameters = () => [
26424
26285
 
26425
26286
  const ICONS_MAP = {
26426
26287
  DEBUG_DATA: { matIcon: 'bug_report' },
26427
- INBOX_MESSAGE: { matIcon: 'mail' }
26288
+ INBOX_MESSAGE: { matIcon: 'mail' },
26428
26289
  };
26429
26290
  // TODO: refactor with a registration done by data service:
26430
26291
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -26490,7 +26351,7 @@ class UserEventsTable extends AppTable {
26490
26351
  }
26491
26352
  }));
26492
26353
  const filter = this.filter || new UserEventFilter();
26493
- filter.recipients = [this.recipient];
26354
+ filter.recipient = this.recipient;
26494
26355
  this.setFilter(filter, { emitEvent: true });
26495
26356
  }
26496
26357
  start() {
@@ -26503,17 +26364,17 @@ class UserEventsTable extends AppTable {
26503
26364
  });
26504
26365
  }
26505
26366
  getIcon(source) {
26506
- return ICONS_MAP[source.type];
26367
+ return ICONS_MAP[source.eventType];
26507
26368
  }
26508
26369
  getDetail(source) {
26509
26370
  if (!source)
26510
26371
  return undefined;
26511
- if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
26372
+ if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
26512
26373
  const context = source.content.context;
26513
26374
  if (context && context.__typename) {
26514
- // const actions = this.service.getActionsByTypename(context.__typename);
26375
+ const actions = this.service.getActionsByTypename(context.__typename);
26515
26376
  return {
26516
- // actions,
26377
+ actions,
26517
26378
  title: source.content.error && source.content.error.message || source.content.message,
26518
26379
  description: source.content.error && source.content.error.details || undefined
26519
26380
  };
@@ -26525,11 +26386,11 @@ class UserEventsTable extends AppTable {
26525
26386
  doAction(action, row) {
26526
26387
  return __awaiter(this, void 0, void 0, function* () {
26527
26388
  const event = row.currentData;
26528
- // const context = event.content && event.content.context;
26389
+ const context = event.content && event.content.context;
26529
26390
  this.markAsLoading();
26530
26391
  if (action && typeof action.executeAction === 'function') {
26531
26392
  try {
26532
- let res = action.executeAction(event /*, context*/);
26393
+ let res = action.executeAction(event, context);
26533
26394
  res = (res instanceof Promise) ? yield res : res;
26534
26395
  }
26535
26396
  catch (err) {
@@ -26548,18 +26409,13 @@ UserEventsTable.decorators = [
26548
26409
  selector: 'app-user-events-table',
26549
26410
  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",
26550
26411
  changeDetection: ChangeDetectionStrategy.OnPush,
26551
- providers: [
26552
- {
26553
- provide: UserEventServiceToken, useClass: UserEventService
26554
- }
26555
- ],
26556
26412
  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}"]
26557
26413
  },] }
26558
26414
  ];
26559
26415
  UserEventsTable.ctorParameters = () => [
26560
26416
  { type: Injector },
26561
26417
  { type: AccountService },
26562
- { type: undefined, decorators: [{ type: Inject, args: [UserEventServiceToken,] }] },
26418
+ { type: UserEventService },
26563
26419
  { type: EntitiesStorage },
26564
26420
  { type: ChangeDetectorRef },
26565
26421
  { type: undefined, decorators: [{ type: Inject, args: [ENVIRONMENT,] }] }
@@ -26571,147 +26427,6 @@ UserEventsTable.propDecorators = {
26571
26427
  defaultSortDirection: [{ type: Input }]
26572
26428
  };
26573
26429
 
26574
- class UserEventNotificationList {
26575
- constructor(popoverController) {
26576
- this.popoverController = popoverController;
26577
- }
26578
- ngOnInit() {
26579
- }
26580
- read($event, userEvent) {
26581
- var _a;
26582
- if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
26583
- return;
26584
- (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
26585
- }
26586
- executeAction(action, userEvent) {
26587
- // Execute then close popover
26588
- action.executeAction(userEvent);
26589
- this.dismiss();
26590
- }
26591
- dismiss() {
26592
- this.popoverController.dismiss();
26593
- }
26594
- }
26595
- UserEventNotificationList.decorators = [
26596
- { type: Component, args: [{
26597
- selector: 'app-user-event-notification-list',
26598
- 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",
26599
- styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}"]
26600
- },] }
26601
- ];
26602
- UserEventNotificationList.ctorParameters = () => [
26603
- { type: PopoverController }
26604
- ];
26605
- UserEventNotificationList.propDecorators = {
26606
- titleI18n: [{ type: Input }],
26607
- userEvents: [{ type: Input }],
26608
- readEvent: [{ type: Output }]
26609
- };
26610
-
26611
- class UserEventNotificationComponent {
26612
- constructor(userEventService, accountService, popoverController, cd) {
26613
- this.userEventService = userEventService;
26614
- this.accountService = accountService;
26615
- this.popoverController = popoverController;
26616
- this.cd = cd;
26617
- this.debug = false;
26618
- this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
26619
- this.disabled = false;
26620
- this.userEventsSubject = new BehaviorSubject(undefined);
26621
- this._subscriptions = new Subscription();
26622
- this._logPrefix = '[user-event-notification] ';
26623
- this._readEvent = new EventEmitter();
26624
- }
26625
- get count() {
26626
- var _a;
26627
- return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(map(value => value === 0 ? undefined : value));
26628
- }
26629
- ngOnInit() {
26630
- if (isNil(this.userEventService)) {
26631
- console.warn(`${this._logPrefix}No service injected`);
26632
- this.disabled = true;
26633
- return;
26634
- }
26635
- this._subscriptions.add(this.userEventService.watchAll(0, 10, 'creationDate', "desc").subscribe(value => {
26636
- const data = value.data;
26637
- if (this.debug) {
26638
- console.debug(`${this._logPrefix}Receiving user events`, data);
26639
- }
26640
- this.userEventsSubject.next(data);
26641
- }));
26642
- this._readEvent.subscribe(value => {
26643
- this.userEventService.markAsRead(value);
26644
- });
26645
- }
26646
- showList(event) {
26647
- return __awaiter(this, void 0, void 0, function* () {
26648
- const popover = yield this.popoverController.create({
26649
- component: UserEventNotificationList,
26650
- componentProps: {
26651
- titleI18n: this.titleI18n,
26652
- userEvents: this.userEventsSubject,
26653
- readEvent: this._readEvent
26654
- },
26655
- backdropDismiss: true,
26656
- keyboardClose: true,
26657
- event,
26658
- translucent: true,
26659
- cssClass: 'popover-large'
26660
- });
26661
- yield popover.present();
26662
- });
26663
- }
26664
- markForCheck() {
26665
- this.cd.markForCheck();
26666
- }
26667
- ngOnDestroy() {
26668
- if (this.debug) {
26669
- console.debug(`${this._logPrefix}Destroying`);
26670
- }
26671
- this._subscriptions.unsubscribe();
26672
- }
26673
- }
26674
- UserEventNotificationComponent.decorators = [
26675
- { type: Component, args: [{
26676
- selector: 'app-user-event-notification-component',
26677
- 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",
26678
- changeDetection: ChangeDetectionStrategy.OnPush,
26679
- styles: [""]
26680
- },] }
26681
- ];
26682
- UserEventNotificationComponent.ctorParameters = () => [
26683
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [UserEventServiceToken,] }] },
26684
- { type: AccountService },
26685
- { type: PopoverController },
26686
- { type: ChangeDetectorRef }
26687
- ];
26688
- UserEventNotificationComponent.propDecorators = {
26689
- debug: [{ type: Input }],
26690
- titleI18n: [{ type: Input }],
26691
- disabled: [{ type: Input }]
26692
- };
26693
-
26694
- class UserEventModule {
26695
- }
26696
- UserEventModule.decorators = [
26697
- { type: NgModule, args: [{
26698
- imports: [
26699
- CommonModule,
26700
- CoreModule,
26701
- SharedModule
26702
- ],
26703
- declarations: [
26704
- UserEventsTable,
26705
- UserEventNotificationComponent,
26706
- UserEventNotificationList,
26707
- ],
26708
- exports: [
26709
- UserEventsTable,
26710
- UserEventNotificationComponent
26711
- ]
26712
- },] }
26713
- ];
26714
-
26715
26430
  const MessageTypes = {
26716
26431
  INBOX_MESSAGE: 'INBOX_MESSAGE',
26717
26432
  EMAIL: 'EMAIL',
@@ -26923,9 +26638,9 @@ MessageForm.propDecorators = {
26923
26638
  canSelectType: [{ type: Input }]
26924
26639
  };
26925
26640
 
26926
- class MessageModule {
26641
+ class SocialModule {
26927
26642
  }
26928
- MessageModule.decorators = [
26643
+ SocialModule.decorators = [
26929
26644
  { type: NgModule, args: [{
26930
26645
  imports: [
26931
26646
  CommonModule,
@@ -26933,317 +26648,17 @@ MessageModule.decorators = [
26933
26648
  SharedModule
26934
26649
  ],
26935
26650
  declarations: [
26651
+ UserEventsTable,
26936
26652
  MessageModal,
26937
26653
  MessageForm
26938
26654
  ],
26939
26655
  exports: [
26656
+ UserEventsTable,
26940
26657
  MessageModal
26941
26658
  ]
26942
26659
  },] }
26943
26660
  ];
26944
26661
 
26945
- var JobProgression_1;
26946
- // todo use entity
26947
- class Job {
26948
- }
26949
- // @dynamic
26950
- let JobProgression = JobProgression_1 = class JobProgression extends Entity {
26951
- constructor() {
26952
- super(JobProgression_1.TYPENAME);
26953
- }
26954
- fromObject(source) {
26955
- super.fromObject(source);
26956
- this.message = source.message;
26957
- this.current = source.current;
26958
- this.total = source.total;
26959
- }
26960
- };
26961
- JobProgression = JobProgression_1 = __decorate([
26962
- EntityClass({ typename: 'JobProgressionVO' })
26963
- ], JobProgression);
26964
-
26965
- const JobProgressionServiceToken = new InjectionToken('JobProgressionService');
26966
- const jobProgressionSubscription = gql `subscription UpdateJobProgression($id: Int!, $interval: Int){
26967
- data: updateJobProgression(id: $id, interval: $interval) {
26968
- id
26969
- message
26970
- current
26971
- total
26972
- }
26973
- }`;
26974
- class JobProgressionService extends BaseGraphqlService {
26975
- constructor(graphql, environment) {
26976
- super(graphql, environment);
26977
- this.graphql = graphql;
26978
- this.environment = environment;
26979
- this._logPrefix = '[job-progression-service] ';
26980
- // For DEV only
26981
- this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
26982
- }
26983
- listenChanges(id, options) {
26984
- if (isNil(id))
26985
- throw new Error(`${this._logPrefix}Missing argument 'id'`);
26986
- if (this._debug)
26987
- console.debug(`${this._logPrefix}[WS] Listening changes for job progression {${id}}...`);
26988
- return this.graphql.subscribe({
26989
- query: jobProgressionSubscription,
26990
- fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
26991
- variables: { id, interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
26992
- error: { code: SocialErrorCodes.SUBSCRIBE_JOB_PROGRESSION_ERROR, message: 'SOCIAL.ERROR.SUBSCRIBE_JOB_PROGRESSION_ERROR' }
26993
- }).pipe(map(({ data }) => {
26994
- const progression = data && JobProgression.fromObject(data);
26995
- if (progression && this._debug)
26996
- console.debug(`${this._logPrefix}Job progression ${id} updated on server`, progression);
26997
- return progression;
26998
- }));
26999
- }
27000
- }
27001
- JobProgressionService.decorators = [
27002
- { type: Injectable }
27003
- ];
27004
- JobProgressionService.ctorParameters = () => [
27005
- { type: GraphqlService },
27006
- { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
27007
- ];
27008
-
27009
- class JobProgressionList {
27010
- constructor() {
27011
- }
27012
- ngOnInit() {
27013
- }
27014
- }
27015
- JobProgressionList.decorators = [
27016
- { type: Component, args: [{
27017
- selector: 'app-job-progression-list',
27018
- 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",
27019
- styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}"]
27020
- },] }
27021
- ];
27022
- JobProgressionList.ctorParameters = () => [];
27023
- JobProgressionList.propDecorators = {
27024
- titleI18n: [{ type: Input }],
27025
- jobProgressions: [{ type: Input }]
27026
- };
27027
-
27028
- class JobProgressionComponent {
27029
- constructor(jobProgressionService, popoverController, cd) {
27030
- this.jobProgressionService = jobProgressionService;
27031
- this.popoverController = popoverController;
27032
- this.cd = cd;
27033
- this.debug = false;
27034
- this.titleI18n = 'SOCIAL.JOB.PROGRESSION.TITLE';
27035
- this.jobFinished = new EventEmitter();
27036
- this.disabled = true;
27037
- this.color = 'accent';
27038
- this.mode = 'determinate';
27039
- this.value = 0;
27040
- this.jobProgressions = [];
27041
- this._subscriptions = new Subscription();
27042
- this._subscriptionsById = {};
27043
- this._logPrefix = '[job-progression] ';
27044
- }
27045
- ngOnInit() {
27046
- var _a, _b, _c, _d;
27047
- if (isNil(this.jobProgressionService)) {
27048
- console.warn(`${this._logPrefix}No service injected`);
27049
- }
27050
- // parse options
27051
- this.autoHide = toBoolean((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoHide, false);
27052
- this.visible = !this.autoHide;
27053
- this.autoHideDelay = toNumber((_b = this.options) === null || _b === void 0 ? void 0 : _b.autoHideDelay, 1000);
27054
- this.autoRemove = toBoolean((_c = this.options) === null || _c === void 0 ? void 0 : _c.autoRemove, true);
27055
- this.autoRemoveDelay = toNumber((_d = this.options) === null || _d === void 0 ? void 0 : _d.autoRemoveDelay, 1000);
27056
- }
27057
- addJob(id) {
27058
- if (isNil(this.jobProgressionService)) {
27059
- console.warn(`${this._logPrefix}No service injected. Can't add a job`);
27060
- return;
27061
- }
27062
- if (this.debug) {
27063
- console.debug(`${this._logPrefix}Add job id=${id}`);
27064
- }
27065
- if (!!this.getProgression(id)) {
27066
- console.warn(`${this._logPrefix}Job (id=${id}) already present`);
27067
- return;
27068
- }
27069
- this.disabled = false;
27070
- const sub = this.jobProgressionService.listenChanges(id)
27071
- .pipe(filter(progression => {
27072
- if (id !== progression.id) {
27073
- console.error(`${this._logPrefix}Job progression (id=${progression.id}) doesn't match expected job (id=${id})`);
27074
- return false;
27075
- }
27076
- return true;
27077
- }), map(progression => {
27078
- // Ensure visible
27079
- this.visible = true;
27080
- // Get current progression object
27081
- const currentProgression = this.getProgression(id);
27082
- if (!currentProgression) {
27083
- // add it
27084
- this.jobProgressions.push(progression);
27085
- if (this.debug) {
27086
- console.debug(`${this._logPrefix}Progression added id=${id}`, progression);
27087
- }
27088
- }
27089
- else {
27090
- // update current
27091
- Object.assign(currentProgression, progression);
27092
- if (this.debug) {
27093
- console.debug(`${this._logPrefix}Progression updated id=${id}`, progression);
27094
- }
27095
- }
27096
- return progression;
27097
- }))
27098
- .subscribe(progression => {
27099
- // update value
27100
- this.updateValue();
27101
- // job finished
27102
- if (progression.total > 0 && progression.current == progression.total) {
27103
- if (this.debug) {
27104
- console.debug(`${this._logPrefix}Finished job id=${progression.id}`);
27105
- }
27106
- // emit event
27107
- this.jobFinished.emit(progression.id);
27108
- if (this.autoRemove) {
27109
- setTimeout(() => {
27110
- var _a;
27111
- this.removeJob(progression.id);
27112
- // If last job
27113
- if (this.autoHide && !((_a = this.jobProgressions) === null || _a === void 0 ? void 0 : _a.length)) {
27114
- setTimeout(() => {
27115
- this.visible = false;
27116
- this.markForCheck();
27117
- }, this.autoHideDelay);
27118
- }
27119
- }, this.autoRemoveDelay);
27120
- }
27121
- }
27122
- });
27123
- this._subscriptionsById[id] = sub;
27124
- this._subscriptions.add(sub);
27125
- }
27126
- removeJob(id) {
27127
- if (this.debug) {
27128
- console.debug(`${this._logPrefix}Remove job id=${id}`);
27129
- }
27130
- const sub = this._subscriptionsById[id];
27131
- if (sub) {
27132
- this._subscriptions.remove(sub);
27133
- sub.unsubscribe();
27134
- }
27135
- const progression = this.getProgression(id);
27136
- if (progression) {
27137
- this.jobProgressions.splice(this.jobProgressions.indexOf(progression), 1);
27138
- }
27139
- this.updateValue();
27140
- }
27141
- getProgression(id) {
27142
- return this.jobProgressions.find(progression => progression.id === id);
27143
- }
27144
- updateValue() {
27145
- if (this.debug) {
27146
- console.debug(`${this._logPrefix}Updating value`);
27147
- }
27148
- let value = 0;
27149
- const nbProgression = arraySize(this.jobProgressions);
27150
- let allIndeterminate = nbProgression > 0;
27151
- this.jobProgressions.forEach(progression => {
27152
- const indeterminate = progression.total === 0;
27153
- allIndeterminate = allIndeterminate && indeterminate;
27154
- if (!indeterminate) {
27155
- value = value + progression.current * 100 / progression.total;
27156
- }
27157
- });
27158
- this.value = nbProgression > 0 ? value / nbProgression : 0;
27159
- this.mode = allIndeterminate ? 'indeterminate' : 'determinate';
27160
- if (this.debug) {
27161
- console.debug(`${this._logPrefix}Setting value=${this.value}, mode=${this.mode}`);
27162
- }
27163
- this.markForCheck();
27164
- }
27165
- showList(event) {
27166
- return __awaiter(this, void 0, void 0, function* () {
27167
- const popover = yield this.popoverController.create({
27168
- component: JobProgressionList,
27169
- componentProps: {
27170
- titleI18n: this.titleI18n,
27171
- jobProgressions: this.jobProgressions
27172
- },
27173
- backdropDismiss: true,
27174
- keyboardClose: true,
27175
- event,
27176
- translucent: true,
27177
- cssClass: 'popover-large'
27178
- });
27179
- yield popover.present();
27180
- });
27181
- }
27182
- markForCheck() {
27183
- this.cd.markForCheck();
27184
- }
27185
- ngOnDestroy() {
27186
- if (this.debug) {
27187
- console.debug(`${this._logPrefix}Destroying`);
27188
- }
27189
- this._subscriptions.unsubscribe();
27190
- }
27191
- }
27192
- JobProgressionComponent.decorators = [
27193
- { type: Component, args: [{
27194
- selector: 'app-job-progression',
27195
- 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",
27196
- changeDetection: ChangeDetectionStrategy.OnPush,
27197
- styles: [".floating-spinner{position:absolute;top:6px;left:5px}"]
27198
- },] }
27199
- ];
27200
- JobProgressionComponent.ctorParameters = () => [
27201
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [JobProgressionServiceToken,] }] },
27202
- { type: PopoverController },
27203
- { type: ChangeDetectorRef }
27204
- ];
27205
- JobProgressionComponent.propDecorators = {
27206
- debug: [{ type: Input }],
27207
- titleI18n: [{ type: Input }],
27208
- options: [{ type: Input }],
27209
- jobFinished: [{ type: Output }]
27210
- };
27211
-
27212
- class JobModule {
27213
- }
27214
- JobModule.decorators = [
27215
- { type: NgModule, args: [{
27216
- imports: [
27217
- CommonModule,
27218
- SharedModule,
27219
- TranslateModule.forChild(),
27220
- ],
27221
- declarations: [
27222
- JobProgressionComponent,
27223
- JobProgressionList
27224
- ],
27225
- exports: [
27226
- JobProgressionComponent
27227
- ]
27228
- },] }
27229
- ];
27230
-
27231
- const SocialModuleOptionsToken = new InjectionToken("SocialModuleOptions");
27232
- class SocialModule {
27233
- }
27234
- SocialModule.decorators = [
27235
- { type: NgModule, args: [{
27236
- imports: [
27237
- CommonModule,
27238
- CoreModule,
27239
- SharedModule,
27240
- UserEventModule,
27241
- JobModule,
27242
- MessageModule,
27243
- ],
27244
- },] }
27245
- ];
27246
-
27247
26662
  const Mutations = {
27248
26663
  send: gql `mutation SendMessage($data: MessageVOInput){
27249
26664
  done: sendMessage(message: $data)
@@ -27889,10 +27304,12 @@ class AutocompleteTestPage {
27889
27304
  });
27890
27305
  }
27891
27306
  ngAfterViewInit() {
27892
- setTimeout(() => {
27893
- this.farEntityField.suggestLengthThreshold = 2;
27894
- this.farEntityField.reloadItems();
27895
- }, 2000);
27307
+ if (this.farEntityField) {
27308
+ setTimeout(() => {
27309
+ this.farEntityField.suggestLengthThreshold = 2;
27310
+ this.farEntityField.reloadItems();
27311
+ }, 2000);
27312
+ }
27896
27313
  setTimeout(() => this.loadData(), 1000);
27897
27314
  }
27898
27315
  // Load the form with data
@@ -27980,7 +27397,7 @@ class AutocompleteTestPage {
27980
27397
  AutocompleteTestPage.decorators = [
27981
27398
  { type: Component, args: [{
27982
27399
  selector: 'app-autocomplete-test',
27983
- 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"
27400
+ 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"
27984
27401
  },] }
27985
27402
  ];
27986
27403
  AutocompleteTestPage.ctorParameters = () => [
@@ -28056,13 +27473,13 @@ LatLongTestPage.ctorParameters = () => [
28056
27473
  { type: FormBuilder }
28057
27474
  ];
28058
27475
 
28059
- const moment$7 = momentImported;
27476
+ const moment$6 = momentImported;
28060
27477
  class SwipeTestPage {
28061
27478
  constructor(formBuilder, dateFormatPipe) {
28062
27479
  this.formBuilder = formBuilder;
28063
27480
  this.dateFormatPipe = dateFormatPipe;
28064
27481
  this.$dates = new BehaviorSubject(undefined);
28065
- this._today = moment$7().startOf('day');
27482
+ this._today = moment$6().startOf('day');
28066
27483
  this.form = formBuilder.group({
28067
27484
  empty: [null, Validators.required],
28068
27485
  date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
@@ -28075,7 +27492,7 @@ class SwipeTestPage {
28075
27492
  ngOnInit() {
28076
27493
  const dates = [];
28077
27494
  for (let d = 0; d < 7; d++) {
28078
- dates[d] = moment$7(this._today).add(d - 3, 'day');
27495
+ dates[d] = moment$6(this._today).add(d - 3, 'day');
28079
27496
  }
28080
27497
  this.$dates.next(dates);
28081
27498
  this.loadData();
@@ -28116,7 +27533,7 @@ SwipeTestPage.ctorParameters = () => [
28116
27533
  { type: DateFormatPipe }
28117
27534
  ];
28118
27535
 
28119
- const moment$8 = momentImported;
27536
+ const moment$7 = momentImported;
28120
27537
  class DateTimeTestPage {
28121
27538
  constructor(platform, formBuilder, cd) {
28122
27539
  this.platform = platform;
@@ -28148,7 +27565,7 @@ class DateTimeTestPage {
28148
27565
  // Load the form with data
28149
27566
  loadData() {
28150
27567
  return __awaiter(this, void 0, void 0, function* () {
28151
- const now = moment$8();
27568
+ const now = moment$7();
28152
27569
  const data = {
28153
27570
  empty: null,
28154
27571
  emptyRequired: null,
@@ -28394,7 +27811,7 @@ NumpadTestPage.ctorParameters = () => [
28394
27811
  { type: FormBuilder }
28395
27812
  ];
28396
27813
 
28397
- const moment$9 = momentImported;
27814
+ const moment$8 = momentImported;
28398
27815
  class DateTestPage {
28399
27816
  constructor(formBuilder, cd) {
28400
27817
  this.formBuilder = formBuilder;
@@ -28427,7 +27844,7 @@ class DateTestPage {
28427
27844
  // Load the form with data
28428
27845
  loadData() {
28429
27846
  return __awaiter(this, void 0, void 0, function* () {
28430
- const now = moment$9();
27847
+ const now = moment$8();
28431
27848
  const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
28432
27849
  const data = {
28433
27850
  empty: null,
@@ -29173,5 +28590,5 @@ CoreTestingModule.decorators = [
29173
28590
  * Generated bundle index. Do not edit.
29174
28591
  */
29175
28592
 
29176
- 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 };
28593
+ 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 };
29177
28594
  //# sourceMappingURL=sumaris-net.ngx-components.js.map