@sumaris-net/ngx-components 1.20.36 → 1.21.0-beta3

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 (74) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +1099 -326
  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/form/editor.class.js +1 -3
  8. package/esm2015/src/app/core/icon/icon.component.js +5 -2
  9. package/esm2015/src/app/core/menu/menu.component.js +2 -2
  10. package/esm2015/src/app/core/services/local-settings.service.js +2 -2
  11. package/esm2015/src/app/core/table/table.class.js +11 -11
  12. package/esm2015/src/app/shared/functions.js +60 -1
  13. package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +4 -5
  14. package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +7 -10
  15. package/esm2015/src/app/shared/material/chips/material.chips.js +2 -3
  16. package/esm2015/src/app/shared/material/chips/testing/chips.test.js +2 -3
  17. package/esm2015/src/app/shared/material/datetime/material.date.js +2 -3
  18. package/esm2015/src/app/shared/material/datetime/material.datetime.js +2 -3
  19. package/esm2015/src/app/shared/observables.js +5 -4
  20. package/esm2015/src/app/shared/pipes/arrays.pipe.js +1 -1
  21. package/esm2015/src/app/shared/pipes/form.pipes.js +4 -2
  22. package/esm2015/src/app/shared/pipes/highlight.pipe.js +4 -4
  23. package/esm2015/src/app/shared/pipes/string.pipes.js +18 -7
  24. package/esm2015/src/app/shared/services/memory-entity-service.class.js +1 -13
  25. package/esm2015/src/app/shared/types.js +1 -1
  26. package/esm2015/src/app/social/job/job.model.js +24 -0
  27. package/esm2015/src/app/social/job/job.module.js +25 -0
  28. package/esm2015/src/app/social/job/job.service.js +54 -0
  29. package/esm2015/src/app/social/job/progression/job-progression.component.js +192 -0
  30. package/esm2015/src/app/social/job/progression/job-progression.list.js +20 -0
  31. package/esm2015/src/app/social/message/message.module.js +25 -0
  32. package/esm2015/src/app/social/social.errors.js +5 -2
  33. package/esm2015/src/app/social/social.module.js +10 -15
  34. package/esm2015/src/app/social/user-event/notification/user-event-notification.component.js +95 -0
  35. package/esm2015/src/app/social/user-event/notification/user-event-notification.list.js +39 -0
  36. package/esm2015/src/app/social/user-event/user-event.model.js +58 -2
  37. package/esm2015/src/app/social/user-event/user-event.module.js +28 -0
  38. package/esm2015/src/app/social/user-event/user-event.service.js +294 -166
  39. package/esm2015/src/app/social/user-event/user-events.table.js +17 -12
  40. package/esm2015/sumaris-net.ngx-components.js +8 -6
  41. package/fesm2015/sumaris-net.ngx-components.js +927 -288
  42. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  43. package/package.json +2 -3
  44. package/public_api.d.ts +7 -2
  45. package/src/app/core/icon/icon.component.d.ts +4 -4
  46. package/src/app/core/table/table.class.d.ts +6 -8
  47. package/src/app/shared/functions.d.ts +9 -0
  48. package/src/app/shared/material/autocomplete/testing/autocomplete.test.d.ts +2 -1
  49. package/src/app/shared/material/badge/badge-icon.test.d.ts +1 -1
  50. package/src/app/shared/pipes/form.pipes.d.ts +2 -1
  51. package/src/app/shared/services/memory-entity-service.class.d.ts +0 -6
  52. package/src/app/shared/types.d.ts +4 -0
  53. package/src/app/social/job/job.model.d.ts +32 -0
  54. package/src/app/social/job/job.module.d.ts +2 -0
  55. package/src/app/social/job/job.service.d.ts +23 -0
  56. package/src/app/social/job/progression/job-progression.component.d.ts +43 -0
  57. package/src/app/social/job/progression/job-progression.list.d.ts +12 -0
  58. package/src/app/social/message/message.module.d.ts +2 -0
  59. package/src/app/social/social.errors.d.ts +3 -0
  60. package/src/app/social/social.module.d.ts +8 -0
  61. package/src/app/social/user-event/notification/user-event-notification.component.d.ts +25 -0
  62. package/src/app/social/user-event/notification/user-event-notification.list.d.ts +20 -0
  63. package/src/app/social/user-event/user-event.model.d.ts +51 -6
  64. package/src/app/social/user-event/user-event.module.d.ts +2 -0
  65. package/src/app/social/user-event/user-event.service.d.ts +80 -51
  66. package/src/app/social/user-event/user-events.table.d.ts +6 -6
  67. package/src/assets/i18n/en-US.json +15 -2
  68. package/src/assets/i18n/en.json +15 -2
  69. package/src/assets/i18n/fr.json +14 -1
  70. package/src/theme/_ngx-components.scss +7 -0
  71. package/sumaris-net.ngx-components.d.ts +7 -5
  72. package/sumaris-net.ngx-components.metadata.json +1 -1
  73. package/esm2015/src/app/shared/services.js +0 -61
  74. 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))
@@ -1092,13 +1162,14 @@
1092
1162
  }
1093
1163
  function waitForTrue(observable, opts) {
1094
1164
  return __awaiter(this, void 0, void 0, function () {
1095
- var $timeout;
1165
+ var firstTrueObservable, $timeout;
1096
1166
  return __generator(this, function (_a) {
1167
+ firstTrueObservable = firstTrue(observable);
1097
1168
  // Timeout (+ dueTime)
1098
1169
  if (opts && opts.timeout > 0) {
1099
1170
  $timeout = rxjs.timer(opts.timeout);
1100
1171
  return [2 /*return*/, rxjs.merge(rxjs.timer(opts.dueTime || 0)
1101
- .pipe(operators.switchMap(function () { return firstTrue(observable); }), operators.takeUntil($timeout)), $timeout
1172
+ .pipe(operators.switchMap(function () { return firstTrueObservable; }), operators.takeUntil($timeout)), $timeout
1102
1173
  .pipe(operators.map(function () {
1103
1174
  throw new Error("Timeout ready() - after " + opts.timeout + "ms");
1104
1175
  })))
@@ -1107,10 +1178,10 @@
1107
1178
  // dueTime (without timeout)
1108
1179
  if (opts && opts.dueTime > 0) {
1109
1180
  return [2 /*return*/, rxjs.timer(opts.dueTime)
1110
- .pipe(operators.switchMap(function () { return firstTrue(observable); }))
1181
+ .pipe(operators.switchMap(function () { return firstTrueObservable; }))
1111
1182
  .toPromise()];
1112
1183
  }
1113
- return [2 /*return*/, firstTrue(observable).toPromise()];
1184
+ return [2 /*return*/, firstTrueObservable.toPromise()];
1114
1185
  });
1115
1186
  });
1116
1187
  }
@@ -1315,68 +1386,6 @@
1315
1386
  return _cache.mobile;
1316
1387
  };
1317
1388
 
1318
- function suggestFromArray(items, value, opts) {
1319
- var _this = this;
1320
- if (isNotNil(value) && typeof value === 'object')
1321
- return { data: [value] };
1322
- value = (typeof value === 'string' && value !== '*') && value.toUpperCase() || undefined;
1323
- var keys = opts && (opts.searchAttribute && [opts.searchAttribute] || opts.searchAttributes) || ['label'];
1324
- if (!items) {
1325
- return { data: [], total: 0 };
1326
- }
1327
- // Filter items
1328
- var filteredItems = items;
1329
- if (isNotNilOrBlank(value)) {
1330
- // If wildcard, search using regexp
1331
- if (value.indexOf('*') !== -1) {
1332
- value = value.replace(/[*]+/g, '.*');
1333
- filteredItems = filteredItems.filter(function (v) { return keys.findIndex(function (key) { return matchUpperCase(getPropertyByPathAsString(v, key), value); }) !== -1; });
1334
- }
1335
- // Else (no wildcard), search using startsWith
1336
- else {
1337
- filteredItems = filteredItems.filter(function (v) { return keys.findIndex(function (key) { return startsWithUpperCase(getPropertyByPathAsString(v, key), value); }) !== -1; });
1338
- }
1339
- }
1340
- // Exclude ids
1341
- if (isNotEmptyArray(opts === null || opts === void 0 ? void 0 : opts.excludedIds)) {
1342
- filteredItems = filteredItems.filter(function (v) { return !opts.excludedIds.includes(+v['id']); });
1343
- }
1344
- // Sort
1345
- if (!opts || opts.skipSort !== true) {
1346
- // Make to copy input items, before sorting (if not yet already done)
1347
- if (filteredItems === items)
1348
- filteredItems = filteredItems.slice();
1349
- // Sort by keys
1350
- filteredItems.sort(propertiesPathComparator(keys));
1351
- }
1352
- var total = filteredItems.length || 0;
1353
- // Pagination (truncate if need)
1354
- var pageData = filteredItems;
1355
- if (opts) {
1356
- if ((opts.offset || 0) > 0) {
1357
- pageData = pageData.slice(opts.offset);
1358
- }
1359
- if (isNotNil(opts.size) && pageData.length > opts.size) {
1360
- pageData = pageData.slice(0, opts.size);
1361
- }
1362
- }
1363
- var result = {
1364
- data: pageData,
1365
- total: total
1366
- };
1367
- // Add fetch more capability, if total was fetched
1368
- var nextOffset = (opts && opts.offset || 0) + pageData.length;
1369
- if (nextOffset < total) {
1370
- result.fetchMore = function (_) { return __awaiter(_this, void 0, void 0, function () {
1371
- return __generator(this, function (_a) {
1372
- return [2 /*return*/, suggestFromArray(filteredItems, undefined /*OPTIMISATION: already applied*/, Object.assign(Object.assign({}, opts), { offset: nextOffset, skipSort: true, excludedIds: undefined // OPTIMISATION: already filtered
1373
- }))];
1374
- });
1375
- }); };
1376
- }
1377
- return result;
1378
- }
1379
-
1380
1389
  var MatAutocompleteConfigHolder = /** @class */ (function () {
1381
1390
  function MatAutocompleteConfigHolder(options) {
1382
1391
  this.options = options;
@@ -1697,11 +1706,11 @@
1697
1706
  // Search text (no distinctUntilChanged() because of the debounceTime() pipe)
1698
1707
  this.formControl.valueChanges
1699
1708
  .pipe(operators.filter(function (value) { return _this.enabled && isNotNilString(value); }),
1700
- // 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
1701
1710
  operators.tap(function (_) { return _this.showLoadingSpinner && _this.markAsLoading(); }),
1702
1711
  // Filter if not enough character
1703
1712
  operators.filter(function (value) {
1704
- if (((value === null || value === void 0 ? void 0 : value.length) || 0) < _this.suggestLengthThreshold) {
1713
+ if (value.length <= _this.suggestLengthThreshold) {
1705
1714
  // Update display value, to enable the message "not enough characters"
1706
1715
  _this.displayValue = value;
1707
1716
  return false;
@@ -2700,9 +2709,9 @@
2700
2709
  var cleanedSearchText = removeDiacritics(searchRegexp).toUpperCase();
2701
2710
  var index = removeDiacritics(value.toUpperCase()).indexOf(cleanedSearchText);
2702
2711
  if (index !== -1) {
2703
- return value.substring(0, index - 1) +
2704
- '<b>' + value.substring(index, cleanedSearchText.length) + '</b>' +
2705
- 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);
2706
2715
  }
2707
2716
  return value;
2708
2717
  }
@@ -3150,10 +3159,12 @@
3150
3159
  };
3151
3160
  return IsNotNilOrBlankPipe;
3152
3161
  }());
3162
+ IsNotNilOrBlankPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function IsNotNilOrBlankPipe_Factory() { return new IsNotNilOrBlankPipe(); }, token: IsNotNilOrBlankPipe, providedIn: "root" });
3153
3163
  IsNotNilOrBlankPipe.decorators = [
3154
3164
  { type: i0.Pipe, args: [{
3155
3165
  name: 'isNotNilOrBlank'
3156
- },] }
3166
+ },] },
3167
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3157
3168
  ];
3158
3169
  var IsNilOrBlankPipe = /** @class */ (function () {
3159
3170
  function IsNilOrBlankPipe() {
@@ -3163,10 +3174,12 @@
3163
3174
  };
3164
3175
  return IsNilOrBlankPipe;
3165
3176
  }());
3177
+ IsNilOrBlankPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function IsNilOrBlankPipe_Factory() { return new IsNilOrBlankPipe(); }, token: IsNilOrBlankPipe, providedIn: "root" });
3166
3178
  IsNilOrBlankPipe.decorators = [
3167
3179
  { type: i0.Pipe, args: [{
3168
3180
  name: 'isNilOrBlank'
3169
- },] }
3181
+ },] },
3182
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3170
3183
  ];
