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

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 +1110 -328
  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 +53 -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 +100 -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 +299 -168
  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 +936 -290
  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 +79 -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,278 @@
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, 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
- _this.toastController = toastController;
30181
+ _this.queries = queries;
30182
+ _this.mutations = mutations;
30183
+ _this.subscriptions = subscriptions;
30153
30184
  _this.environment = environment;
30154
- _this._userEventActions = [];
30185
+ _this._count$ = new rxjs.BehaviorSubject(0);
30186
+ _this._subscriptions = new rxjs.Subscription();
30187
+ _this.listeners = [];
30188
+ _this._logPrefix = '[user-event-service] ';
30155
30189
  // For DEV only
30156
- _this._debug = environment && !environment.production;
30190
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
30191
+ // listen login/logout
30192
+ _this._subscriptions.add(accountService.onLogin.subscribe(function () { return __awaiter(_this, void 0, void 0, function () {
30193
+ var count;
30194
+ return __generator(this, function (_b) {
30195
+ switch (_b.label) {
30196
+ case 0: return [4 /*yield*/, this.count(undefined)];
30197
+ case 1:
30198
+ count = _b.sent();
30199
+ if (count && this._debug) {
30200
+ console.debug(this._logPrefix + "Received " + count + " unread notifications");
30201
+ }
30202
+ this._count$.next(count);
30203
+ return [2 /*return*/];
30204
+ }
30205
+ });
30206
+ }); }));
30157
30207
  return _this;
