@sumaris-net/ngx-components 1.20.35 → 1.21.0-beta10

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 (71) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +1103 -321
  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 +0 -9
  6. package/esm2015/public_api.js +8 -3
  7. package/esm2015/src/app/core/icon/icon.component.js +5 -2
  8. package/esm2015/src/app/core/menu/menu.component.js +2 -2
  9. package/esm2015/src/app/core/table/table.class.js +11 -11
  10. package/esm2015/src/app/shared/functions.js +60 -1
  11. package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +4 -5
  12. package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +7 -10
  13. package/esm2015/src/app/shared/material/chips/material.chips.js +2 -3
  14. package/esm2015/src/app/shared/material/chips/testing/chips.test.js +2 -3
  15. package/esm2015/src/app/shared/material/datetime/material.date.js +2 -3
  16. package/esm2015/src/app/shared/material/datetime/material.datetime.js +2 -3
  17. package/esm2015/src/app/shared/pipes/arrays.pipe.js +1 -1
  18. package/esm2015/src/app/shared/pipes/form.pipes.js +4 -2
  19. package/esm2015/src/app/shared/pipes/highlight.pipe.js +4 -4
  20. package/esm2015/src/app/shared/pipes/string.pipes.js +18 -7
  21. package/esm2015/src/app/shared/services/memory-entity-service.class.js +1 -13
  22. package/esm2015/src/app/shared/types.js +1 -1
  23. package/esm2015/src/app/social/job/job.model.js +24 -0
  24. package/esm2015/src/app/social/job/job.module.js +25 -0
  25. package/esm2015/src/app/social/job/job.service.js +53 -0
  26. package/esm2015/src/app/social/job/progression/job-progression.component.js +192 -0
  27. package/esm2015/src/app/social/job/progression/job-progression.list.js +20 -0
  28. package/esm2015/src/app/social/message/message.module.js +25 -0
  29. package/esm2015/src/app/social/social.errors.js +5 -2
  30. package/esm2015/src/app/social/social.module.js +10 -15
  31. package/esm2015/src/app/social/user-event/notification/user-event-notification.component.js +99 -0
  32. package/esm2015/src/app/social/user-event/notification/user-event-notification.list.js +39 -0
  33. package/esm2015/src/app/social/user-event/user-event.model.js +58 -2
  34. package/esm2015/src/app/social/user-event/user-event.module.js +28 -0
  35. package/esm2015/src/app/social/user-event/user-event.service.js +299 -168
  36. package/esm2015/src/app/social/user-event/user-events.table.js +17 -12
  37. package/esm2015/sumaris-net.ngx-components.js +8 -6
  38. package/fesm2015/sumaris-net.ngx-components.js +930 -284
  39. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  40. package/package.json +2 -3
  41. package/public_api.d.ts +7 -2
  42. package/src/app/core/icon/icon.component.d.ts +4 -4
  43. package/src/app/core/table/table.class.d.ts +6 -8
  44. package/src/app/shared/functions.d.ts +9 -0
  45. package/src/app/shared/material/autocomplete/testing/autocomplete.test.d.ts +2 -1
  46. package/src/app/shared/material/badge/badge-icon.test.d.ts +1 -1
  47. package/src/app/shared/pipes/form.pipes.d.ts +2 -1
  48. package/src/app/shared/services/memory-entity-service.class.d.ts +0 -6
  49. package/src/app/shared/types.d.ts +4 -0
  50. package/src/app/social/job/job.model.d.ts +32 -0
  51. package/src/app/social/job/job.module.d.ts +2 -0
  52. package/src/app/social/job/job.service.d.ts +23 -0
  53. package/src/app/social/job/progression/job-progression.component.d.ts +43 -0
  54. package/src/app/social/job/progression/job-progression.list.d.ts +12 -0
  55. package/src/app/social/message/message.module.d.ts +2 -0
  56. package/src/app/social/social.errors.d.ts +3 -0
  57. package/src/app/social/social.module.d.ts +8 -0
  58. package/src/app/social/user-event/notification/user-event-notification.component.d.ts +25 -0
  59. package/src/app/social/user-event/notification/user-event-notification.list.d.ts +20 -0
  60. package/src/app/social/user-event/user-event.model.d.ts +51 -6
  61. package/src/app/social/user-event/user-event.module.d.ts +2 -0
  62. package/src/app/social/user-event/user-event.service.d.ts +79 -51
  63. package/src/app/social/user-event/user-events.table.d.ts +6 -6
  64. package/src/assets/i18n/en-US.json +15 -2
  65. package/src/assets/i18n/en.json +15 -2
  66. package/src/assets/i18n/fr.json +14 -1
  67. package/src/theme/_ngx-components.scss +7 -0
  68. package/sumaris-net.ngx-components.d.ts +7 -5
  69. package/sumaris-net.ngx-components.metadata.json +1 -1
  70. package/esm2015/src/app/shared/services.js +0 -61
  71. package/src/app/shared/services.d.ts +0 -9
@@ -46,7 +46,7 @@
46
46
  var SPACE_PLACEHOLDER_CHAR = '\u2000';
47
47
  var KEYBOARD_HIDE_DELAY_MS = 250; // 1s
48
48
 
49
- /*! *****************************************************************************
49
+ /******************************************************************************
50
50
  Copyright (c) Microsoft Corporation.
51
51
 
52
52
  Permission to use, copy, modify, and/or distribute this software for any
@@ -208,7 +208,11 @@
208
208
  var __createBinding = Object.create ? (function (o, m, k, k2) {
209
209
  if (k2 === undefined)
210
210
  k2 = k;
211
- Object.defineProperty(o, k2, { enumerable: true, get: function () { return m[k]; } });
211
+ var desc = Object.getOwnPropertyDescriptor(m, k);
212
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
213
+ desc = { enumerable: true, get: function () { return m[k]; } };
214
+ }
215
+ Object.defineProperty(o, k2, desc);
212
216
  }) : (function (o, m, k, k2) {
213
217
  if (k2 === undefined)
214
218
  k2 = k;
@@ -363,6 +367,11 @@
363
367
  throw new TypeError("Cannot write private member to an object whose class did not declare it");
364
368
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
365
369
  }
370
+ function __classPrivateFieldIn(state, receiver) {
371
+ if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function"))
372
+ throw new TypeError("Cannot use 'in' operator on non-object");
373
+ return typeof state === "function" ? receiver === state : state.has(receiver);
374
+ }
366
375
 
367
376
  function isNil(obj) {
368
377
  return obj === undefined || obj === null;
@@ -500,6 +509,67 @@
500
509
  function removeDiacritics(text) {
501
510
  return text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
502
511
  }
512
+ function suggestFromArray(items, value, opts) {
513
+ var _this = this;
514
+ if (isNotNil(value) && typeof value === 'object')
515
+ return { data: [value] };
516
+ value = (typeof value === 'string' && value !== '*') && value.toUpperCase() || undefined;
517
+ var keys = opts && (opts.searchAttribute && [opts.searchAttribute] || opts.searchAttributes) || ['label'];
518
+ if (!items) {
519
+ return { data: [], total: 0 };
520
+ }
521
+ // Filter items
522
+ var filteredItems = items;
523
+ if (isNotNilOrBlank(value)) {
524
+ // If wildcard, search using regexp
525
+ if (value.indexOf('*') !== -1) {
526
+ value = value.replace(/[*]+/g, '.*');
527
+ filteredItems = filteredItems.filter(function (v) { return keys.findIndex(function (key) { return matchUpperCase(getPropertyByPathAsString(v, key), value); }) !== -1; });
528
+ }
529
+ // Else (no wildcard), search using startsWith
530
+ else {
531
+ filteredItems = filteredItems.filter(function (v) { return keys.findIndex(function (key) { return startsWithUpperCase(getPropertyByPathAsString(v, key), value); }) !== -1; });
532
+ }
533
+ }
534
+ // Exclude ids
535
+ if (isNotEmptyArray(opts === null || opts === void 0 ? void 0 : opts.excludedIds)) {
536
+ filteredItems = filteredItems.filter(function (v) { return !opts.excludedIds.includes(+v['id']); });
537
+ }
538
+ // Sort
539
+ if (!opts || opts.skipSort !== true) {
540
+ // Make to copy input items, before sorting (if not yet already done)
541
+ if (filteredItems === items)
542
+ filteredItems = filteredItems.slice();
543
+ // Sort by keys
544
+ filteredItems.sort(propertiesPathComparator(keys));
545
+ }
546
+ var total = filteredItems.length || 0;
547
+ // Pagination (truncate if need)
548
+ var pageData = filteredItems;
549
+ if (opts) {
550
+ if ((opts.offset || 0) > 0) {
551
+ pageData = pageData.slice(opts.offset);
552
+ }
553
+ if (isNotNil(opts.size) && pageData.length > opts.size) {
554
+ pageData = pageData.slice(0, opts.size);
555
+ }
556
+ }
557
+ var result = {
558
+ data: pageData,
559
+ total: total
560
+ };
561
+ // Add fetch more capability, if total was fetched
562
+ var nextOffset = (opts && opts.offset || 0) + pageData.length;
563
+ if (nextOffset < total) {
564
+ result.fetchMore = function (_) { return __awaiter(_this, void 0, void 0, function () {
565
+ return __generator(this, function (_b) {
566
+ return [2 /*return*/, suggestFromArray(filteredItems, undefined /*OPTIMISATION: already applied*/, Object.assign(Object.assign({}, opts), { offset: nextOffset, skipSort: true, excludedIds: undefined // OPTIMISATION: already filtered
567
+ }))];
568
+ });
569
+ }); };
570
+ }
571
+ return result;
572
+ }
503
573
  function suggestFromStringArray(values, value, options) {
504
574
  value = (typeof value === 'string' && value !== '*') && value.toUpperCase() || undefined;
505
575
  if (isNilOrBlank(value))
@@ -1316,68 +1386,6 @@
1316
1386
  return _cache.mobile;
1317
1387
  };
1318
1388
 
1319
- function suggestFromArray(items, value, opts) {
1320
- var _this = this;
1321
- if (isNotNil(value) && typeof value === 'object')
1322
- return { data: [value] };
1323
- value = (typeof value === 'string' && value !== '*') && value.toUpperCase() || undefined;
1324
- var keys = opts && (opts.searchAttribute && [opts.searchAttribute] || opts.searchAttributes) || ['label'];
1325
- if (!items) {
1326
- return { data: [], total: 0 };
1327
- }
1328
- // Filter items
1329
- var filteredItems = items;
1330
- if (isNotNilOrBlank(value)) {
1331
- // If wildcard, search using regexp
1332
- if (value.indexOf('*') !== -1) {
1333
- value = value.replace(/[*]+/g, '.*');
1334
- filteredItems = filteredItems.filter(function (v) { return keys.findIndex(function (key) { return matchUpperCase(getPropertyByPathAsString(v, key), value); }) !== -1; });
1335
- }
1336
- // Else (no wildcard), search using startsWith
1337
- else {
1338
- filteredItems = filteredItems.filter(function (v) { return keys.findIndex(function (key) { return startsWithUpperCase(getPropertyByPathAsString(v, key), value); }) !== -1; });
1339
- }
1340
- }
1341
- // Exclude ids
1342
- if (isNotEmptyArray(opts === null || opts === void 0 ? void 0 : opts.excludedIds)) {
1343
- filteredItems = filteredItems.filter(function (v) { return !opts.excludedIds.includes(+v['id']); });
1344
- }
1345
- // Sort
1346
- if (!opts || opts.skipSort !== true) {
1347
- // Make to copy input items, before sorting (if not yet already done)
1348
- if (filteredItems === items)
1349
- filteredItems = filteredItems.slice();
1350
- // Sort by keys
1351
- filteredItems.sort(propertiesPathComparator(keys));
1352
- }
1353
- var total = filteredItems.length || 0;
1354
- // Pagination (truncate if need)
1355
- var pageData = filteredItems;
1356
- if (opts) {
1357
- if ((opts.offset || 0) > 0) {
1358
- pageData = pageData.slice(opts.offset);
1359
- }
1360
- if (isNotNil(opts.size) && pageData.length > opts.size) {
1361
- pageData = pageData.slice(0, opts.size);
1362
- }
1363
- }
1364
- var result = {
1365
- data: pageData,
1366
- total: total
1367
- };
1368
- // Add fetch more capability, if total was fetched
1369
- var nextOffset = (opts && opts.offset || 0) + pageData.length;
1370
- if (nextOffset < total) {
1371
- result.fetchMore = function (_) { return __awaiter(_this, void 0, void 0, function () {
1372
- return __generator(this, function (_a) {
1373
- return [2 /*return*/, suggestFromArray(filteredItems, undefined /*OPTIMISATION: already applied*/, Object.assign(Object.assign({}, opts), { offset: nextOffset, skipSort: true, excludedIds: undefined // OPTIMISATION: already filtered
1374
- }))];
1375
- });
1376
- }); };
1377
- }
1378
- return result;
1379
- }
1380
-
1381
1389
  var MatAutocompleteConfigHolder = /** @class */ (function () {
1382
1390
  function MatAutocompleteConfigHolder(options) {
1383
1391
  this.options = options;
@@ -1698,11 +1706,11 @@
1698
1706
  // Search text (no distinctUntilChanged() because of the debounceTime() pipe)
1699
1707
  this.formControl.valueChanges
1700
1708
  .pipe(operators.filter(function (value) { return _this.enabled && isNotNilString(value); }),
1701
- // Mark as loading (to show loading spinner) - as soon as possible, and before debounceTime
1709
+ // Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
1702
1710
  operators.tap(function (_) { return _this.showLoadingSpinner && _this.markAsLoading(); }),
1703
1711
  // Filter if not enough character
1704
1712
  operators.filter(function (value) {
1705
- if (((value === null || value === void 0 ? void 0 : value.length) || 0) < _this.suggestLengthThreshold) {
1713
+ if (value.length <= _this.suggestLengthThreshold) {
1706
1714
  // Update display value, to enable the message "not enough characters"
1707
1715
  _this.displayValue = value;
1708
1716
  return false;
@@ -2701,9 +2709,9 @@
2701
2709
  var cleanedSearchText = removeDiacritics(searchRegexp).toUpperCase();
2702
2710
  var index = removeDiacritics(value.toUpperCase()).indexOf(cleanedSearchText);
2703
2711
  if (index !== -1) {
2704
- return value.substring(0, index - 1) +
2705
- '<b>' + value.substring(index, cleanedSearchText.length) + '</b>' +
2706
- value.substring(index + cleanedSearchText.length);
2712
+ return value.substr(0, index - 1) +
2713
+ '<b>' + value.substr(index, cleanedSearchText.length) + '</b>' +
2714
+ value.substr(index + cleanedSearchText.length);
2707
2715
  }
2708
2716
  return value;
2709
2717
  }
@@ -3151,10 +3159,12 @@
3151
3159
  };
3152
3160
  return IsNotNilOrBlankPipe;
3153
3161
  }());
3162
+ IsNotNilOrBlankPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function IsNotNilOrBlankPipe_Factory() { return new IsNotNilOrBlankPipe(); }, token: IsNotNilOrBlankPipe, providedIn: "root" });
3154
3163
  IsNotNilOrBlankPipe.decorators = [
3155
3164
  { type: i0.Pipe, args: [{
3156
3165
  name: 'isNotNilOrBlank'
3157
- },] }
3166
+ },] },
3167
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3158
3168
  ];