3171
3184
  var ToStringPipe = /** @class */ (function () {
3172
3185
  function ToStringPipe() {
@@ -3176,10 +3189,12 @@
3176
3189
  };
3177
3190
  return ToStringPipe;
3178
3191
  }());
3192
+ ToStringPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function ToStringPipe_Factory() { return new ToStringPipe(); }, token: ToStringPipe, providedIn: "root" });
3179
3193
  ToStringPipe.decorators = [
3180
3194
  { type: i0.Pipe, args: [{
3181
3195
  name: 'toString'
3182
- },] }
3196
+ },] },
3197
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3183
3198
  ];
3184
3199
  var StrLengthPipe = /** @class */ (function () {
3185
3200
  function StrLengthPipe() {
@@ -3189,10 +3204,12 @@
3189
3204
  };
3190
3205
  return StrLengthPipe;
3191
3206
  }());
3207
+ StrLengthPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function StrLengthPipe_Factory() { return new StrLengthPipe(); }, token: StrLengthPipe, providedIn: "root" });
3192
3208
  StrLengthPipe.decorators = [
3193
3209
  { type: i0.Pipe, args: [{
3194
3210
  name: 'strLength'
3195
- },] }
3211
+ },] },
3212
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3196
3213
  ];
3197
3214
  var StrIncludesPipe = /** @class */ (function () {
3198
3215
  function StrIncludesPipe() {
@@ -3202,10 +3219,12 @@
3202
3219
  };
3203
3220
  return StrIncludesPipe;
3204
3221
  }());
3222
+ StrIncludesPipe.ɵprov = i0.ɵɵdefineInjectable({ factory: function StrIncludesPipe_Factory() { return new StrIncludesPipe(); }, token: StrIncludesPipe, providedIn: "root" });
3205
3223
  StrIncludesPipe.decorators = [
3206
3224
  { type: i0.Pipe, args: [{
3207
3225
  name: 'strIncludes'
3208
- },] }
3226
+ },] },
3227
+ { type: i0.Injectable, args: [{ providedIn: 'root' },] }
3209
3228
  ];
3210
3229
 
3211
3230
  var TranslateContextService = /** @class */ (function () {
@@ -4786,7 +4805,8 @@
4786
4805
  },] }
4787
4806
  ];
4788
4807
  var FormGetValuePipe = /** @class */ (function () {
4789
- function FormGetValuePipe(_ref) {
4808
+ function FormGetValuePipe(adapter, _ref) {
4809
+ this.adapter = adapter;
4790
4810
  this._ref = _ref;
4791
4811
  this.value = undefined;
4792
4812
  this._lastControl = null;
@@ -4854,6 +4874,7 @@
4854
4874
  },] }
4855
4875
  ];
4856
4876
  FormGetValuePipe.ctorParameters = function () { return [
4877
+ { type: FormErrorTranslator },
4857
4878
  { type: i0.ChangeDetectorRef }
4858
4879
  ]; };
4859
4880
 
@@ -5775,10 +5796,10 @@
5775
5796
  return this._tabindex;
5776
5797
  },
5777
5798
  set: function (value) {
5799
+ var _this = this;
5778
5800
  if (this._tabindex !== value) {
5779
5801
  this._tabindex = value;
5780
- if (!this._writing)
5781
- this.updateTabIndex();
5802
+ setTimeout(function () { return _this.updateTabIndex(); });
5782
5803
  }
5783
5804
  },
5784
5805
  enumerable: false,
@@ -6170,10 +6191,10 @@
6170
6191
  return this._tabindex;
6171
6192
  },
6172
6193
  set: function (value) {
6194
+ var _this = this;
6173
6195
  if (this._tabindex !== value) {
6174
6196
  this._tabindex = value;
6175
- if (!this._writing)
6176
- this.updateTabIndex();
6197
+ setTimeout(function () { return _this.updateTabIndex(); });
6177
6198
  }
6178
6199
  },
6179
6200
  enumerable: false,
