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

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 +1100 -319
  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 +9 -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 +54 -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 +95 -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 +294 -166
  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 +931 -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 +80 -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
@@ -24386,6 +24386,9 @@
24386
24386
  this._subscription = new rxjs.Subscription();
24387
24387
  this.loading = true;
24388
24388
  this.isLogin = false;
24389
+ // showUserEventNotification: boolean;
24390
+ // showJobProgression: boolean;
24391
+ // jobProgressionOptions: JobProgressionOptions;
24389
24392
  this.$items = new rxjs.BehaviorSubject(undefined);
24390
24393
  this.id = 'menu';
24391
24394
  this.menuId = 'left';
@@ -24410,6 +24413,10 @@
24410
24413
  case 2:
24411
24414
  // Wait platform started
24412
24415
  _b.sent();
24416
+ // Init social options
24417
+ // this.showUserEventNotification = toBoolean(this.socialModuleOptions?.showUserEventNotification, false);
24418
+ // this.showJobProgression = toBoolean(this.socialModuleOptions?.showJobProgression, false);
24419
+ // this.jobProgressionOptions = this.socialModuleOptions?.jobProgressionOptions;
24413
24420
  // Listen to menu service event
24414
24421
  this.menuService.splitPaneWhen
24415
24422
  .subscribe(function (value) { return _this.setSplitPaneWhen(value); });
@@ -24749,7 +24756,7 @@
24749
24756
  MenuComponent.decorators = [
24750
24757
  { type: i0.Component, args: [{
24751
24758
  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",
24759
+ 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
24760
  animations: [fadeInAnimation],
24754
24761
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
24755
24762
  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 +24824,7 @@
24817
24824
  this.icon = value.icon;
24818
24825
  this.matIcon = value.matIcon;
24819
24826
  this.matSvgIcon = value.matSvgIcon;
24827
+ this.color = value.color;
24820
24828
  },
24821
24829
  enumerable: false,
24822
24830
  configurable: true
@@ -24827,7 +24835,7 @@
24827
24835
  AppIconComponent.decorators = [
24828
24836
  { type: i0.Component, args: [{
24829
24837
  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"
24838
+ 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
24839
  },] }
24832
24840
  ];
24833
24841
  AppIconComponent.propDecorators = {
@@ -24835,6 +24843,8 @@
24835
24843
  matIcon: [{ type: i0.Input }],
24836
24844
  matSvgIcon: [{ type: i0.Input }],
24837
24845
  color: [{ type: i0.Input }],
24846
+ height: [{ type: i0.Input }],
24847
+ width: [{ type: i0.Input }],
24838
24848
  ref: [{ type: i0.Input }]
24839
24849
  };
24840
24850
 
@@ -26600,7 +26610,7 @@
26600
26610
  .then(function () { return _this.editRowById(event, row.id, { focusColumn: _this.lastUserColumn }); });
26601
26611
  return true;
26602
26612
  }
26603
- // Edit previous row
26613
+ // Edit next row
26604
26614
  this.editRow(event, row, { focusColumn: this.lastUserColumn });
26605
26615
  return true;
26606
26616
  };
@@ -26628,7 +26638,8 @@
26628
26638
  if (id < 0)
26629
26639
  return [2 /*return*/];
26630
26640
  if (!(id >= this.visibleRowCount)) return [3 /*break*/, 1];
26631
- this.addRow(event, undefined, opts);
26641
+ this.focusColumn = opts && opts.focusColumn || this.firstUserColumn;
26642
+ this.addRow(event);
26632
26643
  return [3 /*break*/, 3];
26633
26644
  case 1: return [4 /*yield*/, this.dataSource.getRow(id)];
26634
26645
  case 2:
@@ -26706,7 +26717,7 @@
26706
26717
  this.cancelExistingRow(event, row, opts);
26707
26718
  }
26708
26719
  };
26709
- AppTable.prototype.addRow = function (event, insertAt, opts) {
26720
+ AppTable.prototype.addRow = function (event, insertAt) {
26710
26721
  if (this.debug)
26711
26722
  console.debug('[table] Asking for new row...');
26712
26723
  if (!this._enabled)
@@ -26721,7 +26732,7 @@
26721
26732
  return false;
26722
26733
  }
26723
26734
  // Add new row
26724
- this.addRowToTable(insertAt, opts);
26735
+ this.addRowToTable(insertAt);
26725
26736
  return true;
26726
26737
  };