3159
3169
  var IsNilOrBlankPipe = /** @class */ (function () {
3160
3170
  function IsNilOrBlankPipe() {
@@ -3164,10 +3174,12 @@
3164
3174
  };
3165
3175
  return IsNilOrBlankPipe;
3166
3176
  }());
3177
+ IsNilOrBlankPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function IsNilOrBlankPipe_Factory() { return new IsNilOrBlankPipe(); }, token: IsNilOrBlankPipe, providedIn: "root" });
3167
3178
  IsNilOrBlankPipe.decorators = [
3168
3179
  { type: i0.Pipe, args: [{
3169
3180
  name: 'isNilOrBlank'
3170
- },] }
3181
+ },] },
3182
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3171
3183
  ];
3172
3184
  var ToStringPipe = /** @class */ (function () {
3173
3185
  function ToStringPipe() {
@@ -3177,10 +3189,12 @@
3177
3189
  };
3178
3190
  return ToStringPipe;
3179
3191
  }());
3192
+ ToStringPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function ToStringPipe_Factory() { return new ToStringPipe(); }, token: ToStringPipe, providedIn: "root" });
3180
3193
  ToStringPipe.decorators = [
3181
3194
  { type: i0.Pipe, args: [{
3182
3195
  name: 'toString'
3183
- },] }
3196
+ },] },
3197
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3184
3198
  ];
3185
3199
  var StrLengthPipe = /** @class */ (function () {
3186
3200
  function StrLengthPipe() {
@@ -3190,10 +3204,12 @@
3190
3204
  };
3191
3205
  return StrLengthPipe;
3192
3206
  }());
3207
+ StrLengthPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function StrLengthPipe_Factory() { return new StrLengthPipe(); }, token: StrLengthPipe, providedIn: "root" });
3193
3208
  StrLengthPipe.decorators = [
3194
3209
  { type: i0.Pipe, args: [{
3195
3210
  name: 'strLength'
3196
- },] }
3211
+ },] },
3212
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3197
3213
  ];
3198
3214
  var StrIncludesPipe = /** @class */ (function () {
3199
3215
  function StrIncludesPipe() {
@@ -3203,10 +3219,12 @@
3203
3219
  };
3204
3220
  return StrIncludesPipe;
3205
3221
  }());
3222
+ StrIncludesPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function StrIncludesPipe_Factory() { return new StrIncludesPipe(); }, token: StrIncludesPipe, providedIn: "root" });
3206
3223
  StrIncludesPipe.decorators = [
3207
3224
  { type: i0.Pipe, args: [{
3208
3225
  name: 'strIncludes'
3209
- },] }
3226
+ },] },
3227
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3210
3228
  ];
3211
3229
 
3212
3230
  var TranslateContextService = /** @class */ (function () {
@@ -4787,7 +4805,8 @@
4787
4805
  },] }
4788
4806
  ];
4789
4807
  var FormGetValuePipe = /** @class */ (function () {
4790
- function FormGetValuePipe(_ref) {
4808
+ function FormGetValuePipe(adapter, _ref) {
4809
+ this.adapter = adapter;
4791
4810
  this._ref = _ref;
4792
4811
  this.value = undefined;
4793
4812
  this._lastControl = null;
@@ -4855,6 +4874,7 @@
4855
4874
  },] }
4856
4875
  ];
4857
4876
  FormGetValuePipe.ctorParameters = function () { return [
4877
+ { type: FormErrorTranslator },
4858
4878
  { type: i0.ChangeDetectorRef }
4859
4879
  ]; };
4860
4880
 
@@ -5776,10 +5796,10 @@
5776
5796
  return this._tabindex;
5777
5797
  },
5778
5798
  set: function (value) {
5799
+ var _this = this;
5779
5800
  if (this._tabindex !== value) {
5780
5801
  this._tabindex = value;
5781
- if (!this._writing)
5782
- this.updateTabIndex();
5802
+ setTimeout(function () { return _this.updateTabIndex(); });
5783
5803
  }
5784
5804
  },
5785
5805
  enumerable: false,
@@ -6171,10 +6191,10 @@
6171
6191
  return this._tabindex;
6172
6192
  },
6173
6193
  set: function (value) {
6194
+ var _this = this;
6174
6195
  if (this._tabindex !== value) {
6175
6196
  this._tabindex = value;
6176
- if (!this._writing)
6177
- this.updateTabIndex();
6197
+ setTimeout(function () { return _this.updateTabIndex(); });
6178
6198
  }
6179
6199
  },
6180
6200
  enumerable: false,
@@ -20719,14 +20739,14 @@
20719
20739
  }
20720
20740
  return this._onChange
