@sumaris-net/ngx-components 1.21.0-beta8 → 1.21.1

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 +535 -1191
  2. package/bundles/sumaris-net.ngx-components.umd.js.map +1 -1
  3. package/bundles/sumaris-net.ngx-components.umd.min.js +2 -2
  4. package/bundles/sumaris-net.ngx-components.umd.min.js.map +1 -1
  5. package/doc/changelog.md +12 -0
  6. package/esm2015/public_api.js +3 -8
  7. package/esm2015/src/app/core/account/account.js +2 -2
  8. package/esm2015/src/app/core/auth/form/form-auth.js +4 -2
  9. package/esm2015/src/app/core/form/editor.class.js +52 -20
  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 +66 -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 +437 -990
  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 +38 -12
  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,18 @@ class AppForm {
17653
17666
  * @param opts
17654
17667
  */
17655
17668
  ready(opts) {
17656
- return waitForTrue(this._$ready, opts);
17669
+ if (this.readySubject.value)
17670
+ return Promise.resolve();
17671
+ return waitForTrue(this.readySubject, opts);
17657
17672
  }
17658
17673
  /**
17659
- * Wait form is idle (not loading)
17674
+ * Wait form is not busy (=loaded)
17660
17675
  * @param opts
17661
17676
  */
17662
17677
  waitIdle(opts) {
17663
- return __awaiter(this, void 0, void 0, function* () {
17664
- return AppFormUtils.waitIdle(this, opts);
17665
- });
17678
+ if (!this.loadingSubject.value)
17679
+ return Promise.resolve();
17680
+ return waitForFalse(this.loadingSubject, opts);
17666
17681
  }
17667
17682
  updateValueAndValidity(opts) {
17668
17683
  AppFormUtils.updateValueAndValidity(this.form, opts);
@@ -17692,10 +17707,27 @@ class AppForm {
17692
17707
  registerAutocompleteField(fieldName, opts) {
17693
17708
  return this.autocompleteHelper.add(fieldName, opts);
17694
17709
  }
17710
+ setError(value, opts) {
17711
+ if (this.errorSubject.value !== value) {
17712
+ this.errorSubject.next(value);
17713
+ if (!opts || opts.emitEvent !== false) {
17714
+ this.markForCheck();
17715
+ }
17716
+ }
17717
+ }
17695
17718
  markForCheck() {
17696
17719
  // Should be overwritten by subclasses
17697
17720
  console.warn('markForCheck() has been called, but is not overwritten by component ' + this.constructor.name);
17698
17721
  }
17722
+ /* -- private function -- */
17723
+ setLoading(value, opts) {
17724
+ if (this.loadingSubject.value !== value) {
17725
+ this.loadingSubject.next(value);
17726
+ if (!opts || opts.emitEvent !== false) {
17727
+ this.markForCheck();
17728
+ }
17729
+ }
17730
+ }
17699
17731
  }
17700
17732
  AppForm.decorators = [
17701
17733
  { type: Directive }
@@ -18213,6 +18245,18 @@ class InMemoryEntitiesService extends EntitiesService {
18213
18245
  return this._equalsFn(d1, d2);
18214
18246
  return d1 && d1.equals ? d1.equals(d2) : EntityUtils.equals(d1, d2, 'id');
18215
18247
  }
18248
+ /**
18249
+ * Count data stored by the service (without hidden data).
18250
+ * @param opts
18251
+ */
18252
+ get count() {
18253
+ var _a;
18254
+ return (((_a = this.data) === null || _a === void 0 ? void 0 : _a.length) || 0);
18255
+ }
18256
+ get hiddenCount() {
18257
+ var _a;
18258
+ return ((_a = this._hiddenData) === null || _a === void 0 ? void 0 : _a.length) || 0;
18259
+ }
18216
18260
  /* -- protected methods -- */
18217
18261
  filter(data, _filter, hiddenData) {
18218
18262
  // if filter is DataFilter instance, use its test function
@@ -18766,7 +18810,9 @@ class AuthForm extends AppForm {
18766
18810
  }
18767
18811
  }
18768
18812
  cancel() {
18769
- this.onCancel.emit();
18813
+ return __awaiter(this, void 0, void 0, function* () {
18814
+ this.onCancel.emit();
18815
+ });
18770
18816
  }
18771
18817
  doSubmit(event) {
18772
18818
  return __awaiter(this, void 0, void 0, function* () {
@@ -19623,7 +19669,7 @@ class AccountPage extends AppForm {
19623
19669
  cancel: { get: () => super.cancel }
19624
19670
  });
19625
19671
  return __awaiter(this, void 0, void 0, function* () {
19626
- _super.cancel.call(this);
19672
+ yield _super.cancel.call(this);
19627
19673
  });
19628
19674
  }
19629
19675
  markForCheck() {
@@ -21431,7 +21477,7 @@ class MenuComponent {
21431
21477
  MenuComponent.decorators = [
21432
21478
  { type: Component, args: [{
21433
21479
  selector: 'app-menu',
21434
- template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n<!-- todo ajouter ici les 2 composants du module social -->\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
21480
+ template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
21435
21481
  animations: [fadeInAnimation],
21436
21482
  changeDetection: ChangeDetectionStrategy.OnPush,
21437
21483
  styles: ["ion-menu{--ion-item-background:transparent;--ion-item-divider-background:transparent;--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint);--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-text-color-selected:var(--ion-color-primary);--ion-item-icon-color-selected:var(--ion-color-primary);--ion-item-text-color-disable:var(--ion-color-medium);--ion-item-icon-color-disable:var(--ion-color-medium)}ion-menu ion-header ion-text{color:var(--ion-color-primary)}ion-menu ion-header .user-avatar{background-size:cover;background-repeat:no-repeat;background-position:50%;background-color:var(--ion-color-secondary);border:1px solid var(--ion-color-primary);overflow:hidden!important;font-size:var(--avatar-size,60px)!important;line-height:var(--avatar-size,60px);height:var(--avatar-size,60px)!important;width:var(--avatar-size,60px)!important;border-radius:50%;display:inline-block}ion-menu ion-header .user-logo{text-align:right}ion-menu ion-header .user-logo img{max-width:120px;max-height:var(--avatar-size,60px);width:auto}ion-menu ion-header .username{padding-top:0;margin-top:0;margin-bottom:0;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-menu ion-header button[mat-button]{padding:0;text-align:start!important;width:100%}ion-menu .scroll-content{margin-top:79px!important}ion-menu .has-user-header .scroll-content{margin-top:188px!important}ion-menu ion-content.has-profile-header{--offset-top:188px}ion-menu ion-content.no-profile-header{--offset-top:79px}ion-menu ion-content ion-list{min-height:100%;display:flex;flex-direction:column;justify-content:flex-start}ion-menu ion-content ion-list ion-menu-toggle.flex-spacer{flex:1 1 auto;display:flex;flex-direction:column;justify-content:flex-end}ion-menu ion-content ion-list ion-item.primary{--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint)}ion-menu ion-content ion-list ion-item.secondary{--ion-item-icon-color:var(--ion-color-secondary-tint);--ion-item-text-color:var(--ion-color-secondary-tint)}ion-menu ion-content ion-list ion-item.tertiary{--ion-item-icon-color:var(--ion-color-tertiary-tint);--ion-item-text-color:var(--ion-color-tertiary-tint)}ion-menu ion-content ion-list ion-item.danger{--ion-item-icon-color:var(--ion-color-danger-tint);--ion-item-text-color:var(--ion-color-danger-tint)}ion-menu ion-content ion-list ion-item.medium{--ion-item-icon-color:var(--ion-color-medium-shade);--ion-item-text-color:var(--ion-color-medium-shade)}ion-menu ion-content ion-list ion-item.dark{--ion-item-icon-color:var(--ion-color-dark-tint);--ion-item-text-color:var(--ion-color-dark-tint)}ion-menu ion-content ion-list ion-item ion-icon,ion-menu ion-content ion-list ion-item mat-icon{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item ion-label,ion-menu ion-content ion-list ion-item ion-text{color:var(--ion-item-text-color)!important}ion-menu ion-content ion-list ion-item.selected{background-color:var(--ion-item-background-selected)!important;--color-hover:var(--ion-item-background-selected)!important}ion-menu ion-content ion-list ion-item.selected ion-icon,ion-menu ion-content ion-list ion-item.selected mat-icon{color:var(--ion-item-icon-color-selected)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item.selected ion-label,ion-menu ion-content ion-list ion-item.selected ion-text{color:var(--ion-item-text-color-selected)!important}ion-menu ion-content ion-list ion-item.selected:hover{--color-hover:var(--ion-item-background-selected)!important;--ion-item-icon-color-selected:var(--ion-item-icon-color)!important;--ion-item-text-color-selected:var(--ion-item-text-color)!important}ion-menu ion-footer{display:block!important}ion-menu ion-footer ion-toolbar ion-title{cursor:pointer;font-size:12pt;font-weight:400;text-align:center;padding:0 8px}ion-menu ion-footer ion-toolbar ion-button{--width:40px}@media screen and (max-width:767px){ion-menu ion-footer{display:none!important;visibility:hidden!important}}@media screen and (min-width:768px){ion-menu ion-scroll{overflow-y:auto!important}ion-menu .user-avatar{font-size:var(--avatar-size,80px)!important;line-height:var(--avatar-size,80px);height:var(--avatar-size,80px)!important;width:var(--avatar-size,80px)!important}ion-menu .user-logo img{max-height:var(--avatar-size,80px)}}"]
@@ -21495,14 +21541,13 @@ class AppIconComponent {
21495
21541
  this.icon = value.icon;
21496
21542
  this.matIcon = value.matIcon;
21497
21543
  this.matSvgIcon = value.matSvgIcon;
21498
- this.color = value.color;
21499
21544
  }
21500
21545
  ;
21501
21546
  }
21502
21547
  AppIconComponent.decorators = [
21503
21548
  { type: Component, args: [{
21504
21549
  selector: 'app-icon',
21505
- template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n [style.font-size.px]=\"height || width\"\n >{{matIcon}}</mat-icon>\n</ng-template>\n\n"
21550
+ template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\">{{matIcon}}</mat-icon>\n</ng-template>\n\n"
21506
21551
  },] }
21507
21552
  ];
21508
21553
  AppIconComponent.propDecorators = {
@@ -21510,8 +21555,6 @@ AppIconComponent.propDecorators = {
21510
21555
  matIcon: [{ type: Input }],
21511
21556
  matSvgIcon: [{ type: Input }],
21512
21557
  color: [{ type: Input }],
21513
- height: [{ type: Input }],
21514
- width: [{ type: Input }],
21515
21558
  ref: [{ type: Input }]
21516
21559
  };
21517
21560
 
@@ -22583,13 +22626,12 @@ class AppTable {
22583
22626
  get error() {
22584
22627
  return this.errorSubject.value;
22585
22628
  }
22586
- get error$() {
22587
- return this.errorSubject.asObservable();
22588
- }
22589
22629
  /**
22590
22630
  * @deprecated
22591
- * @param error
22592
22631
  */
22632
+ get error$() {
22633
+ return this.errorSubject.asObservable();
22634
+ }
22593
22635
  set error(error) {
22594
22636
  this.setError(error);
22595
22637
  }
@@ -23013,7 +23055,7 @@ class AppTable {
23013
23055
  .then(() => this.editRowById(event, row.id, { focusColumn: this.lastUserColumn }));
23014
23056
  return true;
23015
23057
  }
23016
- // Edit next row
23058
+ // Edit previous row
23017
23059
  this.editRow(event, row, { focusColumn: this.lastUserColumn });
23018
23060
  return true;
23019
23061
  }
@@ -23036,8 +23078,7 @@ class AppTable {
23036
23078
  if (id < 0)
23037
23079
  return;
23038
23080
  if (id >= this.visibleRowCount) {
23039
- this.focusColumn = opts && opts.focusColumn || this.firstUserColumn;
23040
- this.addRow(event);
23081
+ this.addRow(event, undefined, opts);
23041
23082
  }
23042
23083
  else {
23043
23084
  const row = yield this.dataSource.getRow(id);
@@ -23110,7 +23151,7 @@ class AppTable {
23110
23151
  this.cancelExistingRow(event, row, opts);
23111
23152
  }
23112
23153
  }
23113
- addRow(event, insertAt) {
23154
+ addRow(event, insertAt, opts) {
23114
23155
  if (this.debug)
23115
23156
  console.debug('[table] Asking for new row...');
23116
23157
  if (!this._enabled)
@@ -23125,7 +23166,7 @@ class AppTable {
23125
23166
  return false;
23126
23167
  }
23127
23168
  // Add new row
23128
- this.addRowToTable(insertAt);
23169
+ this.addRowToTable(insertAt, opts);
23129
23170
  return true;
23130
23171
  }
23131
23172
  save(opts) {
@@ -23240,7 +23281,7 @@ class AppTable {
23240
23281
  * @param event
23241
23282
  * @param row
23242
23283
  * @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
23284
+ * And to force deletion even if table is busy
23244
23285
  */
23245
23286
  deleteRow(event, row, opts) {
23246
23287
  return __awaiter(this, void 0, void 0, function* () {
@@ -23253,7 +23294,7 @@ class AppTable {
23253
23294
  * @param event
23254
23295
  * @param rows
23255
23296
  * @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
23297
+ * And to force deletion even if table is busy
23257
23298
  */
23258
23299
  deleteRows(event, rows, opts) {
23259
23300
  var _a;
@@ -23266,8 +23307,8 @@ class AppTable {
23266
23307
  event === null || event === void 0 ? void 0 : event.preventDefault();
23267
23308
  if (!this._enabled || isEmptyArray(rows))
23268
23309
  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');
23310
+ if (this.loading && (!opts || opts.interactive !== false)) {
23311
+ console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.interactive = false to force deletion');
23271
23312
  return 0; // Skip if loading
23272
23313
  }
23273
23314
  // Make sure to keep newly created row
@@ -23404,15 +23445,11 @@ class AppTable {
23404
23445
  moveRow(id, direction) {
23405
23446
  this.dataSource.move(id, direction);
23406
23447
  }
23407
- ready() {
23408
- return __awaiter(this, void 0, void 0, function* () {
23409
- yield firstTruePromise(this.readySubject);
23410
- });
23448
+ ready(opts) {
23449
+ return waitForTrue(this.readySubject, opts);
23411
23450
  }
23412
23451
  waitIdle(opts) {
23413
- return __awaiter(this, void 0, void 0, function* () {
23414
- yield firstFalsePromise(this.loadingSubject);
23415
- });
23452
+ return waitForFalse(this.loadingSubject, opts);
23416
23453
  }
23417
23454
  openSelectColumnsModal(event) {
23418
23455
  return __awaiter(this, void 0, void 0, function* () {
@@ -23790,9 +23827,10 @@ class AppTable {
23790
23827
  //if (this.debug) console.debug("[table] id = " + id);
23791
23828
  return id;
23792
23829
  }
23793
- addRowToTable(insertAt) {
23830
+ addRowToTable(insertAt, opts) {
23794
23831
  return __awaiter(this, void 0, void 0, function* () {
23795
23832
  this.focusFirstColumn = true;
23833
+ this.focusColumn = (opts === null || opts === void 0 ? void 0 : opts.focusColumn) || this.firstUserColumn;
23796
23834
  yield this._dataSource.asyncCreateNew(insertAt);
23797
23835
  this.editedRow = this._dataSource.getRow(-1);
23798
23836
  // Emit start editing event
@@ -24139,8 +24177,9 @@ class AppEditor {
24139
24177
  this._subscription = new Subscription();
24140
24178
  this._enabled = false;
24141
24179
  this._dirty = false;
24142
- this._$ready = new BehaviorSubject(false);
24143
- this._$loading = new BehaviorSubject(true);
24180
+ this.readySubject = new BehaviorSubject(false);
24181
+ this.loadingSubject = new BehaviorSubject(true);
24182
+ this.errorSubject = new BehaviorSubject(undefined);
24144
24183
  this.debug = false;
24145
24184
  this.submitted = false;
24146
24185
  this.toolbar = null;
@@ -24150,13 +24189,31 @@ class AppEditor {
24150
24189
  * @deprecated
24151
24190
  */
24152
24191
  set _loading(value) {
24153
- this._$loading.next(value);
24192
+ this.readySubject.next(value);
24154
24193
  }
24155
24194
  /**
24156
24195
  * @deprecated
24157
24196
  */
24158
24197
  get _loading() {
24159
- return this._$loading.value;
24198
+ return this.loadingSubject.value;
24199
+ }
24200
+ /**
24201
+ * @deprecated
24202
+ */
24203
+ get _$ready() {
24204
+ return this.readySubject;
24205
+ }
24206
+ /**
24207
+ * @deprecated
24208
+ */
24209
+ get _$loading() {
24210
+ return this.loadingSubject;
24211
+ }
24212
+ get error() {
24213
+ return this.errorSubject.value;
24214
+ }
24215
+ set error(error) {
24216
+ this.setError(error);
24160
24217
  }
24161
24218
  get tables() {
24162
24219
  return this._children && this._children.filter(c => c instanceof AppTable);
@@ -24185,7 +24242,7 @@ class AppEditor {
24185
24242
  }
24186
24243
  get loading() {
24187
24244
  var _a;
24188
- return this._$loading.value || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
24245
+ return this.loadingSubject.value || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
24189
24246
  }
24190
24247
  get enabled() {
24191
24248
  return this._enabled;
@@ -24209,12 +24266,11 @@ class AppEditor {
24209
24266
  }
24210
24267
  ngOnDestroy() {
24211
24268
  this._subscription.unsubscribe();
24212
- this._$ready.complete();
24213
- this._$ready.unsubscribe();
24214
- this._$loading.complete();
24215
- this._$loading.unsubscribe();
24216
- }
24217
- addChildForm(form) {
24269
+ this.readySubject.unsubscribe();
24270
+ this.loadingSubject.unsubscribe();
24271
+ this.errorSubject.unsubscribe();
24272
+ }
24273
+ addChildForm(form) {
24218
24274
  if (!form)
24219
24275
  throw new Error('Trying to register an undefined child form');
24220
24276
  this._children = this._children || [];
@@ -24281,16 +24337,16 @@ class AppEditor {
24281
24337
  this.markForCheck();
24282
24338
  }
24283
24339
  markAsLoading(opts) {
24284
- if (!this._loading) {
24285
- this._loading = true;
24340
+ if (!this.loadingSubject.value) {
24341
+ this.loadingSubject.next(true);
24286
24342
  if (!opts || opts.emitEvent !== false)
24287
24343
  this.markForCheck();
24288
24344
  }
24289
24345
  }
24290
24346
  markAsLoaded(opts) {
24291
24347
  var _a;
24292
- if (this._loading) {
24293
- this._loading = false;
24348
+ if (this.loadingSubject.value) {
24349
+ this.loadingSubject.next(false);
24294
24350
  if (!opts || opts.onlySelf !== true) {
24295
24351
  // Emit to children forms
24296
24352
  // Tables should be changed by parent
@@ -24304,15 +24360,17 @@ class AppEditor {
24304
24360
  markAsReady(opts) {
24305
24361
  var _a;
24306
24362
  (_a = this._children) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markAsReady(opts));
24307
- this._$ready.next(true);
24363
+ this.readySubject.next(true);
24308
24364
  }
24309
24365
  ready(opts) {
24310
- return __awaiter(this, void 0, void 0, function* () {
24311
- return waitForTrue(this._$ready, opts);
24312
- });
24366
+ if (this.readySubject.value)
24367
+ return Promise.resolve();
24368
+ return waitForTrue(this.readySubject, opts);
24313
24369
  }
24314
24370
  waitIdle(opts) {
24315
- return AppFormUtils.waitIdle(this, opts);
24371
+ if (!this.loadingSubject.value)
24372
+ return Promise.resolve();
24373
+ return waitForFalse(this.loadingSubject, opts);
24316
24374
  }
24317
24375
  cancel(event) {
24318
24376
  return __awaiter(this, void 0, void 0, function* () {
@@ -24515,6 +24573,14 @@ class AppEditor {
24515
24573
  console.warn(`${prefix} Unknown children sub-form: `, c);
24516
24574
  }
24517
24575
  }
24576
+ setError(value, opts) {
24577
+ if (this.errorSubject.value !== value) {
24578
+ this.errorSubject.next(value);
24579
+ if (!opts || opts.emitEvent !== false) {
24580
+ this.markForCheck();
24581
+ }
24582
+ }
24583
+ }
24518
24584
  markForCheck() {
24519
24585
  // Should be override by subclasses, if change detection is Push
24520
24586
  }
@@ -24601,6 +24667,10 @@ class AppTabEditor extends AppEditor {
24601
24667
  this.markForCheck();
24602
24668
  }
24603
24669
  }
24670
+ realignInkBar() {
24671
+ var _a;
24672
+ (_a = this.tabGroup) === null || _a === void 0 ? void 0 : _a.realignInkBar();
24673
+ }
24604
24674
  onTabChange(event, queryTabIndexParamName) {
24605
24675
  queryTabIndexParamName = queryTabIndexParamName || this.queryTabIndexParamName;
24606
24676
  if (!queryTabIndexParamName || !this.route)
@@ -25580,13 +25650,14 @@ class AppEntityEditorModal extends AppTabEditor {
25580
25650
  console.debug(this._logPrefix + 'Saving data...');
25581
25651
  try {
25582
25652
  // 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);
25653
+ const saved = yield this.saveDirtyTables();
25654
+ if (!saved)
25655
+ return false;
25656
+ // Fill data
25587
25657
  this.data = yield this.getValue();
25658
+ // Mark as submitted
25588
25659
  this.submitted = true;
25589
- return saved;
25660
+ return true;
25590
25661
  }
25591
25662
  catch (err) {
25592
25663
  this.submitted = true;
@@ -25698,6 +25769,16 @@ class AppEntityEditorModal extends AppTabEditor {
25698
25769
  this.markForCheck();
25699
25770
  }
25700
25771
  /* -- protected methods -- */
25772
+ saveDirtyTables() {
25773
+ return __awaiter(this, void 0, void 0, function* () {
25774
+ // Save all dirty tables
25775
+ const results = yield Promise.all((this.tables || [])
25776
+ .filter(c => c.dirty)
25777
+ .map(c => c.save()));
25778
+ const saved = results.findIndex(result => result !== true) === -1;
25779
+ return saved;
25780
+ });
25781
+ }
25701
25782
  waitWhilePending(opts) {
25702
25783
  return AppFormUtils.waitWhilePending(this, opts);
25703
25784
  }
@@ -25823,10 +25904,7 @@ AppInMemoryTable.propDecorators = {
25823
25904
  const SocialErrorCodes = {
25824
25905
  LOAD_USER_EVENTS_ERROR: 50000,
25825
25906
  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
25907
+ SEND_MESSAGE_ERROR: 50003
25830
25908
  };
25831
25909
 
25832
25910
  var UserEvent_1;
@@ -25841,23 +25919,16 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25841
25919
  }
25842
25920
  asObject(opts) {
25843
25921
  const target = super.asObject(opts);
25844
- target.creationDate = toDateISOString(this.creationDate);
25845
- target.readDate = toDateISOString(this.readDate);
25846
25922
  // Serialize content
25847
25923
  if (typeof target.content === 'object') {
25848
25924
  target.content = JSON.stringify(target.content);
25849
25925
  }
25850
- delete target.avatar;
25851
- delete target.avatarIcon;
25852
- delete target.icon;
25853
- delete target.actions;
25854
25926
  return target;
25855
25927
  }
25856
25928
  fromObject(source) {
25857
25929
  Object.assign(this, source); // Copy all properties
25858
25930
  super.fromObject(source);
25859
25931
  this.creationDate = fromDateISOString(source.creationDate);
25860
- this.readDate = fromDateISOString(source.readDate);
25861
25932
  try {
25862
25933
  // Deserialize content
25863
25934
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -25876,52 +25947,6 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25876
25947
  UserEvent = UserEvent_1 = __decorate([
25877
25948
  EntityClass({ typename: 'UserEventVO' })
25878
25949
  ], 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
25950
 
25926
25951
  const UserEventFragments = {
25927
25952
  userEvent: gql `fragment UserEventFragment on UserEventVO {
@@ -25949,188 +25974,134 @@ const UserEventFragments = {
25949
25974
  }`
25950
25975
  };
25951
25976
 
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) {
25977
+ // @dynamic
25978
+ let UserEventFilter = class UserEventFilter extends EntityFilter {
25979
+ constructor() {
25980
+ super(...arguments);
25981
+ this.issuer = null;
25982
+ this.recipient = null;
25983
+ }
25984
+ fromObject(source, opts) {
25985
+ super.fromObject(source, opts);
25986
+ this.issuer = source.issuer;
25987
+ this.recipient = source.recipient;
25988
+ }
25989
+ buildFilter() {
25990
+ const filterFns = super.buildFilter();
25991
+ // issuer
25992
+ if (this.issuer) {
25993
+ filterFns.push(t => (t.issuer === this.issuer));
25994
+ }
25995
+ if (this.recipient) {
25996
+ filterFns.push(t => (t.recipient === this.recipient));
25997
+ }
25998
+ return filterFns;
25999
+ }
26000
+ };
26001
+ UserEventFilter = __decorate([
26002
+ EntityClass({ typename: 'UserEventFilterVO' })
26003
+ ], UserEventFilter);
26004
+ const SaveQuery = gql `
26005
+ mutation SaveUserEvent($data: UserEventVOInput){
26006
+ data: saveUserEvent(userEvent: $data){
26007
+ ...UserEventFragment
26008
+ }
26009
+ }
26010
+ ${UserEventFragments.userEvent}
26011
+ `;
26012
+ const LoadAllQuery = gql `
26013
+ query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26014
+ data: userEvents(filter: $filter, page: $page){
26015
+ ...LightUserEventFragment
26016
+ }
26017
+ }
26018
+ ${UserEventFragments.lightUserEvent}
26019
+ `;
26020
+ const DeleteByIdsMutation = gql `
26021
+ mutation DeleteUserEvents($ids:[Int]){
26022
+ deleteUserEvents(ids: $ids)
26023
+ }
26024
+ `;
26025
+ const LoadAllWithContentQuery = gql `
26026
+ query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26027
+ data: userEvents(filter: $filter, page: $page){
26028
+ ...UserEventFragment
26029
+ }
26030
+ }
26031
+ ${UserEventFragments.userEvent}
26032
+ `;
26033
+ class UserEventService extends BaseGraphqlService {
26034
+ constructor(graphql, accountService, network, translate, toastController, environment) {
25956
26035
  super(graphql, environment);
25957
26036
  this.graphql = graphql;
25958
26037
  this.accountService = accountService;
25959
26038
  this.network = network;
25960
26039
  this.translate = translate;
25961
- this.queries = queries;
25962
- this.mutations = mutations;
25963
- this.subscriptions = subscriptions;
26040
+ this.toastController = toastController;
25964
26041
  this.environment = environment;
25965
- this._count$ = new BehaviorSubject(0);
25966
- this._subscriptions = new Subscription();
25967
- this.listeners = [];
25968
- this._logPrefix = '[user-event-service] ';
26042
+ this._userEventActions = [];
25969
26043
  // 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();
26044
+ this._debug = environment && !environment.production;
25985
26045
  }
26046
+ /**
26047
+ *
26048
+ * @param offset
26049
+ * @param size
26050
+ * @param sortBy
26051
+ * @param sortDirection
26052
+ * @param filter
26053
+ * @param options
26054
+ * @deprecated use watchPage() instead
26055
+ */
25986
26056
  watchAll(offset, size, sortBy, sortDirection, filter, options) {
25987
26057
  return this.watchPage({ offset, size, sortBy, sortDirection }, filter, options);
25988
26058
  }
25989
26059
  watchPage(page, filter, options) {
25990
- var _a;
25991
26060
  let now = this._debug && Date.now();
25992
26061
  //if (this._debug)
25993
- console.debug(`${this._logPrefix}Loading user events...`, filter);
26062
+ console.debug('[user-event-service] Loading user events...', filter);
25994
26063
  filter = this.asFilter(filter);
25995
26064
  // Force recipient to current issuer, if not admin and not specified
25996
- if (isEmptyArray(filter === null || filter === void 0 ? void 0 : filter.recipients) || !this.accountService.isAdmin()) {
25997
- const recipient = this.defaultRecipient();
25998
- if (!((_a = filter === null || filter === void 0 ? void 0 : filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
26065
+ if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
26066
+ const recipient = this.accountService.account.pubkey;
26067
+ if (recipient !== filter.recipient) {
25999
26068
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
26000
- filter.recipients = [recipient];
26069
+ filter.recipient = recipient;
26001
26070
  }
26002
26071
  }
26003
- const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26072
+ const withContent = options && options.withContent === true;
26004
26073
  return this.mutableWatchQuery({
26005
26074
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
26006
- query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26075
+ query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
26007
26076
  variables: {
26008
- page: Object.assign({ sortBy: 'updateDate', sortDirection: 'desc' }, page),
26077
+ page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
26009
26078
  filter: filter && filter.asPodObject()
26010
26079
  },
26011
26080
  arrayFieldName: 'data',
26012
26081
  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"
26082
+ fetchPolicy: options && options.fetchPolicy || undefined
26014
26083
  })
26015
26084
  .pipe(map(res => {
26016
- const data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(this.processUserEvent);
26085
+ const data = res && (res.data || []).map(UserEvent.fromObject);
26017
26086
  if (now) {
26018
- console.debug(`${this._logPrefix}${data.length} user events loaded in ${Date.now() - now}ms`);
26087
+ console.debug(`[user-event-service] ${data.length} user events loaded in ${Date.now() - now}ms`);
26019
26088
  now = null;
26020
26089
  }
26021
- const unreadCount = this.unreadEvents(data);
26022
26090
  return {
26023
26091
  data,
26024
- total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
26092
+ total: res && toNumber(res.total, data.length)
26025
26093
  };
26026
26094
  }));
26027
26095
  }
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
- });
26096
+ saveAll(data, options) {
26097
+ return Promise.all(data
26098
+ .map(entity => this.save(entity, options)));
26133
26099
  }
26100
+ /**
26101
+ * Save a userEvent entity
26102
+ *
26103
+ * @param entity
26104
+ */
26134
26105
  save(entity, options) {
26135
26106
  return __awaiter(this, void 0, void 0, function* () {
26136
26107
  this.fillDefaultProperties(entity);
@@ -26139,9 +26110,9 @@ class AbstractUserEventService extends BaseGraphqlService {
26139
26110
  const json = entity.asObject();
26140
26111
  const now = Date.now();
26141
26112
  if (this._debug)
26142
- console.debug(`${this._logPrefix}Saving user event...`, json);
26113
+ console.debug(`[user-event-service] Saving user event...`, json);
26143
26114
  yield this.graphql.mutate({
26144
- mutation: this.mutations.save,
26115
+ mutation: SaveQuery,
26145
26116
  variables: {
26146
26117
  data: json
26147
26118
  },
@@ -26151,16 +26122,16 @@ class AbstractUserEventService extends BaseGraphqlService {
26151
26122
  const savedEntity = data && data.data;
26152
26123
  if (savedEntity) {
26153
26124
  if (this._debug)
26154
- console.debug(`${this._logPrefix}User event saved in ${Date.now() - now}ms`, entity);
26125
+ console.debug(`[user-event-service] User event saved in ${Date.now() - now}ms`, entity);
26155
26126
  this.copyIdAndUpdateDate(savedEntity, entity);
26156
26127
  // Add to cache
26157
26128
  if (isNew) {
26158
26129
  this.insertIntoMutableCachedQueries(proxy, {
26159
- query: this.queries.loadAll,
26130
+ query: LoadAllQuery,
26160
26131
  data: Object.assign(Object.assign({}, savedEntity), { content: null })
26161
26132
  });
26162
26133
  this.insertIntoMutableCachedQueries(proxy, {
26163
- query: this.queries.loadAllWithContent,
26134
+ query: LoadAllWithContentQuery,
26164
26135
  data: savedEntity
26165
26136
  });
26166
26137
  }
@@ -26170,144 +26141,63 @@ class AbstractUserEventService extends BaseGraphqlService {
26170
26141
  return entity;
26171
26142
  });
26172
26143
  }
26173
- saveAll(data, opts) {
26174
- return Promise.all(data
26175
- .map(entity => this.save(entity, opts)));
26176
- }
26177
- markAsRead(entity) {
26144
+ /**
26145
+ * Save many trips
26146
+ *
26147
+ * @param entities
26148
+ * @param opts
26149
+ */
26150
+ deleteAll(entities, opts) {
26178
26151
  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);
26152
+ const ids = entities && entities
26153
+ .map(t => t.id);
26154
+ if (isEmptyArray(ids))
26155
+ return; // stop, if nothing else to do
26156
+ const now = Date.now();
26157
+ if (this._debug)
26158
+ console.debug('[user-event-service] Deleting events... ids:', ids);
26159
+ yield this.graphql.mutate({
26160
+ mutation: DeleteByIdsMutation,
26161
+ variables: {
26162
+ ids
26163
+ },
26164
+ update: (proxy) => {
26165
+ // Remove from caches
26166
+ this.removeFromMutableCachedQueriesByIds(proxy, {
26167
+ query: LoadAllQuery,
26168
+ ids
26169
+ });
26170
+ this.removeFromMutableCachedQueriesByIds(proxy, {
26171
+ query: LoadAllWithContentQuery,
26172
+ ids
26173
+ });
26174
+ if (this._debug)
26175
+ console.debug(`[user-event-service] Events deleted in ${Date.now() - now}ms`);
26184
26176
  }
26185
- }
26186
- else {
26187
- // Use default
26188
- yield this.defaultMarkAsRead(entity);
26189
- }
26177
+ });
26190
26178
  });
26191
26179
  }
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) {
26180
+ /**
26181
+ * Delete userEvent entities
26182
+ */
26183
+ delete(data) {
26216
26184
  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
- }
26185
+ if (!data)
26186
+ return; // skip
26187
+ yield this.deleteAll([data]);
26229
26188
  });
26230
26189
  }
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
- }
26190
+ listenChanges(id, options) {
26191
+ // TODO
26192
+ console.warn('TODO: implement listen changes on user events');
26193
+ return of();
26283
26194
  }
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
- }
26195
+ registerAction(definition) {
26196
+ console.info(`[user-event-service] Registering action ${definition.name} for ${definition.__typename}`);
26197
+ this._userEventActions.push(definition);
26298
26198
  }
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;
26199
+ getActionsByTypename(typename) {
26200
+ return this._userEventActions.filter(def => def.__typename === typename);
26311
26201
  }
26312
26202
  showToastErrorWithContext(opts) {
26313
26203
  return __awaiter(this, void 0, void 0, function* () {
@@ -26371,16 +26261,13 @@ class UserEventService extends AbstractUserEventService {
26371
26261
  }
26372
26262
  sendDataForDebug(data) {
26373
26263
  const userEvent = new UserEvent();
26374
- userEvent.type = UserEventTypes.DEBUG_DATA;
26264
+ userEvent.eventType = UserEventTypes.DEBUG_DATA;
26375
26265
  userEvent.content = this.convertObjectToString(data);
26376
26266
  return this.save(userEvent);
26377
26267
  }
26378
26268
  asFilter(filter) {
26379
26269
  return UserEventFilter.fromObject(filter);
26380
26270
  }
26381
- fromObject(source) {
26382
- return UserEvent.fromObject(source);
26383
- }
26384
26271
  /* -- protected methods -- */
26385
26272
  convertObjectToString(data) {
26386
26273
  if (typeof data === 'string') {
@@ -26409,9 +26296,13 @@ class UserEventService extends AbstractUserEventService {
26409
26296
  // TODO: compute sign
26410
26297
  console.warn('TODO: sign user event before sending');
26411
26298
  }
26299
+ copyIdAndUpdateDate(source, target) {
26300
+ EntityUtils.copyIdAndUpdateDate(source, target);
26301
+ }
26412
26302
  }
26303
+ 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
26304
  UserEventService.decorators = [
26414
- { type: Injectable }
26305
+ { type: Injectable, args: [{ providedIn: 'root' },] }
26415
26306
  ];
26416
26307
  UserEventService.ctorParameters = () => [
26417
26308
  { type: GraphqlService },
@@ -26424,7 +26315,7 @@ UserEventService.ctorParameters = () => [
26424
26315
 
26425
26316
  const ICONS_MAP = {
26426
26317
  DEBUG_DATA: { matIcon: 'bug_report' },
26427
- INBOX_MESSAGE: { matIcon: 'mail' }
26318
+ INBOX_MESSAGE: { matIcon: 'mail' },
26428
26319
  };
26429
26320
  // TODO: refactor with a registration done by data service:
26430
26321
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -26490,7 +26381,7 @@ class UserEventsTable extends AppTable {
26490
26381
  }
26491
26382
  }));
26492
26383
  const filter = this.filter || new UserEventFilter();
26493
- filter.recipients = [this.recipient];
26384
+ filter.recipient = this.recipient;
26494
26385
  this.setFilter(filter, { emitEvent: true });
26495
26386
  }
26496
26387
  start() {
@@ -26503,17 +26394,17 @@ class UserEventsTable extends AppTable {
26503
26394
  });
26504
26395
  }
26505
26396
  getIcon(source) {
26506
- return ICONS_MAP[source.type];
26397
+ return ICONS_MAP[source.eventType];
26507
26398
  }
26508
26399
  getDetail(source) {
26509
26400
  if (!source)
26510
26401
  return undefined;
26511
- if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
26402
+ if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
26512
26403
  const context = source.content.context;
26513
26404
  if (context && context.__typename) {
26514
- // const actions = this.service.getActionsByTypename(context.__typename);
26405
+ const actions = this.service.getActionsByTypename(context.__typename);
26515
26406
  return {
26516
- // actions,
26407
+ actions,
26517
26408
  title: source.content.error && source.content.error.message || source.content.message,
26518
26409
  description: source.content.error && source.content.error.details || undefined
26519
26410
  };
@@ -26525,11 +26416,11 @@ class UserEventsTable extends AppTable {
26525
26416
  doAction(action, row) {
26526
26417
  return __awaiter(this, void 0, void 0, function* () {
26527
26418
  const event = row.currentData;
26528
- // const context = event.content && event.content.context;
26419
+ const context = event.content && event.content.context;
26529
26420
  this.markAsLoading();
26530
26421
  if (action && typeof action.executeAction === 'function') {
26531
26422
  try {
26532
- let res = action.executeAction(event /*, context*/);
26423
+ let res = action.executeAction(event, context);
26533
26424
  res = (res instanceof Promise) ? yield res : res;
26534
26425
  }
26535
26426
  catch (err) {
@@ -26548,18 +26439,13 @@ UserEventsTable.decorators = [
26548
26439
  selector: 'app-user-events-table',
26549
26440
  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
26441
  changeDetection: ChangeDetectionStrategy.OnPush,
26551
- providers: [
26552
- {
26553
- provide: UserEventServiceToken, useClass: UserEventService
26554
- }
26555
- ],
26556
26442
  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
26443
  },] }
26558
26444
  ];
26559
26445
  UserEventsTable.ctorParameters = () => [
26560
26446
  { type: Injector },
26561
26447
  { type: AccountService },
26562
- { type: undefined, decorators: [{ type: Inject, args: [UserEventServiceToken,] }] },
26448
+ { type: UserEventService },
26563
26449
  { type: EntitiesStorage },
26564
26450
  { type: ChangeDetectorRef },
26565
26451
  { type: undefined, decorators: [{ type: Inject, args: [ENVIRONMENT,] }] }
@@ -26571,147 +26457,6 @@ UserEventsTable.propDecorators = {
26571
26457
  defaultSortDirection: [{ type: Input }]
26572
26458
  };
26573
26459
 
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
26460
  const MessageTypes = {
26716
26461
  INBOX_MESSAGE: 'INBOX_MESSAGE',
26717
26462
  EMAIL: 'EMAIL',
@@ -26923,9 +26668,9 @@ MessageForm.propDecorators = {
26923
26668
  canSelectType: [{ type: Input }]
26924
26669
  };
26925
26670
 
26926
- class MessageModule {
26671
+ class SocialModule {
26927
26672
  }
26928
- MessageModule.decorators = [
26673
+ SocialModule.decorators = [
26929
26674
  { type: NgModule, args: [{
26930
26675
  imports: [
26931
26676
  CommonModule,
@@ -26933,317 +26678,17 @@ MessageModule.decorators = [
26933
26678
  SharedModule
26934
26679
  ],
26935
26680
  declarations: [
26681
+ UserEventsTable,
26936
26682
  MessageModal,
26937
26683
  MessageForm
26938
26684
  ],
26939
26685
  exports: [
26686
+ UserEventsTable,
26940
26687
  MessageModal
26941
26688
  ]
26942
26689
  },] }
26943
26690
  ];
26944
26691
 
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
26692
  const Mutations = {
27248
26693
  send: gql `mutation SendMessage($data: MessageVOInput){
27249
26694
  done: sendMessage(message: $data)
@@ -27889,10 +27334,12 @@ class AutocompleteTestPage {
27889
27334
  });
27890
27335
  }
27891
27336
  ngAfterViewInit() {
27892
- setTimeout(() => {
27893
- this.farEntityField.suggestLengthThreshold = 2;
27894
- this.farEntityField.reloadItems();
27895
- }, 2000);
27337
+ if (this.farEntityField) {
27338
+ setTimeout(() => {
27339
+ this.farEntityField.suggestLengthThreshold = 2;
27340
+ this.farEntityField.reloadItems();
27341
+ }, 2000);
27342
+ }
27896
27343
  setTimeout(() => this.loadData(), 1000);
27897
27344
  }
27898
27345
  // Load the form with data
@@ -27980,7 +27427,7 @@ class AutocompleteTestPage {
27980
27427
  AutocompleteTestPage.decorators = [
27981
27428
  { type: Component, args: [{
27982
27429
  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"
27430
+ 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
27431
  },] }
27985
27432
  ];
27986
27433
  AutocompleteTestPage.ctorParameters = () => [
@@ -28056,13 +27503,13 @@ LatLongTestPage.ctorParameters = () => [
28056
27503
  { type: FormBuilder }
28057
27504
  ];
28058
27505
 
28059
- const moment$7 = momentImported;
27506
+ const moment$6 = momentImported;
28060
27507
  class SwipeTestPage {
28061
27508
  constructor(formBuilder, dateFormatPipe) {
28062
27509
  this.formBuilder = formBuilder;
28063
27510
  this.dateFormatPipe = dateFormatPipe;
28064
27511
  this.$dates = new BehaviorSubject(undefined);
28065
- this._today = moment$7().startOf('day');
27512
+ this._today = moment$6().startOf('day');
28066
27513
  this.form = formBuilder.group({
28067
27514
  empty: [null, Validators.required],
28068
27515
  date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
@@ -28075,7 +27522,7 @@ class SwipeTestPage {
28075
27522
  ngOnInit() {
28076
27523
  const dates = [];
28077
27524
  for (let d = 0; d < 7; d++) {
28078
- dates[d] = moment$7(this._today).add(d - 3, 'day');
27525
+ dates[d] = moment$6(this._today).add(d - 3, 'day');
28079
27526
  }
28080
27527
  this.$dates.next(dates);
28081
27528
  this.loadData();
@@ -28116,7 +27563,7 @@ SwipeTestPage.ctorParameters = () => [
28116
27563
  { type: DateFormatPipe }
28117
27564
  ];
28118
27565
 
28119
- const moment$8 = momentImported;
27566
+ const moment$7 = momentImported;
28120
27567
  class DateTimeTestPage {
28121
27568
  constructor(platform, formBuilder, cd) {
28122
27569
  this.platform = platform;
@@ -28148,7 +27595,7 @@ class DateTimeTestPage {
28148
27595
  // Load the form with data
28149
27596
  loadData() {
28150
27597
  return __awaiter(this, void 0, void 0, function* () {
28151
- const now = moment$8();
27598
+ const now = moment$7();
28152
27599
  const data = {
28153
27600
  empty: null,
28154
27601
  emptyRequired: null,
@@ -28394,7 +27841,7 @@ NumpadTestPage.ctorParameters = () => [
28394
27841
  { type: FormBuilder }
28395
27842
  ];
28396
27843
 
28397
- const moment$9 = momentImported;
27844
+ const moment$8 = momentImported;
28398
27845
  class DateTestPage {
28399
27846
  constructor(formBuilder, cd) {
28400
27847
  this.formBuilder = formBuilder;
@@ -28427,7 +27874,7 @@ class DateTestPage {
28427
27874
  // Load the form with data
28428
27875
  loadData() {
28429
27876
  return __awaiter(this, void 0, void 0, function* () {
28430
- const now = moment$9();
27877
+ const now = moment$8();
28431
27878
  const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
28432
27879
  const data = {
28433
27880
  empty: null,
@@ -29173,5 +28620,5 @@ CoreTestingModule.decorators = [
29173
28620
  * Generated bundle index. Do not edit.
29174
28621
  */
29175
28622
 
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 };
28623
+ 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
28624
  //# sourceMappingURL=sumaris-net.ngx-components.js.map