26727
26738
  AppTable.prototype.save = function (opts) {
@@ -26866,7 +26877,7 @@
26866
26877
  * @param event
26867
26878
  * @param row
26868
26879
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
26869
- * And to force deletion even if table is busy
26880
+ * Use skipIfLoading=false to force deletion even if table is busy
26870
26881
  */
26871
26882
  AppTable.prototype.deleteRow = function (event, row, opts) {
26872
26883
  return __awaiter(this, void 0, void 0, function () {
@@ -26886,7 +26897,7 @@
26886
26897
  * @param event
26887
26898
  * @param rows
26888
26899
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
26889
- * And to force deletion even if table is busy
26900
+ * Use skipIfLoading=false to force deletion even if table is busy
26890
26901
  */
26891
26902
  AppTable.prototype.deleteRows = function (event, rows, opts) {
26892
26903
  var _a;
@@ -26904,8 +26915,8 @@
26904
26915
  event === null || event === void 0 ? void 0 : event.preventDefault();
26905
26916
  if (!this._enabled || isEmptyArray(rows))
26906
26917
  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');
26918
+ if (this.loading && (!opts || opts.skipIfLoading !== false)) {
26919
+ console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.skipLoading = false to force deletion');
26909
26920
  return [2 /*return*/, 0]; // Skip if loading
26910
26921
  }
26911
26922
  // Make sure to keep newly created row
@@ -27544,13 +27555,12 @@
27544
27555
  //if (this.debug) console.debug("[table] id = " + id);
27545
27556
  return id;
27546
27557
  };
27547
- AppTable.prototype.addRowToTable = function (insertAt, opts) {
27558
+ AppTable.prototype.addRowToTable = function (insertAt) {
27548
27559
  return __awaiter(this, void 0, void 0, function () {
27549
27560
  return __generator(this, function (_e) {
27550
27561
  switch (_e.label) {
27551
27562
  case 0:
27552
27563
  this.focusFirstColumn = true;
27553
- this.focusColumn = (opts === null || opts === void 0 ? void 0 : opts.focusColumn) || this.firstUserColumn;
27554
27564
  return [4 /*yield*/, this._dataSource.asyncCreateNew(insertAt)];
27555
27565
  case 1:
27556
27566
  _e.sent();
@@ -30053,7 +30063,10 @@
30053
30063
  var SocialErrorCodes = {
30054
30064
  LOAD_USER_EVENTS_ERROR: 50000,
30055
30065
  SAVE_USER_EVENT_ERROR: 50001,
30056
- SEND_MESSAGE_ERROR: 50003
30066
+ COUNT_USER_EVENT_ERROR: 50002,
30067
+ SEND_MESSAGE_ERROR: 50003,
30068
+ SUBSCRIBE_USER_EVENTS_ERROR: 50005,
30069
+ SUBSCRIBE_JOB_PROGRESSION_ERROR: 50010
30057
30070
  };
30058
30071
 
30059
30072
  var UserEvent_1;
@@ -30069,16 +30082,23 @@
30069
30082
  }
30070
30083
  UserEvent.prototype.asObject = function (opts) {
30071
30084
  var target = _super.prototype.asObject.call(this, opts);
30085
+ target.creationDate = toDateISOString(this.creationDate);
30086
+ target.readDate = toDateISOString(this.readDate);
30072
30087
  // Serialize content
30073
30088
  if (typeof target.content === 'object') {
30074
30089
  target.content = JSON.stringify(target.content);
30075
30090
  }
30091
+ delete target.avatar;
30092
+ delete target.avatarIcon;
30093
+ delete target.icon;
30094
+ delete target.actions;
30076
30095
  return target;
30077
30096
  };
30078
30097
  UserEvent.prototype.fromObject = function (source) {
30079
30098
  Object.assign(this, source); // Copy all properties
30080
30099
  _super.prototype.fromObject.call(this, source);
30081
30100
  this.creationDate = fromDateISOString(source.creationDate);
30101
+ this.readDate = fromDateISOString(source.readDate);
30082
30102
  try {
30083
30103
  // Deserialize content
30084
30104
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -30098,36 +30118,48 @@
30098
30118
  exports.UserEvent = UserEvent_1 = __decorate([
30099
30119
  EntityClass({ typename: 'UserEventVO' })
30100
30120
  ], 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
30121
  // @dynamic
30109
30122
  exports.UserEventFilter = /** @class */ (function (_super) {
30110
30123
  __extends(UserEventFilter, _super);
30111
30124
  function UserEventFilter() {
30112
30125
  var _this = _super.apply(this, __spread(arguments)) || this;
30113
- _this.issuer = null;
30114
- _this.recipient = null;
30126
+ _this.types = [];
30127
+ _this.levels = [];
30128
+ _this.issuers = [];
30129
+ _this.recipients = [];
30130
+ _this.startDate = null;
30131
+ _this.excludeRead = false;
30115
30132
  return _this;
30116
30133
  }
30117
30134
  UserEventFilter.prototype.fromObject = function (source, opts) {
30118
30135
  _super.prototype.fromObject.call(this, source, opts);
30119
- this.issuer = source.issuer;
30120
- this.recipient = source.recipient;
30136
+ this.types = source.types || [];
30137
+ this.levels = source.levels || [];
30138
+ this.issuers = source.issuers || [];
30139
+ this.recipients = source.recipients || [];
30140
+ this.startDate = fromDateISOString(source.startDate);
30141
+ this.excludeRead = source.excludeRead || false;
30121
30142
  };
30122
30143
  UserEventFilter.prototype.buildFilter = function () {
30123
30144
  var _this = this;
30124
30145
  var filterFns = _super.prototype.buildFilter.call(this);
30125
- // issuer
30126
- if (this.issuer) {
30127
- filterFns.push(function (t) { return (t.issuer === _this.issuer); });
30146
+ if (isNotEmptyArray(this.types)) {
30147
+ filterFns.push(function (t) { return _this.types.includes(t.type); });
30148
+ }
30149
+ if (isNotEmptyArray(this.levels)) {
30150
+ filterFns.push(function (t) { return _this.levels.includes(t.level); });
30151
+ }
30152
+ if (isNotEmptyArray(this.issuers)) {
30153
+ filterFns.push(function (t) { return _this.issuers.includes(t.issuer); });
30154
+ }
30155
+ if (isNotEmptyArray(this.recipients)) {
30156
+ filterFns.push(function (t) { return _this.recipients.includes(t.recipient); });
30128
30157
  }
30129
- if (this.recipient) {
30130
- filterFns.push(function (t) { return (t.recipient === _this.recipient); });
30158
+ if (isNotNil(this.startDate)) {
30159
+ filterFns.push(function (t) { return _this.startDate.isSameOrBefore(t.creationDate); });
30160
+ }
30161
+ if (this.excludeRead === true) {
30162
+ filterFns.push(function (t) { return isNil(t.readSignature); }); // todo or t.signature ?
30131
30163
  }
30132
30164
  return filterFns;
30133
30165
  };
@@ -30136,120 +30168,274 @@
30136
30168
  exports.UserEventFilter = __decorate([
30137
30169
  EntityClass({ typename: 'UserEventFilterVO' })
30138
30170
  ], 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) {
30171
+
30172
+ var UserEventFragments = {
30173
+ 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 }"]))),
30174
+ 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 }"])))
30175
+ };
30176
+ var templateObject_1$2, templateObject_2$2;
30177
+
30178
+ var moment$6 = momentImported__namespace;
30179
+ var UserEventServiceToken = new i0.InjectionToken('UserEventService');
30180
+ var AbstractUserEventService = /** @class */ (function (_super) {
30181
+ __extends(AbstractUserEventService, _super);
30182
+ function AbstractUserEventService(graphql, accountService, network, translate, toastController, queries, mutations, subscriptions, environment) {
30146
30183
  var _this = _super.call(this, graphql, environment) || this;
30147
30184
  _this.graphql = graphql;
30148
30185
  _this.accountService = accountService;
30149
30186
  _this.network = network;
30150
30187
  _this.translate = translate;
30151
30188
  _this.toastController = toastController;
30189
+ _this.queries = queries;
30190
+ _this.mutations = mutations;
30191
+ _this.subscriptions = subscriptions;
30152
30192
  _this.environment = environment;
30153
- _this._userEventActions = [];
30193
+ _this._count$ = new rxjs.BehaviorSubject(0);
30194
+ _this._subscriptions = new rxjs.Subscription();
30195
+ _this.listeners = [];
30196
+ _this._logPrefix = '[user-event-service] ';
30154
30197
  // For DEV only
30155
- _this._debug = environment && !environment.production;
30198
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
30199
+ // listen login/logout
30200
+ _this._subscriptions.add(accountService.onLogin.subscribe(function () { return __awaiter(_this, void 0, void 0, function () {
30201
+ var count;
30202
+ return __generator(this, function (_b) {
30203
+ switch (_b.label) {
30204
+ case 0: return [4 /*yield*/, this.count(this.defaultFilter())];
30205
+ case 1:
30206
+ count = _b.sent();
30207
+ if (count && this._debug) {
30208
+ console.debug(this._logPrefix + "Received " + count + " unread notifications");
30209
+ }
30210
+ this._count$.next(count);
30211
+ return [2 /*return*/];
30212
+ }
30213
+ });
30214
+ }); }));
30156
30215
  return _this;
30157
30216
  }
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) {
30217
+ Object.defineProperty(AbstractUserEventService.prototype, "userEventCount", {
30218
+ get: function () {
30219
+ return this._count$.asObservable();
30220
+ },
30221
+ enumerable: false,
30222
+ configurable: true
30223
+ });
30224
+ AbstractUserEventService.prototype.ngOnDestroy = function () {
30225
+ this._subscriptions.unsubscribe();
30226
+ };
30227
+ AbstractUserEventService.prototype.watchAll = function (offset, size, sortBy, sortDirection, filter, options) {
30169
30228
  return this.watchPage({ offset: offset, size: size, sortBy: sortBy, sortDirection: sortDirection }, filter, options);
30170
30229
  };
30171
- UserEventService.prototype.watchPage = function (page, filter, options) {
30230
+ AbstractUserEventService.prototype.watchPage = function (page, filter, options) {
30231
+ var _this = this;
30232
+ var _a;
30172
30233
  var now = this._debug && Date.now();
30173
30234
  //if (this._debug)
30174
- console.debug('[user-event-service] Loading user events...', filter);
30235
+ console.debug(this._logPrefix + "Loading user events...", filter);
30175
30236
  filter = this.asFilter(filter);
30176
30237
  // 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) {
30238
+ if (isEmptyArray(filter.recipients) || !this.accountService.isAdmin()) {
30239
+ var recipient = this.defaultRecipient();
30240
+ if (!((_a = filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
30180
30241
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
30181
- filter.recipient = recipient;
30242
+ filter.recipients = [recipient];
30182
30243
  }
30183
30244
  }
30184
- var withContent = options && options.withContent === true;
30245
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30185
30246
  return this.mutableWatchQuery({
30186
30247
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
30187
- query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
30248
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30188
30249
  variables: {
30189
- page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
30250
+ page: Object.assign({ sortBy: 'updateDate', sortDirection: 'desc' }, page),
30190
30251
  filter: filter && filter.asPodObject()
30191
30252
  },
30192
30253
  arrayFieldName: 'data',
30193
30254
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
30194
- fetchPolicy: options && options.fetchPolicy || undefined
30255
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || "cache-first"
30195
30256
  })
30196
30257
  .pipe(operators.map(function (res) {
30197
- var data = res && (res.data || []).map(exports.UserEvent.fromObject);
30258
+ var data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(_this.processUserEvent);
30198
30259
  if (now) {
30199
- console.debug("[user-event-service] " + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30260
+ console.debug("" + _this._logPrefix + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30200
30261
  now = null;
30201
30262
  }
30263
+ var unreadCount = _this.unreadEvents(data);
30202
30264
  return {
30203
30265
  data: data,
30204
- total: res && toNumber(res.total, data.length)
30266
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
30205
30267
  };
30206
30268
  }));
30207
30269
  };
30208
- UserEventService.prototype.saveAll = function (data, options) {
30270
+ AbstractUserEventService.prototype.add = function (entity) {
30271
+ // TODO set an id !!!!!!!!!!!!!!!!!!!!!!!!!
30272
+ entity = this.processUserEvent(entity);
30273
+ var withContent = !!entity.content;
30274
+ // Add user event locally
30275
+ this.insertIntoMutableCachedQueries(this.graphql.cache, {
30276
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30277
+ data: entity
30278
+ });
30279
+ // Update count
30280
+ this._count$.next(this._count$.value + 1);
30281
+ };
30282
+ AbstractUserEventService.prototype.count = function (filter, options) {
30283
+ var _a;
30284
+ return __awaiter(this, void 0, void 0, function () {
30285
+ var res;
30286
+ return __generator(this, function (_b) {
30287
+ switch (_b.label) {
30288
+ case 0:
30289
+ if (!((_a = this.queries) === null || _a === void 0 ? void 0 : _a.count)) {
30290
+ console.warn(this._logPrefix + "Query 'count' not provided, skip.");
30291
+ return [2 /*return*/, undefined];
30292
+ }
30293
+ if (!filter)
30294
+ throw new Error("Missing argument 'filter'");
30295
+ filter = this.asFilter(filter);
30296
+ if (this._debug)
30297
+ console.debug(this._logPrefix + "Counting user events with filter:", filter);
30298
+ return [4 /*yield*/, this.graphql.query({
30299
+ query: this.queries.count,
30300
+ variables: {
30301
+ filter: filter.asPodObject()
30302
+ },
30303
+ error: { code: SocialErrorCodes.COUNT_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.COUNT_USER_EVENT_ERROR' },
30304
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'network-only'
30305
+ })];
30306
+ case 1:
30307
+ res = _b.sent();
30308
+ return [2 /*return*/, res.total];
30309
+ }
30310
+ });
30311
+ });
30312
+ };
30313
+ AbstractUserEventService.prototype.listenChanges = function (filter, options) {
30209
30314
  var _this = this;
30210
- return Promise.all(data
30211
- .map(function (entity) { return _this.save(entity, options); }));
30315
+ var _a;
30316
+ if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
30317
+ console.warn(this._logPrefix + "Subscription query 'listenChanges' not provided, skip.");
30318
+ return rxjs.of();
30319
+ }
30320
+ if (!filter)
30321
+ throw new Error("Missing argument 'filter'");
30322
+ filter = this.asFilter(filter);
30323
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30324
+ if (this._debug)
30325
+ console.debug(this._logPrefix + "[WS] Listening changes for user events with filter:", filter);
30326
+ return this.graphql.subscribe({
30327
+ query: this.subscriptions.listenChanges,
30328
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
30329
+ variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
30330
+ error: {
30331
+ code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
30332
+ message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
30333
+ }
30334
+ }).pipe(operators.map(function (_b) {
30335
+ var data = _b.data;
30336
+ if (data && _this._debug)
30337
+ console.debug(_this._logPrefix + "Received new user events:", data);
30338
+ var updatedData = data === null || data === void 0 ? void 0 : data.map(_this.processUserEvent);
30339
+ // Update cache
30340
+ _this.insertIntoMutableCachedQueries(_this.graphql.cache, {
30341
+ query: withContent ? _this.queries.loadAllWithContent : _this.queries.loadAll,
30342
+ data: updatedData
30343
+ });
30344
+ // update count
30345
+ _this._count$.next(_this.unreadEvents(updatedData));
30346
+ return updatedData;
30347
+ }));
30212
30348
  };
30213
- /**
30214
- * Save a userEvent entity
30215
- *
30216
- * @param entity
30217
- */
30218
- UserEventService.prototype.save = function (entity, options) {
30349
+ AbstractUserEventService.prototype.delete = function (entity) {
30350
+ return __awaiter(this, void 0, void 0, function () {
30351
+ return __generator(this, function (_b) {
30352
+ switch (_b.label) {
30353
+ case 0:
30354
+ if (!entity)
30355
+ return [2 /*return*/]; // skip
30356
+ return [4 /*yield*/, this.deleteAll([entity])];
30357
+ case 1:
30358
+ _b.sent();
30359
+ return [2 /*return*/];
30360
+ }
30361
+ });
30362
+ });
30363
+ };
30364
+ AbstractUserEventService.prototype.deleteAll = function (entities, opts) {
30365
+ return __awaiter(this, void 0, void 0, function () {
30366
+ var ids, now;
30367
+ var _this = this;
30368
+ return __generator(this, function (_b) {
30369
+ switch (_b.label) {
30370
+ case 0:
30371
+ ids = entities && entities
30372
+ .map(function (t) { return t.id; });
30373
+ if (isEmptyArray(ids))
30374
+ return [2 /*return*/]; // stop, if nothing else to do
30375
+ now = Date.now();
30376
+ if (this._debug)
30377
+ console.debug(this._logPrefix + "Deleting events... ids:", ids);
30378
+ return [4 /*yield*/, this.graphql.mutate({
30379
+ mutation: this.mutations.deleteByIds,
30380
+ variables: {
30381
+ ids: ids
30382
+ },
30383
+ update: function (proxy) {
30384
+ // Remove from caches
30385
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30386
+ query: _this.queries.loadAll,
30387
+ ids: ids
30388
+ });
30389
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30390
+ query: _this.queries.loadAllWithContent,
30391
+ ids: ids
30392
+ });
30393
+ if (_this._debug)
30394
+ console.debug(_this._logPrefix + "Events deleted in " + (Date.now() - now) + "ms");
30395
+ }
30396
+ })];
30397
+ case 1:
30398
+ _b.sent();
30399
+ return [2 /*return*/];
30400
+ }
30401
+ });
30402
+ });
30403
+ };
30404
+ AbstractUserEventService.prototype.save = function (entity, options) {
30219
30405
  return __awaiter(this, void 0, void 0, function () {
30220
30406
  var isNew, json, now;
30221
30407
  var _this = this;
30222
- return __generator(this, function (_a) {
30223
- switch (_a.label) {
30408
+ return __generator(this, function (_b) {
30409
+ switch (_b.label) {
30224
30410
  case 0:
30225
30411
  this.fillDefaultProperties(entity);
30226
30412
  isNew = isNil(entity.id);
30227
30413
  json = entity.asObject();
30228
30414
  now = Date.now();
30229
30415
  if (this._debug)
30230
- console.debug("[user-event-service] Saving user event...", json);
30416
+ console.debug(this._logPrefix + "Saving user event...", json);
30231
30417
  return [4 /*yield*/, this.graphql.mutate({
30232
- mutation: SaveQuery,
30418
+ mutation: this.mutations.save,
30233
30419
  variables: {
30234
30420
  data: json
30235
30421
  },
30236
30422
  error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
30237
- update: function (proxy, _a) {
30238
- var data = _a.data;
30423
+ update: function (proxy, _b) {
30424
+ var data = _b.data;
30239
30425
  // Update entity
30240
30426
  var savedEntity = data && data.data;
30241
30427
  if (savedEntity) {
30242
30428
  if (_this._debug)
30243
- console.debug("[user-event-service] User event saved in " + (Date.now() - now) + "ms", entity);
30429
+ console.debug(_this._logPrefix + "User event saved in " + (Date.now() - now) + "ms", entity);
30244
30430
  _this.copyIdAndUpdateDate(savedEntity, entity);
30245
30431
  // Add to cache
30246
30432
  if (isNew) {
30247
30433
  _this.insertIntoMutableCachedQueries(proxy, {
30248
- query: LoadAllQuery,
30434
+ query: _this.queries.loadAll,
30249
30435
  data: Object.assign(Object.assign({}, savedEntity), { content: null })
30250
30436
  });
30251
30437
  _this.insertIntoMutableCachedQueries(proxy, {
30252
- query: LoadAllWithContentQuery,
30438
+ query: _this.queries.loadAllWithContent,
30253
30439
  data: savedEntity
30254
30440
  });
30255
30441
  }
@@ -30257,93 +30443,186 @@
30257
30443
  }
30258
30444
  })];
30259
30445
  case 1:
30260
- _a.sent();
30446
+ _b.sent();
30261
30447
  return [2 /*return*/, entity];
30262
30448
  }
30263
30449
  });
30264
30450
  });
30265
30451
  };
30266
- /**
30267
- * Save many trips
30268
- *
30269
- * @param entities
30270
- * @param opts
30271
- */
30272
- UserEventService.prototype.deleteAll = function (entities, opts) {
30452
+ AbstractUserEventService.prototype.saveAll = function (data, opts) {
30453
+ var _this = this;
30454
+ return Promise.all(data
30455
+ .map(function (entity) { return _this.save(entity, opts); }));
30456
+ };
30457
+ AbstractUserEventService.prototype.markAsRead = function (entity) {
30273
30458
  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) {
30459
+ var onReadListeners, onReadListeners_1, onReadListeners_1_1, listener, e_1_1;
30460
+ var e_1, _b;
30461
+ return __generator(this, function (_c) {
30462
+ switch (_c.label) {
30278
30463
  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
- })];
30464
+ onReadListeners = (this.listeners || []).filter(function (listener) { return !!listener.onRead; }).filter(function (listener) { return listener.accept(entity); });
30465
+ if (!onReadListeners.length) return [3 /*break*/, 9];
30466
+ _c.label = 1;
30305
30467
  case 1:
30306
- _a.sent();
30307
- return [2 /*return*/];
30468
+ _c.trys.push([1, 6, 7, 8]);
30469
+ onReadListeners_1 = __values(onReadListeners), onReadListeners_1_1 = onReadListeners_1.next();
30470
+ _c.label = 2;
30471
+ case 2:
30472
+ if (!!onReadListeners_1_1.done) return [3 /*break*/, 5];
30473
+ listener = onReadListeners_1_1.value;
30474
+ return [4 /*yield*/, listener.onRead(entity)];
30475
+ case 3:
30476
+ _c.sent();
30477
+ _c.label = 4;
30478
+ case 4:
30479
+ onReadListeners_1_1 = onReadListeners_1.next();
30480
+ return [3 /*break*/, 2];
30481
+ case 5: return [3 /*break*/, 8];
30482
+ case 6:
30483
+ e_1_1 = _c.sent();
30484
+ e_1 = { error: e_1_1 };
30485
+ return [3 /*break*/, 8];
30486
+ case 7:
30487
+ try {
30488
+ if (onReadListeners_1_1 && !onReadListeners_1_1.done && (_b = onReadListeners_1.return)) _b.call(onReadListeners_1);
30489
+ }
30490
+ finally { if (e_1) throw e_1.error; }
30491
+ return [7 /*endfinally*/];
30492
+ case 8: return [3 /*break*/, 11];
30493
+ case 9:
30494
+ // Use default
30495
+ return [4 /*yield*/, this.defaultMarkAsRead(entity)];
30496
+ case 10:
30497
+ // Use default
30498
+ _c.sent();
30499
+ _c.label = 11;
30500
+ case 11: return [2 /*return*/];
30308
30501
  }
30309
30502
  });
30310
30503
  });
30311
30504
  };
30312
- /**
30313
- * Delete userEvent entities
30314
- */
30315
- UserEventService.prototype.delete = function (data) {
30505
+ AbstractUserEventService.prototype.registerListener = function (listener) {
30506
+ if (!this.listeners)
30507
+ this.listeners = [];
30508
+ this.listeners.push(listener);
30509
+ };
30510
+ /* -- protected methods -- */
30511
+ AbstractUserEventService.prototype.processUserEvent = function (source) {
30512
+ var e_2, _b;
30513
+ // Convert json source to IUserEvent
30514
+ var target = this.fromObject(source);
30515
+ // Get listeners
30516
+ var listeners = (this.listeners || []).filter(function (listener) { return listener.onReceived; }).filter(function (listener) { return listener.accept(target); });
30517
+ try {
30518
+ for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
30519
+ var listener = listeners_1_1.value;
30520
+ if (target) {
30521
+ target = listener.onReceived(target);
30522
+ }
30523
+ else {
30524
+ if (this._debug)
30525
+ console.debug(this._logPrefix + "Event has been rejected by a listener", source);
30526
+ break;
30527
+ }
30528
+ }
30529
+ }
30530
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
30531
+ finally {
30532
+ try {
30533
+ if (listeners_1_1 && !listeners_1_1.done && (_b = listeners_1.return)) _b.call(listeners_1);
30534
+ }
30535
+ finally { if (e_2) throw e_2.error; }
30536
+ }
30537
+ return target;
30538
+ };
30539
+ AbstractUserEventService.prototype.defaultMarkAsRead = function (userEvent) {
30316
30540
  return __awaiter(this, void 0, void 0, function () {
30317
- return __generator(this, function (_a) {
30318
- switch (_a.label) {
30541
+ return __generator(this, function (_b) {
30542
+ switch (_b.label) {
30319
30543
  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*/];
30544
+ if (!userEvent)
30545
+ throw new Error(this._logPrefix + "Invalid event to save");
30546
+ // set read date
30547
+ userEvent.readDate = moment$6();
30548
+ if (!(!userEvent.id || userEvent.id < 0)) return [3 /*break*/, 1];
30549
+ if (this._debug)
30550
+ console.debug(this._logPrefix + "Save local user event");
30551
+ return [3 /*break*/, 3];
30552
+ case 1: return [4 /*yield*/, this.save(userEvent)];
30553
+ case 2:
30554
+ _b.sent();
30555
+ _b.label = 3;
30556
+ case 3: return [2 /*return*/];
30326
30557
  }
30327
30558
  });
30328
30559
  });
30329
30560
  };
30330
- UserEventService.prototype.listenChanges = function (id, options) {
30331
- // TODO
30332
- console.warn('TODO: implement listen changes on user events');
30333
- return rxjs.of();
30561
+ AbstractUserEventService.prototype.defaultFilter = function () {
30562
+ // By default
30563
+ return {
30564
+ recipients: [this.defaultRecipient()]
30565
+ };
30566
+ };
30567
+ AbstractUserEventService.prototype.defaultRecipient = function () {
30568
+ return this.accountService.person.pubkey;
30569
+ };
30570
+ AbstractUserEventService.prototype.fillDefaultProperties = function (entity) {
30334
30571
  };
30335
- UserEventService.prototype.registerAction = function (definition) {
30336
- console.info("[user-event-service] Registering action " + definition.name + " for " + definition.__typename);
30337
- this._userEventActions.push(definition);
30572
+ AbstractUserEventService.prototype.unreadEvents = function (events) {
30573
+ // default calculation on unread events from a list
30574
+ if (isEmptyArray(events))
30575
+ return undefined;
30576
+ var lastReadDate = events
30577
+ .filter(function (event) { return isNotNil(event.readDate); })
30578
+ .reduce(function (lastDate, event) { return DateUtils.max(lastDate, event.readDate); }, undefined);
30579
+ return events
30580
+ .filter(function (event) { return event.creationDate.isSameOrAfter(lastReadDate); }).length;
30338
30581
  };
30339
- UserEventService.prototype.getActionsByTypename = function (typename) {
30340
- return this._userEventActions.filter(function (def) { return def.__typename === typename; });
30582
+ AbstractUserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30583
+ EntityUtils.copyIdAndUpdateDate(source, target);
30341
30584
  };
30585
+ return AbstractUserEventService;
30586
+ }(BaseGraphqlService));
30587
+ AbstractUserEventService.decorators = [
30588
+ { type: i0.Directive }
30589
+ ];
30590
+ AbstractUserEventService.ctorParameters = function () { return [
30591
+ { type: GraphqlService },
30592
+ { type: AccountService },
30593
+ { type: NetworkService },
30594
+ { type: i1$2.TranslateService },
30595
+ { type: i1$5.ToastController },
30596
+ { type: undefined },
30597
+ { type: undefined },
30598
+ { type: undefined },
30599
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30600
+ ]; };
30601
+ var userEventQueries = {
30602
+ 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),
30603
+ 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)
30604
+ };
30605
+ var userEventMutations = {
30606
+ 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 "]))),
30607
+ 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)
30608
+ };
30609
+ var UserEventService = /** @class */ (function (_super) {
30610
+ __extends(UserEventService, _super);
30611
+ function UserEventService(graphql, accountService, network, translate, toastController, environment) {
30612
+ var _this = _super.call(this, graphql, accountService, network, translate, toastController, userEventQueries, userEventMutations, undefined, environment) || this;
30613
+ _this.graphql = graphql;
30614
+ _this.accountService = accountService;
30615
+ _this.network = network;
30616
+ _this.translate = translate;
30617
+ _this.toastController = toastController;
30618
+ _this.environment = environment;
30619
+ return _this;
30620
+ }
30342
30621
  UserEventService.prototype.showToastErrorWithContext = function (opts) {
30343
30622
  return __awaiter(this, void 0, void 0, function () {
30344
30623
  var message, res, context, userEvent, err_1;
30345
- return __generator(this, function (_a) {
30346
- switch (_a.label) {
30624
+ return __generator(this, function (_b) {
30625
+ switch (_b.label) {
30347
30626
  case 0:
30348
30627
  message = opts.message || (opts.error && opts.error.message || opts.error);
30349
30628
  // Make sure message a string
@@ -30372,12 +30651,12 @@
30372
30651
  }]
30373
30652
  })];
30374
30653
  case 1:
30375
- res = _a.sent();
30654
+ res = _b.sent();
30376
30655
  if (!res || res.role !== 'send')
30377
30656
  return [2 /*return*/];
30378
- _a.label = 2;
30657
+ _b.label = 2;
30379
30658
  case 2:
30380
- _a.trys.push([2, 6, , 7]);
30659
+ _b.trys.push([2, 6, , 7]);
30381
30660
  if (this._debug)
30382
30661
  console.debug('Sending debug data...');
30383
30662
  context = opts && opts.context;
@@ -30387,15 +30666,15 @@
30387
30666
  if (!(context instanceof Promise)) return [3 /*break*/, 4];
30388
30667
  return [4 /*yield*/, context];
30389
30668
  case 3:
30390
- context = _a.sent();
30391
- _a.label = 4;
30669
+ context = _b.sent();
30670
+ _b.label = 4;
30392
30671
  case 4: return [4 /*yield*/, this.sendDataForDebug({
30393
30672
  message: message,
30394
30673
  error: opts.error || undefined,
30395
30674
  context: this.convertObjectToString(context)
30396
30675
  })];
30397
30676
  case 5:
30398
- userEvent = _a.sent();
30677
+ userEvent = _b.sent();
30399
30678
  console.info('Debug data successfully sent to admin', userEvent);
30400
30679
  this.showToast({
30401
30680
  type: 'info',
@@ -30404,7 +30683,7 @@
30404
30683
  });
30405
30684
  return [3 /*break*/, 7];
30406
30685
  case 6:
30407
- err_1 = _a.sent();
30686
+ err_1 = _b.sent();
30408
30687
  console.error('Error while sending debug data:', err_1);
30409
30688
  return [3 /*break*/, 7];
30410
30689
  case 7: return [2 /*return*/];
@@ -30414,13 +30693,16 @@
30414
30693
  };
30415
30694
  UserEventService.prototype.sendDataForDebug = function (data) {
30416
30695
  var userEvent = new exports.UserEvent();
30417
- userEvent.eventType = UserEventTypes.DEBUG_DATA;
30696
+ userEvent.type = UserEventTypes.DEBUG_DATA;
30418
30697
  userEvent.content = this.convertObjectToString(data);
30419
30698
  return this.save(userEvent);
30420
30699
  };
30421
30700
  UserEventService.prototype.asFilter = function (filter) {
30422
30701
  return exports.UserEventFilter.fromObject(filter);
30423
30702
  };
30703
+ UserEventService.prototype.fromObject = function (source) {
30704
+ return exports.UserEvent.fromObject(source);
30705
+ };
30424
30706
  /* -- protected methods -- */
30425
30707
  UserEventService.prototype.convertObjectToString = function (data) {
30426
30708
  if (typeof data === 'string') {
@@ -30438,13 +30720,13 @@
30438
30720
  };
30439
30721
  UserEventService.prototype.showToast = function (opts) {
30440
30722
  return __awaiter(this, void 0, void 0, function () {
30441
- return __generator(this, function (_a) {
30442
- switch (_a.label) {
30723
+ return __generator(this, function (_b) {
30724
+ switch (_b.label) {
30443
30725
  case 0:
30444
30726
  if (!this.toastController)
30445
30727
  throw new Error('Missing toastController in component\'s constructor');
30446
30728
  return [4 /*yield*/, Toasts.show(this.toastController, this.translate, opts)];
30447
- case 1: return [2 /*return*/, _a.sent()];
30729
+ case 1: return [2 /*return*/, _b.sent()];
30448
30730
  }
30449
30731
  });
30450
30732
  });
@@ -30455,14 +30737,10 @@
30455
30737
  // TODO: compute sign
30456
30738
  console.warn('TODO: sign user event before sending');
30457
30739
  };
30458
- UserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30459
- EntityUtils.copyIdAndUpdateDate(source, target);
30460
- };
30461
30740
  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" });
30741
+ }(AbstractUserEventService));
30464
30742
  UserEventService.decorators = [
30465
- { type: i0.Injectable, args: [{ providedIn: 'root' },] }
30743
+ { type: i0.Injectable }
30466
30744
  ];
30467
30745
  UserEventService.ctorParameters = function () { return [
30468
30746
  { type: GraphqlService },
@@ -30476,7 +30754,7 @@
30476
30754
 
30477
30755
  var ICONS_MAP = {
30478
30756
  DEBUG_DATA: { matIcon: 'bug_report' },
30479
- INBOX_MESSAGE: { matIcon: 'mail' },
30757
+ INBOX_MESSAGE: { matIcon: 'mail' }
30480
30758
  };
30481
30759
  // TODO: refactor with a registration done by data service:
30482
30760
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -30544,7 +30822,7 @@
30544
30822
  }
30545
30823
  }));
30546
30824
  var filter = this.filter || new exports.UserEventFilter();
30547
- filter.recipient = this.recipient;
30825
+ filter.recipients = [this.recipient];
30548
30826
  this.setFilter(filter, { emitEvent: true });
30549
30827
  };
30550
30828
  UserEventsTable.prototype.start = function () {
@@ -30566,17 +30844,17 @@
30566
30844
  });
30567
30845
  };
30568
30846
  UserEventsTable.prototype.getIcon = function (source) {
30569
- return ICONS_MAP[source.eventType];
30847
+ return ICONS_MAP[source.type];
30570
30848
  };
30571
30849
  UserEventsTable.prototype.getDetail = function (source) {
30572
30850
  if (!source)
30573
30851
  return undefined;
30574
- if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
30852
+ if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
30575
30853
  var context = source.content.context;
30576
30854
  if (context && context.__typename) {
30577
- var actions = this.service.getActionsByTypename(context.__typename);
30855
+ // const actions = this.service.getActionsByTypename(context.__typename);
30578
30856
  return {
30579
- actions: actions,
30857
+ // actions,
30580
30858
  title: source.content.error && source.content.error.message || source.content.message,
30581
30859
  description: source.content.error && source.content.error.details || undefined
30582
30860
  };
@@ -30587,18 +30865,18 @@
30587
30865
  };
30588
30866
  UserEventsTable.prototype.doAction = function (action, row) {
30589
30867
  return __awaiter(this, void 0, void 0, function () {
30590
- var event, context, res, _a, err_1;
30868
+ var event, res, _a, err_1;
30591
30869
  return __generator(this, function (_b) {
30592
30870
  switch (_b.label) {
30593
30871
  case 0:
30594
30872
  event = row.currentData;
30595
- context = event.content && event.content.context;
30873
+ // const context = event.content && event.content.context;
30596
30874
  this.markAsLoading();
30597
30875
  if (!(action && typeof action.executeAction === 'function')) return [3 /*break*/, 7];
30598
30876
  _b.label = 1;
30599
30877
  case 1:
30600
30878
  _b.trys.push([1, 5, 6, 7]);
30601
- res = action.executeAction(event, context);
30879
+ res = action.executeAction(event /*, context*/);
30602
30880
  if (!(res instanceof Promise)) return [3 /*break*/, 3];
30603
30881
  return [4 /*yield*/, res];
30604
30882
  case 2:
@@ -30630,13 +30908,18 @@
30630
30908
  selector: 'app-user-events-table',
30631
30909
  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
30910
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
30911
+ providers: [
30912
+ {
30913
+ provide: UserEventServiceToken, useClass: UserEventService
30914
+ }
30915
+ ],
30633
30916
  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
30917
  },] }
30635
30918
  ];
30636
30919
  UserEventsTable.ctorParameters = function () { return [
30637
30920
  { type: i0.Injector },
30638
30921
  { type: AccountService },
30639
- { type: UserEventService },
30922
+ { type: undefined, decorators: [{ type: i0.Inject, args: [UserEventServiceToken,] }] },
30640
30923
  { type: EntitiesStorage },
30641
30924
  { type: i0.ChangeDetectorRef },
30642
30925
  { type: undefined, decorators: [{ type: i0.Inject, args: [ENVIRONMENT,] }] }
@@ -30648,6 +30931,170 @@
30648
30931
  defaultSortDirection: [{ type: i0.Input }]
30649
30932
  };
30650
30933
 
30934
+ var UserEventNotificationList = /** @class */ (function () {
30935
+ function UserEventNotificationList(popoverController) {
30936
+ this.popoverController = popoverController;
30937
+ }
30938
+ UserEventNotificationList.prototype.ngOnInit = function () {
30939
+ };
30940
+ UserEventNotificationList.prototype.read = function ($event, userEvent) {
30941
+ var _a;
30942
+ if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
30943
+ return;
30944
+ (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
30945
+ };
30946
+ UserEventNotificationList.prototype.executeAction = function (action, userEvent) {
30947
+ // Execute then close popover
30948
+ action.executeAction(userEvent);
30949
+ this.dismiss();
30950
+ };
30951
+ UserEventNotificationList.prototype.dismiss = function () {
30952
+ this.popoverController.dismiss();
30953
+ };
30954
+ return UserEventNotificationList;
30955
+ }());
30956
+ UserEventNotificationList.decorators = [
30957
+ { type: i0.Component, args: [{
30958
+ selector: 'app-user-event-notification-list',
30959
+ 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",
30960
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}"]
30961
+ },] }
30962
+ ];
30963
+ UserEventNotificationList.ctorParameters = function () { return [
30964
+ { type: i1$5.PopoverController }
30965
+ ]; };
30966
+ UserEventNotificationList.propDecorators = {
30967
+ titleI18n: [{ type: i0.Input }],
30968
+ userEvents: [{ type: i0.Input }],
30969
+ readEvent: [{ type: i0.Output }]
30970
+ };
30971
+
30972
+ var UserEventNotificationComponent = /** @class */ (function () {
30973
+ function UserEventNotificationComponent(userEventService, accountService, popoverController, cd) {
30974
+ this.userEventService = userEventService;
30975
+ this.accountService = accountService;
30976
+ this.popoverController = popoverController;
30977
+ this.cd = cd;
30978
+ this.debug = false;
30979
+ this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
30980
+ this.disabled = false;
30981
+ this.userEventsSubject = new rxjs.BehaviorSubject(undefined);
30982
+ this._subscriptions = new rxjs.Subscription();
30983
+ this._logPrefix = '[user-event-notification] ';
30984
+ this._readEvent = new i0.EventEmitter();
30985
+ }
30986
+ Object.defineProperty(UserEventNotificationComponent.prototype, "count", {
30987
+ get: function () {
30988
+ var _a;
30989
+ return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(operators.map(function (value) { return value === 0 ? undefined : value; }));
30990
+ },
30991
+ enumerable: false,
30992
+ configurable: true
30993
+ });
30994
+ UserEventNotificationComponent.prototype.ngOnInit = function () {
30995
+ var _this = this;
30996
+ var _a;
30997
+ if (isNil(this.userEventService)) {
30998
+ console.warn(this._logPrefix + "No service injected");
30999
+ this.disabled = true;
31000
+ return;
31001
+ }
31002
+ this._subscriptions.add(this.userEventService.watchAll(0, 10, 'creationDate', "desc", {
31003
+ recipients: [(_a = this.accountService.person) === null || _a === void 0 ? void 0 : _a.pubkey]
31004
+ }).subscribe(function (value) {
31005
+ var data = value.data;
31006
+ if (_this.debug) {
31007
+ console.debug(_this._logPrefix + "Receiving user events", data);
31008
+ }
31009
+ _this.userEventsSubject.next(data);
31010
+ }));
31011
+ this._readEvent.subscribe(function (value) {
31012
+ _this.userEventService.markAsRead(value);
31013
+ });
31014
+ };
31015
+ UserEventNotificationComponent.prototype.showList = function (event) {
31016
+ return __awaiter(this, void 0, void 0, function () {
31017
+ var popover;
31018
+ return __generator(this, function (_b) {
31019
+ switch (_b.label) {
31020
+ case 0: return [4 /*yield*/, this.popoverController.create({
31021
+ component: UserEventNotificationList,
31022
+ componentProps: {
31023
+ titleI18n: this.titleI18n,
31024
+ userEvents: this.userEventsSubject,
31025
+ readEvent: this._readEvent
31026
+ },
31027
+ backdropDismiss: true,
31028
+ keyboardClose: true,
31029
+ event: event,
31030
+ translucent: true,
31031
+ cssClass: 'popover-large'
31032
+ })];
31033
+ case 1:
31034
+ popover = _b.sent();
31035
+ return [4 /*yield*/, popover.present()];
31036
+ case 2:
31037
+ _b.sent();
31038
+ return [2 /*return*/];
31039
+ }
31040
+ });
31041
+ });
31042
+ };
31043
+ UserEventNotificationComponent.prototype.markForCheck = function () {
31044
+ this.cd.markForCheck();
31045
+ };
31046
+ UserEventNotificationComponent.prototype.ngOnDestroy = function () {
31047
+ if (this.debug) {
31048
+ console.debug(this._logPrefix + "Destroying");
31049
+ }
31050
+ this._subscriptions.unsubscribe();
31051
+ };
31052
+ return UserEventNotificationComponent;
31053
+ }());
31054
+ UserEventNotificationComponent.decorators = [
31055
+ { type: i0.Component, args: [{
31056
+ selector: 'app-user-event-notification-component',
31057
+ 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",
31058
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31059
+ styles: [""]
31060
+ },] }
31061
+ ];
31062
+ UserEventNotificationComponent.ctorParameters = function () { return [
31063
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [UserEventServiceToken,] }] },
31064
+ { type: AccountService },
31065
+ { type: i1$5.PopoverController },
31066
+ { type: i0.ChangeDetectorRef }
31067
+ ]; };
31068
+ UserEventNotificationComponent.propDecorators = {
31069
+ debug: [{ type: i0.Input }],
31070
+ titleI18n: [{ type: i0.Input }],
31071
+ disabled: [{ type: i0.Input }]
31072
+ };
31073
+
31074
+ var UserEventModule = /** @class */ (function () {
31075
+ function UserEventModule() {
31076
+ }
31077
+ return UserEventModule;
31078
+ }());
31079
+ UserEventModule.decorators = [
31080
+ { type: i0.NgModule, args: [{
31081
+ imports: [
31082
+ i1$4.CommonModule,
31083
+ CoreModule,
31084
+ SharedModule
31085
+ ],
31086
+ declarations: [
31087
+ UserEventsTable,
31088
+ UserEventNotificationComponent,
31089
+ UserEventNotificationList,
31090
+ ],
31091
+ exports: [
31092
+ UserEventsTable,
31093
+ UserEventNotificationComponent
31094
+ ]
31095
+ },] }
31096
+ ];
31097
+
30651
31098
  var MessageTypes = {
30652
31099
  INBOX_MESSAGE: 'INBOX_MESSAGE',
30653
31100
  EMAIL: 'EMAIL',
@@ -30881,12 +31328,12 @@
30881
31328
  canSelectType: [{ type: i0.Input }]
30882
31329
  };
30883
31330
 
30884
- var SocialModule = /** @class */ (function () {
30885
- function SocialModule() {
31331
+ var MessageModule = /** @class */ (function () {
31332
+ function MessageModule() {
30886
31333
  }
30887
- return SocialModule;
31334
+ return MessageModule;
30888
31335
  }());
30889
- SocialModule.decorators = [
31336
+ MessageModule.decorators = [
30890
31337
  { type: i0.NgModule, args: [{
30891
31338
  imports: [
30892
31339
  i1$4.CommonModule,
@@ -30894,19 +31341,342 @@
30894
31341
  SharedModule
30895
31342
  ],
30896
31343
  declarations: [
30897
- UserEventsTable,
30898
31344
  MessageModal,
30899
31345
  MessageForm
30900
31346
  ],
30901
31347
  exports: [
30902
- UserEventsTable,
30903
31348
  MessageModal
30904
31349
  ]
30905
31350
  },] }
30906
31351
  ];
30907
31352
 
31353
+ var JobProgression_1;
31354
+ // todo use entity
31355
+ var Job = /** @class */ (function () {
31356
+ function Job() {
31357
+ }
31358
+ return Job;
31359
+ }());
31360
+ // @dynamic
31361
+ exports.JobProgression = JobProgression_1 = /** @class */ (function (_super) {
31362
+ __extends(JobProgression, _super);
31363
+ function JobProgression() {
31364
+ return _super.call(this, JobProgression_1.TYPENAME) || this;
31365
+ }
31366
+ JobProgression.prototype.fromObject = function (source) {
31367
+ _super.prototype.fromObject.call(this, source);
31368
+ this.message = source.message;
31369
+ this.current = source.current;
31370
+ this.total = source.total;
31371
+ };
31372
+ return JobProgression;
31373
+ }(Entity));
31374
+ exports.JobProgression = JobProgression_1 = __decorate([
31375
+ EntityClass({ typename: 'JobProgressionVO' })
31376
+ ], exports.JobProgression);
31377
+
31378
+ var JobProgressionServiceToken = new i0.InjectionToken('JobProgressionService');
31379
+ 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 updateDate\n }\n}"], ["subscription UpdateJobProgression($id: Int!, $interval: Int){\n data: updateJobProgression(id: $id, interval: $interval) {\n id\n message\n current\n total\n updateDate\n }\n}"])));
31380
+ var JobProgressionService = /** @class */ (function (_super) {
31381
+ __extends(JobProgressionService, _super);
31382
+ function JobProgressionService(graphql, environment) {
31383
+ var _this = _super.call(this, graphql, environment) || this;
31384
+ _this.graphql = graphql;
31385
+ _this.environment = environment;
31386
+ _this._logPrefix = '[job-progression-service] ';
31387
+ // For DEV only
31388
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
31389
+ return _this;
31390
+ }
31391
+ JobProgressionService.prototype.listenChanges = function (id, options) {
31392
+ var _this = this;
31393
+ if (isNil(id))
31394
+ throw new Error(this._logPrefix + "Missing argument 'id'");
31395
+ if (this._debug)
31396
+ console.debug(this._logPrefix + "[WS] Listening changes for job progression {" + id + "}...");
31397
+ return this.graphql.subscribe({
31398
+ query: jobProgressionSubscription,
31399
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
31400
+ variables: { id: id, interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
31401
+ error: { code: SocialErrorCodes.SUBSCRIBE_JOB_PROGRESSION_ERROR, message: 'SOCIAL.ERROR.SUBSCRIBE_JOB_PROGRESSION_ERROR' }
31402
+ }).pipe(operators.map(function (_a) {
31403
+ var data = _a.data;
31404
+ var progression = data && exports.JobProgression.fromObject(data);
31405
+ if (progression && _this._debug)
31406
+ console.debug(_this._logPrefix + "Job progression " + id + " updated on server", progression);
31407
+ return progression;
31408
+ }));
31409
+ };
31410
+ return JobProgressionService;
31411
+ }(BaseGraphqlService));
31412
+ JobProgressionService.decorators = [
31413
+ { type: i0.Injectable }
31414
+ ];
31415
+ JobProgressionService.ctorParameters = function () { return [
31416
+ { type: GraphqlService },
31417
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
31418
+ ]; };
31419
+ var templateObject_1$4;
31420
+
31421
+ var JobProgressionList = /** @class */ (function () {
31422
+ function JobProgressionList() {
31423
+ }
31424
+ JobProgressionList.prototype.ngOnInit = function () {
31425
+ };
31426
+ return JobProgressionList;
31427
+ }());
31428
+ JobProgressionList.decorators = [
31429
+ { type: i0.Component, args: [{
31430
+ selector: 'app-job-progression-list',
31431
+ 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",
31432
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}"]
31433
+ },] }
31434
+ ];
31435
+ JobProgressionList.ctorParameters = function () { return []; };
31436
+ JobProgressionList.propDecorators = {
31437
+ titleI18n: [{ type: i0.Input }],
31438
+ jobProgressions: [{ type: i0.Input }]
31439
+ };
31440
+
31441
+ var JobProgressionComponent = /** @class */ (function () {
31442
+ function JobProgressionComponent(jobProgressionService, popoverController, cd) {
31443
+ this.jobProgressionService = jobProgressionService;
31444
+ this.popoverController = popoverController;
31445
+ this.cd = cd;
31446
+ this.debug = false;
31447
+ this.titleI18n = 'SOCIAL.JOB.PROGRESSION.TITLE';
31448
+ this.jobFinished = new i0.EventEmitter();
31449
+ this.disabled = true;
31450
+ this.color = 'accent';
31451
+ this.mode = 'determinate';
31452
+ this.value = 0;
31453
+ this.jobProgressions = [];
31454
+ this._subscriptions = new rxjs.Subscription();
31455
+ this._subscriptionsById = {};
31456
+ this._logPrefix = '[job-progression] ';
31457
+ }
31458
+ JobProgressionComponent.prototype.ngOnInit = function () {
31459
+ var _a, _b, _c, _d;
31460
+ if (isNil(this.jobProgressionService)) {
31461
+ console.warn(this._logPrefix + "No service injected");
31462
+ }
31463
+ // parse options
31464
+ this.autoHide = toBoolean((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoHide, false);
31465
+ this.visible = !this.autoHide;
31466
+ this.autoHideDelay = toNumber((_b = this.options) === null || _b === void 0 ? void 0 : _b.autoHideDelay, 1000);
31467
+ this.autoRemove = toBoolean((_c = this.options) === null || _c === void 0 ? void 0 : _c.autoRemove, true);
31468
+ this.autoRemoveDelay = toNumber((_d = this.options) === null || _d === void 0 ? void 0 : _d.autoRemoveDelay, 1000);
31469
+ };
31470
+ JobProgressionComponent.prototype.addJob = function (id) {
31471
+ var _this = this;
31472
+ if (isNil(this.jobProgressionService)) {
31473
+ console.warn(this._logPrefix + "No service injected. Can't add a job");
31474
+ return;
31475
+ }
31476
+ if (this.debug) {
31477
+ console.debug(this._logPrefix + "Add job id=" + id);
31478
+ }
31479
+ if (!!this.getProgression(id)) {
31480
+ console.warn(this._logPrefix + "Job (id=" + id + ") already present");
31481
+ return;
31482
+ }
31483
+ this.disabled = false;
31484
+ var sub = this.jobProgressionService.listenChanges(id)
31485
+ .pipe(operators.filter(function (progression) {
31486
+ if (id !== progression.id) {
31487
+ console.error(_this._logPrefix + "Job progression (id=" + progression.id + ") doesn't match expected job (id=" + id + ")");
31488
+ return false;
31489
+ }
31490
+ return true;
31491
+ }), operators.map(function (progression) {
31492
+ // Ensure visible
31493
+ _this.visible = true;
31494
+ // Get current progression object
31495
+ var currentProgression = _this.getProgression(id);
31496
+ if (!currentProgression) {
31497
+ // add it
31498
+ _this.jobProgressions.push(progression);
31499
+ if (_this.debug) {
31500
+ console.debug(_this._logPrefix + "Progression added id=" + id, progression);
31501
+ }
31502
+ }
31503
+ else {
31504
+ // update current
31505
+ Object.assign(currentProgression, progression);
31506
+ if (_this.debug) {
31507
+ console.debug(_this._logPrefix + "Progression updated id=" + id, progression);
31508
+ }
31509
+ }
31510
+ return progression;
31511
+ }))
31512
+ .subscribe(function (progression) {
31513
+ // update value
31514
+ _this.updateValue();
31515
+ // job finished
31516
+ if (progression.total > 0 && progression.current == progression.total) {
31517
+ if (_this.debug) {
31518
+ console.debug(_this._logPrefix + "Finished job id=" + progression.id);
31519
+ }
31520
+ // emit event
31521
+ _this.jobFinished.emit(progression.id);
31522
+ if (_this.autoRemove) {
31523
+ setTimeout(function () {
31524
+ var _a;
31525
+ _this.removeJob(progression.id);
31526
+ // If last job
31527
+ if (_this.autoHide && !((_a = _this.jobProgressions) === null || _a === void 0 ? void 0 : _a.length)) {
31528
+ setTimeout(function () {
31529
+ _this.visible = false;
31530
+ _this.markForCheck();
31531
+ }, _this.autoHideDelay);
31532
+ }
31533
+ }, _this.autoRemoveDelay);
31534
+ }
31535
+ }
31536
+ });
31537
+ this._subscriptionsById[id] = sub;
31538
+ this._subscriptions.add(sub);
31539
+ };
31540
+ JobProgressionComponent.prototype.removeJob = function (id) {
31541
+ if (this.debug) {
31542
+ console.debug(this._logPrefix + "Remove job id=" + id);
31543
+ }
31544
+ var sub = this._subscriptionsById[id];
31545
+ if (sub) {
31546
+ this._subscriptions.remove(sub);
31547
+ sub.unsubscribe();
31548
+ }
31549
+ var progression = this.getProgression(id);
31550
+ if (progression) {
31551
+ this.jobProgressions.splice(this.jobProgressions.indexOf(progression), 1);
31552
+ }
31553
+ this.updateValue();
31554
+ };
31555
+ JobProgressionComponent.prototype.getProgression = function (id) {
31556
+ return this.jobProgressions.find(function (progression) { return progression.id === id; });
31557
+ };
31558
+ JobProgressionComponent.prototype.updateValue = function () {
31559
+ if (this.debug) {
31560
+ console.debug(this._logPrefix + "Updating value");
31561
+ }
31562
+ var value = 0;
31563
+ var nbProgression = arraySize(this.jobProgressions);
31564
+ var allIndeterminate = nbProgression > 0;
31565
+ this.jobProgressions.forEach(function (progression) {
31566
+ var indeterminate = progression.total === 0;
31567
+ allIndeterminate = allIndeterminate && indeterminate;
31568
+ if (!indeterminate) {
31569
+ value = value + progression.current * 100 / progression.total;
31570
+ }
31571
+ });
31572
+ this.value = nbProgression > 0 ? value / nbProgression : 0;
31573
+ this.mode = allIndeterminate ? 'indeterminate' : 'determinate';
31574
+ if (this.debug) {
31575
+ console.debug(this._logPrefix + "Setting value=" + this.value + ", mode=" + this.mode);
31576
+ }
31577
+ this.markForCheck();
31578
+ };
31579
+ JobProgressionComponent.prototype.showList = function (event) {
31580
+ return __awaiter(this, void 0, void 0, function () {
31581
+ var popover;
31582
+ return __generator(this, function (_e) {
31583
+ switch (_e.label) {
31584
+ case 0: return [4 /*yield*/, this.popoverController.create({
31585
+ component: JobProgressionList,
31586
+ componentProps: {
31587
+ titleI18n: this.titleI18n,
31588
+ jobProgressions: this.jobProgressions
31589
+ },
31590
+ backdropDismiss: true,
31591
+ keyboardClose: true,
31592
+ event: event,
31593
+ translucent: true,
31594
+ cssClass: 'popover-large'
31595
+ })];
31596
+ case 1:
31597
+ popover = _e.sent();
31598
+ return [4 /*yield*/, popover.present()];
31599
+ case 2:
31600
+ _e.sent();
31601
+ return [2 /*return*/];
31602
+ }
31603
+ });
31604
+ });
31605
+ };
31606
+ JobProgressionComponent.prototype.markForCheck = function () {
31607
+ this.cd.markForCheck();
31608
+ };
31609
+ JobProgressionComponent.prototype.ngOnDestroy = function () {
31610
+ if (this.debug) {
31611
+ console.debug(this._logPrefix + "Destroying");
31612
+ }
31613
+ this._subscriptions.unsubscribe();
31614
+ };
31615
+ return JobProgressionComponent;
31616
+ }());
31617
+ JobProgressionComponent.decorators = [
31618
+ { type: i0.Component, args: [{
31619
+ selector: 'app-job-progression',
31620
+ 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",
31621
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31622
+ styles: [".floating-spinner{position:absolute;top:6px;left:5px}"]
31623
+ },] }
31624
+ ];
31625
+ JobProgressionComponent.ctorParameters = function () { return [
31626
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [JobProgressionServiceToken,] }] },
31627
+ { type: i1$5.PopoverController },
31628
+ { type: i0.ChangeDetectorRef }
31629
+ ]; };
31630
+ JobProgressionComponent.propDecorators = {
31631
+ debug: [{ type: i0.Input }],
31632
+ titleI18n: [{ type: i0.Input }],
31633
+ options: [{ type: i0.Input }],
31634
+ jobFinished: [{ type: i0.Output }]
31635
+ };
31636
+
31637
+ var JobModule = /** @class */ (function () {
31638
+ function JobModule() {
31639
+ }
31640
+ return JobModule;
31641
+ }());
31642
+ JobModule.decorators = [
31643
+ { type: i0.NgModule, args: [{
31644
+ imports: [
31645
+ i1$4.CommonModule,
31646
+ SharedModule,
31647
+ i1$2.TranslateModule.forChild(),
31648
+ ],
31649
+ declarations: [
31650
+ JobProgressionComponent,
31651
+ JobProgressionList
31652
+ ],
31653
+ exports: [
31654
+ JobProgressionComponent
31655
+ ]
31656
+ },] }
31657
+ ];
31658
+
31659
+ var SocialModuleOptionsToken = new i0.InjectionToken("SocialModuleOptions");
31660
+ var SocialModule = /** @class */ (function () {
31661
+ function SocialModule() {
31662
+ }
31663
+ return SocialModule;
31664
+ }());
31665
+ SocialModule.decorators = [
31666
+ { type: i0.NgModule, args: [{
31667
+ imports: [
31668
+ i1$4.CommonModule,
31669
+ CoreModule,
31670
+ SharedModule,
31671
+ UserEventModule,
31672
+ JobModule,
31673
+ MessageModule,
31674
+ ],
31675
+ },] }
31676
+ ];
31677
+
30908
31678
  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 }"])))
31679
+ 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
31680
  };
30911
31681
  var MessageService = /** @class */ (function (_super) {
30912
31682
  __extends(MessageService, _super);
@@ -30990,7 +31760,7 @@
30990
31760
  { type: i1$5.ToastController },
30991
31761
  { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30992
31762
  ]; };
30993
- var templateObject_1$4;
31763
+ var templateObject_1$5;
30994
31764
 
30995
31765
  var PersonFilter_1;
30996
31766
  // @dynamic
@@ -31049,7 +31819,7 @@
31049
31819
  ], exports.PersonFilter);
31050
31820
 
31051
31821
  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 }"])))
31822
+ 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
31823
  };
31054
31824
  // Load persons query
31055
31825
  var PersonQueries = {
@@ -31189,7 +31959,7 @@
31189
31959
  { type: NetworkService },
31190
31960
  { type: EntitiesStorage }
31191
31961
  ]; };
31192
- var templateObject_1$5, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31962
+ var templateObject_1$6, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31193
31963
 
31194
31964
  var PersonValidatorService = /** @class */ (function () {
31195
31965
  function PersonValidatorService(formBuilder, accountValidatorService) {
@@ -31599,12 +32369,10 @@
31599
32369
  };
31600
32370
  AutocompleteTestPage.prototype.ngAfterViewInit = function () {
31601
32371
  var _this = this;
31602
- if (this.farEntityField) {
31603
- setTimeout(function () {
31604
- _this.farEntityField.suggestLengthThreshold = 2;
31605
- _this.farEntityField.reloadItems();
31606
- }, 2000);
31607
- }
32372
+ setTimeout(function () {
32373
+ _this.farEntityField.suggestLengthThreshold = 2;
32374
+ _this.farEntityField.reloadItems();
32375
+ }, 2000);
31608
32376
  setTimeout(function () { return _this.loadData(); }, 1000);
31609
32377
  };
31610
32378
  // Load the form with data
@@ -31711,7 +32479,7 @@
31711
32479
  AutocompleteTestPage.decorators = [
31712
32480
  { type: i0.Component, args: [{
31713
32481
  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"
32482
+ 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
32483
  },] }
31716
32484
  ];
31717
32485
  AutocompleteTestPage.ctorParameters = function () { return [
@@ -31793,13 +32561,13 @@
31793
32561
  { type: i1.FormBuilder }
31794
32562
  ]; };
31795
32563
 
31796
- var moment$6 = momentImported__namespace;
32564
+ var moment$7 = momentImported__namespace;
31797
32565
  var SwipeTestPage = /** @class */ (function () {
31798
32566
  function SwipeTestPage(formBuilder, dateFormatPipe) {
31799
32567
  this.formBuilder = formBuilder;
31800
32568
  this.dateFormatPipe = dateFormatPipe;
31801
32569
  this.$dates = new rxjs.BehaviorSubject(undefined);
31802
- this._today = moment$6().startOf('day');
32570
+ this._today = moment$7().startOf('day');
31803
32571
  this.form = formBuilder.group({
31804
32572
  empty: [null, i1.Validators.required],
31805
32573
  date: [null, i1.Validators.compose([i1.Validators.required, SharedValidators.validDate])],
@@ -31813,7 +32581,7 @@
31813
32581
  var _this = this;
31814
32582
  var dates = [];
31815
32583
  for (var d = 0; d < 7; d++) {
31816
- dates[d] = moment$6(this._today).add(d - 3, 'day');
32584
+ dates[d] = moment$7(this._today).add(d - 3, 'day');
31817
32585
  }
31818
32586
  this.$dates.next(dates);
31819
32587
  this.loadData();
@@ -31860,7 +32628,7 @@
31860
32628
  { type: DateFormatPipe }
31861
32629
  ]; };
31862
32630
 
31863
- var moment$7 = momentImported__namespace;
32631
+ var moment$8 = momentImported__namespace;
31864
32632
  var DateTimeTestPage = /** @class */ (function () {
31865
32633
  function DateTimeTestPage(platform, formBuilder, cd) {
31866
32634
  this.platform = platform;
@@ -31896,7 +32664,7 @@
31896
32664
  var now, data;
31897
32665
  var _this = this;
31898
32666
  return __generator(this, function (_a) {
31899
- now = moment$7();
32667
+ now = moment$8();
31900
32668
  data = {
31901
32669
  empty: null,
31902
32670
  emptyRequired: null,
@@ -32174,7 +32942,7 @@
32174
32942
  { type: i1.FormBuilder }
32175
32943
  ]; };
32176
32944
 
32177
- var moment$8 = momentImported__namespace;
32945
+ var moment$9 = momentImported__namespace;
32178
32946
  var DateTestPage = /** @class */ (function () {
32179
32947
  function DateTestPage(formBuilder, cd) {
32180
32948
  this.formBuilder = formBuilder;
@@ -32211,7 +32979,7 @@
32211
32979
  var now, nowAtMahe, data;
32212
32980
  var _this = this;
32213
32981
  return __generator(this, function (_a) {
32214
- now = moment$8();
32982
+ now = moment$9();
32215
32983
  nowAtMahe = now.clone().tz(this.timezone).startOf('day');
32216
32984
  data = {
32217
32985
  empty: null,
@@ -33050,6 +33818,7 @@
33050
33818
  exports.APP_MENU_ITEMS = APP_MENU_ITEMS;
33051
33819
  exports.APP_TESTING_PAGES = APP_TESTING_PAGES;
33052
33820
  exports.AboutModal = AboutModal;
33821
+ exports.AbstractUserEventService = AbstractUserEventService;
33053
33822
  exports.AccountPage = AccountPage;
33054
33823
  exports.AccountService = AccountService;
33055
33824
  exports.AccountToStringPipe = AccountToStringPipe;
@@ -33176,6 +33945,11 @@
33176
33945
  exports.IsNotNilOrBlankPipe = IsNotNilOrBlankPipe;
33177
33946
  exports.IsNotOnFieldModePipe = IsNotOnFieldModePipe;
33178
33947
  exports.IsOnFieldModePipe = IsOnFieldModePipe;
33948
+ exports.Job = Job;
33949
+ exports.JobModule = JobModule;
33950
+ exports.JobProgressionComponent = JobProgressionComponent;
33951
+ exports.JobProgressionService = JobProgressionService;
33952
+ exports.JobProgressionServiceToken = JobProgressionServiceToken;
33179
33953
  exports.JobUtils = JobUtils;
33180
33954
  exports.KEYBOARD_HIDE_DELAY_MS = KEYBOARD_HIDE_DELAY_MS;
33181
33955
  exports.LAT_LONG_DEFAULT_MAX_DECIMALS = LAT_LONG_DEFAULT_MAX_DECIMALS;
@@ -33213,6 +33987,7 @@
33213
33987
  exports.MenuService = MenuService;
33214
33988
  exports.MessageForm = MessageForm;
33215
33989
  exports.MessageModal = MessageModal;
33990
+ exports.MessageModule = MessageModule;
33216
33991
  exports.MessageService = MessageService;
33217
33992
  exports.MessageTypeList = MessageTypeList;
33218
33993
  exports.MessageTypes = MessageTypes;
@@ -33280,6 +34055,7 @@
33280
34055
  exports.SharedValidators = SharedValidators;
33281
34056
  exports.SocialErrorCodes = SocialErrorCodes;
33282
34057
  exports.SocialModule = SocialModule;
34058
+ exports.SocialModuleOptionsToken = SocialModuleOptionsToken;
33283
34059
  exports.StartableService = StartableService;
33284
34060
  exports.StatusById = StatusById;
33285
34061
  exports.StatusIds = StatusIds;
@@ -33308,7 +34084,10 @@
33308
34084
  exports.UploadFileTestingPage = UploadFileTestingPage;
33309
34085
  exports.UriUtils = UriUtils;
33310
34086
  exports.UserEventFragments = UserEventFragments;
34087
+ exports.UserEventModule = UserEventModule;
34088
+ exports.UserEventNotificationComponent = UserEventNotificationComponent;
33311
34089
  exports.UserEventService = UserEventService;
34090
+ exports.UserEventServiceToken = UserEventServiceToken;
33312
34091
  exports.UserEventTypes = UserEventTypes;
33313
34092
  exports.UserEventsTable = UserEventsTable;
33314
34093
  exports.UsersPage = UsersPage;
@@ -33473,11 +34252,13 @@
33473
34252
  exports.ɵh = LocalSettingsValidatorService;
33474
34253
  exports.ɵi = AppUpdateOfflineModeCard;
33475
34254
  exports.ɵj = AppIconComponent;
33476
- exports.ɵk = DateTestPage;
33477
- exports.ɵl = NumpadTestPage;
33478
- exports.ɵm = MatBadgeIconTestPage;
33479
- exports.ɵn = ToastTestingModule;
33480
- exports.ɵo = ToastTestingPage;
34255
+ exports.ɵk = UserEventNotificationList;
34256
+ exports.ɵl = JobProgressionList;
34257
+ exports.ɵm = DateTestPage;
34258
+ exports.ɵn = NumpadTestPage;
34259
+ exports.ɵo = MatBadgeIconTestPage;
34260
+ exports.ɵp = ToastTestingModule;
34261
+ exports.ɵq = ToastTestingPage;
33481
34262
 
33482
34263
  Object.defineProperty(exports, '__esModule', { value: true });
33483
34264