20721
20741
  .pipe(operators.filter(isNotNil), operators.mergeMap(function (_) { return waitFor(function () { return !_this._saving; }); }), operators.mergeMap(function (_) { return __awaiter(_this, void 0, void 0, function () {
20722
- var excludedDataByFilter, excludedDataByPagination, data, promiseOrData, _b, total;
20723
- return __generator(this, function (_c) {
20724
- switch (_c.label) {
20742
+ var excludedDataByFilter, excludedDataByPagination, data, promiseOrData, _a, total;
20743
+ return __generator(this, function (_b) {
20744
+ switch (_b.label) {
20725
20745
  case 0:
20726
20746
  excludedDataByFilter = [];
20727
- _c.label = 1;
20747
+ _b.label = 1;
20728
20748
  case 1:
20729
- _c.trys.push([1, , 6, 7]);
20749
+ _b.trys.push([1, , 6, 7]);
20730
20750
  if (isEmptyArray(this.data)) {
20731
20751
  return [2 /*return*/, { data: [], total: 0 }];
20732
20752
  }
@@ -20736,14 +20756,14 @@
20736
20756
  if (!((promiseOrData instanceof Promise))) return [3 /*break*/, 3];
20737
20757
  return [4 /*yield*/, promiseOrData];
20738
20758
  case 2:
20739
- _b = _c.sent();
20759
+ _a = _b.sent();
20740
20760
  return [3 /*break*/, 4];
20741
20761
  case 3:
20742
- _b = promiseOrData;
20743
- _c.label = 4;
20762
+ _a = promiseOrData;
20763
+ _b.label = 4;
20744
20764
  case 4:
20745
- data = _b;
20746
- _c.label = 5;
20765
+ data = _a;
20766
+ _b.label = 5;
20747
20767
  case 5:
20748
20768
  // Apply filter (will update hiddenData)
20749
20769
  data = this.filter(data, filterData, excludedDataByFilter);
@@ -20799,16 +20819,16 @@
20799
20819
  };
20800
20820
  InMemoryEntitiesService.prototype.saveAll = function (data, options) {
20801
20821
  return __awaiter(this, void 0, void 0, function () {
20802
- var res, _b;
20803
- return __generator(this, function (_c) {
20804
- switch (_c.label) {
20822
+ var res, _a;
20823
+ return __generator(this, function (_b) {
20824
+ switch (_b.label) {
20805
20825
  case 0:
20806
20826
  if (!this.data)
20807
20827
  throw new Error('[memory-service] Could not save, because value not set');
20808
20828
  this.markAsSaving();
20809
- _c.label = 1;
20829
+ _b.label = 1;
20810
20830
  case 1:
20811
- _c.trys.push([1, , 6, 7]);
20831
+ _b.trys.push([1, , 6, 7]);
20812
20832
  // Restore hidden data
20813
20833
  if (isNotEmptyArray(this._hiddenData))
20814
20834
  data = data.concat.apply(data, __spread(this._hiddenData));
@@ -20817,14 +20837,14 @@
20817
20837
  if (!((res instanceof Promise))) return [3 /*break*/, 3];
20818
20838
  return [4 /*yield*/, res];
20819
20839
  case 2:
20820
- _b = _c.sent();
20840
+ _a = _b.sent();
20821
20841
  return [3 /*break*/, 4];
20822
20842
  case 3:
20823
- _b = res;
20824
- _c.label = 4;
20843
+ _a = res;
20844
+ _b.label = 4;
20825
20845
  case 4:
20826
- data = _b;
20827
- _c.label = 5;
20846
+ data = _a;
20847
+ _b.label = 5;
20828
20848
  case 5:
20829
20849
  this.data = data;
20830
20850
  this.dirty = true;
@@ -20841,7 +20861,7 @@
20841
20861
  return __awaiter(this, void 0, void 0, function () {
20842
20862
  var updatedData, deleteCount;
20843
20863
  var _this = this;
20844
- return __generator(this, function (_b) {
20864
+ return __generator(this, function (_a) {
20845
20865
  if (!this.data)
20846
20866
  throw new Error('[memory-service] Could not delete, because value not set');
20847
20867
  updatedData = this.data.filter(function (entity) {
@@ -20875,26 +20895,6 @@
20875
20895
  return this._equalsFn(d1, d2);
20876
20896
  return d1 && d1.equals ? d1.equals(d2) : EntityUtils.equals(d1, d2, 'id');
20877
20897
  };
20878
- Object.defineProperty(InMemoryEntitiesService.prototype, "count", {
20879
- /**
20880
- * Count data stored by the service (without hidden data).
20881
- * @param opts
20882
- */
20883
- get: function () {
20884
- var _a;
20885
- return (((_a = this.data) === null || _a === void 0 ? void 0 : _a.length) || 0);
20886
- },
20887
- enumerable: false,
20888
- configurable: true
20889
- });
20890
- Object.defineProperty(InMemoryEntitiesService.prototype, "hiddenCount", {
20891
- get: function () {
20892
- var _a;
20893
- return ((_a = this._hiddenData) === null || _a === void 0 ? void 0 : _a.length) || 0;
20894
- },
20895
- enumerable: false,
20896
- configurable: true
20897
- });
20898
20898
  /* -- protected methods -- */
20899
20899
  InMemoryEntitiesService.prototype.filter = function (data, _filter, hiddenData) {
20900
20900
  // if filter is DataFilter instance, use its test function
@@ -24749,7 +24749,7 @@
24749
24749
  MenuComponent.decorators = [
24750
24750
  { type: i0.Component, args: [{
24751
24751
  selector: 'app-menu',
24752
- 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",
24752
+ 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",
24753
24753
  animations: [fadeInAnimation],
24754
24754
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
24755
24755
  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)}}"]
@@ -24817,6 +24817,7 @@
24817
24817
  this.icon = value.icon;
24818
24818
  this.matIcon = value.matIcon;
24819
24819
  this.matSvgIcon = value.matSvgIcon;
24820
+ this.color = value.color;
24820
24821
  },
24821
24822
  enumerable: false,
24822
24823
  configurable: true
@@ -24827,7 +24828,7 @@
24827
24828
  AppIconComponent.decorators = [
24828
24829
  { type: i0.Component, args: [{
24829
24830
  selector: 'app-icon',
24830
- 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"
24831
+ 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"
24831
24832
  },] }
24832
24833
  ];
24833
24834
  AppIconComponent.propDecorators = {
@@ -24835,6 +24836,8 @@
24835
24836
  matIcon: [{ type: i0.Input }],
24836
24837
  matSvgIcon: [{ type: i0.Input }],
24837
24838
  color: [{ type: i0.Input }],
24839
+ height: [{ type: i0.Input }],
24840
+ width: [{ type: i0.Input }],
24838
24841
  ref: [{ type: i0.Input }]
24839
24842
  };
24840
24843
 
@@ -26600,7 +26603,7 @@
26600
26603
  .then(function () { return _this.editRowById(event, row.id, { focusColumn: _this.lastUserColumn }); });
26601
26604
  return true;
26602
26605
  }
26603
- // Edit previous row
26606
+ // Edit next row
26604
26607
  this.editRow(event, row, { focusColumn: this.lastUserColumn });
26605
26608
  return true;
26606
26609
  };
@@ -26628,7 +26631,8 @@
26628
26631
  if (id < 0)
26629
26632
  return [2 /*return*/];
26630
26633
  if (!(id >= this.visibleRowCount)) return [3 /*break*/, 1];
26631
- this.addRow(event, undefined, opts);
26634
+ this.focusColumn = opts && opts.focusColumn || this.firstUserColumn;
26635
+ this.addRow(event);
26632
26636
  return [3 /*break*/, 3];
26633
26637
  case 1: return [4 /*yield*/, this.dataSource.getRow(id)];
26634
26638
  case 2:
@@ -26706,7 +26710,7 @@
26706
26710
  this.cancelExistingRow(event, row, opts);
26707
26711
  }
26708
26712
  };
26709
- AppTable.prototype.addRow = function (event, insertAt, opts) {
26713
+ AppTable.prototype.addRow = function (event, insertAt) {
26710
26714
  if (this.debug)
26711
26715
  console.debug('[table] Asking for new row...');
26712
26716
  if (!this._enabled)
@@ -26721,7 +26725,7 @@
26721
26725
  return false;
26722
26726
  }
26723
26727
  // Add new row
26724
- this.addRowToTable(insertAt, opts);
26728
+ this.addRowToTable(insertAt);
26725
26729
  return true;
26726
26730
  };
26727
26731
  AppTable.prototype.save = function (opts) {
@@ -26866,7 +26870,7 @@
26866
26870
  * @param event
26867
26871
  * @param row
26868
26872
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
26869
- * And to force deletion even if table is busy
26873
+ * Use skipIfLoading=false to force deletion even if table is busy
26870
26874
  */
26871
26875
  AppTable.prototype.deleteRow = function (event, row, opts) {
26872
26876
  return __awaiter(this, void 0, void 0, function () {
@@ -26886,7 +26890,7 @@
26886
26890
  * @param event
26887
26891
  * @param rows
26888
26892
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
26889
- * And to force deletion even if table is busy
26893
+ * Use skipIfLoading=false to force deletion even if table is busy
26890
26894
  */
26891
26895
  AppTable.prototype.deleteRows = function (event, rows, opts) {
26892
26896
  var _a;
@@ -26904,8 +26908,8 @@
26904
26908
  event === null || event === void 0 ? void 0 : event.preventDefault();
26905
26909
  if (!this._enabled || isEmptyArray(rows))
26906
26910
  return [2 /*return*/, 0]; // Skip is disabled, or no rows to delete
26907
- if (this.loading && (!opts || opts.interactive !== false)) {
26908
- console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.interactive = false to force deletion');
26911
+ if (this.loading && (!opts || opts.skipIfLoading !== false)) {
26912
+ console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.skipLoading = false to force deletion');
26909
26913
  return [2 /*return*/, 0]; // Skip if loading
26910
26914
  }
26911
26915
  // Make sure to keep newly created row
@@ -27544,13 +27548,12 @@
27544
27548
  //if (this.debug) console.debug("[table] id = " + id);
27545
27549
  return id;
27546
27550
  };
27547
- AppTable.prototype.addRowToTable = function (insertAt, opts) {
27551
+ AppTable.prototype.addRowToTable = function (insertAt) {
27548
27552
  return __awaiter(this, void 0, void 0, function () {
27549
27553
  return __generator(this, function (_e) {
27550
27554
  switch (_e.label) {
27551
27555
  case 0:
27552
27556
  this.focusFirstColumn = true;
27553
- this.focusColumn = (opts === null || opts === void 0 ? void 0 : opts.focusColumn) || this.firstUserColumn;
27554
27557
  return [4 /*yield*/, this._dataSource.asyncCreateNew(insertAt)];
27555
27558
  case 1:
27556
27559
  _e.sent();
@@ -30053,7 +30056,10 @@
30053
30056
  var SocialErrorCodes = {
30054
30057
  LOAD_USER_EVENTS_ERROR: 50000,
30055
30058
  SAVE_USER_EVENT_ERROR: 50001,
30056
- SEND_MESSAGE_ERROR: 50003
30059
+ COUNT_USER_EVENT_ERROR: 50002,
30060
+ SEND_MESSAGE_ERROR: 50003,
30061
+ SUBSCRIBE_USER_EVENTS_ERROR: 50005,
30062
+ SUBSCRIBE_JOB_PROGRESSION_ERROR: 50010
30057
30063
  };
30058
30064
 
30059
30065
  var UserEvent_1;
@@ -30069,16 +30075,23 @@
30069
30075
  }
30070
30076
  UserEvent.prototype.asObject = function (opts) {
30071
30077
  var target = _super.prototype.asObject.call(this, opts);
30078
+ target.creationDate = toDateISOString(this.creationDate);
30079
+ target.readDate = toDateISOString(this.readDate);
30072
30080
  // Serialize content
30073
30081
  if (typeof target.content === 'object') {
30074
30082
  target.content = JSON.stringify(target.content);
30075
30083
  }
30084
+ delete target.avatar;
30085
+ delete target.avatarIcon;
30086
+ delete target.icon;
30087
+ delete target.actions;
30076
30088
  return target;
30077
30089
  };
30078
30090
  UserEvent.prototype.fromObject = function (source) {
30079
30091
  Object.assign(this, source); // Copy all properties
30080
30092
  _super.prototype.fromObject.call(this, source);
30081
30093
  this.creationDate = fromDateISOString(source.creationDate);
30094
+ this.readDate = fromDateISOString(source.readDate);
30082
30095
  try {
30083
30096
  // Deserialize content
30084
30097
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -30098,36 +30111,48 @@
30098
30111
  exports.UserEvent = UserEvent_1 = __decorate([
30099
30112
  EntityClass({ typename: 'UserEventVO' })
30100
30113
  ], exports.UserEvent);
30101
-
30102
- var UserEventFragments = {
30103
- userEvent: core.gql(templateObject_1$2 || (templateObject_1$2 = __makeTemplateObject(["fragment UserEventFragment on UserEventVO {\n id\n issuer\n updateDate\n creationDate\n eventType\n recipient\n content\n hash\n signature\n readSignature\n __typename\n }"], ["fragment UserEventFragment on UserEventVO {\n id\n issuer\n updateDate\n creationDate\n eventType\n recipient\n content\n hash\n signature\n readSignature\n __typename\n }"]))),
30104
- lightUserEvent: core.gql(templateObject_2$2 || (templateObject_2$2 = __makeTemplateObject(["fragment LightUserEventFragment on UserEventVO {\n id\n issuer\n recipient\n updateDate\n creationDate\n eventType\n readSignature\n __typename\n }"], ["fragment LightUserEventFragment on UserEventVO {\n id\n issuer\n recipient\n updateDate\n creationDate\n eventType\n readSignature\n __typename\n }"])))
30105
- };
30106
- var templateObject_1$2, templateObject_2$2;
30107
-
30108
30114
  // @dynamic
30109
30115
  exports.UserEventFilter = /** @class */ (function (_super) {
30110
30116
  __extends(UserEventFilter, _super);
30111
30117
  function UserEventFilter() {
30112
30118
  var _this = _super.apply(this, __spread(arguments)) || this;
30113
- _this.issuer = null;
30114
- _this.recipient = null;
30119
+ _this.types = [];
30120
+ _this.levels = [];
30121
+ _this.issuers = [];
30122
+ _this.recipients = [];
30123
+ _this.startDate = null;
30124
+ _this.excludeRead = false;
30115
30125
  return _this;
30116
30126
  }
30117
30127
  UserEventFilter.prototype.fromObject = function (source, opts) {
30118
30128
  _super.prototype.fromObject.call(this, source, opts);
30119
- this.issuer = source.issuer;
30120
- this.recipient = source.recipient;
30129
+ this.types = source.types || [];
30130
+ this.levels = source.levels || [];
30131
+ this.issuers = source.issuers || [];
30132
+ this.recipients = source.recipients || [];
30133
+ this.startDate = fromDateISOString(source.startDate);
30134
+ this.excludeRead = source.excludeRead || false;
30121
30135
  };
30122
30136
  UserEventFilter.prototype.buildFilter = function () {
30123
30137
  var _this = this;
30124
30138
  var filterFns = _super.prototype.buildFilter.call(this);
30125
- // issuer
30126
- if (this.issuer) {
30127
- filterFns.push(function (t) { return (t.issuer === _this.issuer); });
30139
+ if (isNotEmptyArray(this.types)) {
30140
+ filterFns.push(function (t) { return _this.types.includes(t.type); });
30141
+ }
30142
+ if (isNotEmptyArray(this.levels)) {
30143
+ filterFns.push(function (t) { return _this.levels.includes(t.level); });
30144
+ }
30145
+ if (isNotEmptyArray(this.issuers)) {
30146
+ filterFns.push(function (t) { return _this.issuers.includes(t.issuer); });
30147
+ }
30148
+ if (isNotEmptyArray(this.recipients)) {
30149
+ filterFns.push(function (t) { return _this.recipients.includes(t.recipient); });
30128
30150
  }
30129
- if (this.recipient) {
30130
- filterFns.push(function (t) { return (t.recipient === _this.recipient); });
30151
+ if (isNotNil(this.startDate)) {
30152
+ filterFns.push(function (t) { return _this.startDate.isSameOrBefore(t.creationDate); });
30153
+ }
30154
+ if (this.excludeRead === true) {
30155
+ filterFns.push(function (t) { return isNil(t.readSignature); }); // todo or t.signature ?
30131
30156
  }
30132
30157
  return filterFns;
30133
30158
  };
@@ -30136,120 +30161,278 @@
30136
30161
  exports.UserEventFilter = __decorate([
30137
30162
  EntityClass({ typename: 'UserEventFilterVO' })
30138
30163
  ], exports.UserEventFilter);
30139
- var SaveQuery = core.gql(templateObject_1$3 || (templateObject_1$3 = __makeTemplateObject(["\n mutation SaveUserEvent($data: UserEventVOInput){\n data: saveUserEvent(userEvent: $data){\n ...UserEventFragment\n }\n }\n ", "\n"], ["\n mutation SaveUserEvent($data: UserEventVOInput){\n data: saveUserEvent(userEvent: $data){\n ...UserEventFragment\n }\n }\n ", "\n"])), UserEventFragments.userEvent);
30140
- var LoadAllQuery = core.gql(templateObject_2$3 || (templateObject_2$3 = __makeTemplateObject(["\n query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...LightUserEventFragment\n }\n }\n ", "\n"], ["\n query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...LightUserEventFragment\n }\n }\n ", "\n"])), UserEventFragments.lightUserEvent);
30141
- var DeleteByIdsMutation = core.gql(templateObject_3$2 || (templateObject_3$2 = __makeTemplateObject(["\n mutation DeleteUserEvents($ids:[Int]){\n deleteUserEvents(ids: $ids)\n }\n"], ["\n mutation DeleteUserEvents($ids:[Int]){\n deleteUserEvents(ids: $ids)\n }\n"])));
30142
- var LoadAllWithContentQuery = core.gql(templateObject_4$2 || (templateObject_4$2 = __makeTemplateObject(["\n query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...UserEventFragment\n }\n }\n ", "\n"], ["\n query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...UserEventFragment\n }\n }\n ", "\n"])), UserEventFragments.userEvent);
30143
- var UserEventService = /** @class */ (function (_super) {
30144
- __extends(UserEventService, _super);
30145
- function UserEventService(graphql, accountService, network, translate, toastController, environment) {
30164
+
30165
+ var UserEventFragments = {
30166
+ userEvent: core.gql(templateObject_1$2 || (templateObject_1$2 = __makeTemplateObject(["fragment UserEventFragment on UserEventVO {\n id\n issuer\n updateDate\n creationDate\n eventType\n recipient\n content\n hash\n signature\n readSignature\n __typename\n }"], ["fragment UserEventFragment on UserEventVO {\n id\n issuer\n updateDate\n creationDate\n eventType\n recipient\n content\n hash\n signature\n readSignature\n __typename\n }"]))),
30167
+ lightUserEvent: core.gql(templateObject_2$2 || (templateObject_2$2 = __makeTemplateObject(["fragment LightUserEventFragment on UserEventVO {\n id\n issuer\n recipient\n updateDate\n creationDate\n eventType\n readSignature\n __typename\n }"], ["fragment LightUserEventFragment on UserEventVO {\n id\n issuer\n recipient\n updateDate\n creationDate\n eventType\n readSignature\n __typename\n }"])))
30168
+ };
30169
+ var templateObject_1$2, templateObject_2$2;
30170
+
30171
+ var moment$6 = momentImported__namespace;
30172
+ var UserEventServiceToken = new i0.InjectionToken('UserEventService');
30173
+ var AbstractUserEventService = /** @class */ (function (_super) {
30174
+ __extends(AbstractUserEventService, _super);
30175
+ function AbstractUserEventService(graphql, accountService, network, translate, queries, mutations, subscriptions, environment) {
30146
30176
  var _this = _super.call(this, graphql, environment) || this;
30147
30177
  _this.graphql = graphql;
30148
30178
  _this.accountService = accountService;
30149
30179
  _this.network = network;
30150
30180
  _this.translate = translate;
30151
- _this.toastController = toastController;
30181
+ _this.queries = queries;
30182
+ _this.mutations = mutations;
30183
+ _this.subscriptions = subscriptions;
30152
30184
  _this.environment = environment;
30153
- _this._userEventActions = [];
30185
+ _this._count$ = new rxjs.BehaviorSubject(0);
30186
+ _this._subscriptions = new rxjs.Subscription();
30187
+ _this.listeners = [];
30188
+ _this._logPrefix = '[user-event-service] ';
30154
30189
  // For DEV only
30155
- _this._debug = environment && !environment.production;
30190
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
30191
+ // listen login/logout
30192
+ _this._subscriptions.add(accountService.onLogin.subscribe(function () { return __awaiter(_this, void 0, void 0, function () {
30193
+ var count;
30194
+ return __generator(this, function (_b) {
30195
+ switch (_b.label) {
30196
+ case 0: return [4 /*yield*/, this.count(undefined)];
30197
+ case 1:
30198
+ count = _b.sent();
30199
+ if (count && this._debug) {
30200
+ console.debug(this._logPrefix + "Received " + count + " unread notifications");
30201
+ }
30202
+ this._count$.next(count);
30203
+ return [2 /*return*/];
30204
+ }
30205
+ });
30206
+ }); }));
30156
30207
  return _this;
30157
30208
  }
30158
- /**
30159
- *
30160
- * @param offset
30161
- * @param size
30162
- * @param sortBy
30163
- * @param sortDirection
30164
- * @param filter
30165
- * @param options
30166
- * @deprecated use watchPage() instead
30167
- */
30168
- UserEventService.prototype.watchAll = function (offset, size, sortBy, sortDirection, filter, options) {
30209
+ Object.defineProperty(AbstractUserEventService.prototype, "userEventCount", {
30210
+ get: function () {
30211
+ return this._count$.asObservable();
30212
+ },
30213
+ enumerable: false,
30214
+ configurable: true
30215
+ });
30216
+ AbstractUserEventService.prototype.ngOnDestroy = function () {
30217
+ this._subscriptions.unsubscribe();
30218
+ };
30219
+ AbstractUserEventService.prototype.watchAll = function (offset, size, sortBy, sortDirection, filter, options) {
30169
30220
  return this.watchPage({ offset: offset, size: size, sortBy: sortBy, sortDirection: sortDirection }, filter, options);
30170
30221
  };
30171
- UserEventService.prototype.watchPage = function (page, filter, options) {
30222
+ AbstractUserEventService.prototype.watchPage = function (page, filter, options) {
30223
+ var _this = this;
30224
+ var _a;
30172
30225
  var now = this._debug && Date.now();
30173
- //if (this._debug)
30174
- console.debug('[user-event-service] Loading user events...', filter);
30226
+ if (!filter) {
30227
+ filter = this.defaultFilter();
30228
+ }
30229
+ console.debug(this._logPrefix + "Loading user events...", filter);
30175
30230
  filter = this.asFilter(filter);
30176
30231
  // Force recipient to current issuer, if not admin and not specified
30177
- if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
30178
- var recipient = this.accountService.account.pubkey;
30179
- if (recipient !== filter.recipient) {
30232
+ if (isEmptyArray(filter === null || filter === void 0 ? void 0 : filter.recipients) || !this.accountService.isAdmin()) {
30233
+ var recipient = this.defaultRecipient();
30234
+ if (!((_a = filter === null || filter === void 0 ? void 0 : filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
30180
30235
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
30181
- filter.recipient = recipient;
30236
+ filter.recipients = [recipient];
30182
30237
  }
30183
30238
  }
30184
- var withContent = options && options.withContent === true;
30239
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30185
30240
  return this.mutableWatchQuery({
30186
30241
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
30187
- query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
30242
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30188
30243
  variables: {
30189
- page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
30244
+ page: Object.assign(Object.assign({ sortBy: 'creationDate' }, page), {
30245
+ // @ts-ignore
30246
+ sortDirection: (page.sortDirection || 'desc').toUpperCase()
30247
+ }),
30190
30248
  filter: filter && filter.asPodObject()
30191
30249
  },
30192
30250
  arrayFieldName: 'data',
30193
30251
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
30194
- fetchPolicy: options && options.fetchPolicy || undefined
30252
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || "cache-first"
30195
30253
  })
30196
30254
  .pipe(operators.map(function (res) {
30197
- var data = res && (res.data || []).map(exports.UserEvent.fromObject);
30255
+ var data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(function (value) { return _this.processUserEvent(value, _this); });
30198
30256
  if (now) {
30199
- console.debug("[user-event-service] " + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30257
+ console.debug("" + _this._logPrefix + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30200
30258
  now = null;
30201
30259
  }
30260
+ var unreadCount = _this.unreadEvents(data);
30202
30261
  return {
30203
30262
  data: data,
30204
- total: res && toNumber(res.total, data.length)
30263
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
30205
30264
  };
30206
30265
  }));
30207
30266
  };
30208
- UserEventService.prototype.saveAll = function (data, options) {
30267
+ AbstractUserEventService.prototype.add = function (entity) {
30268
+ // TODO set an id !!!!!!!!!!!!!!!!!!!!!!!!!
30269
+ entity = this.processUserEvent(entity);
30270
+ var withContent = !!entity.content;
30271
+ // Add user event locally
30272
+ this.insertIntoMutableCachedQueries(this.graphql.cache, {
30273
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30274
+ data: entity
30275
+ });
30276
+ // Update count
30277
+ this._count$.next(this._count$.value + 1);
30278
+ };
30279
+ AbstractUserEventService.prototype.count = function (filter, options) {
30280
+ var _a;
30281
+ return __awaiter(this, void 0, void 0, function () {
30282
+ var res;
30283
+ return __generator(this, function (_b) {
30284
+ switch (_b.label) {
30285
+ case 0:
30286
+ if (!((_a = this.queries) === null || _a === void 0 ? void 0 : _a.count)) {
30287
+ console.warn(this._logPrefix + "Query 'count' not provided, skip.");
30288
+ return [2 /*return*/, undefined];
30289
+ }
30290
+ if (!filter)
30291
+ filter = this.defaultFilter();
30292
+ filter = this.asFilter(filter);
30293
+ if (this._debug)
30294
+ console.debug(this._logPrefix + "Counting user events with filter:", filter);
30295
+ return [4 /*yield*/, this.graphql.query({
30296
+ query: this.queries.count,
30297
+ variables: {
30298
+ filter: filter.asPodObject()
30299
+ },
30300
+ error: { code: SocialErrorCodes.COUNT_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.COUNT_USER_EVENT_ERROR' },
30301
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'network-only'
30302
+ })];
30303
+ case 1:
30304
+ res = _b.sent();
30305
+ return [2 /*return*/, res.total];
30306
+ }
30307
+ });
30308
+ });
30309
+ };
30310
+ AbstractUserEventService.prototype.listenChanges = function (filter, options) {
30209
30311
  var _this = this;
30210
- return Promise.all(data
30211
- .map(function (entity) { return _this.save(entity, options); }));
30312
+ var _a;
30313
+ if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
30314
+ console.warn(this._logPrefix + "Subscription query 'listenChanges' not provided, skip.");
30315
+ return rxjs.of();
30316
+ }
30317
+ if (!filter)
30318
+ filter = this.defaultFilter();
30319
+ filter = this.asFilter(filter);
30320
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30321
+ if (this._debug)
30322
+ console.debug(this._logPrefix + "[WS] Listening changes for user events with filter:", filter);
30323
+ return this.graphql.subscribe({
30324
+ query: this.subscriptions.listenChanges,
30325
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
30326
+ variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
30327
+ error: {
30328
+ code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
30329
+ message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
30330
+ }
30331
+ }).pipe(operators.map(function (_b) {
30332
+ var data = _b.data;
30333
+ if (data && _this._debug)
30334
+ console.debug(_this._logPrefix + "Received new user events:", data);
30335
+ var updatedData = data === null || data === void 0 ? void 0 : data.map(function (value) { return _this.processUserEvent(value, _this); });
30336
+ // Update cache
30337
+ _this.insertIntoMutableCachedQueries(_this.graphql.cache, {
30338
+ query: withContent ? _this.queries.loadAllWithContent : _this.queries.loadAll,
30339
+ data: updatedData
30340
+ });
30341
+ // update count
30342
+ _this._count$.next(_this.unreadEvents(updatedData));
30343
+ return updatedData;
30344
+ }));
30212
30345
  };
30213
- /**
30214
- * Save a userEvent entity
30215
- *
30216
- * @param entity
30217
- */
30218
- UserEventService.prototype.save = function (entity, options) {
30346
+ AbstractUserEventService.prototype.delete = function (entity) {
30347
+ return __awaiter(this, void 0, void 0, function () {
30348
+ return __generator(this, function (_b) {
30349
+ switch (_b.label) {
30350
+ case 0:
30351
+ if (!entity)
30352
+ return [2 /*return*/]; // skip
30353
+ return [4 /*yield*/, this.deleteAll([entity])];
30354
+ case 1:
30355
+ _b.sent();
30356
+ return [2 /*return*/];
30357
+ }
30358
+ });
30359
+ });
30360
+ };
30361
+ AbstractUserEventService.prototype.deleteAll = function (entities, opts) {
30362
+ return __awaiter(this, void 0, void 0, function () {
30363
+ var ids, now;
30364
+ var _this = this;
30365
+ return __generator(this, function (_b) {
30366
+ switch (_b.label) {
30367
+ case 0:
30368
+ ids = entities && entities
30369
+ .map(function (t) { return t.id; });
30370
+ if (isEmptyArray(ids))
30371
+ return [2 /*return*/]; // stop, if nothing else to do
30372
+ now = Date.now();
30373
+ if (this._debug)
30374
+ console.debug(this._logPrefix + "Deleting events... ids:", ids);
30375
+ return [4 /*yield*/, this.graphql.mutate({
30376
+ mutation: this.mutations.deleteByIds,
30377
+ variables: {
30378
+ ids: ids
30379
+ },
30380
+ update: function (proxy) {
30381
+ // Remove from caches
30382
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30383
+ query: _this.queries.loadAll,
30384
+ ids: ids
30385
+ });
30386
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30387
+ query: _this.queries.loadAllWithContent,
30388
+ ids: ids
30389
+ });
30390
+ if (_this._debug)
30391
+ console.debug(_this._logPrefix + "Events deleted in " + (Date.now() - now) + "ms");
30392
+ }
30393
+ })];
30394
+ case 1:
30395
+ _b.sent();
30396
+ return [2 /*return*/];
30397
+ }
30398
+ });
30399
+ });
30400
+ };
30401
+ AbstractUserEventService.prototype.save = function (entity, options) {
30219
30402
  return __awaiter(this, void 0, void 0, function () {
30220
30403
  var isNew, json, now;
30221
30404
  var _this = this;
30222
- return __generator(this, function (_a) {
30223
- switch (_a.label) {
30405
+ return __generator(this, function (_b) {
30406
+ switch (_b.label) {
30224
30407
  case 0:
30225
30408
  this.fillDefaultProperties(entity);
30226
30409
  isNew = isNil(entity.id);
30227
30410
  json = entity.asObject();
30228
30411
  now = Date.now();
30229
30412
  if (this._debug)
30230
- console.debug("[user-event-service] Saving user event...", json);
30413
+ console.debug(this._logPrefix + "Saving user event...", json);
30231
30414
  return [4 /*yield*/, this.graphql.mutate({
30232
- mutation: SaveQuery,
30415
+ mutation: this.mutations.save,
30233
30416
  variables: {
30234
30417
  data: json
30235
30418
  },
30236
30419
  error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
30237
- update: function (proxy, _a) {
30238
- var data = _a.data;
30420
+ update: function (proxy, _b) {
30421
+ var data = _b.data;
30239
30422
  // Update entity
30240
30423
  var savedEntity = data && data.data;
30241
30424
  if (savedEntity) {
30242
30425
  if (_this._debug)
30243
- console.debug("[user-event-service] User event saved in " + (Date.now() - now) + "ms", entity);
30426
+ console.debug(_this._logPrefix + "User event saved in " + (Date.now() - now) + "ms", entity);
30244
30427
  _this.copyIdAndUpdateDate(savedEntity, entity);
30245
30428
  // Add to cache
30246
30429
  if (isNew) {
30247
30430
  _this.insertIntoMutableCachedQueries(proxy, {
30248
- query: LoadAllQuery,
30431
+ query: _this.queries.loadAll,
30249
30432
  data: Object.assign(Object.assign({}, savedEntity), { content: null })
30250
30433
  });
30251
30434
  _this.insertIntoMutableCachedQueries(proxy, {
30252
- query: LoadAllWithContentQuery,
30435
+ query: _this.queries.loadAllWithContent,
30253
30436
  data: savedEntity
30254
30437
  });
30255
30438
  }
@@ -30257,93 +30440,186 @@
30257
30440
  }
30258
30441
  })];
30259
30442
  case 1:
30260
- _a.sent();
30443
+ _b.sent();
30261
30444
  return [2 /*return*/, entity];
30262
30445
  }
30263
30446
  });
30264
30447
  });
30265
30448
  };
30266
- /**
30267
- * Save many trips
30268
- *
30269
- * @param entities
30270
- * @param opts
30271
- */
30272
- UserEventService.prototype.deleteAll = function (entities, opts) {
30449
+ AbstractUserEventService.prototype.saveAll = function (data, opts) {
30450
+ var _this = this;
30451
+ return Promise.all(data
30452
+ .map(function (entity) { return _this.save(entity, opts); }));
30453
+ };
30454
+ AbstractUserEventService.prototype.markAsRead = function (entity) {
30273
30455
  return __awaiter(this, void 0, void 0, function () {
30274
- var ids, now;
30275
- var _this = this;
30276
- return __generator(this, function (_a) {
30277
- switch (_a.label) {
30456
+ var onReadListeners, onReadListeners_1, onReadListeners_1_1, listener, e_1_1;
30457
+ var e_1, _b;
30458
+ return __generator(this, function (_c) {
30459
+ switch (_c.label) {
30278
30460
  case 0:
30279
- ids = entities && entities
30280
- .map(function (t) { return t.id; });
30281
- if (isEmptyArray(ids))
30282
- return [2 /*return*/]; // stop, if nothing else to do
30283
- now = Date.now();
30284
- if (this._debug)
30285
- console.debug('[user-event-service] Deleting events... ids:', ids);
30286
- return [4 /*yield*/, this.graphql.mutate({
30287
- mutation: DeleteByIdsMutation,
30288
- variables: {
30289
- ids: ids
30290
- },
30291
- update: function (proxy) {
30292
- // Remove from caches
30293
- _this.removeFromMutableCachedQueriesByIds(proxy, {
30294
- query: LoadAllQuery,
30295
- ids: ids
30296
- });
30297
- _this.removeFromMutableCachedQueriesByIds(proxy, {
30298
- query: LoadAllWithContentQuery,
30299
- ids: ids
30300
- });
30301
- if (_this._debug)
30302
- console.debug("[user-event-service] Events deleted in " + (Date.now() - now) + "ms");
30303
- }
30304
- })];
30461
+ onReadListeners = (this.listeners || []).filter(function (listener) { return !!listener.onRead; }).filter(function (listener) { return listener.accept(entity); });
30462
+ if (!onReadListeners.length) return [3 /*break*/, 9];
30463
+ _c.label = 1;
30305
30464
  case 1:
30306
- _a.sent();
30307
- return [2 /*return*/];
30465
+ _c.trys.push([1, 6, 7, 8]);
30466
+ onReadListeners_1 = __values(onReadListeners), onReadListeners_1_1 = onReadListeners_1.next();
30467
+ _c.label = 2;
30468
+ case 2:
30469
+ if (!!onReadListeners_1_1.done) return [3 /*break*/, 5];
30470
+ listener = onReadListeners_1_1.value;
30471
+ return [4 /*yield*/, listener.onRead(entity)];
30472
+ case 3:
30473
+ _c.sent();
30474
+ _c.label = 4;
30475
+ case 4:
30476
+ onReadListeners_1_1 = onReadListeners_1.next();
30477
+ return [3 /*break*/, 2];
30478
+ case 5: return [3 /*break*/, 8];
30479
+ case 6:
30480
+ e_1_1 = _c.sent();
30481
+ e_1 = { error: e_1_1 };
30482
+ return [3 /*break*/, 8];
30483
+ case 7:
30484
+ try {
30485
+ if (onReadListeners_1_1 && !onReadListeners_1_1.done && (_b = onReadListeners_1.return)) _b.call(onReadListeners_1);
30486
+ }
30487
+ finally { if (e_1) throw e_1.error; }
30488
+ return [7 /*endfinally*/];
30489
+ case 8: return [3 /*break*/, 11];
30490
+ case 9:
30491
+ // Use default
30492
+ return [4 /*yield*/, this.defaultMarkAsRead(entity)];
30493
+ case 10:
30494
+ // Use default
30495
+ _c.sent();
30496
+ _c.label = 11;
30497
+ case 11: return [2 /*return*/];
30308
30498
  }
30309
30499
  });
30310
30500
  });
30311
30501
  };
30312
- /**
30313
- * Delete userEvent entities
30314
- */
30315
- UserEventService.prototype.delete = function (data) {
30502
+ AbstractUserEventService.prototype.registerListener = function (listener) {
30503
+ if (!this.listeners)
30504
+ this.listeners = [];
30505
+ this.listeners.push(listener);
30506
+ };
30507
+ /* -- protected methods -- */
30508
+ AbstractUserEventService.prototype.processUserEvent = function (source, that) {
30509
+ var e_2, _b;
30510
+ that = that || this;
30511
+ // Convert json source to IUserEvent
30512
+ var target = that.fromObject(source);
30513
+ // Get listeners
30514
+ var listeners = (that.listeners || []).filter(function (listener) { return listener.onReceived; }).filter(function (listener) { return listener.accept(target); });
30515
+ try {
30516
+ for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
30517
+ var listener = listeners_1_1.value;
30518
+ if (target) {
30519
+ target = listener.onReceived(target);
30520
+ }
30521
+ else {
30522
+ if (that._debug)
30523
+ console.debug(that._logPrefix + "Event has been rejected by a listener", source);
30524
+ break;
30525
+ }
30526
+ }
30527
+ }
30528
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
30529
+ finally {
30530
+ try {
30531
+ if (listeners_1_1 && !listeners_1_1.done && (_b = listeners_1.return)) _b.call(listeners_1);
30532
+ }
30533
+ finally { if (e_2) throw e_2.error; }
30534
+ }
30535
+ return target;
30536
+ };
30537
+ AbstractUserEventService.prototype.defaultMarkAsRead = function (userEvent) {
30316
30538
  return __awaiter(this, void 0, void 0, function () {
30317
- return __generator(this, function (_a) {
30318
- switch (_a.label) {
30539
+ return __generator(this, function (_b) {
30540
+ switch (_b.label) {
30319
30541
  case 0:
30320
- if (!data)
30321
- return [2 /*return*/]; // skip
30322
- return [4 /*yield*/, this.deleteAll([data])];
30323
- case 1:
30324
- _a.sent();
30325
- return [2 /*return*/];
30542
+ if (!userEvent)
30543
+ throw new Error(this._logPrefix + "Invalid event to save");
30544
+ // set read date
30545
+ userEvent.readDate = moment$6();
30546
+ if (!(!userEvent.id || userEvent.id < 0)) return [3 /*break*/, 1];
30547
+ if (this._debug)
30548
+ console.debug(this._logPrefix + "Save local user event");
30549
+ return [3 /*break*/, 3];
30550
+ case 1: return [4 /*yield*/, this.save(userEvent)];
30551
+ case 2:
30552
+ _b.sent();
30553
+ _b.label = 3;
30554
+ case 3: return [2 /*return*/];
30326
30555
  }
30327
30556
  });
30328
30557
  });
30329
30558
  };
30330
- UserEventService.prototype.listenChanges = function (id, options) {
30331
- // TODO
30332
- console.warn('TODO: implement listen changes on user events');
30333
- return rxjs.of();
30559
+ AbstractUserEventService.prototype.defaultFilter = function () {
30560
+ // By default
30561
+ return {
30562
+ recipients: [this.defaultRecipient()]
30563
+ };
30564
+ };
30565
+ AbstractUserEventService.prototype.defaultRecipient = function () {
30566
+ return this.accountService.person.pubkey;
30334
30567
  };
30335
- UserEventService.prototype.registerAction = function (definition) {
30336
- console.info("[user-event-service] Registering action " + definition.name + " for " + definition.__typename);
30337
- this._userEventActions.push(definition);
30568
+ AbstractUserEventService.prototype.fillDefaultProperties = function (entity) {
30338
30569
  };
30339
- UserEventService.prototype.getActionsByTypename = function (typename) {
30340
- return this._userEventActions.filter(function (def) { return def.__typename === typename; });
30570
+ AbstractUserEventService.prototype.unreadEvents = function (events) {
30571
+ // default calculation on unread events from a list
30572
+ if (isEmptyArray(events))
30573
+ return undefined;
30574
+ var lastReadDate = events
30575
+ .filter(function (event) { return isNotNil(event.readDate); })
30576
+ .reduce(function (lastDate, event) { return DateUtils.max(lastDate, event.readDate); }, undefined);
30577
+ return events
30578
+ .filter(function (event) { return event.creationDate.isSameOrAfter(lastReadDate); }).length;
30341
30579
  };
30580
+ AbstractUserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30581
+ EntityUtils.copyIdAndUpdateDate(source, target);
30582
+ };
30583
+ return AbstractUserEventService;
30584
+ }(BaseGraphqlService));
30585
+ AbstractUserEventService.decorators = [
30586
+ { type: i0.Directive }
30587
+ ];
30588
+ AbstractUserEventService.ctorParameters = function () { return [
30589
+ { type: GraphqlService },
30590
+ { type: AccountService },
30591
+ { type: NetworkService },
30592
+ { type: i1$2.TranslateService },
30593
+ { type: undefined },
30594
+ { type: undefined },
30595
+ { type: undefined },
30596
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30597
+ ]; };
30598
+ var userEventQueries = {
30599
+ loadAll: core.gql(templateObject_1$3 || (templateObject_1$3 = __makeTemplateObject(["\n query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...LightUserEventFragment\n }\n }\n ", "\n "], ["\n query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...LightUserEventFragment\n }\n }\n ", "\n "])), UserEventFragments.lightUserEvent),
30600
+ loadAllWithContent: core.gql(templateObject_2$3 || (templateObject_2$3 = __makeTemplateObject(["\n query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...UserEventFragment\n }\n }\n ", "\n "], ["\n query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...UserEventFragment\n }\n }\n ", "\n "])), UserEventFragments.userEvent)
30601
+ };
30602
+ var userEventMutations = {
30603
+ deleteByIds: core.gql(templateObject_3$2 || (templateObject_3$2 = __makeTemplateObject(["\n mutation DeleteUserEvents($ids:[Int]){\n deleteUserEvents(ids: $ids)\n }\n "], ["\n mutation DeleteUserEvents($ids:[Int]){\n deleteUserEvents(ids: $ids)\n }\n "]))),
30604
+ save: core.gql(templateObject_4$2 || (templateObject_4$2 = __makeTemplateObject(["\n mutation SaveUserEvent($data: UserEventVOInput){\n data: saveUserEvent(userEvent: $data){\n ...UserEventFragment\n }\n }\n ", "\n "], ["\n mutation SaveUserEvent($data: UserEventVOInput){\n data: saveUserEvent(userEvent: $data){\n ...UserEventFragment\n }\n }\n ", "\n "])), UserEventFragments.userEvent)
30605
+ };
30606
+ var UserEventService = /** @class */ (function (_super) {
30607
+ __extends(UserEventService, _super);
30608
+ function UserEventService(graphql, accountService, network, translate, toastController, environment) {
30609
+ var _this = _super.call(this, graphql, accountService, network, translate, userEventQueries, userEventMutations, undefined, environment) || this;
30610
+ _this.graphql = graphql;
30611
+ _this.accountService = accountService;
30612
+ _this.network = network;
30613
+ _this.translate = translate;
30614
+ _this.toastController = toastController;
30615
+ _this.environment = environment;
30616
+ return _this;
30617
+ }
30342
30618
  UserEventService.prototype.showToastErrorWithContext = function (opts) {
30343
30619
  return __awaiter(this, void 0, void 0, function () {
30344
30620
  var message, res, context, userEvent, err_1;
30345
- return __generator(this, function (_a) {
30346
- switch (_a.label) {
30621
+ return __generator(this, function (_b) {
30622
+ switch (_b.label) {
30347
30623
  case 0:
30348
30624
  message = opts.message || (opts.error && opts.error.message || opts.error);
30349
30625
  // Make sure message a string
@@ -30372,12 +30648,12 @@
30372
30648
  }]
30373
30649
  })];
30374
30650
  case 1:
30375
- res = _a.sent();
30651
+ res = _b.sent();
30376
30652
  if (!res || res.role !== 'send')
30377
30653
  return [2 /*return*/];
30378
- _a.label = 2;
30654
+ _b.label = 2;
30379
30655
  case 2:
30380
- _a.trys.push([2, 6, , 7]);
30656
+ _b.trys.push([2, 6, , 7]);
30381
30657
  if (this._debug)
30382
30658
  console.debug('Sending debug data...');
30383
30659
  context = opts && opts.context;
@@ -30387,15 +30663,15 @@
30387
30663
  if (!(context instanceof Promise)) return [3 /*break*/, 4];
30388
30664
  return [4 /*yield*/, context];
30389
30665
  case 3:
30390
- context = _a.sent();
30391
- _a.label = 4;
30666
+ context = _b.sent();
30667
+ _b.label = 4;
30392
30668
  case 4: return [4 /*yield*/, this.sendDataForDebug({
30393
30669
  message: message,
30394
30670
  error: opts.error || undefined,
30395
30671
  context: this.convertObjectToString(context)
30396
30672
  })];
30397
30673
  case 5:
30398
- userEvent = _a.sent();
30674
+ userEvent = _b.sent();
30399
30675
  console.info('Debug data successfully sent to admin', userEvent);
30400
30676
  this.showToast({
30401
30677
  type: 'info',
@@ -30404,7 +30680,7 @@
30404
30680
  });
30405
30681
  return [3 /*break*/, 7];
30406
30682
  case 6:
30407
- err_1 = _a.sent();
30683
+ err_1 = _b.sent();
30408
30684
  console.error('Error while sending debug data:', err_1);
30409
30685
  return [3 /*break*/, 7];
30410
30686
  case 7: return [2 /*return*/];
@@ -30414,13 +30690,16 @@
30414
30690
  };
30415
30691
  UserEventService.prototype.sendDataForDebug = function (data) {
30416
30692
  var userEvent = new exports.UserEvent();
30417
- userEvent.eventType = UserEventTypes.DEBUG_DATA;
30693
+ userEvent.type = UserEventTypes.DEBUG_DATA;
30418
30694
  userEvent.content = this.convertObjectToString(data);
30419
30695
  return this.save(userEvent);
30420
30696
  };
30421
30697
  UserEventService.prototype.asFilter = function (filter) {
30422
30698
  return exports.UserEventFilter.fromObject(filter);
30423
30699
  };
30700
+ UserEventService.prototype.fromObject = function (source) {
30701
+ return exports.UserEvent.fromObject(source);
30702
+ };
30424
30703
  /* -- protected methods -- */
30425
30704
  UserEventService.prototype.convertObjectToString = function (data) {
30426
30705
  if (typeof data === 'string') {
@@ -30438,13 +30717,13 @@
30438
30717
  };
30439
30718
  UserEventService.prototype.showToast = function (opts) {
30440
30719
  return __awaiter(this, void 0, void 0, function () {
30441
- return __generator(this, function (_a) {
30442
- switch (_a.label) {
30720
+ return __generator(this, function (_b) {
30721
+ switch (_b.label) {
30443
30722
  case 0:
30444
30723
  if (!this.toastController)
30445
30724
  throw new Error('Missing toastController in component\'s constructor');
30446
30725
  return [4 /*yield*/, Toasts.show(this.toastController, this.translate, opts)];
30447
- case 1: return [2 /*return*/, _a.sent()];
30726
+ case 1: return [2 /*return*/, _b.sent()];
30448
30727
  }
30449
30728
  });
30450
30729
  });
@@ -30455,14 +30734,10 @@
30455
30734
  // TODO: compute sign
30456
30735
  console.warn('TODO: sign user event before sending');
30457
30736
  };
30458
- UserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30459
- EntityUtils.copyIdAndUpdateDate(source, target);
30460
- };
30461
30737
  return UserEventService;
30462
- }(BaseGraphqlService));
30463
- UserEventService.ɵprov = i0.ɵɵdefineInjectable({ factory: function UserEventService_Factory() { return new UserEventService(i0.ɵɵinject(GraphqlService), i0.ɵɵinject(AccountService), i0.ɵɵinject(NetworkService), i0.ɵɵinject(i1$2.TranslateService), i0.ɵɵinject(i1$5.ToastController), i0.ɵɵinject(ENVIRONMENT, 8)); }, token: UserEventService, providedIn: "root" });
30738
+ }(AbstractUserEventService));
30464
30739
  UserEventService.decorators = [
30465
- { type: i0.Injectable, args: [{ providedIn: 'root' },] }
30740
+ { type: i0.Injectable }
30466
30741
  ];
30467
30742
  UserEventService.ctorParameters = function () { return [
30468
30743
  { type: GraphqlService },
@@ -30476,7 +30751,7 @@
30476
30751
 
30477
30752
  var ICONS_MAP = {
30478
30753
  DEBUG_DATA: { matIcon: 'bug_report' },
30479
- INBOX_MESSAGE: { matIcon: 'mail' },
30754
+ INBOX_MESSAGE: { matIcon: 'mail' }
30480
30755
  };
30481
30756
  // TODO: refactor with a registration done by data service:
30482
30757
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -30544,7 +30819,7 @@
30544
30819
  }
30545
30820
  }));
30546
30821
  var filter = this.filter || new exports.UserEventFilter();
30547
- filter.recipient = this.recipient;
30822
+ filter.recipients = [this.recipient];
30548
30823
  this.setFilter(filter, { emitEvent: true });
30549
30824
  };
30550
30825
  UserEventsTable.prototype.start = function () {
@@ -30566,17 +30841,17 @@
30566
30841
  });
30567
30842
  };
30568
30843
  UserEventsTable.prototype.getIcon = function (source) {
30569
- return ICONS_MAP[source.eventType];
30844
+ return ICONS_MAP[source.type];
30570
30845
  };
30571
30846
  UserEventsTable.prototype.getDetail = function (source) {
30572
30847
  if (!source)
30573
30848
  return undefined;
30574
- if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
30849
+ if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
30575
30850
  var context = source.content.context;
30576
30851
  if (context && context.__typename) {
30577
- var actions = this.service.getActionsByTypename(context.__typename);
30852
+ // const actions = this.service.getActionsByTypename(context.__typename);
30578
30853
  return {
30579
- actions: actions,
30854
+ // actions,
30580
30855
  title: source.content.error && source.content.error.message || source.content.message,
30581
30856
  description: source.content.error && source.content.error.details || undefined
30582
30857
  };
@@ -30587,18 +30862,18 @@
30587
30862
  };
30588
30863
  UserEventsTable.prototype.doAction = function (action, row) {
30589
30864
  return __awaiter(this, void 0, void 0, function () {
30590
- var event, context, res, _a, err_1;
30865
+ var event, res, _a, err_1;
30591
30866
  return __generator(this, function (_b) {
30592
30867
  switch (_b.label) {
30593
30868
  case 0:
30594
30869
  event = row.currentData;
30595
- context = event.content && event.content.context;
30870
+ // const context = event.content && event.content.context;
30596
30871
  this.markAsLoading();
30597
30872
  if (!(action && typeof action.executeAction === 'function')) return [3 /*break*/, 7];
30598
30873
  _b.label = 1;
30599
30874
  case 1:
30600
30875
  _b.trys.push([1, 5, 6, 7]);
30601
- res = action.executeAction(event, context);
30876
+ res = action.executeAction(event /*, context*/);
30602
30877
  if (!(res instanceof Promise)) return [3 /*break*/, 3];
30603
30878
  return [4 /*yield*/, res];
30604
30879
  case 2:
@@ -30630,13 +30905,18 @@
30630
30905
  selector: 'app-user-events-table',
30631
30906
  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",
30632
30907
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
30908
+ providers: [
30909
+ {
30910
+ provide: UserEventServiceToken, useClass: UserEventService
30911
+ }
30912
+ ],
30633
30913
  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}"]
30634
30914
  },] }
30635
30915
  ];
30636
30916
  UserEventsTable.ctorParameters = function () { return [
30637
30917
  { type: i0.Injector },
30638
30918
  { type: AccountService },
30639
- { type: UserEventService },
30919
+ { type: undefined, decorators: [{ type: i0.Inject, args: [UserEventServiceToken,] }] },
30640
30920
  { type: EntitiesStorage },
30641
30921
  { type: i0.ChangeDetectorRef },
30642
30922
  { type: undefined, decorators: [{ type: i0.Inject, args: [ENVIRONMENT,] }] }
@@ -30648,6 +30928,174 @@
30648
30928
  defaultSortDirection: [{ type: i0.Input }]
30649
30929
  };
30650
30930
 
30931
+ var UserEventNotificationList = /** @class */ (function () {
30932
+ function UserEventNotificationList(popoverController) {
30933
+ this.popoverController = popoverController;
30934
+ }
30935
+ UserEventNotificationList.prototype.ngOnInit = function () {
30936
+ };
30937
+ UserEventNotificationList.prototype.read = function ($event, userEvent) {
30938
+ var _a;
30939
+ if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
30940
+ return;
30941
+ (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
30942
+ };
30943
+ UserEventNotificationList.prototype.executeAction = function (action, userEvent) {
30944
+ // Execute then close popover
30945
+ action.executeAction(userEvent);
30946
+ this.dismiss();
30947
+ };
30948
+ UserEventNotificationList.prototype.dismiss = function () {
30949
+ this.popoverController.dismiss();
30950
+ };
30951
+ return UserEventNotificationList;
30952
+ }());
30953
+ UserEventNotificationList.decorators = [
30954
+ { type: i0.Component, args: [{
30955
+ selector: 'app-user-event-notification-list',
30956
+ 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",
30957
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}"]
30958
+ },] }
30959
+ ];
30960
+ UserEventNotificationList.ctorParameters = function () { return [
30961
+ { type: i1$5.PopoverController }
30962
+ ]; };
30963
+ UserEventNotificationList.propDecorators = {
30964
+ titleI18n: [{ type: i0.Input }],
30965
+ userEvents: [{ type: i0.Input }],
30966
+ readEvent: [{ type: i0.Output }]
30967
+ };
30968
+
30969
+ var UserEventNotificationComponent = /** @class */ (function () {
30970
+ function UserEventNotificationComponent(userEventService, accountService, popoverController, cd) {
30971
+ this.userEventService = userEventService;
30972
+ this.accountService = accountService;
30973
+ this.popoverController = popoverController;
30974
+ this.cd = cd;
30975
+ this.debug = false;
30976
+ this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
30977
+ this.disabled = false;
30978
+ this.userEventsSubject = new rxjs.BehaviorSubject(undefined);
30979
+ this._subscriptions = new rxjs.Subscription();
30980
+ this._logPrefix = '[user-event-notification] ';
30981
+ this._readEvent = new i0.EventEmitter();
30982
+ }
30983
+ Object.defineProperty(UserEventNotificationComponent.prototype, "count", {
30984
+ get: function () {
30985
+ var _a;
30986
+ return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(operators.map(function (value) { return value === 0 ? undefined : value; }));
30987
+ },
30988
+ enumerable: false,
30989
+ configurable: true
30990
+ });
30991
+ UserEventNotificationComponent.prototype.ngOnInit = function () {
30992
+ var _this = this;
30993
+ if (isNil(this.userEventService)) {
30994
+ console.warn(this._logPrefix + "No service injected");
30995
+ this.disabled = true;
30996
+ return;
30997
+ }
30998
+ // Watch first
30999
+ this._subscriptions.add(this.userEventService.watchAll(0, 10, 'creationDate', 'desc').subscribe(function (value) {
31000
+ var data = value.data;
31001
+ if (_this.debug) {
31002
+ console.debug(_this._logPrefix + "Receiving user events", data);
31003
+ }
31004
+ _this.userEventsSubject.next(data);
31005
+ }));
31006
+ // Then listen changes
31007
+ this._subscriptions.add(this.userEventService.listenChanges(undefined).subscribe(function (data) {
31008
+ if (_this.debug) {
31009
+ console.debug(_this._logPrefix + "Receiving new user events", data);
31010
+ }
31011
+ }));
31012
+ this._readEvent.subscribe(function (value) {
31013
+ _this.userEventService.markAsRead(value);
31014
+ });
31015
+ };
31016
+ UserEventNotificationComponent.prototype.showList = function (event) {
31017
+ return __awaiter(this, void 0, void 0, function () {
31018
+ var popover;
31019
+ return __generator(this, function (_b) {
31020
+ switch (_b.label) {
31021
+ case 0: return [4 /*yield*/, this.popoverController.create({
31022
+ component: UserEventNotificationList,
31023
+ componentProps: {
31024
+ titleI18n: this.titleI18n,
31025
+ userEvents: this.userEventsSubject,
31026
+ readEvent: this._readEvent
31027
+ },
31028
+ backdropDismiss: true,
31029
+ keyboardClose: true,
31030
+ event: event,
31031
+ translucent: true,
31032
+ cssClass: 'popover-large'
31033
+ })];
31034
+ case 1:
31035
+ popover = _b.sent();
31036
+ return [4 /*yield*/, popover.present()];
31037
+ case 2:
31038
+ _b.sent();
31039
+ return [2 /*return*/];
31040
+ }
31041
+ });
31042
+ });
31043
+ };
31044
+ UserEventNotificationComponent.prototype.markForCheck = function () {
31045
+ this.cd.markForCheck();
31046
+ };
31047
+ UserEventNotificationComponent.prototype.ngOnDestroy = function () {
31048
+ if (this.debug) {
31049
+ console.debug(this._logPrefix + "Destroying");
31050
+ }
31051
+ this._subscriptions.unsubscribe();
31052
+ };
31053
+ return UserEventNotificationComponent;
31054
+ }());
31055
+ UserEventNotificationComponent.decorators = [
31056
+ { type: i0.Component, args: [{
31057
+ selector: 'app-user-event-notification-component',
31058
+ 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",
31059
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31060
+ styles: [""]
31061
+ },] }
31062
+ ];
31063
+ UserEventNotificationComponent.ctorParameters = function () { return [
31064
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [UserEventServiceToken,] }] },
31065
+ { type: AccountService },
31066
+ { type: i1$5.PopoverController },
31067
+ { type: i0.ChangeDetectorRef }
31068
+ ]; };
31069
+ UserEventNotificationComponent.propDecorators = {
31070
+ debug: [{ type: i0.Input }],
31071
+ titleI18n: [{ type: i0.Input }],
31072
+ disabled: [{ type: i0.Input }]
31073
+ };
31074
+
31075
+ var UserEventModule = /** @class */ (function () {
31076
+ function UserEventModule() {
31077
+ }
31078
+ return UserEventModule;
31079
+ }());
31080
+ UserEventModule.decorators = [
31081
+ { type: i0.NgModule, args: [{
31082
+ imports: [
31083
+ i1$4.CommonModule,
31084
+ CoreModule,
31085
+ SharedModule
31086
+ ],
31087
+ declarations: [
31088
+ UserEventsTable,
31089
+ UserEventNotificationComponent,
31090
+ UserEventNotificationList,
31091
+ ],
31092
+ exports: [
31093
+ UserEventsTable,
31094
+ UserEventNotificationComponent
31095
+ ]
31096
+ },] }
31097
+ ];
31098
+
30651
31099
  var MessageTypes = {
30652
31100
  INBOX_MESSAGE: 'INBOX_MESSAGE',
30653
31101
  EMAIL: 'EMAIL',
@@ -30881,12 +31329,12 @@
30881
31329
  canSelectType: [{ type: i0.Input }]
30882
31330
  };
30883
31331
 
30884
- var SocialModule = /** @class */ (function () {
30885
- function SocialModule() {
31332
+ var MessageModule = /** @class */ (function () {
31333
+ function MessageModule() {
30886
31334
  }
30887
- return SocialModule;
31335
+ return MessageModule;
30888
31336
  }());
30889
- SocialModule.decorators = [
31337
+ MessageModule.decorators = [
30890
31338
  { type: i0.NgModule, args: [{
30891
31339
  imports: [
30892
31340
  i1$4.CommonModule,
@@ -30894,19 +31342,342 @@
30894
31342
  SharedModule
30895
31343
  ],
30896
31344
  declarations: [
30897
- UserEventsTable,
30898
31345
  MessageModal,
30899
31346
  MessageForm
30900
31347
  ],
30901
31348
  exports: [
30902
- UserEventsTable,
30903
31349
  MessageModal
30904
31350
  ]
30905
31351
  },] }
30906
31352
  ];
30907
31353
 
31354
+ var JobProgression_1;
31355
+ // todo use entity
31356
+ var Job = /** @class */ (function () {
31357
+ function Job() {
31358
+ }
31359
+ return Job;
31360
+ }());
31361
+ // @dynamic
31362
+ exports.JobProgression = JobProgression_1 = /** @class */ (function (_super) {
31363
+ __extends(JobProgression, _super);
31364
+ function JobProgression() {
31365
+ return _super.call(this, JobProgression_1.TYPENAME) || this;
31366
+ }
31367
+ JobProgression.prototype.fromObject = function (source) {
31368
+ _super.prototype.fromObject.call(this, source);
31369
+ this.message = source.message;
31370
+ this.current = source.current;
31371
+ this.total = source.total;
31372
+ };
31373
+ return JobProgression;
31374
+ }(Entity));
31375
+ exports.JobProgression = JobProgression_1 = __decorate([
31376
+ EntityClass({ typename: 'JobProgressionVO' })
31377
+ ], exports.JobProgression);
31378
+
31379
+ var JobProgressionServiceToken = new i0.InjectionToken('JobProgressionService');
31380
+ var jobProgressionSubscription = core.gql(templateObject_1$4 || (templateObject_1$4 = __makeTemplateObject(["subscription UpdateJobProgression($id: Int!, $interval: Int){\n data: updateJobProgression(id: $id, interval: $interval) {\n id\n message\n current\n total\n }\n}"], ["subscription UpdateJobProgression($id: Int!, $interval: Int){\n data: updateJobProgression(id: $id, interval: $interval) {\n id\n message\n current\n total\n }\n}"])));
31381
+ var JobProgressionService = /** @class */ (function (_super) {
31382
+ __extends(JobProgressionService, _super);
31383
+ function JobProgressionService(graphql, environment) {
31384
+ var _this = _super.call(this, graphql, environment) || this;
31385
+ _this.graphql = graphql;
31386
+ _this.environment = environment;
31387
+ _this._logPrefix = '[job-progression-service] ';
31388
+ // For DEV only
31389
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
31390
+ return _this;
31391
+ }
31392
+ JobProgressionService.prototype.listenChanges = function (id, options) {
31393
+ var _this = this;
31394
+ if (isNil(id))
31395
+ throw new Error(this._logPrefix + "Missing argument 'id'");
31396
+ if (this._debug)
31397
+ console.debug(this._logPrefix + "[WS] Listening changes for job progression {" + id + "}...");
31398
+ return this.graphql.subscribe({
31399
+ query: jobProgressionSubscription,
31400
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
31401
+ variables: { id: id, interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
31402
+ error: { code: SocialErrorCodes.SUBSCRIBE_JOB_PROGRESSION_ERROR, message: 'SOCIAL.ERROR.SUBSCRIBE_JOB_PROGRESSION_ERROR' }
31403
+ }).pipe(operators.map(function (_a) {
31404
+ var data = _a.data;
31405
+ var progression = data && exports.JobProgression.fromObject(data);
31406
+ if (progression && _this._debug)
31407
+ console.debug(_this._logPrefix + "Job progression " + id + " updated on server", progression);
31408
+ return progression;
31409
+ }));
31410
+ };
31411
+ return JobProgressionService;
31412
+ }(BaseGraphqlService));
31413
+ JobProgressionService.decorators = [
31414
+ { type: i0.Injectable }
31415
+ ];
31416
+ JobProgressionService.ctorParameters = function () { return [
31417
+ { type: GraphqlService },
31418
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
31419
+ ]; };
31420
+ var templateObject_1$4;
31421
+
31422
+ var JobProgressionList = /** @class */ (function () {
31423
+ function JobProgressionList() {
31424
+ }
31425
+ JobProgressionList.prototype.ngOnInit = function () {
31426
+ };
31427
+ return JobProgressionList;
31428
+ }());
31429
+ JobProgressionList.decorators = [
31430
+ { type: i0.Component, args: [{
31431
+ selector: 'app-job-progression-list',
31432
+ 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",
31433
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}"]
31434
+ },] }
31435
+ ];
31436
+ JobProgressionList.ctorParameters = function () { return []; };
31437
+ JobProgressionList.propDecorators = {
31438
+ titleI18n: [{ type: i0.Input }],
31439
+ jobProgressions: [{ type: i0.Input }]
31440
+ };
31441
+
31442
+ var JobProgressionComponent = /** @class */ (function () {
31443
+ function JobProgressionComponent(jobProgressionService, popoverController, cd) {
31444
+ this.jobProgressionService = jobProgressionService;
31445
+ this.popoverController = popoverController;
31446
+ this.cd = cd;
31447
+ this.debug = false;
31448
+ this.titleI18n = 'SOCIAL.JOB.PROGRESSION.TITLE';
31449
+ this.jobFinished = new i0.EventEmitter();
31450
+ this.disabled = true;
31451
+ this.color = 'accent';
31452
+ this.mode = 'determinate';
31453
+ this.value = 0;
31454
+ this.jobProgressions = [];
31455
+ this._subscriptions = new rxjs.Subscription();
31456
+ this._subscriptionsById = {};
31457
+ this._logPrefix = '[job-progression] ';
31458
+ }
31459
+ JobProgressionComponent.prototype.ngOnInit = function () {
31460
+ var _a, _b, _c, _d;
31461
+ if (isNil(this.jobProgressionService)) {
31462
+ console.warn(this._logPrefix + "No service injected");
31463
+ }
31464
+ // parse options
31465
+ this.autoHide = toBoolean((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoHide, false);
31466
+ this.visible = !this.autoHide;
31467
+ this.autoHideDelay = toNumber((_b = this.options) === null || _b === void 0 ? void 0 : _b.autoHideDelay, 1000);
31468
+ this.autoRemove = toBoolean((_c = this.options) === null || _c === void 0 ? void 0 : _c.autoRemove, true);
31469
+ this.autoRemoveDelay = toNumber((_d = this.options) === null || _d === void 0 ? void 0 : _d.autoRemoveDelay, 1000);
31470
+ };
31471
+ JobProgressionComponent.prototype.addJob = function (id) {
31472
+ var _this = this;
31473
+ if (isNil(this.jobProgressionService)) {
31474
+ console.warn(this._logPrefix + "No service injected. Can't add a job");
31475
+ return;
31476
+ }
31477
+ if (this.debug) {
31478
+ console.debug(this._logPrefix + "Add job id=" + id);
31479
+ }
31480
+ if (!!this.getProgression(id)) {
31481
+ console.warn(this._logPrefix + "Job (id=" + id + ") already present");
31482
+ return;
31483
+ }
31484
+ this.disabled = false;
31485
+ var sub = this.jobProgressionService.listenChanges(id)
31486
+ .pipe(operators.filter(function (progression) {
31487
+ if (id !== progression.id) {
31488
+ console.error(_this._logPrefix + "Job progression (id=" + progression.id + ") doesn't match expected job (id=" + id + ")");
31489
+ return false;
31490
+ }
31491
+ return true;
31492
+ }), operators.map(function (progression) {
31493
+ // Ensure visible
31494
+ _this.visible = true;
31495
+ // Get current progression object
31496
+ var currentProgression = _this.getProgression(id);
31497
+ if (!currentProgression) {
31498
+ // add it
31499
+ _this.jobProgressions.push(progression);
31500
+ if (_this.debug) {
31501
+ console.debug(_this._logPrefix + "Progression added id=" + id, progression);
31502
+ }
31503
+ }
31504
+ else {
31505
+ // update current
31506
+ Object.assign(currentProgression, progression);
31507
+ if (_this.debug) {
31508
+ console.debug(_this._logPrefix + "Progression updated id=" + id, progression);
31509
+ }
31510
+ }
31511
+ return progression;
31512
+ }))
31513
+ .subscribe(function (progression) {
31514
+ // update value
31515
+ _this.updateValue();
31516
+ // job finished
31517
+ if (progression.total > 0 && progression.current == progression.total) {
31518
+ if (_this.debug) {
31519
+ console.debug(_this._logPrefix + "Finished job id=" + progression.id);
31520
+ }
31521
+ // emit event
31522
+ _this.jobFinished.emit(progression.id);
31523
+ if (_this.autoRemove) {
31524
+ setTimeout(function () {
31525
+ var _a;
31526
+ _this.removeJob(progression.id);
31527
+ // If last job
31528
+ if (_this.autoHide && !((_a = _this.jobProgressions) === null || _a === void 0 ? void 0 : _a.length)) {
31529
+ setTimeout(function () {
31530
+ _this.visible = false;
31531
+ _this.markForCheck();
31532
+ }, _this.autoHideDelay);
31533
+ }
31534
+ }, _this.autoRemoveDelay);
31535
+ }
31536
+ }
31537
+ });
31538
+ this._subscriptionsById[id] = sub;
31539
+ this._subscriptions.add(sub);
31540
+ };
31541
+ JobProgressionComponent.prototype.removeJob = function (id) {
31542
+ if (this.debug) {
31543
+ console.debug(this._logPrefix + "Remove job id=" + id);
31544
+ }
31545
+ var sub = this._subscriptionsById[id];
31546
+ if (sub) {
31547
+ this._subscriptions.remove(sub);
31548
+ sub.unsubscribe();
31549
+ }
31550
+ var progression = this.getProgression(id);
31551
+ if (progression) {
31552
+ this.jobProgressions.splice(this.jobProgressions.indexOf(progression), 1);
31553
+ }
31554
+ this.updateValue();
31555
+ };
31556
+ JobProgressionComponent.prototype.getProgression = function (id) {
31557
+ return this.jobProgressions.find(function (progression) { return progression.id === id; });
31558
+ };
31559
+ JobProgressionComponent.prototype.updateValue = function () {
31560
+ if (this.debug) {
31561
+ console.debug(this._logPrefix + "Updating value");
31562
+ }
31563
+ var value = 0;
31564
+ var nbProgression = arraySize(this.jobProgressions);
31565
+ var allIndeterminate = nbProgression > 0;
31566
+ this.jobProgressions.forEach(function (progression) {
31567
+ var indeterminate = progression.total === 0;
31568
+ allIndeterminate = allIndeterminate && indeterminate;
31569
+ if (!indeterminate) {
31570
+ value = value + progression.current * 100 / progression.total;
31571
+ }
31572
+ });
31573
+ this.value = nbProgression > 0 ? value / nbProgression : 0;
31574
+ this.mode = allIndeterminate ? 'indeterminate' : 'determinate';
31575
+ if (this.debug) {
31576
+ console.debug(this._logPrefix + "Setting value=" + this.value + ", mode=" + this.mode);
31577
+ }
31578
+ this.markForCheck();
31579
+ };
31580
+ JobProgressionComponent.prototype.showList = function (event) {
31581
+ return __awaiter(this, void 0, void 0, function () {
31582
+ var popover;
31583
+ return __generator(this, function (_e) {
31584
+ switch (_e.label) {
31585
+ case 0: return [4 /*yield*/, this.popoverController.create({
31586
+ component: JobProgressionList,
31587
+ componentProps: {
31588
+ titleI18n: this.titleI18n,
31589
+ jobProgressions: this.jobProgressions
31590
+ },
31591
+ backdropDismiss: true,
31592
+ keyboardClose: true,
31593
+ event: event,
31594
+ translucent: true,
31595
+ cssClass: 'popover-large'
31596
+ })];
31597
+ case 1:
31598
+ popover = _e.sent();
31599
+ return [4 /*yield*/, popover.present()];
31600
+ case 2:
31601
+ _e.sent();
31602
+ return [2 /*return*/];
31603
+ }
31604
+ });
31605
+ });
31606
+ };
31607
+ JobProgressionComponent.prototype.markForCheck = function () {
31608
+ this.cd.markForCheck();
31609
+ };
31610
+ JobProgressionComponent.prototype.ngOnDestroy = function () {
31611
+ if (this.debug) {
31612
+ console.debug(this._logPrefix + "Destroying");
31613
+ }
31614
+ this._subscriptions.unsubscribe();
31615
+ };
31616
+ return JobProgressionComponent;
31617
+ }());
31618
+ JobProgressionComponent.decorators = [
31619
+ { type: i0.Component, args: [{
31620
+ selector: 'app-job-progression',
31621
+ 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",
31622
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31623
+ styles: [".floating-spinner{position:absolute;top:6px;left:5px}"]
31624
+ },] }
31625
+ ];
31626
+ JobProgressionComponent.ctorParameters = function () { return [
31627
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [JobProgressionServiceToken,] }] },
31628
+ { type: i1$5.PopoverController },
31629
+ { type: i0.ChangeDetectorRef }
31630
+ ]; };
31631
+ JobProgressionComponent.propDecorators = {
31632
+ debug: [{ type: i0.Input }],
31633
+ titleI18n: [{ type: i0.Input }],
31634
+ options: [{ type: i0.Input }],
31635
+ jobFinished: [{ type: i0.Output }]
31636
+ };
31637
+
31638
+ var JobModule = /** @class */ (function () {
31639
+ function JobModule() {
31640
+ }
31641
+ return JobModule;
31642
+ }());
31643
+ JobModule.decorators = [
31644
+ { type: i0.NgModule, args: [{
31645
+ imports: [
31646
+ i1$4.CommonModule,
31647
+ SharedModule,
31648
+ i1$2.TranslateModule.forChild(),
31649
+ ],
31650
+ declarations: [
31651
+ JobProgressionComponent,
31652
+ JobProgressionList
31653
+ ],
31654
+ exports: [
31655
+ JobProgressionComponent
31656
+ ]
31657
+ },] }
31658
+ ];
31659
+
31660
+ var SocialModuleOptionsToken = new i0.InjectionToken("SocialModuleOptions");
31661
+ var SocialModule = /** @class */ (function () {
31662
+ function SocialModule() {
31663
+ }
31664
+ return SocialModule;
31665
+ }());
31666
+ SocialModule.decorators = [
31667
+ { type: i0.NgModule, args: [{
31668
+ imports: [
31669
+ i1$4.CommonModule,
31670
+ CoreModule,
31671
+ SharedModule,
31672
+ UserEventModule,
31673
+ JobModule,
31674
+ MessageModule,
31675
+ ],
31676
+ },] }
31677
+ ];
31678
+
30908
31679
  var Mutations = {
30909
- send: core.gql(templateObject_1$4 || (templateObject_1$4 = __makeTemplateObject(["mutation SendMessage($data: MessageVOInput){\n done: sendMessage(message: $data)\n }"], ["mutation SendMessage($data: MessageVOInput){\n done: sendMessage(message: $data)\n }"])))
31680
+ send: core.gql(templateObject_1$5 || (templateObject_1$5 = __makeTemplateObject(["mutation SendMessage($data: MessageVOInput){\n done: sendMessage(message: $data)\n }"], ["mutation SendMessage($data: MessageVOInput){\n done: sendMessage(message: $data)\n }"])))
30910
31681
  };
30911
31682
  var MessageService = /** @class */ (function (_super) {
30912
31683
  __extends(MessageService, _super);
@@ -30990,7 +31761,7 @@
30990
31761
  { type: i1$5.ToastController },
30991
31762
  { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30992
31763
  ]; };
30993
- var templateObject_1$4;
31764
+ var templateObject_1$5;
30994
31765
 
30995
31766
  var PersonFilter_1;
30996
31767
  // @dynamic
@@ -31049,7 +31820,7 @@
31049
31820
  ], exports.PersonFilter);
31050
31821
 
31051
31822
  var PersonFragments = {
31052
- person: core.gql(templateObject_1$5 || (templateObject_1$5 = __makeTemplateObject(["fragment PersonFragment on PersonVO {\n id\n firstName\n lastName\n email\n pubkey\n avatar\n statusId\n updateDate\n creationDate\n profiles\n username\n usernameExtranet\n department {\n id\n label\n name\n logo\n __typename\n }\n __typename\n }"], ["fragment PersonFragment on PersonVO {\n id\n firstName\n lastName\n email\n pubkey\n avatar\n statusId\n updateDate\n creationDate\n profiles\n username\n usernameExtranet\n department {\n id\n label\n name\n logo\n __typename\n }\n __typename\n }"])))
31823
+ person: core.gql(templateObject_1$6 || (templateObject_1$6 = __makeTemplateObject(["fragment PersonFragment on PersonVO {\n id\n firstName\n lastName\n email\n pubkey\n avatar\n statusId\n updateDate\n creationDate\n profiles\n username\n usernameExtranet\n department {\n id\n label\n name\n logo\n __typename\n }\n __typename\n }"], ["fragment PersonFragment on PersonVO {\n id\n firstName\n lastName\n email\n pubkey\n avatar\n statusId\n updateDate\n creationDate\n profiles\n username\n usernameExtranet\n department {\n id\n label\n name\n logo\n __typename\n }\n __typename\n }"])))
31053
31824
  };
31054
31825
  // Load persons query
31055
31826
  var PersonQueries = {
@@ -31189,7 +31960,7 @@
31189
31960
  { type: NetworkService },
31190
31961
  { type: EntitiesStorage }
31191
31962
  ]; };
31192
- var templateObject_1$5, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31963
+ var templateObject_1$6, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31193
31964
 
31194
31965
  var PersonValidatorService = /** @class */ (function () {
31195
31966
  function PersonValidatorService(formBuilder, accountValidatorService) {
@@ -31599,12 +32370,10 @@
31599
32370
  };
31600
32371
  AutocompleteTestPage.prototype.ngAfterViewInit = function () {
31601
32372
  var _this = this;
31602
- if (this.farEntityField) {
31603
- setTimeout(function () {
31604
- _this.farEntityField.suggestLengthThreshold = 2;
31605
- _this.farEntityField.reloadItems();
31606
- }, 2000);
31607
- }
32373
+ setTimeout(function () {
32374
+ _this.farEntityField.suggestLengthThreshold = 2;
32375
+ _this.farEntityField.reloadItems();
32376
+ }, 2000);
31608
32377
  setTimeout(function () { return _this.loadData(); }, 1000);
31609
32378
  };
31610
32379
  // Load the form with data
@@ -31711,7 +32480,7 @@
31711
32480
  AutocompleteTestPage.decorators = [
31712
32481
  { type: i0.Component, args: [{
31713
32482
  selector: 'app-autocomplete-test',
31714
- 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"
32483
+ 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"
31715
32484
  },] }
31716
32485
  ];
31717
32486
  AutocompleteTestPage.ctorParameters = function () { return [
@@ -31793,13 +32562,13 @@
31793
32562
  { type: i1.FormBuilder }
31794
32563
  ]; };
31795
32564
 
31796
- var moment$6 = momentImported__namespace;
32565
+ var moment$7 = momentImported__namespace;
31797
32566
  var SwipeTestPage = /** @class */ (function () {
31798
32567
  function SwipeTestPage(formBuilder, dateFormatPipe) {
31799
32568
  this.formBuilder = formBuilder;
31800
32569
  this.dateFormatPipe = dateFormatPipe;
31801
32570
  this.$dates = new rxjs.BehaviorSubject(undefined);
31802
- this._today = moment$6().startOf('day');
32571
+ this._today = moment$7().startOf('day');
31803
32572
  this.form = formBuilder.group({
31804
32573
  empty: [null, i1.Validators.required],
31805
32574
  date: [null, i1.Validators.compose([i1.Validators.required, SharedValidators.validDate])],
@@ -31813,7 +32582,7 @@
31813
32582
  var _this = this;
31814
32583
  var dates = [];
31815
32584
  for (var d = 0; d < 7; d++) {
31816
- dates[d] = moment$6(this._today).add(d - 3, 'day');
32585
+ dates[d] = moment$7(this._today).add(d - 3, 'day');
31817
32586
  }
31818
32587
  this.$dates.next(dates);
31819
32588
  this.loadData();
@@ -31860,7 +32629,7 @@
31860
32629
  { type: DateFormatPipe }
31861
32630
  ]; };
31862
32631
 
31863
- var moment$7 = momentImported__namespace;
32632
+ var moment$8 = momentImported__namespace;
31864
32633
  var DateTimeTestPage = /** @class */ (function () {
31865
32634
  function DateTimeTestPage(platform, formBuilder, cd) {
31866
32635
  this.platform = platform;
@@ -31896,7 +32665,7 @@
31896
32665
  var now, data;
31897
32666
  var _this = this;
31898
32667
  return __generator(this, function (_a) {
31899
- now = moment$7();
32668
+ now = moment$8();
31900
32669
  data = {
31901
32670
  empty: null,
31902
32671
  emptyRequired: null,
@@ -32174,7 +32943,7 @@
32174
32943
  { type: i1.FormBuilder }
32175
32944
  ]; };
32176
32945
 
32177
- var moment$8 = momentImported__namespace;
32946
+ var moment$9 = momentImported__namespace;
32178
32947
  var DateTestPage = /** @class */ (function () {
32179
32948
  function DateTestPage(formBuilder, cd) {
32180
32949
  this.formBuilder = formBuilder;
@@ -32211,7 +32980,7 @@
32211
32980
  var now, nowAtMahe, data;
32212
32981
  var _this = this;
32213
32982
  return __generator(this, function (_a) {
32214
- now = moment$8();
32983
+ now = moment$9();
32215
32984
  nowAtMahe = now.clone().tz(this.timezone).startOf('day');
32216
32985
  data = {
32217
32986
  empty: null,
@@ -33050,6 +33819,7 @@
33050
33819
  exports.APP_MENU_ITEMS = APP_MENU_ITEMS;
33051
33820
  exports.APP_TESTING_PAGES = APP_TESTING_PAGES;
33052
33821
  exports.AboutModal = AboutModal;
33822
+ exports.AbstractUserEventService = AbstractUserEventService;
33053
33823
  exports.AccountPage = AccountPage;
33054
33824
  exports.AccountService = AccountService;
33055
33825
  exports.AccountToStringPipe = AccountToStringPipe;
@@ -33176,6 +33946,11 @@
33176
33946
  exports.IsNotNilOrBlankPipe = IsNotNilOrBlankPipe;
33177
33947
  exports.IsNotOnFieldModePipe = IsNotOnFieldModePipe;
33178
33948
  exports.IsOnFieldModePipe = IsOnFieldModePipe;
33949
+ exports.Job = Job;
33950
+ exports.JobModule = JobModule;
33951
+ exports.JobProgressionComponent = JobProgressionComponent;
33952
+ exports.JobProgressionService = JobProgressionService;
33953
+ exports.JobProgressionServiceToken = JobProgressionServiceToken;
33179
33954
  exports.JobUtils = JobUtils;
33180
33955
  exports.KEYBOARD_HIDE_DELAY_MS = KEYBOARD_HIDE_DELAY_MS;
33181
33956
  exports.LAT_LONG_DEFAULT_MAX_DECIMALS = LAT_LONG_DEFAULT_MAX_DECIMALS;
@@ -33213,6 +33988,7 @@
33213
33988
  exports.MenuService = MenuService;
33214
33989
  exports.MessageForm = MessageForm;
33215
33990
  exports.MessageModal = MessageModal;
33991
+ exports.MessageModule = MessageModule;
33216
33992
  exports.MessageService = MessageService;
33217
33993
  exports.MessageTypeList = MessageTypeList;
33218
33994
  exports.MessageTypes = MessageTypes;
@@ -33280,6 +34056,7 @@
33280
34056
  exports.SharedValidators = SharedValidators;
33281
34057
  exports.SocialErrorCodes = SocialErrorCodes;
33282
34058
  exports.SocialModule = SocialModule;
34059
+ exports.SocialModuleOptionsToken = SocialModuleOptionsToken;
33283
34060
  exports.StartableService = StartableService;
33284
34061
  exports.StatusById = StatusById;
33285
34062
  exports.StatusIds = StatusIds;
@@ -33308,7 +34085,10 @@
33308
34085
  exports.UploadFileTestingPage = UploadFileTestingPage;
33309
34086
  exports.UriUtils = UriUtils;
33310
34087
  exports.UserEventFragments = UserEventFragments;
34088
+ exports.UserEventModule = UserEventModule;
34089
+ exports.UserEventNotificationComponent = UserEventNotificationComponent;
33311
34090
  exports.UserEventService = UserEventService;
34091
+ exports.UserEventServiceToken = UserEventServiceToken;
33312
34092
  exports.UserEventTypes = UserEventTypes;
33313
34093
  exports.UserEventsTable = UserEventsTable;
33314
34094
  exports.UsersPage = UsersPage;
@@ -33473,11 +34253,13 @@
33473
34253
  exports.ɵh = LocalSettingsValidatorService;
33474
34254
  exports.ɵi = AppUpdateOfflineModeCard;
33475
34255
  exports.ɵj = AppIconComponent;
33476
- exports.ɵk = DateTestPage;
33477
- exports.ɵl = NumpadTestPage;
33478
- exports.ɵm = MatBadgeIconTestPage;
33479
- exports.ɵn = ToastTestingModule;
33480
- exports.ɵo = ToastTestingPage;
34256
+ exports.ɵk = UserEventNotificationList;
34257
+ exports.ɵl = JobProgressionList;
34258
+ exports.ɵm = DateTestPage;
34259
+ exports.ɵn = NumpadTestPage;
34260
+ exports.ɵo = MatBadgeIconTestPage;
34261
+ exports.ɵp = ToastTestingModule;
34262
+ exports.ɵq = ToastTestingPage;
33481
34263
 
33482
34264
  Object.defineProperty(exports, '__esModule', { value: true });
33483
34265