30158
30208
  }
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) {
30209
+ Object.defineProperty(AbstractUserEventService.prototype, "userEventCount", {
30210
+ get: function () {
30211
+ return this._count$.asObservable();
30212
+ },
30213
+ enumerable: false,
30214
+ configurable: true
30215
+ });
30216
+ AbstractUserEventService.prototype.ngOnDestroy = function () {
30217
+ this._subscriptions.unsubscribe();
30218
+ };
30219
+ AbstractUserEventService.prototype.watchAll = function (offset, size, sortBy, sortDirection, filter, options) {
30170
30220
  return this.watchPage({ offset: offset, size: size, sortBy: sortBy, sortDirection: sortDirection }, filter, options);
30171
30221
  };
30172
- UserEventService.prototype.watchPage = function (page, filter, options) {
30222
+ AbstractUserEventService.prototype.watchPage = function (page, filter, options) {
30223
+ var _this = this;
30224
+ var _a;
30173
30225
  var now = this._debug && Date.now();
30174
- //if (this._debug)
30175
- console.debug('[user-event-service] Loading user events...', filter);
30226
+ if (!filter) {
30227
+ filter = this.defaultFilter();
30228
+ }
30229
+ console.debug(this._logPrefix + "Loading user events...", filter);
30176
30230
  filter = this.asFilter(filter);
30177
30231
  // 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) {
30232
+ if (isEmptyArray(filter === null || filter === void 0 ? void 0 : filter.recipients) || !this.accountService.isAdmin()) {
30233
+ var recipient = this.defaultRecipient();
30234
+ if (!((_a = filter === null || filter === void 0 ? void 0 : filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
30181
30235
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
30182
- filter.recipient = recipient;
30236
+ filter.recipients = [recipient];
30183
30237
  }
30184
30238
  }
30185
- var withContent = options && options.withContent === true;
30239
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30186
30240
  return this.mutableWatchQuery({
30187
30241
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
30188
- query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
30242
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30189
30243
  variables: {
30190
- page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
30244
+ page: Object.assign(Object.assign({ sortBy: 'creationDate' }, page), {
30245
+ // @ts-ignore
30246
+ sortDirection: (page.sortDirection || 'desc').toUpperCase()
30247
+ }),
30191
30248
  filter: filter && filter.asPodObject()
30192
30249
  },
30193
30250
  arrayFieldName: 'data',
30194
30251
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
30195
- fetchPolicy: options && options.fetchPolicy || undefined
30252
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || "cache-first"
30196
30253
  })
30197
30254
  .pipe(operators.map(function (res) {
30198
- var data = res && (res.data || []).map(exports.UserEvent.fromObject);
30255
+ var data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(function (value) { return _this.processUserEvent(value, _this); });
30199
30256
  if (now) {
30200
- console.debug("[user-event-service] " + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30257
+ console.debug("" + _this._logPrefix + data.length + " user events loaded in " + (Date.now() - now) + "ms");
30201
30258
  now = null;
30202
30259
  }
30260
+ var unreadCount = _this.unreadEvents(data);
30203
30261
  return {
30204
30262
  data: data,
30205
- total: res && toNumber(res.total, data.length)
30263
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
30206
30264
  };
30207
30265
  }));
30208
30266
  };
30209
- UserEventService.prototype.saveAll = function (data, options) {
30267
+ AbstractUserEventService.prototype.add = function (entity) {
30268
+ // TODO set an id !!!!!!!!!!!!!!!!!!!!!!!!!
30269
+ entity = this.processUserEvent(entity);
30270
+ var withContent = !!entity.content;
30271
+ // Add user event locally
30272
+ this.insertIntoMutableCachedQueries(this.graphql.cache, {
30273
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
30274
+ data: entity
30275
+ });
30276
+ // Update count
30277
+ this._count$.next(this._count$.value + 1);
30278
+ };
30279
+ AbstractUserEventService.prototype.count = function (filter, options) {
30280
+ var _a;
30281
+ return __awaiter(this, void 0, void 0, function () {
30282
+ var res;
30283
+ return __generator(this, function (_b) {
30284
+ switch (_b.label) {
30285
+ case 0:
30286
+ if (!((_a = this.queries) === null || _a === void 0 ? void 0 : _a.count)) {
30287
+ console.warn(this._logPrefix + "Query 'count' not provided, skip.");
30288
+ return [2 /*return*/, undefined];
30289
+ }
30290
+ if (!filter)
30291
+ filter = this.defaultFilter();
30292
+ filter = this.asFilter(filter);
30293
+ if (this._debug)
30294
+ console.debug(this._logPrefix + "Counting user events with filter:", filter);
30295
+ return [4 /*yield*/, this.graphql.query({
30296
+ query: this.queries.count,
30297
+ variables: {
30298
+ filter: filter.asPodObject()
30299
+ },
30300
+ error: { code: SocialErrorCodes.COUNT_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.COUNT_USER_EVENT_ERROR' },
30301
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'network-only'
30302
+ })];
30303
+ case 1:
30304
+ res = _b.sent();
30305
+ return [2 /*return*/, res.total];
30306
+ }
30307
+ });
30308
+ });
30309
+ };
30310
+ AbstractUserEventService.prototype.listenChanges = function (filter, options) {
30210
30311
  var _this = this;
30211
- return Promise.all(data
30212
- .map(function (entity) { return _this.save(entity, options); }));
30312
+ var _a;
30313
+ if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
30314
+ console.warn(this._logPrefix + "Subscription query 'listenChanges' not provided, skip.");
30315
+ return rxjs.of();
30316
+ }
30317
+ if (!filter)
30318
+ filter = this.defaultFilter();
30319
+ filter = this.asFilter(filter);
30320
+ var withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
30321
+ if (this._debug)
30322
+ console.debug(this._logPrefix + "[WS] Listening changes for user events with filter:", filter);
30323
+ return this.graphql.subscribe({
30324
+ query: this.subscriptions.listenChanges,
30325
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
30326
+ variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
30327
+ error: {
30328
+ code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
30329
+ message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
30330
+ }
30331
+ }).pipe(operators.map(function (_b) {
30332
+ var data = _b.data;
30333
+ if (data && _this._debug)
30334
+ console.debug(_this._logPrefix + "Received new user events:", data);
30335
+ var updatedData = data === null || data === void 0 ? void 0 : data.map(function (value) { return _this.processUserEvent(value, _this); });
30336
+ // Update cache
30337
+ _this.insertIntoMutableCachedQueries(_this.graphql.cache, {
30338
+ query: withContent ? _this.queries.loadAllWithContent : _this.queries.loadAll,
30339
+ data: updatedData
30340
+ });
30341
+ // update count
30342
+ _this._count$.next(_this.unreadEvents(updatedData));
30343
+ return updatedData;
30344
+ }));
30213
30345
  };
30214
- /**
30215
- * Save a userEvent entity
30216
- *
30217
- * @param entity
30218
- */
30219
- UserEventService.prototype.save = function (entity, options) {
30346
+ AbstractUserEventService.prototype.delete = function (entity) {
30347
+ return __awaiter(this, void 0, void 0, function () {
30348
+ return __generator(this, function (_b) {
30349
+ switch (_b.label) {
30350
+ case 0:
30351
+ if (!entity)
30352
+ return [2 /*return*/]; // skip
30353
+ return [4 /*yield*/, this.deleteAll([entity])];
30354
+ case 1:
30355
+ _b.sent();
30356
+ return [2 /*return*/];
30357
+ }
30358
+ });
30359
+ });
30360
+ };
30361
+ AbstractUserEventService.prototype.deleteAll = function (entities, opts) {
30362
+ return __awaiter(this, void 0, void 0, function () {
30363
+ var ids, now;
30364
+ var _this = this;
30365
+ return __generator(this, function (_b) {
30366
+ switch (_b.label) {
30367
+ case 0:
30368
+ ids = entities && entities
30369
+ .map(function (t) { return t.id; });
30370
+ if (isEmptyArray(ids))
30371
+ return [2 /*return*/]; // stop, if nothing else to do
30372
+ now = Date.now();
30373
+ if (this._debug)
30374
+ console.debug(this._logPrefix + "Deleting events... ids:", ids);
30375
+ return [4 /*yield*/, this.graphql.mutate({
30376
+ mutation: this.mutations.deleteByIds,
30377
+ variables: {
30378
+ ids: ids
30379
+ },
30380
+ update: function (proxy) {
30381
+ // Remove from caches
30382
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30383
+ query: _this.queries.loadAll,
30384
+ ids: ids
30385
+ });
30386
+ _this.removeFromMutableCachedQueriesByIds(proxy, {
30387
+ query: _this.queries.loadAllWithContent,
30388
+ ids: ids
30389
+ });
30390
+ if (_this._debug)
30391
+ console.debug(_this._logPrefix + "Events deleted in " + (Date.now() - now) + "ms");
30392
+ }
30393
+ })];
30394
+ case 1:
30395
+ _b.sent();
30396
+ return [2 /*return*/];
30397
+ }
30398
+ });
30399
+ });
30400
+ };
30401
+ AbstractUserEventService.prototype.save = function (entity, options) {
30220
30402
  return __awaiter(this, void 0, void 0, function () {
30221
30403
  var isNew, json, now;
30222
30404
  var _this = this;
30223
- return __generator(this, function (_a) {
30224
- switch (_a.label) {
30405
+ return __generator(this, function (_b) {
30406
+ switch (_b.label) {
30225
30407
  case 0:
30226
30408
  this.fillDefaultProperties(entity);
30227
30409
  isNew = isNil(entity.id);
30228
30410
  json = entity.asObject();
30229
30411
  now = Date.now();
30230
30412
  if (this._debug)
30231
- console.debug("[user-event-service] Saving user event...", json);
30413
+ console.debug(this._logPrefix + "Saving user event...", json);
30232
30414
  return [4 /*yield*/, this.graphql.mutate({
30233
- mutation: SaveQuery,
30415
+ mutation: this.mutations.save,
30234
30416
  variables: {
30235
30417
  data: json
30236
30418
  },
30237
30419
  error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
30238
- update: function (proxy, _a) {
30239
- var data = _a.data;
30420
+ update: function (proxy, _b) {
30421
+ var data = _b.data;
30240
30422
  // Update entity
30241
30423
  var savedEntity = data && data.data;
30242
30424
  if (savedEntity) {
30243
30425
  if (_this._debug)
30244
- console.debug("[user-event-service] User event saved in " + (Date.now() - now) + "ms", entity);
30426
+ console.debug(_this._logPrefix + "User event saved in " + (Date.now() - now) + "ms", entity);
30245
30427
  _this.copyIdAndUpdateDate(savedEntity, entity);
30246
30428
  // Add to cache
30247
30429
  if (isNew) {
30248
30430
  _this.insertIntoMutableCachedQueries(proxy, {
30249
- query: LoadAllQuery,
30431
+ query: _this.queries.loadAll,
30250
30432
  data: Object.assign(Object.assign({}, savedEntity), { content: null })
30251
30433
  });
30252
30434
  _this.insertIntoMutableCachedQueries(proxy, {
30253
- query: LoadAllWithContentQuery,
30435
+ query: _this.queries.loadAllWithContent,
30254
30436
  data: savedEntity
30255
30437
  });
30256
30438
  }
@@ -30258,93 +30440,186 @@
30258
30440
  }
30259
30441
  })];
30260
30442
  case 1:
30261
- _a.sent();
30443
+ _b.sent();
30262
30444
  return [2 /*return*/, entity];
30263
30445
  }
30264
30446
  });
30265
30447
  });
30266
30448
  };
30267
- /**
30268
- * Save many trips
30269
- *
30270
- * @param entities
30271
- * @param opts
30272
- */
30273
- UserEventService.prototype.deleteAll = function (entities, opts) {
30449
+ AbstractUserEventService.prototype.saveAll = function (data, opts) {
30450
+ var _this = this;
30451
+ return Promise.all(data
30452
+ .map(function (entity) { return _this.save(entity, opts); }));
30453
+ };
30454
+ AbstractUserEventService.prototype.markAsRead = function (entity) {
30274
30455
  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) {
30456
+ var onReadListeners, onReadListeners_1, onReadListeners_1_1, listener, e_1_1;
30457
+ var e_1, _b;
30458
+ return __generator(this, function (_c) {
30459
+ switch (_c.label) {
30279
30460
  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
- })];
30461
+ onReadListeners = (this.listeners || []).filter(function (listener) { return !!listener.onRead; }).filter(function (listener) { return listener.accept(entity); });
30462
+ if (!onReadListeners.length) return [3 /*break*/, 9];
30463
+ _c.label = 1;
30306
30464
  case 1:
30307
- _a.sent();
30308
- return [2 /*return*/];
30465
+ _c.trys.push([1, 6, 7, 8]);
30466
+ onReadListeners_1 = __values(onReadListeners), onReadListeners_1_1 = onReadListeners_1.next();
30467
+ _c.label = 2;
30468
+ case 2:
30469
+ if (!!onReadListeners_1_1.done) return [3 /*break*/, 5];
30470
+ listener = onReadListeners_1_1.value;
30471
+ return [4 /*yield*/, listener.onRead(entity)];
30472
+ case 3:
30473
+ _c.sent();
30474
+ _c.label = 4;
30475
+ case 4:
30476
+ onReadListeners_1_1 = onReadListeners_1.next();
30477
+ return [3 /*break*/, 2];
30478
+ case 5: return [3 /*break*/, 8];
30479
+ case 6:
30480
+ e_1_1 = _c.sent();
30481
+ e_1 = { error: e_1_1 };
30482
+ return [3 /*break*/, 8];
30483
+ case 7:
30484
+ try {
30485
+ if (onReadListeners_1_1 && !onReadListeners_1_1.done && (_b = onReadListeners_1.return)) _b.call(onReadListeners_1);
30486
+ }
30487
+ finally { if (e_1) throw e_1.error; }
30488
+ return [7 /*endfinally*/];
30489
+ case 8: return [3 /*break*/, 11];
30490
+ case 9:
30491
+ // Use default
30492
+ return [4 /*yield*/, this.defaultMarkAsRead(entity)];
30493
+ case 10:
30494
+ // Use default
30495
+ _c.sent();
30496
+ _c.label = 11;
30497
+ case 11: return [2 /*return*/];
30309
30498
  }
30310
30499
  });
30311
30500
  });
30312
30501
  };
30313
- /**
30314
- * Delete userEvent entities
30315
- */
30316
- UserEventService.prototype.delete = function (data) {
30502
+ AbstractUserEventService.prototype.registerListener = function (listener) {
30503
+ if (!this.listeners)
30504
+ this.listeners = [];
30505
+ this.listeners.push(listener);
30506
+ };
30507
+ /* -- protected methods -- */
30508
+ AbstractUserEventService.prototype.processUserEvent = function (source, that) {
30509
+ var e_2, _b;
30510
+ that = that || this;
30511
+ // Convert json source to IUserEvent
30512
+ var target = that.fromObject(source);
30513
+ // Get listeners
30514
+ var listeners = (that.listeners || []).filter(function (listener) { return listener.onReceived; }).filter(function (listener) { return listener.accept(target); });
30515
+ try {
30516
+ for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
30517
+ var listener = listeners_1_1.value;
30518
+ if (target) {
30519
+ target = listener.onReceived(target);
30520
+ }
30521
+ else {
30522
+ if (that._debug)
30523
+ console.debug(that._logPrefix + "Event has been rejected by a listener", source);
30524
+ break;
30525
+ }
30526
+ }
30527
+ }
30528
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
30529
+ finally {
30530
+ try {
30531
+ if (listeners_1_1 && !listeners_1_1.done && (_b = listeners_1.return)) _b.call(listeners_1);
30532
+ }
30533
+ finally { if (e_2) throw e_2.error; }
30534
+ }
30535
+ return target;
30536
+ };
30537
+ AbstractUserEventService.prototype.defaultMarkAsRead = function (userEvent) {
30317
30538
  return __awaiter(this, void 0, void 0, function () {
30318
- return __generator(this, function (_a) {
30319
- switch (_a.label) {
30539
+ return __generator(this, function (_b) {
30540
+ switch (_b.label) {
30320
30541
  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*/];
30542
+ if (!userEvent)
30543
+ throw new Error(this._logPrefix + "Invalid event to save");
30544
+ // set read date
30545
+ userEvent.readDate = moment$6();
30546
+ if (!(!userEvent.id || userEvent.id < 0)) return [3 /*break*/, 1];
30547
+ if (this._debug)
30548
+ console.debug(this._logPrefix + "Save local user event");
30549
+ return [3 /*break*/, 3];
30550
+ case 1: return [4 /*yield*/, this.save(userEvent)];
30551
+ case 2:
30552
+ _b.sent();
30553
+ _b.label = 3;
30554
+ case 3: return [2 /*return*/];
30327
30555
  }
30328
30556
  });
30329
30557
  });
30330
30558
  };
30331
- UserEventService.prototype.listenChanges = function (id, options) {
30332
- // TODO
30333
- console.warn('TODO: implement listen changes on user events');
30334
- return rxjs.of();
30559
+ AbstractUserEventService.prototype.defaultFilter = function () {
30560
+ // By default
30561
+ return {
30562
+ recipients: [this.defaultRecipient()]
30563
+ };
30335
30564
  };
30336
- UserEventService.prototype.registerAction = function (definition) {
30337
- console.info("[user-event-service] Registering action " + definition.name + " for " + definition.__typename);
30338
- this._userEventActions.push(definition);
30565
+ AbstractUserEventService.prototype.defaultRecipient = function () {
30566
+ return this.accountService.person.pubkey;
30339
30567
  };
30340
- UserEventService.prototype.getActionsByTypename = function (typename) {
30341
- return this._userEventActions.filter(function (def) { return def.__typename === typename; });
30568
+ AbstractUserEventService.prototype.fillDefaultProperties = function (entity) {
30569
+ };
30570
+ AbstractUserEventService.prototype.unreadEvents = function (events) {
30571
+ // default calculation on unread events from a list
30572
+ if (isEmptyArray(events))
30573
+ return undefined;
30574
+ var lastReadDate = events
30575
+ .filter(function (event) { return isNotNil(event.readDate); })
30576
+ .reduce(function (lastDate, event) { return DateUtils.max(lastDate, event.readDate); }, undefined);
30577
+ return events
30578
+ .filter(function (event) { return event.creationDate.isSameOrAfter(lastReadDate); }).length;
30342
30579
  };
30580
+ AbstractUserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30581
+ EntityUtils.copyIdAndUpdateDate(source, target);
30582
+ };
30583
+ return AbstractUserEventService;
30584
+ }(BaseGraphqlService));
30585
+ AbstractUserEventService.decorators = [
30586
+ { type: i0.Directive }
30587
+ ];
30588
+ AbstractUserEventService.ctorParameters = function () { return [
30589
+ { type: GraphqlService },
30590
+ { type: AccountService },
30591
+ { type: NetworkService },
30592
+ { type: i1$2.TranslateService },
30593
+ { type: undefined },
30594
+ { type: undefined },
30595
+ { type: undefined },
30596
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30597
+ ]; };
30598
+ var userEventQueries = {
30599
+ loadAll: core.gql(templateObject_1$3 || (templateObject_1$3 = __makeTemplateObject(["\n query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...LightUserEventFragment\n }\n }\n ", "\n "], ["\n query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...LightUserEventFragment\n }\n }\n ", "\n "])), UserEventFragments.lightUserEvent),
30600
+ loadAllWithContent: core.gql(templateObject_2$3 || (templateObject_2$3 = __makeTemplateObject(["\n query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...UserEventFragment\n }\n }\n ", "\n "], ["\n query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){\n data: userEvents(filter: $filter, page: $page){\n ...UserEventFragment\n }\n }\n ", "\n "])), UserEventFragments.userEvent)
30601
+ };
30602
+ var userEventMutations = {
30603
+ deleteByIds: core.gql(templateObject_3$2 || (templateObject_3$2 = __makeTemplateObject(["\n mutation DeleteUserEvents($ids:[Int]){\n deleteUserEvents(ids: $ids)\n }\n "], ["\n mutation DeleteUserEvents($ids:[Int]){\n deleteUserEvents(ids: $ids)\n }\n "]))),
30604
+ save: core.gql(templateObject_4$2 || (templateObject_4$2 = __makeTemplateObject(["\n mutation SaveUserEvent($data: UserEventVOInput){\n data: saveUserEvent(userEvent: $data){\n ...UserEventFragment\n }\n }\n ", "\n "], ["\n mutation SaveUserEvent($data: UserEventVOInput){\n data: saveUserEvent(userEvent: $data){\n ...UserEventFragment\n }\n }\n ", "\n "])), UserEventFragments.userEvent)
30605
+ };
30606
+ var UserEventService = /** @class */ (function (_super) {
30607
+ __extends(UserEventService, _super);
30608
+ function UserEventService(graphql, accountService, network, translate, toastController, environment) {
30609
+ var _this = _super.call(this, graphql, accountService, network, translate, userEventQueries, userEventMutations, undefined, environment) || this;
30610
+ _this.graphql = graphql;
30611
+ _this.accountService = accountService;
30612
+ _this.network = network;
30613
+ _this.translate = translate;
30614
+ _this.toastController = toastController;
30615
+ _this.environment = environment;
30616
+ return _this;
30617
+ }
30343
30618
  UserEventService.prototype.showToastErrorWithContext = function (opts) {
30344
30619
  return __awaiter(this, void 0, void 0, function () {
30345
30620
  var message, res, context, userEvent, err_1;
30346
- return __generator(this, function (_a) {
30347
- switch (_a.label) {
30621
+ return __generator(this, function (_b) {
30622
+ switch (_b.label) {
30348
30623
  case 0:
30349
30624
  message = opts.message || (opts.error && opts.error.message || opts.error);
30350
30625
  // Make sure message a string
@@ -30373,12 +30648,12 @@
30373
30648
  }]
30374
30649
  })];
30375
30650
  case 1:
30376
- res = _a.sent();
30651
+ res = _b.sent();
30377
30652
  if (!res || res.role !== 'send')
30378
30653
  return [2 /*return*/];
30379
- _a.label = 2;
30654
+ _b.label = 2;
30380
30655
  case 2:
30381
- _a.trys.push([2, 6, , 7]);
30656
+ _b.trys.push([2, 6, , 7]);
30382
30657
  if (this._debug)
30383
30658
  console.debug('Sending debug data...');
30384
30659
  context = opts && opts.context;
@@ -30388,15 +30663,15 @@
30388
30663
  if (!(context instanceof Promise)) return [3 /*break*/, 4];
30389
30664
  return [4 /*yield*/, context];
30390
30665
  case 3:
30391
- context = _a.sent();
30392
- _a.label = 4;
30666
+ context = _b.sent();
30667
+ _b.label = 4;
30393
30668
  case 4: return [4 /*yield*/, this.sendDataForDebug({
30394
30669
  message: message,
30395
30670
  error: opts.error || undefined,
30396
30671
  context: this.convertObjectToString(context)
30397
30672
  })];
30398
30673
  case 5:
30399
- userEvent = _a.sent();
30674
+ userEvent = _b.sent();
30400
30675
  console.info('Debug data successfully sent to admin', userEvent);
30401
30676
  this.showToast({
30402
30677
  type: 'info',
@@ -30405,7 +30680,7 @@
30405
30680
  });
30406
30681
  return [3 /*break*/, 7];
30407
30682
  case 6:
30408
- err_1 = _a.sent();
30683
+ err_1 = _b.sent();
30409
30684
  console.error('Error while sending debug data:', err_1);
30410
30685
  return [3 /*break*/, 7];
30411
30686
  case 7: return [2 /*return*/];
@@ -30415,13 +30690,16 @@
30415
30690
  };
30416
30691
  UserEventService.prototype.sendDataForDebug = function (data) {
30417
30692
  var userEvent = new exports.UserEvent();
30418
- userEvent.eventType = UserEventTypes.DEBUG_DATA;
30693
+ userEvent.type = UserEventTypes.DEBUG_DATA;
30419
30694
  userEvent.content = this.convertObjectToString(data);
30420
30695
  return this.save(userEvent);
30421
30696
  };
30422
30697
  UserEventService.prototype.asFilter = function (filter) {
30423
30698
  return exports.UserEventFilter.fromObject(filter);
30424
30699
  };
30700
+ UserEventService.prototype.fromObject = function (source) {
30701
+ return exports.UserEvent.fromObject(source);
30702
+ };
30425
30703
  /* -- protected methods -- */
30426
30704
  UserEventService.prototype.convertObjectToString = function (data) {
30427
30705
  if (typeof data === 'string') {
@@ -30439,13 +30717,13 @@
30439
30717
  };
30440
30718
  UserEventService.prototype.showToast = function (opts) {
30441
30719
  return __awaiter(this, void 0, void 0, function () {
30442
- return __generator(this, function (_a) {
30443
- switch (_a.label) {
30720
+ return __generator(this, function (_b) {
30721
+ switch (_b.label) {
30444
30722
  case 0:
30445
30723
  if (!this.toastController)
30446
30724
  throw new Error('Missing toastController in component\'s constructor');
30447
30725
  return [4 /*yield*/, Toasts.show(this.toastController, this.translate, opts)];
30448
- case 1: return [2 /*return*/, _a.sent()];
30726
+ case 1: return [2 /*return*/, _b.sent()];
30449
30727
  }
30450
30728
  });
30451
30729
  });
@@ -30456,14 +30734,10 @@
30456
30734
  // TODO: compute sign
30457
30735
  console.warn('TODO: sign user event before sending');
30458
30736
  };
30459
- UserEventService.prototype.copyIdAndUpdateDate = function (source, target) {
30460
- EntityUtils.copyIdAndUpdateDate(source, target);
30461
- };
30462
30737
  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" });
30738
+ }(AbstractUserEventService));
30465
30739
  UserEventService.decorators = [
30466
- { type: i0.Injectable, args: [{ providedIn: 'root' },] }
30740
+ { type: i0.Injectable }
30467
30741
  ];
30468
30742
  UserEventService.ctorParameters = function () { return [
30469
30743
  { type: GraphqlService },
@@ -30477,7 +30751,7 @@
30477
30751
 
30478
30752
  var ICONS_MAP = {
30479
30753
  DEBUG_DATA: { matIcon: 'bug_report' },
30480
- INBOX_MESSAGE: { matIcon: 'mail' },
30754
+ INBOX_MESSAGE: { matIcon: 'mail' }
30481
30755
  };
30482
30756
  // TODO: refactor with a registration done by data service:
30483
30757
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -30545,7 +30819,7 @@
30545
30819
  }
30546
30820
  }));
30547
30821
  var filter = this.filter || new exports.UserEventFilter();
30548
- filter.recipient = this.recipient;
30822
+ filter.recipients = [this.recipient];
30549
30823
  this.setFilter(filter, { emitEvent: true });
30550
30824
  };
30551
30825
  UserEventsTable.prototype.start = function () {
@@ -30567,17 +30841,17 @@
30567
30841
  });
30568
30842
  };
30569
30843
  UserEventsTable.prototype.getIcon = function (source) {
30570
- return ICONS_MAP[source.eventType];
30844
+ return ICONS_MAP[source.type];
30571
30845
  };
30572
30846
  UserEventsTable.prototype.getDetail = function (source) {
30573
30847
  if (!source)
30574
30848
  return undefined;
30575
- if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
30849
+ if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
30576
30850
  var context = source.content.context;
30577
30851
  if (context && context.__typename) {
30578
- var actions = this.service.getActionsByTypename(context.__typename);
30852
+ // const actions = this.service.getActionsByTypename(context.__typename);
30579
30853
  return {
30580
- actions: actions,
30854
+ // actions,
30581
30855
  title: source.content.error && source.content.error.message || source.content.message,
30582
30856
  description: source.content.error && source.content.error.details || undefined
30583
30857
  };
@@ -30588,18 +30862,18 @@
30588
30862
  };
30589
30863
  UserEventsTable.prototype.doAction = function (action, row) {
30590
30864
  return __awaiter(this, void 0, void 0, function () {
30591
- var event, context, res, _a, err_1;
30865
+ var event, res, _a, err_1;
30592
30866
  return __generator(this, function (_b) {
30593
30867
  switch (_b.label) {
30594
30868
  case 0:
30595
30869
  event = row.currentData;
30596
- context = event.content && event.content.context;
30870
+ // const context = event.content && event.content.context;
30597
30871
  this.markAsLoading();
30598
30872
  if (!(action && typeof action.executeAction === 'function')) return [3 /*break*/, 7];
30599
30873
  _b.label = 1;
30600
30874
  case 1:
30601
30875
  _b.trys.push([1, 5, 6, 7]);
30602
- res = action.executeAction(event, context);
30876
+ res = action.executeAction(event /*, context*/);
30603
30877
  if (!(res instanceof Promise)) return [3 /*break*/, 3];
30604
30878
  return [4 /*yield*/, res];
30605
30879
  case 2:
@@ -30631,13 +30905,18 @@
30631
30905
  selector: 'app-user-events-table',
30632
30906
  template: "\n<!-- Type = options menu -->\n<mat-menu #optionsMenu=\"matMenu\" xPosition=\"after\">\n\n <!-- display columns -->\n <button mat-menu-item\n (click)=\"openSelectColumnsModal($event)\">\n <mat-icon>view_column</mat-icon>\n <ion-label translate>COMMON.DISPLAYED_COLUMNS_DOTS</ion-label>\n </button>\n\n</mat-menu>\n\n<!-- top header -->\n<mat-toolbar>\n\n <ng-container *ngIf=\"!selection.hasValue(); else hasSelection\">\n\n <button mat-icon-button [title]=\"'COMMON.BTN_REFRESH'|translate\" (click)=\"onRefresh.emit()\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n </ng-container>\n\n <!-- if row selection -->\n <ng-template #hasSelection>\n\n <!-- delete -->\n <button mat-icon-button class=\"hidden-xs hidden-sm\" *ngIf=\"canDelete\"\n [title]=\"'COMMON.BTN_DELETE'|translate\" (click)=\"deleteSelection($event)\">\n <mat-icon>delete</mat-icon>\n </button>\n </ng-template>\n\n <!-- error -->\n <ion-item *ngIf=\"error\" hidden-xs hidden-sm hidden-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <div class=\"toolbar-spacer\"></div>\n\n <button mat-icon-button\n [title]=\"'COMMON.BTN_OPTIONS'|translate\"\n [matMenuTriggerFor]=\"optionsMenu\">\n <mat-icon>more_vert</mat-icon>\n </button>\n</mat-toolbar>\n\n\n<mat-table [dataSource]=\"dataSource\" matSort\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n matSortDisableClear [trackBy]=\"trackByFn\">\n\n <!-- select -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(row) : null\" [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <!-- id -->\n <ng-container matColumnDef=\"id\">\n <mat-header-cell *matHeaderCellDef mat-sort-header [class.cdk-visually-hidden]=\"!isAdmin\">\n <app-loading-spinner [loading]=\"loadingSubject|async\"><ion-label>#</ion-label></app-loading-spinner>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!isAdmin\">{{ row.currentData.id | mathAbs }}</mat-cell>\n </ng-container>\n\n <!-- creationDate -->\n <ng-container matColumnDef=\"creationDate\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>SOCIAL.USER_EVENT.CREATION_DATE</ion-label>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <ion-text>\n {{row.currentData.creationDate | dateFromNow }}<br/>\n <ion-text color=\"medium\"><small>{{row.currentData.creationDate | dateFormat: {time: true} }}</small></ion-text>\n </ion-text>\n </mat-cell>\n </ng-container>\n\n <!-- icon -->\n <ng-container matColumnDef=\"icon\">\n <mat-header-cell *matHeaderCellDef>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row;\">\n <ng-container *ngIf=\"getIcon(row.currentData); let details\">\n <ion-icon slot=\"start\" *ngIf=\"details.icon\" [name]=\"details.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"details.matIcon\">{{details.matIcon}}</mat-icon>\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <!-- event type -->\n <ng-container matColumnDef=\"eventType\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>SOCIAL.USER_EVENT.EVENT_TYPE</ion-label>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row;\">\n <span>{{'SOCIAL.USER_EVENT.TYPE_ENUM.' + row.currentData.eventType | translate}}</span>\n </mat-cell>\n </ng-container>\n\n <!-- message -->\n <ng-container matColumnDef=\"message\">\n <mat-header-cell *matHeaderCellDef>\n <ion-label translate>SOCIAL.USER_EVENT.MESSAGE</ion-label>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row;\">\n <ng-container *ngIf=\"getDetail(row.currentData); let details\">\n <ion-text [innerHTML]=\"details.title|translate\">\n </ion-text>\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <!-- Actions buttons column -->\n <ng-container matColumnDef=\"actions\">\n <mat-header-cell *matHeaderCellDef>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <ng-container *ngIf=\"getDetail(row.currentData); let details\">\n <button mat-icon-button color=\"light\"\n *ngFor=\"let action of details.actions\"\n [title]=\"action.title |translate\"\n [color]=\"action.color\"\n (click)=\"doAction(action, row)\">\n <ion-icon slot=\"start\" *ngIf=\"action.icon\" [name]=\"action.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"action.matIcon\">{{action.matIcon}}</mat-icon>\n </button>\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns;\"\n class=\"mat-row-disabled\"\n (click)=\"clickRow($event, row)\"></mat-row>\n\n</mat-table>\n\n<ion-row class=\"ion-no-padding\">\n <ion-col></ion-col>\n <ion-col class=\"ion-no-padding\" size=\"auto\">\n <mat-paginator [length]=\"totalRowCount\" [pageSize]=\"defaultPageSize\" [pageSizeOptions]=\"defaultPageSizeOptions\" showFirstLastButtons>\n </mat-paginator>\n </ion-col>\n</ion-row>\n",
30633
30907
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
30908
+ providers: [
30909
+ {
30910
+ provide: UserEventServiceToken, useClass: UserEventService
30911
+ }
30912
+ ],
30634
30913
  styles: [".mat-header-row .mat-column-icon,.mat-row .mat-column-icon{max-width:40px;padding-left:0}.mat-header-row .mat-column-icon ion-icon,.mat-header-row .mat-column-icon mat-icon,.mat-row .mat-column-icon ion-icon,.mat-row .mat-column-icon mat-icon{font-size:1.2em;height:1.2em;width:1.2em}.mat-header-row .mat-column-creationDate,.mat-row .mat-column-creationDate{min-width:100px;max-width:120px}"]
30635
30914
  },] }
30636
30915
  ];
30637
30916
  UserEventsTable.ctorParameters = function () { return [
30638
30917
  { type: i0.Injector },
30639
30918
  { type: AccountService },
30640
- { type: UserEventService },
30919
+ { type: undefined, decorators: [{ type: i0.Inject, args: [UserEventServiceToken,] }] },
30641
30920
  { type: EntitiesStorage },
30642
30921
  { type: i0.ChangeDetectorRef },
30643
30922
  { type: undefined, decorators: [{ type: i0.Inject, args: [ENVIRONMENT,] }] }
@@ -30649,6 +30928,175 @@
30649
30928
  defaultSortDirection: [{ type: i0.Input }]
30650
30929
  };
30651
30930
 
30931
+ var UserEventNotificationList = /** @class */ (function () {
30932
+ function UserEventNotificationList(popoverController) {
30933
+ this.popoverController = popoverController;
30934
+ }
30935
+ UserEventNotificationList.prototype.ngOnInit = function () {
30936
+ };
30937
+ UserEventNotificationList.prototype.read = function ($event, userEvent) {
30938
+ var _a;
30939
+ if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
30940
+ return;
30941
+ (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
30942
+ };
30943
+ UserEventNotificationList.prototype.executeAction = function (action, userEvent) {
30944
+ // Execute then close popover
30945
+ action.executeAction(userEvent);
30946
+ this.dismiss();
30947
+ };
30948
+ UserEventNotificationList.prototype.dismiss = function () {
30949
+ this.popoverController.dismiss();
30950
+ };
30951
+ return UserEventNotificationList;
30952
+ }());
30953
+ UserEventNotificationList.decorators = [
30954
+ { type: i0.Component, args: [{
30955
+ selector: 'app-user-event-notification-list',
30956
+ template: "\n<ion-list class=\"ion-list-popover\">\n\n <ion-row class=\"ion-list-header column\">\n <ion-col>\n <ion-label>{{titleI18n | translate}}</ion-label>\n </ion-col>\n </ion-row>\n\n <ion-item *ngIf=\"!(userEvents | async)?.length\">\n {{'SOCIAL.USER_EVENT.NOTIFICATION.EMPTY' | translate}}\n </ion-item>\n <ion-item\n *ngFor=\"let userEvent of userEvents | async\"\n (click)=\"read($event, userEvent)\"\n >\n\n <ion-avatar slot=\"start\">\n\n <img *ngIf=\"userEvent.avatar; else avatarIcon\" src=\"{{ userEvent.avatar }}\">\n\n <ng-template #avatarIcon>\n <app-icon\n *ngIf=\"userEvent.avatarIcon\"\n [ref]=\"userEvent.avatarIcon\"\n height=\"40\"\n width=\"40\"\n ></app-icon>\n </ng-template>\n\n </ion-avatar>\n\n <ion-grid class=\"ion-no-margin ion-no-padding\">\n <ion-row>\n <ion-col>\n <p [class.unread]=\"!userEvent.readDate\">\n {{userEvent.message}}\n </p>\n </ion-col>\n </ion-row>\n <ion-row *ngIf=\"userEvent.actions?.length\">\n <ion-col>\n <p>\n <span *ngFor=\"let action of userEvent.actions\">\n <a\n [style.margin-right.px]=\"8\"\n [style.cursor]=\"'pointer'\"\n (click)=\"executeAction(action, userEvent)\"\n >\n {{ '&#10142;&nbsp;' + action.name}}\n </a>\n </span>\n </p>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <app-icon\n *ngIf=\"userEvent.icon\"\n [ref]=\"userEvent.icon\"\n height=\"16\"\n width=\"16\"\n [style.vertical-align]=\"'sub'\"\n ></app-icon>\n <small>\n <span>{{userEvent.creationDate|dateFromNow}}</span>\n <span [style.color]=\"'gray'\">{{ ' | ' + (userEvent.creationDate|dateFormat:{time:true}) }}</span>\n </small>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-item>\n\n</ion-list>\n",
30957
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}"]
30958
+ },] }
30959
+ ];
30960
+ UserEventNotificationList.ctorParameters = function () { return [
30961
+ { type: i1$5.PopoverController }
30962
+ ]; };
30963
+ UserEventNotificationList.propDecorators = {
30964
+ titleI18n: [{ type: i0.Input }],
30965
+ userEvents: [{ type: i0.Input }],
30966
+ readEvent: [{ type: i0.Output }]
30967
+ };
30968
+
30969
+ var UserEventNotificationComponent = /** @class */ (function () {
30970
+ function UserEventNotificationComponent(userEventService, accountService, popoverController, cd) {
30971
+ this.userEventService = userEventService;
30972
+ this.accountService = accountService;
30973
+ this.popoverController = popoverController;
30974
+ this.cd = cd;
30975
+ this.debug = false;
30976
+ this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
30977
+ this.disabled = false;
30978
+ this.userEventsSubject = new rxjs.BehaviorSubject(undefined);
30979
+ this._subscriptions = new rxjs.Subscription();
30980
+ this._logPrefix = '[user-event-notification] ';
30981
+ this._readEvent = new i0.EventEmitter();
30982
+ }
30983
+ Object.defineProperty(UserEventNotificationComponent.prototype, "count", {
30984
+ get: function () {
30985
+ var _a;
30986
+ return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(operators.map(function (value) { return value === 0 ? undefined : value; }));
30987
+ },
30988
+ enumerable: false,
30989
+ configurable: true
30990
+ });
30991
+ UserEventNotificationComponent.prototype.ngOnInit = function () {
30992
+ var _this = this;
30993
+ if (isNil(this.userEventService)) {
30994
+ console.warn(this._logPrefix + "No service injected");
30995
+ this.disabled = true;
30996
+ return;
30997
+ }
30998
+ // Watch first
30999
+ this._subscriptions.add(this.userEventService.watchAll(0, 10, 'creationDate', 'desc').subscribe(function (value) {
31000
+ var data = value.data;
31001
+ if (_this.debug) {
31002
+ console.debug(_this._logPrefix + "Receiving user events", data);
31003
+ }
31004
+ _this.userEventsSubject.next(data);
31005
+ }));
31006
+ // Then listen changes
31007
+ this._subscriptions.add(this.userEventService.listenChanges(undefined).subscribe(function (data) {
31008
+ if (_this.debug) {
31009
+ console.debug(_this._logPrefix + "Receiving new user events", data);
31010
+ }
31011
+ _this.userEventsSubject.next(data);
31012
+ }));
31013
+ this._readEvent.subscribe(function (value) {
31014
+ _this.userEventService.markAsRead(value);
31015
+ });
31016
+ };
31017
+ UserEventNotificationComponent.prototype.showList = function (event) {
31018
+ return __awaiter(this, void 0, void 0, function () {
31019
+ var popover;
31020
+ return __generator(this, function (_b) {
31021
+ switch (_b.label) {
31022
+ case 0: return [4 /*yield*/, this.popoverController.create({
31023
+ component: UserEventNotificationList,
31024
+ componentProps: {
31025
+ titleI18n: this.titleI18n,
31026
+ userEvents: this.userEventsSubject,
31027
+ readEvent: this._readEvent
31028
+ },
31029
+ backdropDismiss: true,
31030
+ keyboardClose: true,
31031
+ event: event,
31032
+ translucent: true,
31033
+ cssClass: 'popover-large'
31034
+ })];
31035
+ case 1:
31036
+ popover = _b.sent();
31037
+ return [4 /*yield*/, popover.present()];
31038
+ case 2:
31039
+ _b.sent();
31040
+ return [2 /*return*/];
31041
+ }
31042
+ });
31043
+ });
31044
+ };
31045
+ UserEventNotificationComponent.prototype.markForCheck = function () {
31046
+ this.cd.markForCheck();
31047
+ };
31048
+ UserEventNotificationComponent.prototype.ngOnDestroy = function () {
31049
+ if (this.debug) {
31050
+ console.debug(this._logPrefix + "Destroying");
31051
+ }
31052
+ this._subscriptions.unsubscribe();
31053
+ };
31054
+ return UserEventNotificationComponent;
31055
+ }());
31056
+ UserEventNotificationComponent.decorators = [
31057
+ { type: i0.Component, args: [{
31058
+ selector: 'app-user-event-notification-component',
31059
+ 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",
31060
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31061
+ styles: [""]
31062
+ },] }
31063
+ ];
31064
+ UserEventNotificationComponent.ctorParameters = function () { return [
31065
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [UserEventServiceToken,] }] },
31066
+ { type: AccountService },
31067
+ { type: i1$5.PopoverController },
31068
+ { type: i0.ChangeDetectorRef }
31069
+ ]; };
31070
+ UserEventNotificationComponent.propDecorators = {
31071
+ debug: [{ type: i0.Input }],
31072
+ titleI18n: [{ type: i0.Input }],
31073
+ disabled: [{ type: i0.Input }]
31074
+ };
31075
+
31076
+ var UserEventModule = /** @class */ (function () {
31077
+ function UserEventModule() {
31078
+ }
31079
+ return UserEventModule;
31080
+ }());
31081
+ UserEventModule.decorators = [
31082
+ { type: i0.NgModule, args: [{
31083
+ imports: [
31084
+ i1$4.CommonModule,
31085
+ CoreModule,
31086
+ SharedModule
31087
+ ],
31088
+ declarations: [
31089
+ UserEventsTable,
31090
+ UserEventNotificationComponent,
31091
+ UserEventNotificationList,
31092
+ ],
31093
+ exports: [
31094
+ UserEventsTable,
31095
+ UserEventNotificationComponent
31096
+ ]
31097
+ },] }
31098
+ ];
31099
+
30652
31100
  var MessageTypes = {
30653
31101
  INBOX_MESSAGE: 'INBOX_MESSAGE',
30654
31102
  EMAIL: 'EMAIL',
@@ -30882,12 +31330,12 @@
30882
31330
  canSelectType: [{ type: i0.Input }]
30883
31331
  };
30884
31332
 
30885
- var SocialModule = /** @class */ (function () {
30886
- function SocialModule() {
31333
+ var MessageModule = /** @class */ (function () {
31334
+ function MessageModule() {
30887
31335
  }
30888
- return SocialModule;
31336
+ return MessageModule;
30889
31337
  }());
30890
- SocialModule.decorators = [
31338
+ MessageModule.decorators = [
30891
31339
  { type: i0.NgModule, args: [{
30892
31340
  imports: [
30893
31341
  i1$4.CommonModule,
@@ -30895,19 +31343,342 @@
30895
31343
  SharedModule
30896
31344
  ],
30897
31345
  declarations: [
30898
- UserEventsTable,
30899
31346
  MessageModal,
30900
31347
  MessageForm
30901
31348
  ],
30902
31349
  exports: [
30903
- UserEventsTable,
30904
31350
  MessageModal
30905
31351
  ]
30906
31352
  },] }
30907
31353
  ];
30908
31354
 
31355
+ var JobProgression_1;
31356
+ // todo use entity
31357
+ var Job = /** @class */ (function () {
31358
+ function Job() {
31359
+ }
31360
+ return Job;
31361
+ }());
31362
+ // @dynamic
31363
+ exports.JobProgression = JobProgression_1 = /** @class */ (function (_super) {
31364
+ __extends(JobProgression, _super);
31365
+ function JobProgression() {
31366
+ return _super.call(this, JobProgression_1.TYPENAME) || this;
31367
+ }
31368
+ JobProgression.prototype.fromObject = function (source) {
31369
+ _super.prototype.fromObject.call(this, source);
31370
+ this.message = source.message;
31371
+ this.current = source.current;
31372
+ this.total = source.total;
31373
+ };
31374
+ return JobProgression;
31375
+ }(Entity));
31376
+ exports.JobProgression = JobProgression_1 = __decorate([
31377
+ EntityClass({ typename: 'JobProgressionVO' })
31378
+ ], exports.JobProgression);
31379
+
31380
+ var JobProgressionServiceToken = new i0.InjectionToken('JobProgressionService');
31381
+ var jobProgressionSubscription = core.gql(templateObject_1$4 || (templateObject_1$4 = __makeTemplateObject(["subscription UpdateJobProgression($id: Int!, $interval: Int){\n data: updateJobProgression(id: $id, interval: $interval) {\n id\n message\n current\n total\n }\n}"], ["subscription UpdateJobProgression($id: Int!, $interval: Int){\n data: updateJobProgression(id: $id, interval: $interval) {\n id\n message\n current\n total\n }\n}"])));
31382
+ var JobProgressionService = /** @class */ (function (_super) {
31383
+ __extends(JobProgressionService, _super);
31384
+ function JobProgressionService(graphql, environment) {
31385
+ var _this = _super.call(this, graphql, environment) || this;
31386
+ _this.graphql = graphql;
31387
+ _this.environment = environment;
31388
+ _this._logPrefix = '[job-progression-service] ';
31389
+ // For DEV only
31390
+ _this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
31391
+ return _this;
31392
+ }
31393
+ JobProgressionService.prototype.listenChanges = function (id, options) {
31394
+ var _this = this;
31395
+ if (isNil(id))
31396
+ throw new Error(this._logPrefix + "Missing argument 'id'");
31397
+ if (this._debug)
31398
+ console.debug(this._logPrefix + "[WS] Listening changes for job progression {" + id + "}...");
31399
+ return this.graphql.subscribe({
31400
+ query: jobProgressionSubscription,
31401
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
31402
+ variables: { id: id, interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
31403
+ error: { code: SocialErrorCodes.SUBSCRIBE_JOB_PROGRESSION_ERROR, message: 'SOCIAL.ERROR.SUBSCRIBE_JOB_PROGRESSION_ERROR' }
31404
+ }).pipe(operators.map(function (_a) {
31405
+ var data = _a.data;
31406
+ var progression = data && exports.JobProgression.fromObject(data);
31407
+ if (progression && _this._debug)
31408
+ console.debug(_this._logPrefix + "Job progression " + id + " updated on server", progression);
31409
+ return progression;
31410
+ }));
31411
+ };
31412
+ return JobProgressionService;
31413
+ }(BaseGraphqlService));
31414
+ JobProgressionService.decorators = [
31415
+ { type: i0.Injectable }
31416
+ ];
31417
+ JobProgressionService.ctorParameters = function () { return [
31418
+ { type: GraphqlService },
31419
+ { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
31420
+ ]; };
31421
+ var templateObject_1$4;
31422
+
31423
+ var JobProgressionList = /** @class */ (function () {
31424
+ function JobProgressionList() {
31425
+ }
31426
+ JobProgressionList.prototype.ngOnInit = function () {
31427
+ };
31428
+ return JobProgressionList;
31429
+ }());
31430
+ JobProgressionList.decorators = [
31431
+ { type: i0.Component, args: [{
31432
+ selector: 'app-job-progression-list',
31433
+ 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",
31434
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}"]
31435
+ },] }
31436
+ ];
31437
+ JobProgressionList.ctorParameters = function () { return []; };
31438
+ JobProgressionList.propDecorators = {
31439
+ titleI18n: [{ type: i0.Input }],
31440
+ jobProgressions: [{ type: i0.Input }]
31441
+ };
31442
+
31443
+ var JobProgressionComponent = /** @class */ (function () {
31444
+ function JobProgressionComponent(jobProgressionService, popoverController, cd) {
31445
+ this.jobProgressionService = jobProgressionService;
31446
+ this.popoverController = popoverController;
31447
+ this.cd = cd;
31448
+ this.debug = false;
31449
+ this.titleI18n = 'SOCIAL.JOB.PROGRESSION.TITLE';
31450
+ this.jobFinished = new i0.EventEmitter();
31451
+ this.disabled = true;
31452
+ this.color = 'accent';
31453
+ this.mode = 'determinate';
31454
+ this.value = 0;
31455
+ this.jobProgressions = [];
31456
+ this._subscriptions = new rxjs.Subscription();
31457
+ this._subscriptionsById = {};
31458
+ this._logPrefix = '[job-progression] ';
31459
+ }
31460
+ JobProgressionComponent.prototype.ngOnInit = function () {
31461
+ var _a, _b, _c, _d;
31462
+ if (isNil(this.jobProgressionService)) {
31463
+ console.warn(this._logPrefix + "No service injected");
31464
+ }
31465
+ // parse options
31466
+ this.autoHide = toBoolean((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoHide, false);
31467
+ this.visible = !this.autoHide;
31468
+ this.autoHideDelay = toNumber((_b = this.options) === null || _b === void 0 ? void 0 : _b.autoHideDelay, 1000);
31469
+ this.autoRemove = toBoolean((_c = this.options) === null || _c === void 0 ? void 0 : _c.autoRemove, true);
31470
+ this.autoRemoveDelay = toNumber((_d = this.options) === null || _d === void 0 ? void 0 : _d.autoRemoveDelay, 1000);
31471
+ };
31472
+ JobProgressionComponent.prototype.addJob = function (id) {
31473
+ var _this = this;
31474
+ if (isNil(this.jobProgressionService)) {
31475
+ console.warn(this._logPrefix + "No service injected. Can't add a job");
31476
+ return;
31477
+ }
31478
+ if (this.debug) {
31479
+ console.debug(this._logPrefix + "Add job id=" + id);
31480
+ }
31481
+ if (!!this.getProgression(id)) {
31482
+ console.warn(this._logPrefix + "Job (id=" + id + ") already present");
31483
+ return;
31484
+ }
31485
+ this.disabled = false;
31486
+ var sub = this.jobProgressionService.listenChanges(id)
31487
+ .pipe(operators.filter(function (progression) {
31488
+ if (id !== progression.id) {
31489
+ console.error(_this._logPrefix + "Job progression (id=" + progression.id + ") doesn't match expected job (id=" + id + ")");
31490
+ return false;
31491
+ }
31492
+ return true;
31493
+ }), operators.map(function (progression) {
31494
+ // Ensure visible
31495
+ _this.visible = true;
31496
+ // Get current progression object
31497
+ var currentProgression = _this.getProgression(id);
31498
+ if (!currentProgression) {
31499
+ // add it
31500
+ _this.jobProgressions.push(progression);
31501
+ if (_this.debug) {
31502
+ console.debug(_this._logPrefix + "Progression added id=" + id, progression);
31503
+ }
31504
+ }
31505
+ else {
31506
+ // update current
31507
+ Object.assign(currentProgression, progression);
31508
+ if (_this.debug) {
31509
+ console.debug(_this._logPrefix + "Progression updated id=" + id, progression);
31510
+ }
31511
+ }
31512
+ return progression;
31513
+ }))
31514
+ .subscribe(function (progression) {
31515
+ // update value
31516
+ _this.updateValue();
31517
+ // job finished
31518
+ if (progression.total > 0 && progression.current == progression.total) {
31519
+ if (_this.debug) {
31520
+ console.debug(_this._logPrefix + "Finished job id=" + progression.id);
31521
+ }
31522
+ // emit event
31523
+ _this.jobFinished.emit(progression.id);
31524
+ if (_this.autoRemove) {
31525
+ setTimeout(function () {
31526
+ var _a;
31527
+ _this.removeJob(progression.id);
31528
+ // If last job
31529
+ if (_this.autoHide && !((_a = _this.jobProgressions) === null || _a === void 0 ? void 0 : _a.length)) {
31530
+ setTimeout(function () {
31531
+ _this.visible = false;
31532
+ _this.markForCheck();
31533
+ }, _this.autoHideDelay);
31534
+ }
31535
+ }, _this.autoRemoveDelay);
31536
+ }
31537
+ }
31538
+ });
31539
+ this._subscriptionsById[id] = sub;
31540
+ this._subscriptions.add(sub);
31541
+ };
31542
+ JobProgressionComponent.prototype.removeJob = function (id) {
31543
+ if (this.debug) {
31544
+ console.debug(this._logPrefix + "Remove job id=" + id);
31545
+ }
31546
+ var sub = this._subscriptionsById[id];
31547
+ if (sub) {
31548
+ this._subscriptions.remove(sub);
31549
+ sub.unsubscribe();
31550
+ }
31551
+ var progression = this.getProgression(id);
31552
+ if (progression) {
31553
+ this.jobProgressions.splice(this.jobProgressions.indexOf(progression), 1);
31554
+ }
31555
+ this.updateValue();
31556
+ };
31557
+ JobProgressionComponent.prototype.getProgression = function (id) {
31558
+ return this.jobProgressions.find(function (progression) { return progression.id === id; });
31559
+ };
31560
+ JobProgressionComponent.prototype.updateValue = function () {
31561
+ if (this.debug) {
31562
+ console.debug(this._logPrefix + "Updating value");
31563
+ }
31564
+ var value = 0;
31565
+ var nbProgression = arraySize(this.jobProgressions);
31566
+ var allIndeterminate = nbProgression > 0;
31567
+ this.jobProgressions.forEach(function (progression) {
31568
+ var indeterminate = progression.total === 0;
31569
+ allIndeterminate = allIndeterminate && indeterminate;
31570
+ if (!indeterminate) {
31571
+ value = value + progression.current * 100 / progression.total;
31572
+ }
31573
+ });
31574
+ this.value = nbProgression > 0 ? value / nbProgression : 0;
31575
+ this.mode = allIndeterminate ? 'indeterminate' : 'determinate';
31576
+ if (this.debug) {
31577
+ console.debug(this._logPrefix + "Setting value=" + this.value + ", mode=" + this.mode);
31578
+ }
31579
+ this.markForCheck();
31580
+ };
31581
+ JobProgressionComponent.prototype.showList = function (event) {
31582
+ return __awaiter(this, void 0, void 0, function () {
31583
+ var popover;
31584
+ return __generator(this, function (_e) {
31585
+ switch (_e.label) {
31586
+ case 0: return [4 /*yield*/, this.popoverController.create({
31587
+ component: JobProgressionList,
31588
+ componentProps: {
31589
+ titleI18n: this.titleI18n,
31590
+ jobProgressions: this.jobProgressions
31591
+ },
31592
+ backdropDismiss: true,
31593
+ keyboardClose: true,
31594
+ event: event,
31595
+ translucent: true,
31596
+ cssClass: 'popover-large'
31597
+ })];
31598
+ case 1:
31599
+ popover = _e.sent();
31600
+ return [4 /*yield*/, popover.present()];
31601
+ case 2:
31602
+ _e.sent();
31603
+ return [2 /*return*/];
31604
+ }
31605
+ });
31606
+ });
31607
+ };
31608
+ JobProgressionComponent.prototype.markForCheck = function () {
31609
+ this.cd.markForCheck();
31610
+ };
31611
+ JobProgressionComponent.prototype.ngOnDestroy = function () {
31612
+ if (this.debug) {
31613
+ console.debug(this._logPrefix + "Destroying");
31614
+ }
31615
+ this._subscriptions.unsubscribe();
31616
+ };
31617
+ return JobProgressionComponent;
31618
+ }());
31619
+ JobProgressionComponent.decorators = [
31620
+ { type: i0.Component, args: [{
31621
+ selector: 'app-job-progression',
31622
+ 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",
31623
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
31624
+ styles: [".floating-spinner{position:absolute;top:6px;left:5px}"]
31625
+ },] }
31626
+ ];
31627
+ JobProgressionComponent.ctorParameters = function () { return [
31628
+ { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [JobProgressionServiceToken,] }] },
31629
+ { type: i1$5.PopoverController },
31630
+ { type: i0.ChangeDetectorRef }
31631
+ ]; };
31632
+ JobProgressionComponent.propDecorators = {
31633
+ debug: [{ type: i0.Input }],
31634
+ titleI18n: [{ type: i0.Input }],
31635
+ options: [{ type: i0.Input }],
31636
+ jobFinished: [{ type: i0.Output }]
31637
+ };
31638
+
31639
+ var JobModule = /** @class */ (function () {
31640
+ function JobModule() {
31641
+ }
31642
+ return JobModule;
31643
+ }());
31644
+ JobModule.decorators = [
31645
+ { type: i0.NgModule, args: [{
31646
+ imports: [
31647
+ i1$4.CommonModule,
31648
+ SharedModule,
31649
+ i1$2.TranslateModule.forChild(),
31650
+ ],
31651
+ declarations: [
31652
+ JobProgressionComponent,
31653
+ JobProgressionList
31654
+ ],
31655
+ exports: [
31656
+ JobProgressionComponent
31657
+ ]
31658
+ },] }
31659
+ ];
31660
+
31661
+ var SocialModuleOptionsToken = new i0.InjectionToken("SocialModuleOptions");
31662
+ var SocialModule = /** @class */ (function () {
31663
+ function SocialModule() {
31664
+ }
31665
+ return SocialModule;
31666
+ }());
31667
+ SocialModule.decorators = [
31668
+ { type: i0.NgModule, args: [{
31669
+ imports: [
31670
+ i1$4.CommonModule,
31671
+ CoreModule,
31672
+ SharedModule,
31673
+ UserEventModule,
31674
+ JobModule,
31675
+ MessageModule,
31676
+ ],
31677
+ },] }
31678
+ ];
31679
+
30909
31680
  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 }"])))
31681
+ 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
31682
  };
30912
31683
  var MessageService = /** @class */ (function (_super) {
30913
31684
  __extends(MessageService, _super);
@@ -30991,7 +31762,7 @@
30991
31762
  { type: i1$5.ToastController },
30992
31763
  { type: Environment, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [ENVIRONMENT,] }] }
30993
31764
  ]; };
30994
- var templateObject_1$4;
31765
+ var templateObject_1$5;
30995
31766
 
30996
31767
  var PersonFilter_1;
30997
31768
  // @dynamic
@@ -31050,7 +31821,7 @@
31050
31821
  ], exports.PersonFilter);
31051
31822
 
31052
31823
  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 }"])))
31824
+ 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
31825
  };
31055
31826
  // Load persons query
31056
31827
  var PersonQueries = {
@@ -31190,7 +31961,7 @@
31190
31961
  { type: NetworkService },
31191
31962
  { type: EntitiesStorage }
31192
31963
  ]; };
31193
- var templateObject_1$5, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31964
+ var templateObject_1$6, templateObject_2$4, templateObject_3$3, templateObject_4$3, templateObject_5$2;
31194
31965
 
31195
31966
  var PersonValidatorService = /** @class */ (function () {
31196
31967
  function PersonValidatorService(formBuilder, accountValidatorService) {
@@ -31600,12 +32371,10 @@
31600
32371
  };
31601
32372
  AutocompleteTestPage.prototype.ngAfterViewInit = function () {
31602
32373
  var _this = this;
31603
- if (this.farEntityField) {
31604
- setTimeout(function () {
31605
- _this.farEntityField.suggestLengthThreshold = 2;
31606
- _this.farEntityField.reloadItems();
31607
- }, 2000);
31608
- }
32374
+ setTimeout(function () {
32375
+ _this.farEntityField.suggestLengthThreshold = 2;
32376
+ _this.farEntityField.reloadItems();
32377
+ }, 2000);
31609
32378
  setTimeout(function () { return _this.loadData(); }, 1000);
31610
32379
  };
31611
32380
  // Load the form with data
@@ -31712,7 +32481,7 @@
31712
32481
  AutocompleteTestPage.decorators = [
31713
32482
  { type: i0.Component, args: [{
31714
32483
  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"
32484
+ 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
32485
  },] }
31717
32486
  ];
31718
32487
  AutocompleteTestPage.ctorParameters = function () { return [
@@ -31794,13 +32563,13 @@
31794
32563
  { type: i1.FormBuilder }
31795
32564
  ]; };
31796
32565
 
31797
- var moment$6 = momentImported__namespace;
32566
+ var moment$7 = momentImported__namespace;
31798
32567
  var SwipeTestPage = /** @class */ (function () {
31799
32568
  function SwipeTestPage(formBuilder, dateFormatPipe) {
31800
32569
  this.formBuilder = formBuilder;
31801
32570
  this.dateFormatPipe = dateFormatPipe;
31802
32571
  this.$dates = new rxjs.BehaviorSubject(undefined);
31803
- this._today = moment$6().startOf('day');
32572
+ this._today = moment$7().startOf('day');
31804
32573
  this.form = formBuilder.group({
31805
32574
  empty: [null, i1.Validators.required],
31806
32575
  date: [null, i1.Validators.compose([i1.Validators.required, SharedValidators.validDate])],
@@ -31814,7 +32583,7 @@
31814
32583
  var _this = this;
31815
32584
  var dates = [];
31816
32585
  for (var d = 0; d < 7; d++) {
31817
- dates[d] = moment$6(this._today).add(d - 3, 'day');
32586
+ dates[d] = moment$7(this._today).add(d - 3, 'day');
31818
32587
  }
31819
32588
  this.$dates.next(dates);
31820
32589
  this.loadData();
@@ -31861,7 +32630,7 @@
31861
32630
  { type: DateFormatPipe }
31862
32631
  ]; };
31863
32632
 
31864
- var moment$7 = momentImported__namespace;
32633
+ var moment$8 = momentImported__namespace;
31865
32634
  var DateTimeTestPage = /** @class */ (function () {
31866
32635
  function DateTimeTestPage(platform, formBuilder, cd) {
31867
32636
  this.platform = platform;
@@ -31897,7 +32666,7 @@
31897
32666
  var now, data;
31898
32667
  var _this = this;
31899
32668
  return __generator(this, function (_a) {
31900
- now = moment$7();
32669
+ now = moment$8();
31901
32670
  data = {
31902
32671
  empty: null,
31903
32672
  emptyRequired: null,
@@ -32175,7 +32944,7 @@
32175
32944
  { type: i1.FormBuilder }
32176
32945
  ]; };
32177
32946
 
32178
- var moment$8 = momentImported__namespace;
32947
+ var moment$9 = momentImported__namespace;
32179
32948
  var DateTestPage = /** @class */ (function () {
32180
32949
  function DateTestPage(formBuilder, cd) {
32181
32950
  this.formBuilder = formBuilder;
@@ -32212,7 +32981,7 @@
32212
32981
  var now, nowAtMahe, data;
32213
32982
  var _this = this;
32214
32983
  return __generator(this, function (_a) {
32215
- now = moment$8();
32984
+ now = moment$9();
32216
32985
  nowAtMahe = now.clone().tz(this.timezone).startOf('day');
32217
32986
  data = {
32218
32987
  empty: null,
@@ -33051,6 +33820,7 @@
33051
33820
  exports.APP_MENU_ITEMS = APP_MENU_ITEMS;
33052
33821
  exports.APP_TESTING_PAGES = APP_TESTING_PAGES;
33053
33822
  exports.AboutModal = AboutModal;
33823
+ exports.AbstractUserEventService = AbstractUserEventService;
33054
33824
  exports.AccountPage = AccountPage;
33055
33825
  exports.AccountService = AccountService;
33056
33826
  exports.AccountToStringPipe = AccountToStringPipe;
@@ -33177,6 +33947,11 @@
33177
33947
  exports.IsNotNilOrBlankPipe = IsNotNilOrBlankPipe;
33178
33948
  exports.IsNotOnFieldModePipe = IsNotOnFieldModePipe;
33179
33949
  exports.IsOnFieldModePipe = IsOnFieldModePipe;
33950
+ exports.Job = Job;
33951
+ exports.JobModule = JobModule;
33952
+ exports.JobProgressionComponent = JobProgressionComponent;
33953
+ exports.JobProgressionService = JobProgressionService;
33954
+ exports.JobProgressionServiceToken = JobProgressionServiceToken;
33180
33955
  exports.JobUtils = JobUtils;
33181
33956
  exports.KEYBOARD_HIDE_DELAY_MS = KEYBOARD_HIDE_DELAY_MS;
33182
33957
  exports.LAT_LONG_DEFAULT_MAX_DECIMALS = LAT_LONG_DEFAULT_MAX_DECIMALS;
@@ -33214,6 +33989,7 @@
33214
33989
  exports.MenuService = MenuService;
33215
33990
  exports.MessageForm = MessageForm;
33216
33991
  exports.MessageModal = MessageModal;
33992
+ exports.MessageModule = MessageModule;
33217
33993
  exports.MessageService = MessageService;
33218
33994
  exports.MessageTypeList = MessageTypeList;
33219
33995
  exports.MessageTypes = MessageTypes;
@@ -33281,6 +34057,7 @@
33281
34057
  exports.SharedValidators = SharedValidators;
33282
34058
  exports.SocialErrorCodes = SocialErrorCodes;
33283
34059
  exports.SocialModule = SocialModule;
34060
+ exports.SocialModuleOptionsToken = SocialModuleOptionsToken;
33284
34061
  exports.StartableService = StartableService;
33285
34062
  exports.StatusById = StatusById;
33286
34063
  exports.StatusIds = StatusIds;
@@ -33309,7 +34086,10 @@
33309
34086
  exports.UploadFileTestingPage = UploadFileTestingPage;
33310
34087
  exports.UriUtils = UriUtils;
33311
34088
  exports.UserEventFragments = UserEventFragments;
34089
+ exports.UserEventModule = UserEventModule;
34090
+ exports.UserEventNotificationComponent = UserEventNotificationComponent;
33312
34091
  exports.UserEventService = UserEventService;
34092
+ exports.UserEventServiceToken = UserEventServiceToken;
33313
34093
  exports.UserEventTypes = UserEventTypes;
33314
34094
  exports.UserEventsTable = UserEventsTable;
33315
34095
  exports.UsersPage = UsersPage;
@@ -33474,11 +34254,13 @@
33474
34254
  exports.ɵh = LocalSettingsValidatorService;
33475
34255
  exports.ɵi = AppUpdateOfflineModeCard;
33476
34256
  exports.ɵj = AppIconComponent;
33477
- exports.ɵk = DateTestPage;
33478
- exports.ɵl = NumpadTestPage;
33479
- exports.ɵm = MatBadgeIconTestPage;
33480
- exports.ɵn = ToastTestingModule;
33481
- exports.ɵo = ToastTestingPage;
34257
+ exports.ɵk = UserEventNotificationList;
34258
+ exports.ɵl = JobProgressionList;
34259
+ exports.ɵm = DateTestPage;
34260
+ exports.ɵn = NumpadTestPage;
34261
+ exports.ɵo = MatBadgeIconTestPage;
34262
+ exports.ɵp = ToastTestingModule;
34263
+ exports.ɵq = ToastTestingPage;
33482
34264
 
33483
34265
  Object.defineProperty(exports, '__esModule', { value: true });
33484
34266