@@ -12023,7 +12044,7 @@
12023
12044
  Object.defineProperty(LocalSettingsService.prototype, "usageMode", {
12024
12045
  get: function () {
12025
12046
  var _a;
12026
- if (isNil((_a = this._data) === null || _a === void 0 ? void 0 : _a.usageMode)) {
12047
+ if (isNil((_a = this._data) === null || _a === void 0 ? void 0 : _a.mobile)) {
12027
12048
  console.warn("[settings] Accessing to property 'usageMode' BEFORE service started! Please use ready()");
12028
12049
  return isCordova(window) ? 'FIELD' : 'DESK';
12029
12050
  }
@@ -20718,14 +20739,14 @@
20718
20739
  }
20719
20740
  return this._onChange
20720
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 () {
20721
- var excludedDataByFilter, excludedDataByPagination, data, promiseOrData, _b, total;
20722
- return __generator(this, function (_c) {
20723
- switch (_c.label) {
20742
+ var excludedDataByFilter, excludedDataByPagination, data, promiseOrData, _a, total;
20743
+ return __generator(this, function (_b) {
20744
+ switch (_b.label) {
20724
20745
  case 0:
20725
20746
  excludedDataByFilter = [];
20726
- _c.label = 1;
20747
+ _b.label = 1;
20727
20748
  case 1:
20728
- _c.trys.push([1, , 6, 7]);
20749
+ _b.trys.push([1, , 6, 7]);
20729
20750
  if (isEmptyArray(this.data)) {
20730
20751
  return [2 /*return*/, { data: [], total: 0 }];
20731
20752
  }
@@ -20735,14 +20756,14 @@
20735
20756
  if (!((promiseOrData instanceof Promise))) return [3 /*break*/, 3];
20736
20757
  return [4 /*yield*/, promiseOrData];
20737
20758
  case 2:
20738
- _b = _c.sent();
20759
+ _a = _b.sent();
20739
20760
  return [3 /*break*/, 4];
20740
20761
  case 3:
20741
- _b = promiseOrData;
20742
- _c.label = 4;
20762
+ _a = promiseOrData;
20763
+ _b.label = 4;
20743
20764
  case 4:
20744
- data = _b;
20745
- _c.label = 5;
20765
+ data = _a;
20766
+ _b.label = 5;
20746
20767
  case 5:
20747
20768
  // Apply filter (will update hiddenData)
20748
20769
  data = this.filter(data, filterData, excludedDataByFilter);
@@ -20798,16 +20819,16 @@
20798
20819
  };
20799
20820
  InMemoryEntitiesService.prototype.saveAll = function (data, options) {
20800
20821
  return __awaiter(this, void 0, void 0, function () {
20801
- var res, _b;
20802
- return __generator(this, function (_c) {
20803
- switch (_c.label) {
20822
+ var res, _a;
20823
+ return __generator(this, function (_b) {
20824
+ switch (_b.label) {
20804
20825
  case 0:
20805
20826
  if (!this.data)
20806
20827
  throw new Error('[memory-service] Could not save, because value not set');
20807
20828
  this.markAsSaving();
20808
- _c.label = 1;
20829
+ _b.label = 1;
20809
20830
  case 1:
20810
- _c.trys.push([1, , 6, 7]);
20831
+ _b.trys.push([1, , 6, 7]);
20811
20832
  // Restore hidden data
20812
20833
  if (isNotEmptyArray(this._hiddenData))
20813
20834
  data = data.concat.apply(data, __spread(this._hiddenData));
@@ -20816,14 +20837,14 @@
20816
20837
  if (!((res instanceof Promise))) return [3 /*break*/, 3];
20817
20838
  return [4 /*yield*/, res];
20818
20839
  case 2:
20819
- _b = _c.sent();
20840
+ _a = _b.sent();
20820
20841
  return [3 /*break*/, 4];
20821
20842
  case 3:
20822
- _b = res;
20823
- _c.label = 4;
20843
+ _a = res;
20844
+ _b.label = 4;
20824
20845
  case 4:
20825
- data = _b;
20826
- _c.label = 5;
20846
+ data = _a;
20847
+ _b.label = 5;
20827
20848
  case 5:
20828
20849
  this.data = data;
20829
20850
  this.dirty = true;
@@ -20840,7 +20861,7 @@
20840
20861
  return __awaiter(this, void 0, void 0, function () {
20841
20862
  var updatedData, deleteCount;
20842
20863
  var _this = this;
20843
- return __generator(this, function (_b) {
20864
+ return __generator(this, function (_a) {
20844
20865
  if (!this.data)
20845
20866
  throw new Error('[memory-service] Could not delete, because value not set');
20846
20867
  updatedData = this.data.filter(function (entity) {
@@ -20874,26 +20895,6 @@
20874
20895
  return this._equalsFn(d1, d2);
20875
20896
  return d1 && d1.equals ? d1.equals(d2) : EntityUtils.equals(d1, d2, 'id');
20876
20897
  };
20877
- Object.defineProperty(InMemoryEntitiesService.prototype, "count", {
20878
- /**
20879
- * Count data stored by the service (without hidden data).
20880
- * @param opts
20881
- */
20882
- get: function () {
20883
- var _a;
20884
- return (((_a = this.data) === null || _a === void 0 ? void 0 : _a.length) || 0);
20885
- },
20886
- enumerable: false,
20887
- configurable: true
20888
- });
20889
- Object.defineProperty(InMemoryEntitiesService.prototype, "hiddenCount", {
20890
- get: function () {
20891
- var _a;
20892
- return ((_a = this._hiddenData) === null || _a === void 0 ? void 0 : _a.length) || 0;
20893
- },
20894
- enumerable: false,
20895
- configurable: true
20896
- });
20897
20898
  /* -- protected methods -- */
20898
20899
  InMemoryEntitiesService.prototype.filter = function (data, _filter, hiddenData) {
20899
20900
  // if filter is DataFilter instance, use its test function
@@ -24748,7 +24749,7 @@
24748
24749
  MenuComponent.decorators = [
24749
24750
  { type: i0.Component, args: [{
24750
24751
  selector: 'app-menu',
24751
- template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
24752
+ template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n<!-- todo ajouter ici les 2 composants du module social -->\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
24752
24753
  animations: [fadeInAnimation],
24753
24754
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
24754
24755
  styles: ["ion-menu{--ion-item-background:transparent;--ion-item-divider-background:transparent;--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint);--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-text-color-selected:var(--ion-color-primary);--ion-item-icon-color-selected:var(--ion-color-primary);--ion-item-text-color-disable:var(--ion-color-medium);--ion-item-icon-color-disable:var(--ion-color-medium)}ion-menu ion-header ion-text{color:var(--ion-color-primary)}ion-menu ion-header .user-avatar{background-size:cover;background-repeat:no-repeat;background-position:50%;background-color:var(--ion-color-secondary);border:1px solid var(--ion-color-primary);overflow:hidden!important;font-size:var(--avatar-size,60px)!important;line-height:var(--avatar-size,60px);height:var(--avatar-size,60px)!important;width:var(--avatar-size,60px)!important;border-radius:50%;display:inline-block}ion-menu ion-header .user-logo{text-align:right}ion-menu ion-header .user-logo img{max-width:120px;max-height:var(--avatar-size,60px);width:auto}ion-menu ion-header .username{padding-top:0;margin-top:0;margin-bottom:0;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-menu ion-header button[mat-button]{padding:0;text-align:start!important;width:100%}ion-menu .scroll-content{margin-top:79px!important}ion-menu .has-user-header .scroll-content{margin-top:188px!important}ion-menu ion-content.has-profile-header{--offset-top:188px}ion-menu ion-content.no-profile-header{--offset-top:79px}ion-menu ion-content ion-list{min-height:100%;display:flex;flex-direction:column;justify-content:flex-start}ion-menu ion-content ion-list ion-menu-toggle.flex-spacer{flex:1 1 auto;display:flex;flex-direction:column;justify-content:flex-end}ion-menu ion-content ion-list ion-item.primary{--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint)}ion-menu ion-content ion-list ion-item.secondary{--ion-item-icon-color:var(--ion-color-secondary-tint);--ion-item-text-color:var(--ion-color-secondary-tint)}ion-menu ion-content ion-list ion-item.tertiary{--ion-item-icon-color:var(--ion-color-tertiary-tint);--ion-item-text-color:var(--ion-color-tertiary-tint)}ion-menu ion-content ion-list ion-item.danger{--ion-item-icon-color:var(--ion-color-danger-tint);--ion-item-text-color:var(--ion-color-danger-tint)}ion-menu ion-content ion-list ion-item.medium{--ion-item-icon-color:var(--ion-color-medium-shade);--ion-item-text-color:var(--ion-color-medium-shade)}ion-menu ion-content ion-list ion-item.dark{--ion-item-icon-color:var(--ion-color-dark-tint);--ion-item-text-color:var(--ion-color-dark-tint)}ion-menu ion-content ion-list ion-item ion-icon,ion-menu ion-content ion-list ion-item mat-icon{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item ion-label,ion-menu ion-content ion-list ion-item ion-text{color:var(--ion-item-text-color)!important}ion-menu ion-content ion-list ion-item.selected{background-color:var(--ion-item-background-selected)!important;--color-hover:var(--ion-item-background-selected)!important}ion-menu ion-content ion-list ion-item.selected ion-icon,ion-menu ion-content ion-list ion-item.selected mat-icon{color:var(--ion-item-icon-color-selected)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item.selected ion-label,ion-menu ion-content ion-list ion-item.selected ion-text{color:var(--ion-item-text-color-selected)!important}ion-menu ion-content ion-list ion-item.selected:hover{--color-hover:var(--ion-item-background-selected)!important;--ion-item-icon-color-selected:var(--ion-item-icon-color)!important;--ion-item-text-color-selected:var(--ion-item-text-color)!important}ion-menu ion-footer{display:block!important}ion-menu ion-footer ion-toolbar ion-title{cursor:pointer;font-size:12pt;font-weight:400;text-align:center;padding:0 8px}ion-menu ion-footer ion-toolbar ion-button{--width:40px}@media screen and (max-width:767px){ion-menu ion-footer{display:none!important;visibility:hidden!important}}@media screen and (min-width:768px){ion-menu ion-scroll{overflow-y:auto!important}ion-menu .user-avatar{font-size:var(--avatar-size,80px)!important;line-height:var(--avatar-size,80px);height:var(--avatar-size,80px)!important;width:var(--avatar-size,80px)!important}ion-menu .user-logo img{max-height:var(--avatar-size,80px)}}"]
@@ -24816,6 +24817,7 @@
24816
24817
  this.icon = value.icon;
24817
24818
  this.matIcon = value.matIcon;
24818
24819
  this.matSvgIcon = value.matSvgIcon;
24820
+ this.color = value.color;
24819
24821
  },
24820
24822
  enumerable: false,
24821
24823
  configurable: true
@@ -24826,7 +24828,7 @@
24826
24828
  AppIconComponent.decorators = [
24827
24829
  { type: i0.Component, args: [{
24828
24830
  selector: 'app-icon',
24829
- template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\">{{matIcon}}</mat-icon>\n</ng-template>\n\n"
24831
+ template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n [style.font-size.px]=\"height || width\"\n >{{matIcon}}</mat-icon>\n</ng-template>\n\n"
24830
24832
  },] }
24831
24833
  ];
24832
24834
  AppIconComponent.propDecorators = {
@@ -24834,6 +24836,8 @@
24834
24836
  matIcon: [{ type: i0.Input }],
24835
24837
  matSvgIcon: [{ type: i0.Input }],
24836
24838
  color: [{ type: i0.Input }],
24839
+ height: [{ type: i0.Input }],
24840
+ width: [{ type: i0.Input }],
24837
24841
  ref: [{ type: i0.Input }]
24838
24842
  };
24839
24843
 
@@ -26599,7 +26603,7 @@
26599
26603
  .then(function () { return _this.editRowById(event, row.id, { focusColumn: _this.lastUserColumn }); });
26600
26604
  return true;
26601
26605
  }
26602
- // Edit previous row
26606
+ // Edit next row
26603
26607
  this.editRow(event, row, { focusColumn: this.lastUserColumn });
26604
26608
  return true;
26605
26609
  };
@@ -26627,7 +26631,8 @@
26627
26631
  if (id < 0)
26628
26632
  return [2 /*return*/];
26629
26633
  if (!(id >= this.visibleRowCount)) return [3 /*break*/, 1];
26630
- this.addRow(event, undefined, opts);
26634
+ this.focusColumn = opts && opts.focusColumn || this.firstUserColumn;
26635
+ this.addRow(event);
26631
26636
  return [3 /*break*/, 3];
26632
26637
  case 1: return [4 /*yield*/, this.dataSource.getRow(id)];
26633
26638
  case 2:
@@ -26705,7 +26710,7 @@
26705
26710
  this.cancelExistingRow(event, row, opts);
26706
26711
  }
26707
26712
  };
26708
- AppTable.prototype.addRow = function (event, insertAt, opts) {
26713
+ AppTable.prototype.addRow = function (event, insertAt) {
26709
26714
  if (this.debug)
26710
26715
  console.debug('[table] Asking for new row...');
26711
26716
  if (!this._enabled)
@@ -26720,7 +26725,7 @@
26720
26725
  return false;
26721
26726
  }
26722
26727
  // Add new row
26723
- this.addRowToTable(insertAt, opts);
26728
+ this.addRowToTable(insertAt);
26724
26729
  return true;
26725
26730
  };
26726
26731
  AppTable.prototype.save = function (opts) {
@@ -26865,7 +26870,7 @@
26865
26870
  * @param event
26866
26871
  * @param row
26867
26872
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
26868
- * And to force deletion even if table is busy
26873
+ * Use skipIfLoading=false to force deletion even if table is busy
26869
26874
  */
26870
26875
  AppTable.prototype.deleteRow = function (event, row, opts) {
26871
26876
  return __awaiter(this, void 0, void 0, function () {
@@ -26885,7 +26890,7 @@
26885
26890
  * @param event
26886
26891
  * @param rows
26887
26892
  * @param opts Use interactive=false to avoid user interaction (e.g. user confirmation)
26888
- * And to force deletion even if table is busy
26893
+ * Use skipIfLoading=false to force deletion even if table is busy
26889
26894
  */
26890
26895
  AppTable.prototype.deleteRows = function (event, rows, opts) {
26891
26896
  var _a;
@@ -26903,8 +26908,8 @@
26903
26908
  event === null || event === void 0 ? void 0 : event.preventDefault();
26904
26909
  if (!this._enabled || isEmptyArray(rows))
26905
26910
  return [2 /*return*/, 0]; // Skip is disabled, or no rows to delete
26906
- if (this.loading && (!opts || opts.interactive !== false)) {
26907
- console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.interactive = false to force deletion');
26911
+ if (this.loading && (!opts || opts.skipIfLoading !== false)) {
26912
+ console.warn('[app-table] Skip deleteRows() because table is busy (loading). Use opts.skipLoading = false to force deletion');
26908
26913
  return [2 /*return*/, 0]; // Skip if loading
26909
26914
  }
26910
26915
  // Make sure to keep newly created row
@@ -27543,13 +27548,12 @@
27543
27548
  //if (this.debug) console.debug("[table] id = " + id);
27544
27549
  return id;
27545
27550
  };
27546
- AppTable.prototype.addRowToTable = function (insertAt, opts) {
27551
+ AppTable.prototype.addRowToTable = function (insertAt) {
27547
27552
  return __awaiter(this, void 0, void 0, function () {
27548
27553
  return __generator(this, function (_e) {
27549
27554
  switch (_e.label) {
27550
27555
  case 0:
27551
27556
  this.focusFirstColumn = true;
27552
- this.focusColumn = (opts === null || opts === void 0 ? void 0 : opts.focusColumn) || this.firstUserColumn;
27553
27557
  return [4 /*yield*/, this._dataSource.asyncCreateNew(insertAt)];
27554
27558
  case 1:
27555
27559
  _e.sent();
@@ -28150,8 +28154,6 @@
28150
28154
  AppEditor.prototype.ready = function (opts) {
28151
28155
  return __awaiter(this, void 0, void 0, function () {
28152
28156
  return __generator(this, function (_b) {
28153
- if (this._$ready.value)
28154
- return [2 /*return*/];
28155
28157
  return [2 /*return*/, waitForTrue(this._$ready, opts)];
28156
28158
  });
28157
28159
  });
@@ -30054,7 +30056,10 @@
30054
30056
  var SocialErrorCodes = {
30055
30057
  LOAD_USER_EVENTS_ERROR: 50000,
30056
30058
  SAVE_USER_EVENT_ERROR: 50001,
30057
- SEND_MESSAGE_ERROR: 50003
30059
+ COUNT_USER_EVENT_ERROR: 50002,
30060
+ SEND_MESSAGE_ERROR: 50003,
30061
+ SUBSCRIBE_USER_EVENTS_ERROR: 50005,
30062
+ SUBSCRIBE_JOB_PROGRESSION_ERROR: 50010
30058
30063
  };
30059
30064
 
30060
30065
  var UserEvent_1;
@@ -30070,16 +30075,23 @@
30070
30075
  }
30071
30076
  UserEvent.prototype.asObject = function (opts) {
30072
30077
  var target = _super.prototype.asObject.call(this, opts);
30078
+ target.creationDate = toDateISOString(this.creationDate);
30079
+ target.readDate = toDateISOString(this.readDate);
30073
30080
  // Serialize content
30074
30081
  if (typeof target.content === 'object') {
30075
30082
  target.content = JSON.stringify(target.content);
30076
30083
  }
30084
+ delete target.avatar;
30085
+ delete target.avatarIcon;
30086
+ delete target.icon;
30087
+ delete target.actions;
30077
30088
  return target;
30078
30089
  };
30079
30090
  UserEvent.prototype.fromObject = function (source) {
30080
30091
  Object.assign(this, source); // Copy all properties
30081
30092
  _super.prototype.fromObject.call(this, source);
30082
30093
  this.creationDate = fromDateISOString(source.creationDate);
30094
+ this.readDate = fromDateISOString(source.readDate);
30083
30095
  try {
30084
30096
  // Deserialize content
30085
30097
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -30099,36 +30111,48 @@
30099
30111
  exports.UserEvent = UserEvent_1 = __decorate([
30100
30112
  EntityClass({ typename: 'UserEventVO' })
30101
30113
  ], exports.UserEvent);
30102
-
30103
- var UserEventFragments = {
30104
- 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 }"]))),
30105
- 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 }"])))
30106
- };
30107
- var templateObject_1$2, templateObject_2$2;
30108
-
30109
30114
  // @dynamic
30110
30115
  exports.UserEventFilter = /** @class */ (function (_super) {
30111
30116
  __extends(UserEventFilter, _super);
30112
30117
  function UserEventFilter() {
30113
30118
  var _this = _super.apply(this, __spread(arguments)) || this;
30114
- _this.issuer = null;
30115
- _this.recipient = null;
30119
+ _this.types = [];
30120
+ _this.levels = [];
30121
+ _this.issuers = [];
30122
+ _this.recipients = [];
30123
+ _this.startDate = null;
30124
+ _this.excludeRead = false;
30116
30125
  return _this;
30117
30126
  }
30118
30127
  UserEventFilter.prototype.fromObject = function (source, opts) {
30119
30128
  _super.prototype.fromObject.call(this, source, opts);
30120
- this.issuer = source.issuer;
30121
- this.recipient = source.recipient;
30129
+ this.types = source.types || [];
30130
+ this.levels = source.levels || [];
30131
+ this.issuers = source.issuers || [];
30132
+ this.recipients = source.recipients || [];
30133
+ this.startDate = fromDateISOString(source.startDate);
30134
+ this.excludeRead = source.excludeRead || false;
30122
30135
  };
30123
30136
  UserEventFilter.prototype.buildFilter = function () {
30124
30137
  var _this = this;
30125
30138
  var filterFns = _super.prototype.buildFilter.call(this);
30126
- // issuer
30127
- if (this.issuer) {
30128
- filterFns.push(function (t) { return (t.issuer === _this.issuer); });
30139
+ if (isNotEmptyArray(this.types)) {
30140
+ filterFns.push(function (t) { return _this.types.includes(t.type); });
30141
+ }
30142
+ if (isNotEmptyArray(this.levels)) {
30143
+ filterFns.push(function (t) { return _this.levels.includes(t.level); });
30144
+ }
30145
+ if (isNotEmptyArray(this.issuers)) {
30146
+ filterFns.push(function (t) { return _this.issuers.includes(t.issuer); });
30147
+ }
30148
+ if (isNotEmptyArray(this.recipients)) {
30149
+ filterFns.push(function (t) { return _this.recipients.includes(t.recipient); });
30150
+ }
30151
+ if (isNotNil(this.startDate)) {
30152
+ filterFns.push(function (t) { return _this.startDate.isSameOrBefore(t.creationDate); });
30129
30153
  }
30130
- if (this.recipient) {
30131
- filterFns.push(function (t) { return (t.recipient === _this.recipient); });
30154
+ if (this.excludeRead === true) {
30155
+ filterFns.push(function (t) { return isNil(t.readSignature); }); // todo or t.signature ?
30132
30156
  }
30133
30157
  return filterFns;
30134
30158
  };
@@ -30137,120 +30161,274 @@
30137
30161
  exports.UserEventFilter = __decorate([
30138
30162
  EntityClass({ typename: 'UserEventFilterVO' })
30139
30163
  ], exports.UserEventFilter);
30140
- 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);
30141
- 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);
30142
- 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"])));
30143
- 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);
30144
- var UserEventService = /** @class */ (function (_super) {
30145
- __extends(UserEventService, _super);
30146
- function UserEventService(graphql, accountService, network, translate, toastController, environment) {
30164
+
30165
+ var UserEventFragments = {
30166
+ userEvent: core.gql(templateObject_1$2 || (templateObject_1$2 = __makeTemplateObject(["fragment UserEventFragment on UserEventVO {\n id\n issuer\n updateDate\n creationDate\n eventType\n recipient\n content\n hash\n signature\n readSignature\n __typename\n }"], ["fragment UserEventFragment on UserEventVO {\n id\n issuer\n updateDate\n creationDate\n eventType\n recipient\n content\n hash\n signature\n readSignature\n __typename\n }"]))),
30167
+ lightUserEvent: core.gql(templateObject_2$2 || (templateObject_2$2 = __makeTemplateObject(["fragment LightUserEventFragment on UserEventVO {\n id\n issuer\n recipient\n updateDate\n creationDate\n eventType\n readSignature\n __typename\n }"], ["fragment LightUserEventFragment on UserEventVO {\n id\n issuer\n recipient\n updateDate\n creationDate\n eventType\n readSignature\n __typename\n }"])))
30168
+ };
30169
+ var templateObject_1$2, templateObject_2$2;
30170
+
30171
+ var moment$6 = momentImported__namespace;
30172
+ var UserEventServiceToken = new i0.InjectionToken('UserEventService');
30173
+ var AbstractUserEventService = /** @class */ (function (_super) {
30174
+ __extends(AbstractUserEventService, _super);
30175
+ function AbstractUserEventService(graphql, accountService, network, translate, toastController, queries, mutations, subscriptions, environment) {
30147
30176
  var _this = _super.call(this, graphql, environment) || this;
30148
30177
  _this.graphql = graphql;
30149
30178
  _this.accountService = accountService;
30150
30179
  _this.network = network;
30151
30180
  _this.translate = translate;
30152
30181
  _this.toastController = toastController;
30182
+ _this.queries = queries;
30183
+ _this.mutations = mutations;
30184
+ _this.subscriptions = subscriptions;
30153
30185
  _this.environment = environment;
30154
- _this._userEventActions = [];
30186
+ _this._count$ = new rxjs.BehaviorSubject(0);
30187
+ _this._subscriptions = new rxjs.Subscription();
30188
+ _this.listeners = [];
30189
+ _this._logPrefix = '[user-event-service] ';
30155
30190
  // For DEV only
30156
- _this._debug = environment && !environment.production;
30191
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
30192
+ // listen login/logout
30193
+ _this._subscriptions.add(accountService.onLogin.subscribe(function () { return __awaiter(_this, void 0, void 0, function () {
30194
+ var count;
30195
+ return __generator(this, function (_b) {
30196
+ switch (_b.label) {
30197
+ case 0: return [4 /*yield*/, this.count(this.defaultFilter())];
30198
+ case 1:
30199
+ count = _b.sent();
30200
+ if (count && this._debug) {
30201
+ console.debug(this._logPrefix + "Received " + count + " unread notifications");
30202
+ }
30203
+ this._count$.next(count);
30204
+ return [2 /*return*/];
30205
+ }
30206
+ });
30207
+ }); }));
30157
30208
  return _this;
30158
30209
  }
30159
- /**
30160
- *
30161
- * @param offset
30162
- * @param size
30163
- * @param sortBy
30164
- * @param sortDirection
30165
- * @param filter
30166
- * @param options
30167
- * @deprecated use watchPage() instead
30168
- */
30169
- UserEventService.prototype.watchAll = function (offset, size, sortBy, sortDirection, filter, options) {
30210
+ Object.defineProperty(AbstractUserEventService.prototype, "userEventCount", {
30211
+ get: function () {
30212
+ return this._count$.asObservable();
30213
+ },
30214
+ enumerable: false,
30215
+ configurable: true
30216
+ });
30217
+ AbstractUserEventService.prototype.ngOnDestroy = function () {
30218
+ this._subscriptions.unsubscribe();
30219
+ };
30220
+ AbstractUserEventService.prototype.watchAll = function (offset, size, sortBy, sortDirection, filter, options) {
30170
30221
  return this.watchPage({ offset: offset, size: size, sortBy: sortBy, sortDirection: sortDirection }, filter, options);
30171
30222
  };
30172
- UserEventService.prototype.watchPage = function (page, filter, options) {
30223
+ AbstractUserEventService.prototype.watchPage = function (page, filter, options) {
30224
+ var _this = this;
30225
+ var _a;
30173
30226
  var now = this._debug && Date.now();
30174
30227
  //if (this._debug)
30175
- console.debug('[user-event-service] Loading user events...', filter);
30228
+ console.debug(this._logPrefix + "Loading user events...", filter);
30176
30229
  filter = this.asFilter(filter);
30177
30230
  // Force recipient to current issuer, if not admin and not specified
30178
- if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
30179
- var recipient = this.accountService.account.pubkey;
30180
- if (recipient !== filter.recipient) {
30231
+ if (isEmptyArray(filter.recipients) || !this.accountService.isAdmin()) {
30232
+ var recipient = this.defaultRecipient();
30233
+ if (!((_a = filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
30181
30234
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
30182
- filter.recipient = recipient;
30235
+ filter.recipients = [recipient];
30183
30236
  }
30184
30237
  }
30185
- var withContent = options && options.withContent === true;
30238
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30186
30239
  return this.mutableWatchQuery({
30187
30240
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
30188
- query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
30241
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30189
30242
  variables: {
30190
- page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
30243
+ page: Object.assign({ sortBy: 'updateDate', sortDirection: 'desc' }, page),
30191
30244
  filter: filter && filter.asPodObject()
30192
30245
  },
30193
30246
  arrayFieldName: 'data',
30194
30247
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
30195
- fetchPolicy: options && options.fetchPolicy || undefined
30248
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || "cache-first"
30196
30249
  })
30197
30250
  .pipe(operators.map(function (res) {
30198
- var data = res && (res.data || []).map(exports.UserEvent.fromObject);
30251
+ var data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(_this.processUserEvent);
30199
30252
  if (now) {
30200
- console.debug("[user-event-service] " + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30253
+ console.debug("" + _this._logPrefix + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30201
30254
  now = null;
30202
30255
  }
30256
+ var unreadCount = _this.unreadEvents(data);
30203
30257
  return {
30204
30258
  data: data,
30205
- total: res && toNumber(res.total, data.length)
30259
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
30206
30260
  };
30207
30261
  }));
30208
30262
  };
30209
- UserEventService.prototype.saveAll = function (data, options) {
30263
+ AbstractUserEventService.prototype.add = function (entity) {
30264
+ // TODO set an id !!!!!!!!!!!!!!!!!!!!!!!!!
30265
+ entity = this.processUserEvent(entity);
30266
+ var withContent = !!entity.content;
30267
+ // Add user event locally
30268
+ this.insertIntoMutableCachedQueries(this.graphql.cache, {
30269
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30270
+ data: entity
30271
+ });
30272
+ // Update count
30273
+ this._count$.next(this._count$.value + 1);
30274
+ };
30275
+ AbstractUserEventService.prototype.count = function (filter, options) {
30276
+ var _a;
30277
+ return __awaiter(this, void 0, void 0, function () {
30278
+ var res;
30279
+ return __generator(this, function (_b) {
30280
+ switch (_b.label) {
30281
+ case 0:
30282
+ if (!((_a = this.queries) === null || _a === void 0 ? void 0 : _a.count)) {
30283
+ console.warn(this._logPrefix + "Query 'count' not provided, skip.");
30284
+ return [2 /*return*/, undefined];
30285
+ }
30286
+ if (!filter)
30287
+ throw new Error("Missing argument 'filter'");
30288
+ filter = this.asFilter(filter);
30289
+ if (this._debug)
30290
+ console.debug(this._logPrefix + "Counting user events with filter:", filter);
30291
+ return [4 /*yield*/, this.graphql.query({
30292
+ query: this.queries.count,
30293
+ variables: {
30294
+ filter: filter.asPodObject()
30295
+ },
30296
+ error: { code: SocialErrorCodes.COUNT_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.COUNT_USER_EVENT_ERROR' },
30297
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'network-only'
30298
+ })];
30299
+ case 1:
30300
+ res = _b.sent();
30301
+ return [2 /*return*/, res.total];
30302
+ }
30303
+ });
30304
+ });
30305
+ };
30306
+ AbstractUserEventService.prototype.listenChanges = function (filter, options) {
30210
30307
  var _this = this;
30211
- return Promise.all(data
30212
- .map(function (entity) { return _this.save(entity, options); }));
30308
+ var _a;
30309
+ if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
30310
+ console.warn(this._logPrefix + "Subscription query 'listenChanges' not provided, skip.");
30311
+ return rxjs.of();
30312
+ }
30313
+ if (!filter)
30314
+ throw new Error("Missing argument 'filter'");
30315
+ filter = this.asFilter(filter);
30316
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30317
+ if (this._debug)
30318
+ console.debug(this._logPrefix + "[WS] Listening changes for user events with filter:", filter);
30319
+ return this.graphql.subscribe({
30320
+ query: this.subscriptions.listenChanges,
30321
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
30322
+ variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
30323
+ error: {
30324
+ code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
30325
+ message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
30326
+ }
30327
+ }).pipe(operators.map(function (_b) {
30328
+ var data = _b.data;
30329
+ if (data && _this._debug)
30330
+ console.debug(_this._logPrefix + "Received new user events:", data);
30331
+ var updatedData = data === null || data === void 0 ? void 0 : data.map(_this.processUserEvent);
30332
+ // Update cache
30333
+ _this.insertIntoMutableCachedQueries(_this.graphql.cache, {
30334
+ query: withContent ? _this.queries.loadAllWithContent : _this.queries.loadAll,
30335
+ data: updatedData
30336
+ });
30337
+ // update count
30338
+ _this._count$.next(_this.unreadEvents(updatedData));
30339
+ return updatedData;
30340
+ }));
30213
30341
  };
30214
- /**
30215
- * Save a userEvent entity
30216
- *
30217
- * @param entity
30218
- */
30219
- UserEventService.prototype.save = function (entity, options) {
30342
+ AbstractUserEventService.prototype.delete = function (entity) {
30343
+ return __awaiter(this, void 0, void 0, function () {
30344
+ return __generator(this, function (_b) {
30345
+ switch (_b.label) {
30346
+ case 0:
30347
+ if (!entity)
30348
+ return [2 /*return*/]; // skip
30349
+ return [4 /*yield*/, this.deleteAll([entity])];
30350
+ case 1:
30351
+ _b.sent();
30352
+ return [2 /*return*/];
30353
+ }
30354
+ });
30355
+ });
30356
+ };
30357
+ AbstractUserEventService.prototype.deleteAll = function (entities, opts) {
30358
+ return __awaiter(this, void 0, void 0, function () {
30359
+ var ids, now;
30360
+ var _this = this;
30361
+ return __generator(this, function (_b) {
30362
+ switch (_b.label) {
30363
+ case 0:
30364
+ ids = entities && entities
30365
+ .map(function (t) { return t.id; });
30366
+ if (isEmptyArray(ids))
30367
+ return [2 /*return*/]; // stop, if nothing else to do
30368
+ now = Date.now();
30369
+ if (this._debug)
30370
+ console.debug(this._logPrefix + "Deleting events... ids:", ids);
30371
+ return [4 /*yield*/, this.graphql.mutate({
30372
+ mutation: this.mutations.deleteByIds,
30373
+ variables: {
30374
+ ids: ids
30375
+ },
30376
+ update: function (proxy) {
30377
+ // Remove from caches
30378
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30379
+ query: _this.queries.loadAll,
30380
+ ids: ids
30381
+ });
30382
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30383
+ query: _this.queries.loadAllWithContent,
30384
+ ids: ids
30385
+ });
30386
+ if (_this._debug)
30387
+ console.debug(_this._logPrefix + "Events deleted in " + (Date.now() - now) + "ms");
30388
+ }
30389
+ })];
30390
+ case 1:
30391
+ _b.sent();
30392
+ return [2 /*return*/];
30393
+ }
30394
+ });
30395
+ });
30396
+ };
30397
+ AbstractUserEventService.prototype.save = function (entity, options) {
30220
30398
  return __awaiter(this, void 0, void 0, function () {
30221
30399
  var isNew, json, now;
30222
30400
  var _this = this;
30223
- return __generator(this, function (_a) {
30224
- switch (_a.label) {
30401
+ return __generator(this, function (_b) {
30402
+ switch (_b.label) {
30225
30403
  case 0:
30226
30404
  this.fillDefaultProperties(entity);
30227
30405
  isNew = isNil(entity.id);
30228
30406
  json = entity.asObject();
30229
30407
  now = Date.now();
30230
30408
  if (this._debug)
30231
- console.debug("[user-event-service] Saving user event...", json);
30409
+ console.debug(this._logPrefix + "Saving user event...", json);
30232
30410
  return [4 /*yield*/, this.graphql.mutate({
30233
- mutation: SaveQuery,
30411
+ mutation: this.mutations.save,
30234
30412
  variables: {
30235
30413
  data: json
30236
30414
  },
30237
30415
  error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
30238
- update: function (proxy, _a) {
30239
- var data = _a.data;
30416
+ update: function (proxy, _b) {
30417
+ var data = _b.data;
30240
30418
  // Update entity
30241
30419
  var savedEntity = data && data.data;
30242
30420
  if (savedEntity) {
30243
30421
  if (_this._debug)
30244
- console.debug("[user-event-service] User event saved in " + (Date.now() - now) + "ms", entity);
30422
+ console.debug(_this._logPrefix + "User event saved in " + (Date.now() - now) + "ms", entity);
30245
30423
  _this.copyIdAndUpdateDate(savedEntity, entity);
30246
30424
  // Add to cache
30247
30425
  if (isNew) {
30248
30426
  _this.insertIntoMutableCachedQueries(proxy, {
30249
- query: LoadAllQuery,
30427
+ query: _this.queries.loadAll,
30250
30428
  data: Object.assign(Object.assign({}, savedEntity), { content: null })
30251
30429
  });
30252
30430
  _this.insertIntoMutableCachedQueries(proxy, {
30253
- query: LoadAllWithContentQuery,
30431
+ query: _this.queries.loadAllWithContent,
30254
30432
  data: savedEntity
30255
30433
  });
30256
30434
  }
@@ -30258,93 +30436,186 @@
30258
30436
  }
30259
30437
  })];
30260
30438
  case 1:
30261
- _a.sent();
30439
+ _b.sent();
30262
30440
  return [2 /*return*/, entity];
30263
30441
  }
30264
30442
  });
30265
30443
  });
30266
30444
  };
30267
- /**
30268
- * Save many trips
30269
- *
30270
- * @param entities
30271
- * @param opts
30272
- */
30273
- UserEventService.prototype.deleteAll = function (entities, opts) {
30445
+ AbstractUserEventService.prototype.saveAll = function (data, opts) {
30446
+ var _this = this;
30447
+ return Promise.all(data
30448
+ .map(function (entity) { return _this.save(entity, opts); }));
30449
+ };
30450
+ AbstractUserEventService.prototype.markAsRead = function (entity) {
30274
30451
  return __awaiter(this, void 0, void 0, function () {
30275
- var ids, now;
30276
- var _this = this;
30277
- return __generator(this, function (_a) {
30278
- switch (_a.label) {
30452
+ var onReadListeners, onReadListeners_1, onReadListeners_1_1, listener, e_1_1;
30453
+ var e_1, _b;
30454
+ return __generator(this, function (_c) {
30455
+ switch (_c.label) {
30279
30456
  case 0:
30280
- ids = entities && entities
30281
- .map(function (t) { return t.id; });
30282
- if (isEmptyArray(ids))
30283
- return [2 /*return*/]; // stop, if nothing else to do
30284
- now = Date.now();
30285
- if (this._debug)
30286
- console.debug('[user-event-service] Deleting events... ids:', ids);
30287
- return [4 /*yield*/, this.graphql.mutate({
30288
- mutation: DeleteByIdsMutation,
30289
- variables: {
30290
- ids: ids
30291
- },
30292
- update: function (proxy) {
30293
- // Remove from caches
30294
- _this.removeFromMutableCachedQueriesByIds(proxy, {
30295
- query: LoadAllQuery,
30296
- ids: ids
30297
- });
30298
- _this.removeFromMutableCachedQueriesByIds(proxy, {
30299
- query: LoadAllWithContentQuery,
30300
- ids: ids
30301
- });
30302
- if (_this._debug)
30303
- console.debug("[user-event-service] Events deleted in " + (Date.now() - now) + "ms");
30304
- }
30305
- })];
30457
+ onReadListeners = (this.listeners || []).filter(function (listener) { return !!listener.onRead; }).filter(function (listener) { return listener.accept(entity); });
30458
+ if (!onReadListeners.length) return [3 /*break*/, 9];
30459
+ _c.label = 1;
30306
30460
  case 1:
30307
- _a.sent();
30308
- return [2 /*return*/];
30461
+ _c.trys.push([1, 6, 7, 8]);
30462
+ onReadListeners_1 = __values(onReadListeners), onReadListeners_1_1 = onReadListeners_1.next();
30463
+ _c.label = 2;
30464
+ case 2:
30465
+ if (!!onReadListeners_1_1.done) return [3 /*break*/, 5];
30466
+ listener = onReadListeners_1_1.value;
30467
+ return [4 /*yield*/, listener.onRead(entity)];
30468
+ case 3:
30469
+ _c.sent();
30470
+ _c.label = 4;
30471
+ case 4:
30472
+ onReadListeners_1_1 = onReadListeners_1.next();
30473
+ return [3 /*break*/, 2];
30474
+ case 5: return [3 /*break*/, 8];
30475
+ case 6:
30476
+ e_1_1 = _c.sent();
30477
+ e_1 = { error: e_1_1 };
30478
+ return [3 /*break*/, 8];
30479
+ case 7:
30480
+ try {
30481
+ if (onReadListeners_1_1 && !onReadListeners_1_1.done && (_b = onReadListeners_1.return)) _b.call(onReadListeners_1);
30482
+ }
30483
+ finally { if (e_1) throw e_1.error; }
30484
+ return [7 /*endfinally*/];
30485
+ case 8: return [3 /*break*/, 11];
30486
+ case 9:
30487
+ // Use default
30488
+ return [4 /*yield*/, this.defaultMarkAsRead(entity)];
30489
+ case 10:
30490
+ // Use default
30491
+ _c.sent();
30492
+ _c.label = 11;
30493
+ case 11: return [2 /*return*/];
30309
30494
  }
30310
30495
  });
30311
30496
  });
30312
30497
  };
30313
- /**
30314
- * Delete userEvent entities
30315
- */
30316
- UserEventService.prototype.delete = function (data) {
30498
+ AbstractUserEventService.prototype.registerListener = function (listener) {
30499
+ if (!this.listeners)
30500
+ this.listeners = [];
30501
+ this.listeners.push(listener);
30502
+ };
30503
+ /* -- protected methods -- */
30504
+ AbstractUserEventService.prototype.processUserEvent = function (source) {
30505
+ var e_2, _b;
30506
+ // Convert json source to IUserEvent
30507
+ var target = this.fromObject(source);
30508
+ // Get listeners
30509
+ var listeners = (this.listeners || []).filter(function (listener) { return listener.onReceived; }).filter(function (listener) { return listener.accept(target); });
30510
+ try {
30511
+ for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
30512
+ var listener = listeners_1_1.value;
30513
+ if (target) {
30514
+ target = listener.onReceived(target);
30515
+ }
30516
+ else {
30517
+ if (this._debug)
30518
+ console.debug(this._logPrefix + "Event has been rejected by a listener", source);
30519
+ break;
30520
+ }
30521
+ }
30522
+ }
30523
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
30524
+ finally {
30525
+ try {
30526
+ if (listeners_1_1 && !listeners_1_1.done && (_b = listeners_1.return)) _b.call(listeners_1);
30527
+ }
30528
+ finally { if (e_2) throw e_2.error; }
30529
+ }
30530
+ return target;
30531
+ };
30532
+ AbstractUserEventService.prototype.defaultMarkAsRead = function (userEvent) {
30317
30533
  return __awaiter(this, void 0, void 0, function () {
30318
- return __generator(this, function (_a) {
30319
- switch (_a.label) {
30534
+ return __generator(this, function (_b) {
30535
+ switch (_b.label) {
30320
30536
  case 0:
30321
- if (!data)
30322
- return [2 /*return*/]; // skip
30323
- return [4 /*yield*/, this.deleteAll([data])];
30324
- case 1:
30325
- _a.sent();
30326
- return [2 /*return*/];
30537
+ if (!userEvent)
30538
+ throw new Error(this._logPrefix + "Invalid event to save");
30539
+ // set read date
30540
+ userEvent.readDate = moment$6();
30541
+ if (!(!userEvent.id || userEvent.id < 0)) return [3 /*break*/, 1];
30542
+ if (this._debug)
30543
+ console.debug(this._logPrefix + "Save local user event");
30544
+ return [3 /*break*/, 3];
30545
+ case 1: return [4 /*yield*/, this.save(userEvent)];
30546
+ case 2:
30547
+ _b.sent();
30548
+ _b.label = 3;
30549
+ case 3: return [2 /*return*/];
30327
30550
  }
30328
30551
  });
30329
30552
  });
30330
30553
  };
30331
- UserEventService.prototype.listenChanges = function (id, options) {
30332
- // TODO
30333
- console.warn('TODO: implement listen changes on user events');
30334
- return rxjs.of();
30554
+ AbstractUserEventService.prototype.defaultFilter = function () {
30555
+ // By default
30556
+ return {
30557
+ recipients: [this.defaultRecipient()]
30558
+ };
30559
+ };
30560
+ AbstractUserEventService.prototype.defaultRecipient = function () {
30561
+ return this.accountService.person.pubkey;
30335
30562
  };
30336
- UserEventService.prototype.registerAction = function (definition) {
30337
- console.info("[user-event-service] Registering action " + definition.name + " for " + definition.__typename);
30338
- this._userEventActions.push(definition);
30563
+ AbstractUserEventService.prototype.fillDefaultProperties = function (entity) {
30339
30564
  };
30340
- UserEventService.prototype.getActionsByTypename = function (typename) {
30341
- return this._userEventActions.filter(function (def) { return def.__typename === typename; });
30565
+ AbstractUserEventService.prototype.unreadEvents = function (events) {
30566
+ // default calculation on unread events from a list
30567
+ if (isEmptyArray(events))
30568
+ return undefined;
30569
+ var lastReadDate = events
30570
+ .filter(function (event) { return isNotNil(event.readDate); })
30571
+ .reduce(function (lastDate, event) { return DateUtils.max(lastDate, event.readDate); }, undefined);
30572
+ return events
30573
+ .filter(function (event) { return event.creationDate.isSameOrAfter(lastReadDate); }).length;
30342
30574
  };
30575
+ AbstractUserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30576
+ EntityUtils.copyIdAndUpdateDate(source, target);
30577
+ };
30578
+ return AbstractUserEventService;
30579
+ }(BaseGraphqlService));
30580
+ AbstractUserEventService.decorators = [
30581
+ { type: i0.Directive }
30582
+ ];
30583
+ AbstractUserEventService.ctorParameters = function () { return [
30584
+ { type: GraphqlService },
30585
+ { type: AccountService },
30586
+ { type: NetworkService },
30587
+ { type: i1$2.TranslateService },
30588
+ { type: i1$5.ToastController },
30589
+ { type: undefined },
30590
+ { type: undefined },
30591
+ { type: undefined },
30592
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30593
+ ]; };
30594
+ var userEventQueries = {
30595
+ 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),
30596
+ 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)
30597
+ };
30598
+ var userEventMutations = {
30599
+ 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 "]))),
30600
+ 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)
30601
+ };
30602
+ var UserEventService = /** @class */ (function (_super) {
30603
+ __extends(UserEventService, _super);
30604
+ function UserEventService(graphql, accountService, network, translate, toastController, environment) {
30605
+ var _this = _super.call(this, graphql, accountService, network, translate, toastController, userEventQueries, userEventMutations, undefined, environment) || this;
30606
+ _this.graphql = graphql;
30607
+ _this.accountService = accountService;
30608
+ _this.network = network;
30609
+ _this.translate = translate;
30610
+ _this.toastController = toastController;
30611
+ _this.environment = environment;
30612
+ return _this;
30613
+ }
30343
30614
  UserEventService.prototype.showToastErrorWithContext = function (opts) {
30344
30615
  return __awaiter(this, void 0, void 0, function () {
30345
30616
  var message, res, context, userEvent, err_1;
30346
- return __generator(this, function (_a) {
30347
- switch (_a.label) {
30617
+ return __generator(this, function (_b) {
30618
+ switch (_b.label) {
30348
30619
  case 0:
30349
30620
  message = opts.message || (opts.error && opts.error.message || opts.error);
30350
30621
  // Make sure message a string
@@ -30373,12 +30644,12 @@
30373
30644
  }]
30374
30645
  })];
30375
30646
  case 1:
30376
- res = _a.sent();
30647
+ res = _b.sent();
30377
30648
  if (!res || res.role !== 'send')
30378
30649
  return [2 /*return*/];
30379
- _a.label = 2;
30650
+ _b.label = 2;
30380
30651
  case 2:
30381
- _a.trys.push([2, 6, , 7]);
30652
+ _b.trys.push([2, 6, , 7]);
30382
30653
  if (this._debug)
30383
30654
  console.debug('Sending debug data...');
30384
30655
  context = opts && opts.context;
@@ -30388,15 +30659,15 @@
30388
30659
  if (!(context instanceof Promise)) return [3 /*break*/, 4];
30389
30660
  return [4 /*yield*/, context];
30390
30661
  case 3:
30391
- context = _a.sent();
30392
- _a.label = 4;
30662
+ context = _b.sent();
30663
+ _b.label = 4;
30393
30664
  case 4: return [4 /*yield*/, this.sendDataForDebug({
30394
30665
  message: message,
30395
30666
  error: opts.error || undefined,
30396
30667
  context: this.convertObjectToString(context)
30397
30668
  })];
30398
30669
  case 5:
30399
- userEvent = _a.sent();
30670
+ userEvent = _b.sent();
30400
30671
  console.info('Debug data successfully sent to admin', userEvent);
30401
30672
  this.showToast({
30402
30673
  type: 'info',
@@ -30405,7 +30676,7 @@
30405
30676
  });
30406
30677
  return [3 /*break*/, 7];
30407
30678
  case 6:
30408
- err_1 = _a.sent();
30679
+ err_1 = _b.sent();
30409
30680
  console.error('Error while sending debug data:', err_1);
30410
30681
  return [3 /*break*/, 7];
30411
30682
  case 7: return [2 /*return*/];
@@ -30415,13 +30686,16 @@
30415
30686
  };
30416
30687
  UserEventService.prototype.sendDataForDebug = function (data) {
30417
30688
  var userEvent = new exports.UserEvent();
30418
- userEvent.eventType = UserEventTypes.DEBUG_DATA;
30689
+ userEvent.type = UserEventTypes.DEBUG_DATA;
30419
30690
  userEvent.content = this.convertObjectToString(data);
30420
30691
  return this.save(userEvent);
30421
30692
  };
30422
30693
  UserEventService.prototype.asFilter = function (filter) {
30423
30694
  return exports.UserEventFilter.fromObject(filter);
30424
30695
  };
30696
+ UserEventService.prototype.fromObject = function (source) {
30697
+ return exports.UserEvent.fromObject(source);
30698
+ };
30425
30699
  /* -- protected methods -- */
30426
30700
  UserEventService.prototype.convertObjectToString = function (data) {
30427
30701
  if (typeof data === 'string') {
@@ -30439,13 +30713,13 @@
30439
30713
  };
30440
30714
  UserEventService.prototype.showToast = function (opts) {
30441
30715
  return __awaiter(this, void 0, void 0, function () {
30442
- return __generator(this, function (_a) {
30443
- switch (_a.label) {
30716
+ return __generator(this, function (_b) {
30717
+ switch (_b.label) {
30444
30718
  case 0:
30445
30719
  if (!this.toastController)
30446
30720
  throw new Error('Missing toastController in component\'s constructor');
30447
30721
  return [4 /*yield*/, Toasts.show(this.toastController, this.translate, opts)];
30448
- case 1: return [2 /*return*/, _a.sent()];
30722
+ case 1: return [2 /*return*/, _b.sent()];
30449
30723
  }
30450
30724
  });
30451
30725
  });
@@ -30456,14 +30730,10 @@
30456
30730
  // TODO: compute sign
30457
30731
  console.warn('TODO: sign user event before sending');
30458
30732
  };
30459
- UserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30460
- EntityUtils.copyIdAndUpdateDate(source, target);
30461
- };
30462
30733
  return UserEventService;
30463
- }(BaseGraphqlService));
30464
- 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" });
30734
+ }(AbstractUserEventService));
30465
30735
  UserEventService.decorators = [
30466
- { type: i0.Injectable, args: [{ providedIn: 'root' },] }
30736
+ { type: i0.Injectable }
30467
30737
  ];
30468
30738
  UserEventService.ctorParameters = function () { return [
30469
30739
  { type: GraphqlService },
@@ -30477,7 +30747,7 @@
30477
30747
 
30478
30748
  var ICONS_MAP = {
30479
30749
  DEBUG_DATA: { matIcon: 'bug_report' },
30480
- INBOX_MESSAGE: { matIcon: 'mail' },
30750
+ INBOX_MESSAGE: { matIcon: 'mail' }
30481
30751
  };
30482
30752
  // TODO: refactor with a registration done by data service:
30483
30753
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -30545,7 +30815,7 @@
30545
30815
  }
30546
30816
  }));
30547
30817
  var filter = this.filter || new exports.UserEventFilter();
30548
- filter.recipient = this.recipient;
30818
+ filter.recipients = [this.recipient];
30549
30819
  this.setFilter(filter, { emitEvent: true });
30550
30820
  };
30551
30821
  UserEventsTable.prototype.start = function () {
@@ -30567,17 +30837,17 @@
30567
30837
  });
30568
30838
  };
30569
30839
  UserEventsTable.prototype.getIcon = function (source) {
30570
- return ICONS_MAP[source.eventType];
30840
+ return ICONS_MAP[source.type];
30571
30841
  };
30572
30842
  UserEventsTable.prototype.getDetail = function (source) {
30573
30843
  if (!source)
30574
30844
  return undefined;
30575
- if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
30845
+ if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
30576
30846
  var context = source.content.context;
30577
30847
  if (context && context.__typename) {
30578
- var actions = this.service.getActionsByTypename(context.__typename);
30848
+ // const actions = this.service.getActionsByTypename(context.__typename);
30579
30849
  return {
30580
- actions: actions,
30850
+ // actions,
30581
30851
  title: source.content.error && source.content.error.message || source.content.message,
30582
30852
  description: source.content.error && source.content.error.details || undefined
30583
30853
  };
@@ -30588,18 +30858,18 @@
30588
30858
  };
30589
30859
  UserEventsTable.prototype.doAction = function (action, row) {
30590
30860
  return __awaiter(this, void 0, void 0, function () {
30591
- var event, context, res, _a, err_1;
30861
+ var event, res, _a, err_1;
30592
30862
  return __generator(this, function (_b) {
30593
30863
  switch (_b.label) {
30594
30864
  case 0:
30595
30865
  event = row.currentData;
30596
- context = event.content && event.content.context;
30866
+ // const context = event.content && event.content.context;
30597
30867
  this.markAsLoading();
30598
30868
  if (!(action && typeof action.executeAction === 'function')) return [3 /*break*/, 7];
30599
30869
  _b.label = 1;
30600
30870
  case 1:
30601
30871
  _b.trys.push([1, 5, 6, 7]);
30602
- res = action.executeAction(event, context);
30872
+ res = action.executeAction(event /*, context*/);
30603
30873
  if (!(res instanceof Promise)) return [3 /*break*/, 3];
30604
30874
  return [4 /*yield*/, res];
30605
30875
  case 2:
@@ -30631,13 +30901,18 @@
30631
30901
  selector: 'app-user-events-table',
30632
30902
  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",
30633
30903
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
30904
+ providers: [
30905
+ {
30906
+ provide: UserEventServiceToken, useClass: UserEventService
30907
+ }
30908
+ ],
30634
30909
  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}"]
30635
30910
  },] }
30636
30911
  ];
30637
30912
  UserEventsTable.ctorParameters = function () { return [
30638
30913
  { type: i0.Injector },
30639
30914
  { type: AccountService },
30640
- { type: UserEventService },
30915
+ { type: undefined, decorators: [{ type: i0.Inject, args: [UserEventServiceToken,] }] },
30641
30916
  { type: EntitiesStorage },
30642
30917
  { type: i0.ChangeDetectorRef },
30643
30918
  { type: undefined, decorators: [{ type: i0.Inject, args: [ENVIRONMENT,] }] }
@@ -30649,6 +30924,170 @@
30649
30924
  defaultSortDirection: [{ type: i0.Input }]
30650
30925
  };
30651
30926
 
30927
+ var UserEventNotificationList = /** @class */ (function () {
30928
+ function UserEventNotificationList(popoverController) {
30929
+ this.popoverController = popoverController;
30930
+ }
30931
+ UserEventNotificationList.prototype.ngOnInit = function () {
30932
+ };
30933
+ UserEventNotificationList.prototype.read = function ($event, userEvent) {
30934
+ var _a;
30935
+ if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
30936
+ return;
30937
+ (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
30938
+ };
30939
+ UserEventNotificationList.prototype.executeAction = function (action, userEvent) {
30940
+ // Execute then close popover
30941
+ action.executeAction(userEvent);
30942
+ this.dismiss();
30943
+ };
30944
+ UserEventNotificationList.prototype.dismiss = function () {
30945
+ this.popoverController.dismiss();
30946
+ };
30947
+ return UserEventNotificationList;
30948
+ }());
30949
+ UserEventNotificationList.decorators = [
30950
+ { type: i0.Component, args: [{
30951
+ selector: 'app-user-event-notification-list',
30952
+ 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",
30953
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}"]
30954
+ },] }
30955
+ ];
30956
+ UserEventNotificationList.ctorParameters = function () { return [
30957
+ { type: i1$5.PopoverController }
30958
+ ]; };
30959
+ UserEventNotificationList.propDecorators = {
30960
+ titleI18n: [{ type: i0.Input }],
30961
+ userEvents: [{ type: i0.Input }],
30962
+ readEvent: [{ type: i0.Output }]
30963
+ };
30964
+
30965
+ var UserEventNotificationComponent = /** @class */ (function () {
30966
+ function UserEventNotificationComponent(userEventService, accountService, popoverController, cd) {
30967
+ this.userEventService = userEventService;
30968
+ this.accountService = accountService;
30969
+ this.popoverController = popoverController;
30970
+ this.cd = cd;
30971
+ this.debug = false;
30972
+ this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
30973
+ this.disabled = false;
30974
+ this.userEventsSubject = new rxjs.BehaviorSubject(undefined);
30975
+ this._subscriptions = new rxjs.Subscription();
30976
+ this._logPrefix = '[user-event-notification] ';
30977
+ this._readEvent = new i0.EventEmitter();
30978
+ }
30979
+ Object.defineProperty(UserEventNotificationComponent.prototype, "count", {
30980
+ get: function () {
30981
+ var _a;
30982
+ return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(operators.map(function (value) { return value === 0 ? undefined : value; }));
30983
+ },
30984
+ enumerable: false,
30985
+ configurable: true
30986
+ });
30987
+ UserEventNotificationComponent.prototype.ngOnInit = function () {
30988
+ var _this = this;
30989
+ var _a;
30990
+ if (isNil(this.userEventService)) {
30991
+ console.warn(this._logPrefix + "No service injected");
30992
+ this.disabled = true;
30993
+ return;
30994
+ }
30995
+ this._subscriptions.add(this.userEventService.watchAll(0, 10, 'creationDate', "desc", {
30996
+ recipients: [(_a = this.accountService.person) === null || _a === void 0 ? void 0 : _a.pubkey]
30997
+ }).subscribe(function (value) {
30998
+ var data = value.data;
30999
+ if (_this.debug) {
31000
+ console.debug(_this._logPrefix + "Receiving user events", data);
31001
+ }
31002
+ _this.userEventsSubject.next(data);
31003
+ }));
31004
+ this._readEvent.subscribe(function (value) {
31005
+ _this.userEventService.markAsRead(value);
31006
+ });
31007
+ };
31008
+ UserEventNotificationComponent.prototype.showList = function (event) {
31009
+ return __awaiter(this, void 0, void 0, function () {
31010
+ var popover;
31011
+ return __generator(this, function (_b) {
31012
+ switch (_b.label) {
31013
+ case 0: return [4 /*yield*/, this.popoverController.create({
31014
+ component: UserEventNotificationList,
31015
+ componentProps: {
31016
+ titleI18n: this.titleI18n,
31017
+ userEvents: this.userEventsSubject,
31018
+ readEvent: this._readEvent
31019
+ },
31020
+ backdropDismiss: true,
31021
+ keyboardClose: true,
31022
+ event: event,
31023
+ translucent: true,
31024
+ cssClass: 'popover-large'
31025
+ })];
31026
+ case 1:
31027
+ popover = _b.sent();
31028
+ return [4 /*yield*/, popover.present()];
31029
+ case 2:
31030
+ _b.sent();
31031
+ return [2 /*return*/];
31032
+ }
31033
+ });
31034
+ });
31035
+ };
31036
+ UserEventNotificationComponent.prototype.markForCheck = function () {
31037
+ this.cd.markForCheck();
31038
+ };
31039
+ UserEventNotificationComponent.prototype.ngOnDestroy = function () {
31040
+ if (this.debug) {
31041
+ console.debug(this._logPrefix + "Destroying");
31042
+ }
31043
+ this._subscriptions.unsubscribe();
31044
+ };
31045
+ return UserEventNotificationComponent;
31046
+ }());
31047
+ UserEventNotificationComponent.decorators = [
31048
+ { type: i0.Component, args: [{
31049
+ selector: 'app-user-event-notification-component',
31050
+ 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",
31051
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31052
+ styles: [""]
31053
+ },] }
31054
+ ];
31055
+ UserEventNotificationComponent.ctorParameters = function () { return [
31056
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [UserEventServiceToken,] }] },
31057
+ { type: AccountService },
31058
+ { type: i1$5.PopoverController },
31059
+ { type: i0.ChangeDetectorRef }
31060
+ ]; };
31061
+ UserEventNotificationComponent.propDecorators = {
31062
+ debug: [{ type: i0.Input }],
31063
+ titleI18n: [{ type: i0.Input }],
31064
+ disabled: [{ type: i0.Input }]
31065
+ };
31066
+
31067
+ var UserEventModule = /** @class */ (function () {
31068
+ function UserEventModule() {
31069
+ }
31070
+ return UserEventModule;
31071
+ }());
31072
+ UserEventModule.decorators = [
31073
+ { type: i0.NgModule, args: [{
31074
+ imports: [
31075
+ i1$4.CommonModule,
31076
+ CoreModule,
31077
+ SharedModule
31078
+ ],
31079
+ declarations: [
31080
+ UserEventsTable,
31081
+ UserEventNotificationComponent,
31082
+ UserEventNotificationList,
31083
+ ],
31084
+ exports: [
31085
+ UserEventsTable,
31086
+ UserEventNotificationComponent
31087
+ ]
31088
+ },] }
31089
+ ];
31090
+
30652
31091
  var MessageTypes = {
30653
31092
  INBOX_MESSAGE: 'INBOX_MESSAGE',
30654
31093
  EMAIL: 'EMAIL',
@@ -30882,12 +31321,12 @@
30882
31321
  canSelectType: [{ type: i0.Input }]
30883
31322
  };
30884
31323
 
30885
- var SocialModule = /** @class */ (function () {
30886
- function SocialModule() {
31324
+ var MessageModule = /** @class */ (function () {
31325
+ function MessageModule() {
30887
31326
  }
30888
- return SocialModule;
31327
+ return MessageModule;
30889
31328
  }());
30890
- SocialModule.decorators = [
31329
+ MessageModule.decorators = [
30891
31330
  { type: i0.NgModule, args: [{
30892
31331
  imports: [
30893
31332
  i1$4.CommonModule,
@@ -30895,19 +31334,342 @@
30895
31334
  SharedModule
30896
31335
  ],
30897
31336
  declarations: [
30898
- UserEventsTable,
30899
31337
  MessageModal,
30900
31338
  MessageForm
30901
31339
  ],
30902
31340
  exports: [
30903
- UserEventsTable,
30904
31341
  MessageModal
30905
31342
  ]
30906
31343
  },] }
30907
31344
  ];
30908
31345
 
31346
+ var JobProgression_1;
31347
+ // todo use entity
31348
+ var Job = /** @class */ (function () {
31349
+ function Job() {
31350
+ }
31351
+ return Job;
31352
+ }());
31353
+ // @dynamic
31354
+ exports.JobProgression = JobProgression_1 = /** @class */ (function (_super) {
31355
+ __extends(JobProgression, _super);
31356
+ function JobProgression() {
31357
+ return _super.call(this, JobProgression_1.TYPENAME) || this;
31358
+ }
31359
+ JobProgression.prototype.fromObject = function (source) {
31360
+ _super.prototype.fromObject.call(this, source);
31361
+ this.message = source.message;
31362
+ this.current = source.current;
31363
+ this.total = source.total;
31364
+ };
31365
+ return JobProgression;
31366
+ }(Entity));
31367
+ exports.JobProgression = JobProgression_1 = __decorate([
31368
+ EntityClass({ typename: 'JobProgressionVO' })
31369
+ ], exports.JobProgression);
31370
+
31371
+ var JobProgressionServiceToken = new i0.InjectionToken('JobProgressionService');
31372
+ 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}"])));
31373
+ var JobProgressionService = /** @class */ (function (_super) {
31374
+ __extends(JobProgressionService, _super);
31375
+ function JobProgressionService(graphql, environment) {
31376
+ var _this = _super.call(this, graphql, environment) || this;
31377
+ _this.graphql = graphql;
31378
+ _this.environment = environment;
31379
+ _this._logPrefix = '[job-progression-service] ';
31380
+ // For DEV only
31381
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
31382
+ return _this;
31383
+ }
31384
+ JobProgressionService.prototype.listenChanges = function (id, options) {
31385
+ var _this = this;
31386
+ if (isNil(id))
31387
+ throw new Error(this._logPrefix + "Missing argument 'id'");
31388
+ if (this._debug)
31389
+ console.debug(this._logPrefix + "[WS] Listening changes for job progression {" + id + "}...");
31390
+ return this.graphql.subscribe({
31391
+ query: jobProgressionSubscription,
31392
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
31393
+ variables: { id: id, interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
31394
+ error: { code: SocialErrorCodes.SUBSCRIBE_JOB_PROGRESSION_ERROR, message: 'SOCIAL.ERROR.SUBSCRIBE_JOB_PROGRESSION_ERROR' }
31395
+ }).pipe(operators.map(function (_a) {
31396
+ var data = _a.data;
31397
+ var progression = data && exports.JobProgression.fromObject(data);
31398
+ if (progression && _this._debug)
31399
+ console.debug(_this._logPrefix + "Job progression " + id + " updated on server", progression);
31400
+ return progression;
31401
+ }));
31402
+ };
31403
+ return JobProgressionService;
31404
+ }(BaseGraphqlService));
31405
+ JobProgressionService.decorators = [
31406
+ { type: i0.Injectable }
31407
+ ];
31408
+ JobProgressionService.ctorParameters = function () { return [
31409
+ { type: GraphqlService },
31410
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
31411
+ ]; };
31412
+ var templateObject_1$4;
31413
+
31414
+ var JobProgressionList = /** @class */ (function () {
31415
+ function JobProgressionList() {
31416
+ }
31417
+ JobProgressionList.prototype.ngOnInit = function () {
31418
+ };
31419
+ return JobProgressionList;
31420
+ }());
31421
+ JobProgressionList.decorators = [
31422
+ { type: i0.Component, args: [{
31423
+ selector: 'app-job-progression-list',
31424
+ 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",
31425
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}"]
31426
+ },] }
31427
+ ];
31428
+ JobProgressionList.ctorParameters = function () { return []; };
31429
+ JobProgressionList.propDecorators = {
31430
+ titleI18n: [{ type: i0.Input }],
31431
+ jobProgressions: [{ type: i0.Input }]
31432
+ };
31433
+
31434
+ var JobProgressionComponent = /** @class */ (function () {
31435
+ function JobProgressionComponent(jobProgressionService, popoverController, cd) {
31436
+ this.jobProgressionService = jobProgressionService;
31437
+ this.popoverController = popoverController;
31438
+ this.cd = cd;
31439
+ this.debug = false;
31440
+ this.titleI18n = 'SOCIAL.JOB.PROGRESSION.TITLE';
31441
+ this.jobFinished = new i0.EventEmitter();
31442
+ this.disabled = true;
31443
+ this.color = 'accent';
31444
+ this.mode = 'determinate';
31445
+ this.value = 0;
31446
+ this.jobProgressions = [];
31447
+ this._subscriptions = new rxjs.Subscription();
31448
+ this._subscriptionsById = {};
31449
+ this._logPrefix = '[job-progression] ';
31450
+ }
31451
+ JobProgressionComponent.prototype.ngOnInit = function () {
31452
+ var _a, _b, _c, _d;
31453
+ if (isNil(this.jobProgressionService)) {
31454
+ console.warn(this._logPrefix + "No service injected");
31455
+ }
31456
+ // parse options
31457
+ this.autoHide = toBoolean((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoHide, false);
31458
+ this.visible = !this.autoHide;
31459
+ this.autoHideDelay = toNumber((_b = this.options) === null || _b === void 0 ? void 0 : _b.autoHideDelay, 1000);
31460
+ this.autoRemove = toBoolean((_c = this.options) === null || _c === void 0 ? void 0 : _c.autoRemove, true);
31461
+ this.autoRemoveDelay = toNumber((_d = this.options) === null || _d === void 0 ? void 0 : _d.autoRemoveDelay, 1000);
31462
+ };
31463
+ JobProgressionComponent.prototype.addJob = function (id) {
31464
+ var _this = this;
31465
+ if (isNil(this.jobProgressionService)) {
31466
+ console.warn(this._logPrefix + "No service injected. Can't add a job");
31467
+ return;
31468
+ }
31469
+ if (this.debug) {
31470
+ console.debug(this._logPrefix + "Add job id=" + id);
31471
+ }
31472
+ if (!!this.getProgression(id)) {
31473
+ console.warn(this._logPrefix + "Job (id=" + id + ") already present");
31474
+ return;
31475
+ }
31476
+ this.disabled = false;
31477
+ var sub = this.jobProgressionService.listenChanges(id)
31478
+ .pipe(operators.filter(function (progression) {
31479
+ if (id !== progression.id) {
31480
+ console.error(_this._logPrefix + "Job progression (id=" + progression.id + ") doesn't match expected job (id=" + id + ")");
31481
+ return false;
31482
+ }
31483
+ return true;
31484
+ }), operators.map(function (progression) {
31485
+ // Ensure visible
31486
+ _this.visible = true;
31487
+ // Get current progression object
31488
+ var currentProgression = _this.getProgression(id);
31489
+ if (!currentProgression) {
31490
+ // add it
31491
+ _this.jobProgressions.push(progression);
31492
+ if (_this.debug) {
31493
+ console.debug(_this._logPrefix + "Progression added id=" + id, progression);
31494
+ }
31495
+ }
31496
+ else {
31497
+ // update current
31498
+ Object.assign(currentProgression, progression);
31499
+ if (_this.debug) {
31500
+ console.debug(_this._logPrefix + "Progression updated id=" + id, progression);
31501
+ }
31502
+ }
31503
+ return progression;
31504
+ }))
31505
+ .subscribe(function (progression) {
31506
+ // update value
31507
+ _this.updateValue();
31508
+ // job finished
31509
+ if (progression.total > 0 && progression.current == progression.total) {
31510
+ if (_this.debug) {
31511
+ console.debug(_this._logPrefix + "Finished job id=" + progression.id);
31512
+ }
31513
+ // emit event
31514
+ _this.jobFinished.emit(progression.id);
31515
+ if (_this.autoRemove) {
31516
+ setTimeout(function () {
31517
+ var _a;
31518
+ _this.removeJob(progression.id);
31519
+ // If last job
31520
+ if (_this.autoHide && !((_a = _this.jobProgressions) === null || _a === void 0 ? void 0 : _a.length)) {
31521
+ setTimeout(function () {
31522
+ _this.visible = false;
31523
+ _this.markForCheck();
31524
+ }, _this.autoHideDelay);
31525
+ }
31526
+ }, _this.autoRemoveDelay);
31527
+ }
31528
+ }
31529
+ });
31530
+ this._subscriptionsById[id] = sub;
31531
+ this._subscriptions.add(sub);
31532
+ };
31533
+ JobProgressionComponent.prototype.removeJob = function (id) {
31534
+ if (this.debug) {
31535
+ console.debug(this._logPrefix + "Remove job id=" + id);
31536
+ }
31537
+ var sub = this._subscriptionsById[id];
31538
+ if (sub) {
31539
+ this._subscriptions.remove(sub);
31540
+ sub.unsubscribe();
31541
+ }
31542
+ var progression = this.getProgression(id);
31543
+ if (progression) {
31544
+ this.jobProgressions.splice(this.jobProgressions.indexOf(progression), 1);
31545
+ }
31546
+ this.updateValue();
31547
+ };
31548
+ JobProgressionComponent.prototype.getProgression = function (id) {
31549
+ return this.jobProgressions.find(function (progression) { return progression.id === id; });
31550
+ };
31551
+ JobProgressionComponent.prototype.updateValue = function () {
31552
+ if (this.debug) {
31553
+ console.debug(this._logPrefix + "Updating value");
31554
+ }
31555
+ var value = 0;
31556
+ var nbProgression = arraySize(this.jobProgressions);
31557
+ var allIndeterminate = nbProgression > 0;
31558
+ this.jobProgressions.forEach(function (progression) {
31559
+ var indeterminate = progression.total === 0;
31560
+ allIndeterminate = allIndeterminate && indeterminate;
31561
+ if (!indeterminate) {
31562
+ value = value + progression.current * 100 / progression.total;
31563
+ }
31564
+ });
31565
+ this.value = nbProgression > 0 ? value / nbProgression : 0;
31566
+ this.mode = allIndeterminate ? 'indeterminate' : 'determinate';
31567
+ if (this.debug) {
31568
+ console.debug(this._logPrefix + "Setting value=" + this.value + ", mode=" + this.mode);
31569
+ }
31570
+ this.markForCheck();
31571
+ };
31572
+ JobProgressionComponent.prototype.showList = function (event) {
31573
+ return __awaiter(this, void 0, void 0, function () {
31574
+ var popover;
31575
+ return __generator(this, function (_e) {
31576
+ switch (_e.label) {
31577
+ case 0: return [4 /*yield*/, this.popoverController.create({
31578
+ component: JobProgressionList,
31579
+ componentProps: {
31580
+ titleI18n: this.titleI18n,
31581
+ jobProgressions: this.jobProgressions
31582
+ },
31583
+ backdropDismiss: true,
31584
+ keyboardClose: true,
31585
+ event: event,
31586
+ translucent: true,
31587
+ cssClass: 'popover-large'
31588
+ })];
31589
+ case 1:
31590
+ popover = _e.sent();
31591
+ return [4 /*yield*/, popover.present()];
31592
+ case 2:
31593
+ _e.sent();
31594
+ return [2 /*return*/];
31595
+ }
31596
+ });
31597
+ });
31598
+ };
31599
+ JobProgressionComponent.prototype.markForCheck = function () {
31600
+ this.cd.markForCheck();
31601
+ };
31602
+ JobProgressionComponent.prototype.ngOnDestroy = function () {
31603
+ if (this.debug) {
31604
+ console.debug(this._logPrefix + "Destroying");
31605
+ }
31606
+ this._subscriptions.unsubscribe();
31607
+ };
31608
+ return JobProgressionComponent;
31609
+ }());
31610
+ JobProgressionComponent.decorators = [
31611
+ { type: i0.Component, args: [{
31612
+ selector: 'app-job-progression',
31613
+ 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",
31614
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31615
+ styles: [".floating-spinner{position:absolute;top:6px;left:5px}"]
31616
+ },] }
31617
+ ];
31618
+ JobProgressionComponent.ctorParameters = function () { return [
31619
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [JobProgressionServiceToken,] }] },
31620
+ { type: i1$5.PopoverController },
31621
+ { type: i0.ChangeDetectorRef }
31622
+ ]; };
31623
+ JobProgressionComponent.propDecorators = {
31624
+ debug: [{ type: i0.Input }],
31625
+ titleI18n: [{ type: i0.Input }],
31626
+ options: [{ type: i0.Input }],
31627
+ jobFinished: [{ type: i0.Output }]
31628
+ };
31629
+
31630
+ var JobModule = /** @class */ (function () {
31631
+ function JobModule() {
31632
+ }
31633
+ return JobModule;
31634
+ }());
31635
+ JobModule.decorators = [
31636
+ { type: i0.NgModule, args: [{
31637
+ imports: [
31638
+ i1$4.CommonModule,
31639
+ SharedModule,
31640
+ i1$2.TranslateModule.forChild(),
31641
+ ],
31642
+ declarations: [
31643
+ JobProgressionComponent,
31644
+ JobProgressionList
31645
+ ],
31646
+ exports: [
31647
+ JobProgressionComponent
31648
+ ]
31649
+ },] }
31650
+ ];
31651
+
31652
+ var SocialModuleOptionsToken = new i0.InjectionToken("SocialModuleOptions");
31653
+ var SocialModule = /** @class */ (function () {
31654
+ function SocialModule() {
31655
+ }
31656
+ return SocialModule;
31657
+ }());
31658
+ SocialModule.decorators = [
31659
+ { type: i0.NgModule, args: [{
31660
+ imports: [
31661
+ i1$4.CommonModule,
31662
+ CoreModule,
31663
+ SharedModule,
31664
+ UserEventModule,
31665
+ JobModule,
31666
+ MessageModule,
31667
+ ],
31668
+ },] }
31669
+ ];
31670
+
30909
31671
  var Mutations = {
30910
- 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 }"])))
31672
+ 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 }"])))
30911
31673
  };
30912
31674
  var MessageService = /** @class */ (function (_super) {
30913
31675
  __extends(MessageService, _super);
@@ -30991,7 +31753,7 @@
30991
31753
  { type: i1$5.ToastController },
30992
31754
  { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30993
31755
  ]; };
30994
- var templateObject_1$4;
31756
+ var templateObject_1$5;
30995
31757
 
30996
31758
  var PersonFilter_1;
30997
31759
  // @dynamic
@@ -31050,7 +31812,7 @@
31050
31812
  ], exports.PersonFilter);
31051
31813
 
31052
31814
  var PersonFragments = {
31053
- 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 }"])))
31815
+ 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 }"])))
31054
31816
  };
31055
31817
  // Load persons query
31056
31818
  var PersonQueries = {
@@ -31190,7 +31952,7 @@
31190
31952
  { type: NetworkService },
31191
31953
  { type: EntitiesStorage }
31192
31954
  ]; };
31193
- var templateObject_1$5, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31955
+ var templateObject_1$6, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31194
31956
 
31195
31957
  var PersonValidatorService = /** @class */ (function () {
31196
31958
  function PersonValidatorService(formBuilder, accountValidatorService) {
@@ -31600,12 +32362,10 @@
31600
32362
  };
31601
32363
  AutocompleteTestPage.prototype.ngAfterViewInit = function () {
31602
32364
  var _this = this;
31603
- if (this.farEntityField) {
31604
- setTimeout(function () {
31605
- _this.farEntityField.suggestLengthThreshold = 2;
31606
- _this.farEntityField.reloadItems();
31607
- }, 2000);
31608
- }
32365
+ setTimeout(function () {
32366
+ _this.farEntityField.suggestLengthThreshold = 2;
32367
+ _this.farEntityField.reloadItems();
32368
+ }, 2000);
31609
32369
  setTimeout(function () { return _this.loadData(); }, 1000);
31610
32370
  };
31611
32371
  // Load the form with data
@@ -31712,7 +32472,7 @@
31712
32472
  AutocompleteTestPage.decorators = [
31713
32473
  { type: i0.Component, args: [{
31714
32474
  selector: 'app-autocomplete-test',
31715
- 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"
32475
+ 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"
31716
32476
  },] }
31717
32477
  ];
31718
32478
  AutocompleteTestPage.ctorParameters = function () { return [
@@ -31794,13 +32554,13 @@
31794
32554
  { type: i1.FormBuilder }
31795
32555
  ]; };
31796
32556
 
31797
- var moment$6 = momentImported__namespace;
32557
+ var moment$7 = momentImported__namespace;
31798
32558
  var SwipeTestPage = /** @class */ (function () {
31799
32559
  function SwipeTestPage(formBuilder, dateFormatPipe) {
31800
32560
  this.formBuilder = formBuilder;
31801
32561
  this.dateFormatPipe = dateFormatPipe;
31802
32562
  this.$dates = new rxjs.BehaviorSubject(undefined);
31803
- this._today = moment$6().startOf('day');
32563
+ this._today = moment$7().startOf('day');
31804
32564
  this.form = formBuilder.group({
31805
32565
  empty: [null, i1.Validators.required],
31806
32566
  date: [null, i1.Validators.compose([i1.Validators.required, SharedValidators.validDate])],
@@ -31814,7 +32574,7 @@
31814
32574
  var _this = this;
31815
32575
  var dates = [];
31816
32576
  for (var d = 0; d < 7; d++) {
31817
- dates[d] = moment$6(this._today).add(d - 3, 'day');
32577
+ dates[d] = moment$7(this._today).add(d - 3, 'day');
31818
32578
  }
31819
32579
  this.$dates.next(dates);
31820
32580
  this.loadData();
@@ -31861,7 +32621,7 @@
31861
32621
  { type: DateFormatPipe }
31862
32622
  ]; };
31863
32623
 
31864
- var moment$7 = momentImported__namespace;
32624
+ var moment$8 = momentImported__namespace;
31865
32625
  var DateTimeTestPage = /** @class */ (function () {
31866
32626
  function DateTimeTestPage(platform, formBuilder, cd) {
31867
32627
  this.platform = platform;
@@ -31897,7 +32657,7 @@
31897
32657
  var now, data;
31898
32658
  var _this = this;
31899
32659
  return __generator(this, function (_a) {
31900
- now = moment$7();
32660
+ now = moment$8();
31901
32661
  data = {
31902
32662
  empty: null,
31903
32663
  emptyRequired: null,
@@ -32175,7 +32935,7 @@
32175
32935
  { type: i1.FormBuilder }
32176
32936
  ]; };
32177
32937
 
32178
- var moment$8 = momentImported__namespace;
32938
+ var moment$9 = momentImported__namespace;
32179
32939
  var DateTestPage = /** @class */ (function () {
32180
32940
  function DateTestPage(formBuilder, cd) {
32181
32941
  this.formBuilder = formBuilder;
@@ -32212,7 +32972,7 @@
32212
32972
  var now, nowAtMahe, data;
32213
32973
  var _this = this;
32214
32974
  return __generator(this, function (_a) {
32215
- now = moment$8();
32975
+ now = moment$9();
32216
32976
  nowAtMahe = now.clone().tz(this.timezone).startOf('day');
32217
32977
  data = {
32218
32978
  empty: null,
@@ -33051,6 +33811,7 @@
33051
33811
  exports.APP_MENU_ITEMS = APP_MENU_ITEMS;
33052
33812
  exports.APP_TESTING_PAGES = APP_TESTING_PAGES;
33053
33813
  exports.AboutModal = AboutModal;
33814
+ exports.AbstractUserEventService = AbstractUserEventService;
33054
33815
  exports.AccountPage = AccountPage;
33055
33816
  exports.AccountService = AccountService;
33056
33817
  exports.AccountToStringPipe = AccountToStringPipe;
@@ -33177,6 +33938,11 @@
33177
33938
  exports.IsNotNilOrBlankPipe = IsNotNilOrBlankPipe;
33178
33939
  exports.IsNotOnFieldModePipe = IsNotOnFieldModePipe;
33179
33940
  exports.IsOnFieldModePipe = IsOnFieldModePipe;
33941
+ exports.Job = Job;
33942
+ exports.JobModule = JobModule;
33943
+ exports.JobProgressionComponent = JobProgressionComponent;
33944
+ exports.JobProgressionService = JobProgressionService;
33945
+ exports.JobProgressionServiceToken = JobProgressionServiceToken;
33180
33946
  exports.JobUtils = JobUtils;
33181
33947
  exports.KEYBOARD_HIDE_DELAY_MS = KEYBOARD_HIDE_DELAY_MS;
33182
33948
  exports.LAT_LONG_DEFAULT_MAX_DECIMALS = LAT_LONG_DEFAULT_MAX_DECIMALS;
@@ -33214,6 +33980,7 @@
33214
33980
  exports.MenuService = MenuService;
33215
33981
  exports.MessageForm = MessageForm;
33216
33982
  exports.MessageModal = MessageModal;
33983
+ exports.MessageModule = MessageModule;
33217
33984
  exports.MessageService = MessageService;
33218
33985
  exports.MessageTypeList = MessageTypeList;
33219
33986
  exports.MessageTypes = MessageTypes;
@@ -33281,6 +34048,7 @@
33281
34048
  exports.SharedValidators = SharedValidators;
33282
34049
  exports.SocialErrorCodes = SocialErrorCodes;
33283
34050
  exports.SocialModule = SocialModule;
34051
+ exports.SocialModuleOptionsToken = SocialModuleOptionsToken;
33284
34052
  exports.StartableService = StartableService;
33285
34053
  exports.StatusById = StatusById;
33286
34054
  exports.StatusIds = StatusIds;
@@ -33309,7 +34077,10 @@
33309
34077
  exports.UploadFileTestingPage = UploadFileTestingPage;
33310
34078
  exports.UriUtils = UriUtils;
33311
34079
  exports.UserEventFragments = UserEventFragments;
34080
+ exports.UserEventModule = UserEventModule;
34081
+ exports.UserEventNotificationComponent = UserEventNotificationComponent;
33312
34082
  exports.UserEventService = UserEventService;
34083
+ exports.UserEventServiceToken = UserEventServiceToken;
33313
34084
  exports.UserEventTypes = UserEventTypes;
33314
34085
  exports.UserEventsTable = UserEventsTable;
33315
34086
  exports.UsersPage = UsersPage;
@@ -33474,11 +34245,13 @@
33474
34245
  exports.ɵh = LocalSettingsValidatorService;
33475
34246
  exports.ɵi = AppUpdateOfflineModeCard;
33476
34247
  exports.ɵj = AppIconComponent;
33477
- exports.ɵk = DateTestPage;
33478
- exports.ɵl = NumpadTestPage;
33479
- exports.ɵm = MatBadgeIconTestPage;
33480
- exports.ɵn = ToastTestingModule;
33481
- exports.ɵo = ToastTestingPage;
34248
+ exports.ɵk = UserEventNotificationList;
34249
+ exports.ɵl = JobProgressionList;
34250
+ exports.ɵm = DateTestPage;
34251
+ exports.ɵn = NumpadTestPage;
34252
+ exports.ɵo = MatBadgeIconTestPage;
34253
+ exports.ɵp = ToastTestingModule;
34254
+ exports.ɵq = ToastTestingPage;
33482
34255
 
33483
34256
  Object.defineProperty(exports, '__esModule', { value: true });
33484
34257