@sumaris-net/ngx-components 1.21.7 → 1.22.0

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 (56) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +1305 -200
  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 +3 -0
  6. package/esm2015/public_api.js +8 -1
  7. package/esm2015/src/app/core/form/editor.class.js +7 -11
  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/shared/pipes/date-diff-duration.pipe.js +9 -5
  11. package/esm2015/src/app/shared/types.js +1 -1
  12. package/esm2015/src/app/social/job/job.model.js +26 -0
  13. package/esm2015/src/app/social/job/job.module.js +25 -0
  14. package/esm2015/src/app/social/job/job.service.js +54 -0
  15. package/esm2015/src/app/social/job/progression/job-progression.component.js +200 -0
  16. package/esm2015/src/app/social/job/progression/job-progression.list.js +20 -0
  17. package/esm2015/src/app/social/message/message.module.js +25 -0
  18. package/esm2015/src/app/social/social.errors.js +5 -2
  19. package/esm2015/src/app/social/social.module.js +10 -15
  20. package/esm2015/src/app/social/user-event/notification/user-event-notification.component.js +89 -0
  21. package/esm2015/src/app/social/user-event/notification/user-event-notification.list.js +78 -0
  22. package/esm2015/src/app/social/user-event/testing/user-event.testing.service.js +73 -0
  23. package/esm2015/src/app/social/user-event/user-event.model.js +58 -2
  24. package/esm2015/src/app/social/user-event/user-event.module.js +33 -0
  25. package/esm2015/src/app/social/user-event/user-event.service.js +412 -173
  26. package/esm2015/src/app/social/user-event/user-events.table.js +18 -13
  27. package/esm2015/sumaris-net.ngx-components.js +9 -6
  28. package/fesm2015/sumaris-net.ngx-components.js +1122 -259
  29. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  30. package/package.json +1 -1
  31. package/public_api.d.ts +7 -0
  32. package/src/app/core/icon/icon.component.d.ts +4 -4
  33. package/src/app/shared/material/badge/badge-icon.test.d.ts +1 -1
  34. package/src/app/shared/pipes/date-diff-duration.pipe.d.ts +6 -2
  35. package/src/app/shared/types.d.ts +4 -0
  36. package/src/app/social/job/job.model.d.ts +33 -0
  37. package/src/app/social/job/job.module.d.ts +2 -0
  38. package/src/app/social/job/job.service.d.ts +23 -0
  39. package/src/app/social/job/progression/job-progression.component.d.ts +44 -0
  40. package/src/app/social/job/progression/job-progression.list.d.ts +12 -0
  41. package/src/app/social/message/message.module.d.ts +2 -0
  42. package/src/app/social/social.errors.d.ts +3 -0
  43. package/src/app/social/social.module.d.ts +8 -0
  44. package/src/app/social/user-event/notification/user-event-notification.component.d.ts +22 -0
  45. package/src/app/social/user-event/notification/user-event-notification.list.d.ts +30 -0
  46. package/src/app/social/user-event/testing/user-event.testing.service.d.ts +35 -0
  47. package/src/app/social/user-event/user-event.model.d.ts +52 -8
  48. package/src/app/social/user-event/user-event.module.d.ts +2 -0
  49. package/src/app/social/user-event/user-event.service.d.ts +101 -51
  50. package/src/app/social/user-event/user-events.table.d.ts +6 -6
  51. package/src/assets/i18n/en-US.json +15 -2
  52. package/src/assets/i18n/en.json +16 -2
  53. package/src/assets/i18n/fr.json +15 -1
  54. package/src/theme/_ngx-components.scss +8 -0
  55. package/sumaris-net.ngx-components.d.ts +8 -5
  56. package/sumaris-net.ngx-components.metadata.json +1 -1
@@ -1966,17 +1966,21 @@ class DateDiffDurationPipe {
1966
1966
  return '';
1967
1967
  const startDate = this.dateAdapter.parse(value.startValue, DATE_ISO_PATTERN);
1968
1968
  const endDate = this.dateAdapter.parse(value.endValue, DATE_ISO_PATTERN);
1969
- return this.format(startDate, endDate);
1969
+ return this.format(startDate, endDate, args);
1970
1970
  }
1971
- format(startDate, endDate) {
1971
+ format(startDate, endDate, args) {
1972
1972
  const duration = moment.duration(endDate.diff(startDate));
1973
1973
  if (duration.asMinutes() < 0)
1974
1974
  return '';
1975
+ const withSeconds = args === null || args === void 0 ? void 0 : args.seconds;
1975
1976
  const timeDuration = moment(0)
1976
1977
  .hour(duration.hours())
1977
1978
  .minute(duration.minutes());
1979
+ if (withSeconds) {
1980
+ timeDuration.second(duration.seconds());
1981
+ }
1978
1982
  const days = Math.floor(duration.asDays());
1979
- return (days > 0 ? days.toString() + (this.dayUnit + ' ') : '') + timeDuration.format('HH:mm');
1983
+ return (days > 0 ? days.toString() + (this.dayUnit + ' ') : '') + timeDuration.format(withSeconds ? 'HH:mm:ss' : 'HH:mm');
1980
1984
  }
1981
1985
  }
1982
1986
  DateDiffDurationPipe.ɵprov = ɵɵdefineInjectable({ factory: function DateDiffDurationPipe_Factory() { return new DateDiffDurationPipe(ɵɵinject(DateAdapter), ɵɵinject(TranslateService)); }, token: DateDiffDurationPipe, providedIn: "root" });
@@ -21477,7 +21481,7 @@ class MenuComponent {
21477
21481
  MenuComponent.decorators = [
21478
21482
  { type: Component, args: [{
21479
21483
  selector: 'app-menu',
21480
- template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
21484
+ 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",
21481
21485
  animations: [fadeInAnimation],
21482
21486
  changeDetection: ChangeDetectionStrategy.OnPush,
21483
21487
  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)}}"]
@@ -21541,13 +21545,14 @@ class AppIconComponent {
21541
21545
  this.icon = value.icon;
21542
21546
  this.matIcon = value.matIcon;
21543
21547
  this.matSvgIcon = value.matSvgIcon;
21548
+ this.color = value.color;
21544
21549
  }
21545
21550
  ;
21546
21551
  }
21547
21552
  AppIconComponent.decorators = [
21548
21553
  { type: Component, args: [{
21549
21554
  selector: 'app-icon',
21550
- template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\">{{matIcon}}</mat-icon>\n</ng-template>\n\n"
21555
+ 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"
21551
21556
  },] }
21552
21557
  ];
21553
21558
  AppIconComponent.propDecorators = {
@@ -21555,6 +21560,8 @@ AppIconComponent.propDecorators = {
21555
21560
  matIcon: [{ type: Input }],
21556
21561
  matSvgIcon: [{ type: Input }],
21557
21562
  color: [{ type: Input }],
21563
+ height: [{ type: Input }],
21564
+ width: [{ type: Input }],
21558
21565
  ref: [{ type: Input }]
21559
21566
  };
21560
21567
 
@@ -24229,8 +24236,7 @@ class AppEditor {
24229
24236
  return this._children && this._children.filter(c => c instanceof AppEditor);
24230
24237
  }
24231
24238
  get dirty() {
24232
- var _a;
24233
- return this._dirty || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.dirty)) !== -1) || false;
24239
+ return this._dirty || (this._children && this._children.findIndex(c => c.enabled && c.dirty) !== -1) || false;
24234
24240
  }
24235
24241
  /**
24236
24242
  * Is valid (tables and forms)
@@ -24240,16 +24246,13 @@ class AppEditor {
24240
24246
  return !this._children || this._children.findIndex(c => c.enabled && !c.valid) === -1;
24241
24247
  }
24242
24248
  get invalid() {
24243
- var _a;
24244
- return (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.invalid)) !== -1) || false;
24249
+ return (this._children && this._children.findIndex(c => c.enabled && c.invalid) !== -1) || false;
24245
24250
  }
24246
24251
  get pending() {
24247
- var _a;
24248
- return (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.pending)) !== -1) || false;
24252
+ return (this._children && this._children.findIndex(c => c.enabled && c.pending) !== -1) || false;
24249
24253
  }
24250
24254
  get loading() {
24251
- var _a;
24252
- return this.loadingSubject.value || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
24255
+ return this.loadingSubject.value || (this._children && this._children.findIndex(c => c.enabled && c.loading) !== -1) || false;
24253
24256
  }
24254
24257
  get enabled() {
24255
24258
  return this._enabled;
@@ -24403,10 +24406,11 @@ class AppEditor {
24403
24406
  * @param opts
24404
24407
  */
24405
24408
  unload(opts) {
24409
+ var _a;
24406
24410
  return __awaiter(this, void 0, void 0, function* () {
24407
24411
  console.debug('[tab-page] Unloading data...');
24408
24412
  this.markAsLoading();
24409
- this._children.forEach(f => {
24413
+ (_a = this._children) === null || _a === void 0 ? void 0 : _a.forEach(f => {
24410
24414
  if (f instanceof AppForm) {
24411
24415
  f.reset(null, opts);
24412
24416
  }
@@ -24414,7 +24418,6 @@ class AppEditor {
24414
24418
  f.dataSource.disconnect();
24415
24419
  }
24416
24420
  });
24417
- // TODO: find a way to remove current page from the navigation history
24418
24421
  });
24419
24422
  }
24420
24423
  reloadWithConfirmation(confirm) {
@@ -25923,7 +25926,10 @@ AppInMemoryTable.propDecorators = {
25923
25926
  const SocialErrorCodes = {
25924
25927
  LOAD_USER_EVENTS_ERROR: 50000,
25925
25928
  SAVE_USER_EVENT_ERROR: 50001,
25926
- SEND_MESSAGE_ERROR: 50003
25929
+ COUNT_USER_EVENT_ERROR: 50002,
25930
+ SEND_MESSAGE_ERROR: 50003,
25931
+ SUBSCRIBE_USER_EVENTS_ERROR: 50005,
25932
+ SUBSCRIBE_JOB_PROGRESSION_ERROR: 50010
25927
25933
  };
25928
25934
 
25929
25935
  var UserEvent_1;
@@ -25938,16 +25944,23 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25938
25944
  }
25939
25945
  asObject(opts) {
25940
25946
  const target = super.asObject(opts);
25947
+ target.creationDate = toDateISOString(this.creationDate);
25948
+ target.readDate = toDateISOString(this.readDate);
25941
25949
  // Serialize content
25942
25950
  if (typeof target.content === 'object') {
25943
25951
  target.content = JSON.stringify(target.content);
25944
25952
  }
25953
+ delete target.avatar;
25954
+ delete target.avatarIcon;
25955
+ delete target.icon;
25956
+ delete target.actions;
25945
25957
  return target;
25946
25958
  }
25947
25959
  fromObject(source) {
25948
25960
  Object.assign(this, source); // Copy all properties
25949
25961
  super.fromObject(source);
25950
25962
  this.creationDate = fromDateISOString(source.creationDate);
25963
+ this.readDate = fromDateISOString(source.readDate);
25951
25964
  try {
25952
25965
  // Deserialize content
25953
25966
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -25966,6 +25979,52 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25966
25979
  UserEvent = UserEvent_1 = __decorate([
25967
25980
  EntityClass({ typename: 'UserEventVO' })
25968
25981
  ], UserEvent);
25982
+ // @dynamic
25983
+ let UserEventFilter = class UserEventFilter extends EntityFilter {
25984
+ constructor() {
25985
+ super(...arguments);
25986
+ this.types = [];
25987
+ this.levels = [];
25988
+ this.issuers = [];
25989
+ this.recipients = [];
25990
+ this.startDate = null;
25991
+ this.excludeRead = false;
25992
+ }
25993
+ fromObject(source, opts) {
25994
+ super.fromObject(source, opts);
25995
+ this.types = source.types || [];
25996
+ this.levels = source.levels || [];
25997
+ this.issuers = source.issuers || [];
25998
+ this.recipients = source.recipients || [];
25999
+ this.startDate = fromDateISOString(source.startDate);
26000
+ this.excludeRead = source.excludeRead || false;
26001
+ }
26002
+ buildFilter() {
26003
+ const filterFns = super.buildFilter();
26004
+ if (isNotEmptyArray(this.types)) {
26005
+ filterFns.push(t => this.types.includes(t.type));
26006
+ }
26007
+ if (isNotEmptyArray(this.levels)) {
26008
+ filterFns.push(t => this.levels.includes(t.level));
26009
+ }
26010
+ if (isNotEmptyArray(this.issuers)) {
26011
+ filterFns.push(t => this.issuers.includes(t.issuer));
26012
+ }
26013
+ if (isNotEmptyArray(this.recipients)) {
26014
+ filterFns.push(t => this.recipients.includes(t.recipient));
26015
+ }
26016
+ if (isNotNil(this.startDate)) {
26017
+ filterFns.push(t => this.startDate.isSameOrBefore(t.creationDate));
26018
+ }
26019
+ if (this.excludeRead === true) {
26020
+ filterFns.push(t => isNil(t.readSignature)); // todo or t.signature ?
26021
+ }
26022
+ return filterFns;
26023
+ }
26024
+ };
26025
+ UserEventFilter = __decorate([
26026
+ EntityClass({ typename: 'UserEventFilterVO' })
26027
+ ], UserEventFilter);
25969
26028
 
25970
26029
  const UserEventFragments = {
25971
26030
  userEvent: gql `fragment UserEventFragment on UserEventVO {
@@ -25993,179 +26052,206 @@ const UserEventFragments = {
25993
26052
  }`
25994
26053
  };
25995
26054
 
25996
- // @dynamic
25997
- let UserEventFilter = class UserEventFilter extends EntityFilter {
25998
- constructor() {
25999
- super(...arguments);
26000
- this.issuer = null;
26001
- this.recipient = null;
26002
- }
26003
- fromObject(source, opts) {
26004
- super.fromObject(source, opts);
26005
- this.issuer = source.issuer;
26006
- this.recipient = source.recipient;
26007
- }
26008
- buildFilter() {
26009
- const filterFns = super.buildFilter();
26010
- // issuer
26011
- if (this.issuer) {
26012
- filterFns.push(t => (t.issuer === this.issuer));
26013
- }
26014
- if (this.recipient) {
26015
- filterFns.push(t => (t.recipient === this.recipient));
26016
- }
26017
- return filterFns;
26018
- }
26019
- };
26020
- UserEventFilter = __decorate([
26021
- EntityClass({ typename: 'UserEventFilterVO' })
26022
- ], UserEventFilter);
26023
- const SaveQuery = gql `
26024
- mutation SaveUserEvent($data: UserEventVOInput){
26025
- data: saveUserEvent(userEvent: $data){
26026
- ...UserEventFragment
26027
- }
26028
- }
26029
- ${UserEventFragments.userEvent}
26030
- `;
26031
- const LoadAllQuery = gql `
26032
- query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26033
- data: userEvents(filter: $filter, page: $page){
26034
- ...LightUserEventFragment
26035
- }
26036
- }
26037
- ${UserEventFragments.lightUserEvent}
26038
- `;
26039
- const DeleteByIdsMutation = gql `
26040
- mutation DeleteUserEvents($ids:[Int]){
26041
- deleteUserEvents(ids: $ids)
26042
- }
26043
- `;
26044
- const LoadAllWithContentQuery = gql `
26045
- query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26046
- data: userEvents(filter: $filter, page: $page){
26047
- ...UserEventFragment
26048
- }
26049
- }
26050
- ${UserEventFragments.userEvent}
26051
- `;
26052
- class UserEventService extends BaseGraphqlService {
26053
- constructor(graphql, accountService, network, translate, toastController, environment) {
26055
+ const moment$6 = momentImported;
26056
+ const UserEventServiceToken = new InjectionToken('UserEventService');
26057
+ class AbstractUserEventService extends BaseGraphqlService {
26058
+ constructor(graphql, accountService, network, translate, queries, mutations, subscriptions, environment) {
26054
26059
  super(graphql, environment);
26055
26060
  this.graphql = graphql;
26056
26061
  this.accountService = accountService;
26057
26062
  this.network = network;
26058
26063
  this.translate = translate;
26059
- this.toastController = toastController;
26064
+ this.queries = queries;
26065
+ this.mutations = mutations;
26066
+ this.subscriptions = subscriptions;
26060
26067
  this.environment = environment;
26061
- this._userEventActions = [];
26068
+ this.count$ = new BehaviorSubject(0);
26069
+ this.listeners = [];
26070
+ this._subscriptions = new Subscription();
26071
+ this._logPrefix = '[user-event-service] ';
26062
26072
  // For DEV only
26063
- this._debug = environment && !environment.production;
26073
+ this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
26074
+ }
26075
+ get userEventCount() {
26076
+ return this.count$.asObservable();
26077
+ }
26078
+ ngOnStart() {
26079
+ return __awaiter(this, void 0, void 0, function* () {
26080
+ // Update component when refresh is need (=login events)
26081
+ this._subscriptions.add(merge(this.accountService.onLogin, this.accountService.onLogout)
26082
+ .pipe(
26083
+ // Wait account service ready (can be restarted)
26084
+ mergeMap(() => this.accountService.ready()), map(() => this.accountService.isLogin()), distinctUntilChanged())
26085
+ .subscribe(login => {
26086
+ if (login) {
26087
+ this.onLogin();
26088
+ }
26089
+ else {
26090
+ this.onLogout();
26091
+ }
26092
+ }));
26093
+ // First attempt if account is ready
26094
+ yield this.accountService.ready();
26095
+ if (this.accountService.isLogin()) {
26096
+ setTimeout(() => this.onLogin());
26097
+ }
26098
+ });
26099
+ }
26100
+ ngOnDestroy() {
26101
+ this._subscriptions.unsubscribe();
26064
26102
  }
26065
- /**
26066
- *
26067
- * @param offset
26068
- * @param size
26069
- * @param sortBy
26070
- * @param sortDirection
26071
- * @param filter
26072
- * @param options
26073
- * @deprecated use watchPage() instead
26074
- */
26075
26103
  watchAll(offset, size, sortBy, sortDirection, filter, options) {
26076
26104
  return this.watchPage({ offset, size, sortBy, sortDirection }, filter, options);
26077
26105
  }
26078
26106
  watchPage(page, filter, options) {
26107
+ var _a;
26079
26108
  let now = this._debug && Date.now();
26080
- //if (this._debug)
26081
- console.debug('[user-event-service] Loading user events...', filter);
26109
+ if (!filter) {
26110
+ filter = this.defaultFilter();
26111
+ }
26112
+ console.debug(`${this._logPrefix}Loading user events...`, filter);
26082
26113
  filter = this.asFilter(filter);
26083
26114
  // Force recipient to current issuer, if not admin and not specified
26084
- if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
26085
- const recipient = this.accountService.account.pubkey;
26086
- if (recipient !== filter.recipient) {
26115
+ if (isEmptyArray(filter === null || filter === void 0 ? void 0 : filter.recipients) || !this.accountService.isAdmin()) {
26116
+ const recipient = this.defaultRecipient();
26117
+ if (!((_a = filter === null || filter === void 0 ? void 0 : filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
26087
26118
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
26088
- filter.recipient = recipient;
26119
+ filter.recipients = [recipient];
26089
26120
  }
26090
26121
  }
26091
- const withContent = options && options.withContent === true;
26122
+ const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26092
26123
  return this.mutableWatchQuery({
26093
26124
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
26094
- query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
26125
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26095
26126
  variables: {
26096
- page: Object.assign(Object.assign({ sortBy: 'updateDate' }, page), { sortDirection: (page.sortDirection || 'DESC').toUpperCase() }),
26127
+ page: Object.assign(Object.assign({ sortBy: 'creationDate' }, page), {
26128
+ // @ts-ignore
26129
+ sortDirection: (page.sortDirection || 'desc').toUpperCase() }),
26097
26130
  filter: filter && filter.asPodObject()
26098
26131
  },
26099
26132
  arrayFieldName: 'data',
26100
26133
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
26101
- fetchPolicy: options && options.fetchPolicy || undefined
26134
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'cache-first'
26102
26135
  })
26103
26136
  .pipe(map(res => {
26104
- const data = res && (res.data || []).map(UserEvent.fromObject);
26137
+ let data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(value => this.processUserEvent(value, this));
26105
26138
  if (now) {
26106
- console.debug(`[user-event-service] ${data.length} user events loaded in ${Date.now() - now}ms`);
26139
+ console.debug(`${this._logPrefix}${data.length} user events loaded in ${Date.now() - now}ms`);
26107
26140
  now = null;
26108
26141
  }
26142
+ // Must re-order because of listenChanges result will add new event at the end
26143
+ data = EntityUtils.sort(data, page.sortBy, page.sortDirection);
26109
26144
  return {
26110
26145
  data,
26111
- total: res && toNumber(res.total, data.length)
26146
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, data.length)
26112
26147
  };
26113
26148
  }));
26114
26149
  }
26115
- saveAll(data, options) {
26116
- return Promise.all(data
26117
- .map(entity => this.save(entity, options)));
26150
+ add(entity) {
26151
+ // TODO set an id !!!!!!!!!!!!!!!!!!!!!!!!!
26152
+ entity = this.processUserEvent(entity);
26153
+ const withContent = !!entity.content;
26154
+ // Add user event locally
26155
+ this.insertIntoMutableCachedQueries(this.graphql.cache, {
26156
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26157
+ data: entity
26158
+ });
26159
+ // Update count
26160
+ this.count$.next(this.count$.value + 1);
26118
26161
  }
26119
- /**
26120
- * Save a userEvent entity
26121
- *
26122
- * @param entity
26123
- */
26124
- save(entity, options) {
26162
+ count(filter, options) {
26163
+ var _a;
26125
26164
  return __awaiter(this, void 0, void 0, function* () {
26126
- this.fillDefaultProperties(entity);
26127
- // Transform into json
26128
- const isNew = isNil(entity.id);
26129
- const json = entity.asObject();
26130
- const now = Date.now();
26165
+ if (!((_a = this.queries) === null || _a === void 0 ? void 0 : _a.count)) {
26166
+ console.warn(`${this._logPrefix}Query 'count' not provided, skip.`);
26167
+ return undefined;
26168
+ }
26169
+ if (!filter)
26170
+ filter = this.defaultFilter();
26171
+ // Apply last reset date as start date
26172
+ filter.startDate = this.resetCountDate;
26173
+ filter = this.asFilter(filter);
26131
26174
  if (this._debug)
26132
- console.debug(`[user-event-service] Saving user event...`, json);
26133
- yield this.graphql.mutate({
26134
- mutation: SaveQuery,
26175
+ console.debug(`${this._logPrefix}Counting user events with filter:`, filter);
26176
+ const res = yield this.graphql.query({
26177
+ query: this.queries.count,
26135
26178
  variables: {
26136
- data: json
26179
+ filter: filter.asPodObject()
26137
26180
  },
26138
- error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
26139
- update: (proxy, { data }) => {
26140
- // Update entity
26141
- const savedEntity = data && data.data;
26142
- if (savedEntity) {
26143
- if (this._debug)
26144
- console.debug(`[user-event-service] User event saved in ${Date.now() - now}ms`, entity);
26145
- this.copyIdAndUpdateDate(savedEntity, entity);
26146
- // Add to cache
26147
- if (isNew) {
26148
- this.insertIntoMutableCachedQueries(proxy, {
26149
- query: LoadAllQuery,
26150
- data: Object.assign(Object.assign({}, savedEntity), { content: null })
26151
- });
26152
- this.insertIntoMutableCachedQueries(proxy, {
26153
- query: LoadAllWithContentQuery,
26154
- data: savedEntity
26155
- });
26156
- }
26157
- }
26158
- }
26181
+ error: { code: SocialErrorCodes.COUNT_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.COUNT_USER_EVENT_ERROR' },
26182
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'network-only'
26159
26183
  });
26160
- return entity;
26184
+ return res.total;
26185
+ });
26186
+ }
26187
+ listenCountChanges(filter, options) {
26188
+ var _a;
26189
+ if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenCountChanges)) {
26190
+ console.warn(`${this._logPrefix}Subscription query 'listenCountChanges' not provided, skip.`);
26191
+ return of();
26192
+ }
26193
+ if (!filter)
26194
+ filter = this.defaultFilter();
26195
+ // Apply last reset date as start date
26196
+ filter.startDate = this.resetCountDate;
26197
+ filter = this.asFilter(filter);
26198
+ if (this._debug)
26199
+ console.debug(`${this._logPrefix}[WS] Listening count changes for user events with filter:`, filter);
26200
+ return this.graphql.subscribe({
26201
+ query: this.subscriptions.listenCountChanges,
26202
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
26203
+ variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
26204
+ error: {
26205
+ code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
26206
+ message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
26207
+ }
26208
+ }).pipe(map(({ total }) => {
26209
+ if (total && this._debug)
26210
+ console.debug(`${this._logPrefix}Received new user events count:`, total);
26211
+ // update count
26212
+ this.count$.next(total);
26213
+ return total;
26214
+ }));
26215
+ }
26216
+ listenChanges(filter, options) {
26217
+ var _a;
26218
+ if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
26219
+ console.warn(`${this._logPrefix}Subscription query 'listenChanges' not provided, skip.`);
26220
+ return of();
26221
+ }
26222
+ if (!filter)
26223
+ filter = this.defaultFilter();
26224
+ filter = this.asFilter(filter);
26225
+ const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26226
+ if (this._debug)
26227
+ console.debug(`${this._logPrefix}[WS] Listening changes for user events with filter:`, filter);
26228
+ return this.graphql.subscribe({
26229
+ query: this.subscriptions.listenChanges,
26230
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
26231
+ variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
26232
+ error: {
26233
+ code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
26234
+ message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
26235
+ }
26236
+ }).pipe(map(({ data }) => {
26237
+ if (data && this._debug)
26238
+ console.debug(`${this._logPrefix}Received new user events:`, data);
26239
+ const updatedData = data === null || data === void 0 ? void 0 : data.map(value => this.processUserEvent(value, this));
26240
+ // Update cache
26241
+ this.insertIntoMutableCachedQueries(this.graphql.cache, {
26242
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26243
+ data: updatedData
26244
+ });
26245
+ return updatedData;
26246
+ }));
26247
+ }
26248
+ delete(entity) {
26249
+ return __awaiter(this, void 0, void 0, function* () {
26250
+ if (!entity)
26251
+ return; // skip
26252
+ yield this.deleteAll([entity]);
26161
26253
  });
26162
26254
  }
26163
- /**
26164
- * Save many trips
26165
- *
26166
- * @param entities
26167
- * @param opts
26168
- */
26169
26255
  deleteAll(entities, opts) {
26170
26256
  return __awaiter(this, void 0, void 0, function* () {
26171
26257
  const ids = entities && entities
@@ -26174,122 +26260,346 @@ class UserEventService extends BaseGraphqlService {
26174
26260
  return; // stop, if nothing else to do
26175
26261
  const now = Date.now();
26176
26262
  if (this._debug)
26177
- console.debug('[user-event-service] Deleting events... ids:', ids);
26263
+ console.debug(`${this._logPrefix}Deleting events... ids:`, ids);
26178
26264
  yield this.graphql.mutate({
26179
- mutation: DeleteByIdsMutation,
26265
+ mutation: this.mutations.deleteByIds,
26180
26266
  variables: {
26181
26267
  ids
26182
26268
  },
26183
26269
  update: (proxy) => {
26184
26270
  // Remove from caches
26185
26271
  this.removeFromMutableCachedQueriesByIds(proxy, {
26186
- query: LoadAllQuery,
26272
+ query: this.queries.loadAll,
26187
26273
  ids
26188
26274
  });
26189
26275
  this.removeFromMutableCachedQueriesByIds(proxy, {
26190
- query: LoadAllWithContentQuery,
26276
+ query: this.queries.loadAllWithContent,
26191
26277
  ids
26192
26278
  });
26193
26279
  if (this._debug)
26194
- console.debug(`[user-event-service] Events deleted in ${Date.now() - now}ms`);
26280
+ console.debug(`${this._logPrefix}Events deleted in ${Date.now() - now}ms`);
26195
26281
  }
26196
26282
  });
26197
26283
  });
26198
26284
  }
26199
- /**
26200
- * Delete userEvent entities
26201
- */
26202
- delete(data) {
26285
+ save(entity, options) {
26203
26286
  return __awaiter(this, void 0, void 0, function* () {
26204
- if (!data)
26205
- return; // skip
26206
- yield this.deleteAll([data]);
26287
+ this.fillDefaultProperties(entity);
26288
+ // Transform into json
26289
+ const withContent = !!entity.content;
26290
+ const json = entity.asObject();
26291
+ const now = Date.now();
26292
+ if (this._debug)
26293
+ console.debug(`${this._logPrefix}Saving user event...`, json);
26294
+ yield this.graphql.mutate({
26295
+ mutation: this.mutations.save,
26296
+ variables: {
26297
+ data: json
26298
+ },
26299
+ error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
26300
+ update: (proxy, { data }) => {
26301
+ // Update entity
26302
+ const savedEntity = data && data.data;
26303
+ if (savedEntity) {
26304
+ if (this._debug)
26305
+ console.debug(`${this._logPrefix}User event saved in ${Date.now() - now}ms`, entity);
26306
+ this.copyIdAndUpdateDate(savedEntity, entity);
26307
+ // Add to cache
26308
+ if (withContent) {
26309
+ this.insertIntoMutableCachedQueries(proxy, {
26310
+ query: this.queries.loadAllWithContent,
26311
+ data: savedEntity
26312
+ });
26313
+ }
26314
+ else {
26315
+ this.insertIntoMutableCachedQueries(proxy, {
26316
+ query: this.queries.loadAll,
26317
+ data: Object.assign(Object.assign({}, savedEntity), { content: null })
26318
+ });
26319
+ }
26320
+ }
26321
+ }
26322
+ });
26323
+ return entity;
26207
26324
  });
26208
26325
  }
26209
- listenChanges(id, options) {
26210
- // TODO
26211
- console.warn('TODO: implement listen changes on user events');
26212
- return of();
26213
- }
26214
- registerAction(definition) {
26215
- console.info(`[user-event-service] Registering action ${definition.name} for ${definition.__typename}`);
26216
- this._userEventActions.push(definition);
26217
- }
26218
- getActionsByTypename(typename) {
26219
- return this._userEventActions.filter(def => def.__typename === typename);
26326
+ saveAll(entities, opts) {
26327
+ return __awaiter(this, void 0, void 0, function* () {
26328
+ return Promise.all(entities
26329
+ .map(entity => this.save(entity, opts)));
26330
+ });
26220
26331
  }
26221
- showToastErrorWithContext(opts) {
26332
+ markAsRead(entities) {
26222
26333
  return __awaiter(this, void 0, void 0, function* () {
26223
- let message = opts.message || (opts.error && opts.error.message || opts.error);
26224
- // Make sure message a string
26225
- if (!message || typeof message !== 'string') {
26226
- message = 'ERROR.UNKNOWN_TECHNICAL_ERROR';
26227
- }
26228
- // If offline, display a simple alert
26229
- if (this.network.offline) {
26230
- this.showToast({ message, type: 'error' });
26231
- return;
26232
- }
26233
- // Translate the message (to be able to extract details content)
26234
- message = this.translate.instant(message);
26235
- // Clean details parts
26236
- if (message && message.indexOf('<small>') !== -1) {
26237
- message = message.substr(0, message.indexOf('<small>') - 1);
26238
- }
26239
- const res = yield this.showToast({
26240
- type: 'error',
26241
- duration: 15000,
26242
- message: message + '<br/><br/><b>' + this.translate.instant('CONFIRM.SEND_DEBUG_DATA') + '</b>',
26243
- buttons: [{
26244
- icon: 'bug',
26245
- text: this.translate.instant('COMMON.BTN_SEND'),
26246
- role: 'send'
26247
- }]
26248
- });
26249
- if (!res || res.role !== 'send')
26250
- return;
26251
- // Send debug data
26252
- try {
26253
- if (this._debug)
26254
- console.debug('Sending debug data...');
26255
- // Call content factory
26256
- let context = opts && opts.context;
26257
- if (typeof context === 'function') {
26258
- context = context();
26334
+ const userEventWithoutReadListeners = [];
26335
+ for (const entity of (entities || [])) {
26336
+ // Get onRead listeners
26337
+ const onReadListeners = (this.listeners || []).filter(listener => !!listener.onRead).filter(listener => listener.accept(entity));
26338
+ if (onReadListeners.length) {
26339
+ for (const listener of onReadListeners) {
26340
+ yield listener.onRead(entity);
26341
+ }
26259
26342
  }
26260
- if (context instanceof Promise) {
26261
- context = yield context;
26343
+ else {
26344
+ // Add to this list for default operation
26345
+ userEventWithoutReadListeners.push(entity);
26262
26346
  }
26263
- // Send the message
26264
- const userEvent = yield this.sendDataForDebug({
26265
- message,
26266
- error: opts.error || undefined,
26267
- context: this.convertObjectToString(context)
26268
- });
26269
- console.info('Debug data successfully sent to admin', userEvent);
26270
- this.showToast({
26271
- type: 'info',
26272
- message: 'INFO.DEBUG_DATA_SEND',
26273
- showCloseButton: true
26274
- });
26275
- }
26276
- catch (err) {
26277
- console.error('Error while sending debug data:', err);
26278
26347
  }
26348
+ // Use default
26349
+ yield this.defaultMarkAsRead(userEventWithoutReadListeners);
26279
26350
  });
26280
26351
  }
26281
- sendDataForDebug(data) {
26282
- const userEvent = new UserEvent();
26283
- userEvent.eventType = UserEventTypes.DEBUG_DATA;
26284
- userEvent.content = this.convertObjectToString(data);
26285
- return this.save(userEvent);
26352
+ registerListener(listener) {
26353
+ if (!this.listeners)
26354
+ this.listeners = [];
26355
+ this.listeners.push(listener);
26286
26356
  }
26287
- asFilter(filter) {
26288
- return UserEventFilter.fromObject(filter);
26357
+ resetCount() {
26358
+ this.count$.next(undefined);
26359
+ this.resetCountDate = moment$6();
26360
+ // restart listening count changes
26361
+ this.startListenCountChanges();
26289
26362
  }
26290
26363
  /* -- protected methods -- */
26291
- convertObjectToString(data) {
26292
- if (typeof data === 'string') {
26364
+ onLogin() {
26365
+ return __awaiter(this, void 0, void 0, function* () {
26366
+ // Get first count
26367
+ const count = yield this.count(undefined);
26368
+ if (this._debug)
26369
+ console.debug(`${this._logPrefix}Receiving user events count`, count);
26370
+ // Update count
26371
+ this.count$.next(count);
26372
+ // Then listen changes
26373
+ this.startListenCountChanges();
26374
+ });
26375
+ }
26376
+ onLogout() {
26377
+ this.stopListenCountChanges();
26378
+ }
26379
+ startListenCountChanges() {
26380
+ this.stopListenCountChanges();
26381
+ this._listenSubscription = this.listenCountChanges(undefined).subscribe();
26382
+ }
26383
+ stopListenCountChanges() {
26384
+ var _a;
26385
+ (_a = this._listenSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
26386
+ this._listenSubscription = undefined;
26387
+ }
26388
+ processUserEvent(source, that) {
26389
+ that = that || this;
26390
+ // Convert json source to IUserEvent
26391
+ let target = that.fromObject(source);
26392
+ // Get listeners
26393
+ const listeners = (that.listeners || []).filter(listener => listener.onReceived).filter(listener => listener.accept(target));
26394
+ for (const listener of listeners) {
26395
+ if (target) {
26396
+ target = listener.onReceived(target);
26397
+ }
26398
+ else {
26399
+ if (that._debug)
26400
+ console.debug(`${that._logPrefix}Event has been rejected by a listener`, source);
26401
+ break;
26402
+ }
26403
+ }
26404
+ return target;
26405
+ }
26406
+ defaultMarkAsRead(userEvents) {
26407
+ var _a;
26408
+ return __awaiter(this, void 0, void 0, function* () {
26409
+ if (!userEvents)
26410
+ throw new Error(`${this._logPrefix}Invalid event to save`);
26411
+ if (!userEvents.length)
26412
+ return;
26413
+ // set read date
26414
+ userEvents.forEach(userEvent => userEvent.readDate = moment$6());
26415
+ // split local/remote entities
26416
+ const localEntities = userEvents.filter(userEvent => !userEvent.id || userEvent.id < 0);
26417
+ const remoteEntities = userEvents.filter(userEvent => userEvent.id > 0);
26418
+ // save local entities
26419
+ if (localEntities.length) {
26420
+ if (this._debug)
26421
+ console.debug(`${this._logPrefix}Save local user event`);
26422
+ // TODO !!!!!!!!!!!!!
26423
+ }
26424
+ // mark remote entities as read
26425
+ if (remoteEntities.length) {
26426
+ if (!((_a = this.mutations) === null || _a === void 0 ? void 0 : _a.markAsRead)) {
26427
+ console.warn(`${this._logPrefix}Mutation query 'markAsRead' not provided, skip.`);
26428
+ return;
26429
+ }
26430
+ // Collect ids
26431
+ const ids = remoteEntities.map(value => value.id);
26432
+ const now = Date.now();
26433
+ if (this._debug)
26434
+ console.debug(`${this._logPrefix}Mark user events as read...`, ids);
26435
+ yield this.graphql.mutate({
26436
+ mutation: this.mutations.markAsRead,
26437
+ variables: {
26438
+ ids
26439
+ },
26440
+ error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
26441
+ });
26442
+ if (this._debug)
26443
+ console.debug(`${this._logPrefix}User events marked as read in ${Date.now() - now}ms`, ids);
26444
+ }
26445
+ });
26446
+ }
26447
+ defaultFilter() {
26448
+ // By default
26449
+ return {
26450
+ recipients: [this.defaultRecipient()]
26451
+ };
26452
+ }
26453
+ defaultRecipient() {
26454
+ return this.accountService.person.pubkey;
26455
+ }
26456
+ fillDefaultProperties(entity) {
26457
+ }
26458
+ unreadEvents(events) {
26459
+ // default calculation on unread events from a list
26460
+ if (isEmptyArray(events))
26461
+ return undefined;
26462
+ const lastReadDate = events
26463
+ .filter(event => isNotNil(event.readDate))
26464
+ .reduce((lastDate, event) => DateUtils.max(lastDate, event.readDate), undefined);
26465
+ return events
26466
+ .filter(event => event.creationDate.isSameOrAfter(lastReadDate)).length;
26467
+ }
26468
+ copyIdAndUpdateDate(source, target) {
26469
+ EntityUtils.copyIdAndUpdateDate(source, target);
26470
+ }
26471
+ }
26472
+ AbstractUserEventService.decorators = [
26473
+ { type: Directive }
26474
+ ];
26475
+ AbstractUserEventService.ctorParameters = () => [
26476
+ { type: GraphqlService },
26477
+ { type: AccountService },
26478
+ { type: NetworkService },
26479
+ { type: TranslateService },
26480
+ { type: undefined },
26481
+ { type: undefined },
26482
+ { type: undefined },
26483
+ { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
26484
+ ];
26485
+ const userEventQueries = {
26486
+ loadAll: gql `
26487
+ query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26488
+ data: userEvents(filter: $filter, page: $page){
26489
+ ...LightUserEventFragment
26490
+ }
26491
+ }
26492
+ ${UserEventFragments.lightUserEvent}
26493
+ `,
26494
+ loadAllWithContent: gql `
26495
+ query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26496
+ data: userEvents(filter: $filter, page: $page){
26497
+ ...UserEventFragment
26498
+ }
26499
+ }
26500
+ ${UserEventFragments.userEvent}
26501
+ `
26502
+ };
26503
+ const userEventMutations = {
26504
+ deleteByIds: gql `
26505
+ mutation DeleteUserEvents($ids:[Int]){
26506
+ deleteUserEvents(ids: $ids)
26507
+ }
26508
+ `,
26509
+ save: gql `
26510
+ mutation SaveUserEvent($data: UserEventVOInput){
26511
+ data: saveUserEvent(userEvent: $data){
26512
+ ...UserEventFragment
26513
+ }
26514
+ }
26515
+ ${UserEventFragments.userEvent}
26516
+ `
26517
+ };
26518
+ class UserEventService extends AbstractUserEventService {
26519
+ constructor(graphql, accountService, network, translate, toastController, environment) {
26520
+ super(graphql, accountService, network, translate, userEventQueries, userEventMutations, undefined, environment);
26521
+ this.graphql = graphql;
26522
+ this.accountService = accountService;
26523
+ this.network = network;
26524
+ this.translate = translate;
26525
+ this.toastController = toastController;
26526
+ this.environment = environment;
26527
+ }
26528
+ showToastErrorWithContext(opts) {
26529
+ return __awaiter(this, void 0, void 0, function* () {
26530
+ let message = opts.message || (opts.error && opts.error.message || opts.error);
26531
+ // Make sure message a string
26532
+ if (!message || typeof message !== 'string') {
26533
+ message = 'ERROR.UNKNOWN_TECHNICAL_ERROR';
26534
+ }
26535
+ // If offline, display a simple alert
26536
+ if (this.network.offline) {
26537
+ this.showToast({ message, type: 'error' });
26538
+ return;
26539
+ }
26540
+ // Translate the message (to be able to extract details content)
26541
+ message = this.translate.instant(message);
26542
+ // Clean details parts
26543
+ if (message && message.indexOf('<small>') !== -1) {
26544
+ message = message.substr(0, message.indexOf('<small>') - 1);
26545
+ }
26546
+ const res = yield this.showToast({
26547
+ type: 'error',
26548
+ duration: 15000,
26549
+ message: message + '<br/><br/><b>' + this.translate.instant('CONFIRM.SEND_DEBUG_DATA') + '</b>',
26550
+ buttons: [{
26551
+ icon: 'bug',
26552
+ text: this.translate.instant('COMMON.BTN_SEND'),
26553
+ role: 'send'
26554
+ }]
26555
+ });
26556
+ if (!res || res.role !== 'send')
26557
+ return;
26558
+ // Send debug data
26559
+ try {
26560
+ if (this._debug)
26561
+ console.debug('Sending debug data...');
26562
+ // Call content factory
26563
+ let context = opts && opts.context;
26564
+ if (typeof context === 'function') {
26565
+ context = context();
26566
+ }
26567
+ if (context instanceof Promise) {
26568
+ context = yield context;
26569
+ }
26570
+ // Send the message
26571
+ const userEvent = yield this.sendDataForDebug({
26572
+ message,
26573
+ error: opts.error || undefined,
26574
+ context: this.convertObjectToString(context)
26575
+ });
26576
+ console.info('Debug data successfully sent to admin', userEvent);
26577
+ this.showToast({
26578
+ type: 'info',
26579
+ message: 'INFO.DEBUG_DATA_SEND',
26580
+ showCloseButton: true
26581
+ });
26582
+ }
26583
+ catch (err) {
26584
+ console.error('Error while sending debug data:', err);
26585
+ }
26586
+ });
26587
+ }
26588
+ sendDataForDebug(data) {
26589
+ const userEvent = new UserEvent();
26590
+ userEvent.type = UserEventTypes.DEBUG_DATA;
26591
+ userEvent.content = this.convertObjectToString(data);
26592
+ return this.save(userEvent);
26593
+ }
26594
+ asFilter(filter) {
26595
+ return UserEventFilter.fromObject(filter);
26596
+ }
26597
+ fromObject(source) {
26598
+ return UserEvent.fromObject(source);
26599
+ }
26600
+ /* -- protected methods -- */
26601
+ convertObjectToString(data) {
26602
+ if (typeof data === 'string') {
26293
26603
  return data;
26294
26604
  }
26295
26605
  // Serialize content into string
@@ -26315,13 +26625,9 @@ class UserEventService extends BaseGraphqlService {
26315
26625
  // TODO: compute sign
26316
26626
  console.warn('TODO: sign user event before sending');
26317
26627
  }
26318
- copyIdAndUpdateDate(source, target) {
26319
- EntityUtils.copyIdAndUpdateDate(source, target);
26320
- }
26321
26628
  }
26322
- UserEventService.ɵprov = ɵɵdefineInjectable({ factory: function UserEventService_Factory() { return new UserEventService(ɵɵinject(GraphqlService), ɵɵinject(AccountService), ɵɵinject(NetworkService), ɵɵinject(TranslateService), ɵɵinject(ToastController), ɵɵinject(ENVIRONMENT, 8)); }, token: UserEventService, providedIn: "root" });
26323
26629
  UserEventService.decorators = [
26324
- { type: Injectable, args: [{ providedIn: 'root' },] }
26630
+ { type: Injectable }
26325
26631
  ];
26326
26632
  UserEventService.ctorParameters = () => [
26327
26633
  { type: GraphqlService },
@@ -26334,7 +26640,7 @@ UserEventService.ctorParameters = () => [
26334
26640
 
26335
26641
  const ICONS_MAP = {
26336
26642
  DEBUG_DATA: { matIcon: 'bug_report' },
26337
- INBOX_MESSAGE: { matIcon: 'mail' },
26643
+ INBOX_MESSAGE: { matIcon: 'mail' }
26338
26644
  };
26339
26645
  // TODO: refactor with a registration done by data service:
26340
26646
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -26400,7 +26706,7 @@ class UserEventsTable extends AppTable {
26400
26706
  }
26401
26707
  }));
26402
26708
  const filter = this.filter || new UserEventFilter();
26403
- filter.recipient = this.recipient;
26709
+ filter.recipients = [this.recipient];
26404
26710
  this.setFilter(filter, { emitEvent: true });
26405
26711
  }
26406
26712
  start() {
@@ -26413,17 +26719,17 @@ class UserEventsTable extends AppTable {
26413
26719
  });
26414
26720
  }
26415
26721
  getIcon(source) {
26416
- return ICONS_MAP[source.eventType];
26722
+ return ICONS_MAP[source.type];
26417
26723
  }
26418
26724
  getDetail(source) {
26419
26725
  if (!source)
26420
26726
  return undefined;
26421
- if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
26727
+ if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
26422
26728
  const context = source.content.context;
26423
26729
  if (context && context.__typename) {
26424
- const actions = this.service.getActionsByTypename(context.__typename);
26730
+ // const actions = this.service.getActionsByTypename(context.__typename);
26425
26731
  return {
26426
- actions,
26732
+ // actions,
26427
26733
  title: source.content.error && source.content.error.message || source.content.message,
26428
26734
  description: source.content.error && source.content.error.details || undefined
26429
26735
  };
@@ -26435,11 +26741,11 @@ class UserEventsTable extends AppTable {
26435
26741
  doAction(action, row) {
26436
26742
  return __awaiter(this, void 0, void 0, function* () {
26437
26743
  const event = row.currentData;
26438
- const context = event.content && event.content.context;
26744
+ // const context = event.content && event.content.context;
26439
26745
  this.markAsLoading();
26440
26746
  if (action && typeof action.executeAction === 'function') {
26441
26747
  try {
26442
- let res = action.executeAction(event, context);
26748
+ let res = action.executeAction(event /*, context*/);
26443
26749
  res = (res instanceof Promise) ? yield res : res;
26444
26750
  }
26445
26751
  catch (err) {
@@ -26456,15 +26762,20 @@ class UserEventsTable extends AppTable {
26456
26762
  UserEventsTable.decorators = [
26457
26763
  { type: Component, args: [{
26458
26764
  selector: 'app-user-events-table',
26459
- 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",
26765
+ 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 <app-icon slot=\"start\" *ngIf=\"action.iconRef\" [ref]=\"action.iconRef\"></app-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",
26460
26766
  changeDetection: ChangeDetectionStrategy.OnPush,
26767
+ providers: [
26768
+ {
26769
+ provide: UserEventServiceToken, useClass: UserEventService
26770
+ }
26771
+ ],
26461
26772
  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}"]
26462
26773
  },] }
26463
26774
  ];
26464
26775
  UserEventsTable.ctorParameters = () => [
26465
26776
  { type: Injector },
26466
26777
  { type: AccountService },
26467
- { type: UserEventService },
26778
+ { type: undefined, decorators: [{ type: Inject, args: [UserEventServiceToken,] }] },
26468
26779
  { type: EntitiesStorage },
26469
26780
  { type: ChangeDetectorRef },
26470
26781
  { type: undefined, decorators: [{ type: Inject, args: [ENVIRONMENT,] }] }
@@ -26476,6 +26787,248 @@ UserEventsTable.propDecorators = {
26476
26787
  defaultSortDirection: [{ type: Input }]
26477
26788
  };
26478
26789
 
26790
+ class UserEventNotificationList {
26791
+ constructor(cd, popoverController, userEventService) {
26792
+ this.cd = cd;
26793
+ this.popoverController = popoverController;
26794
+ this.userEventService = userEventService;
26795
+ this.debug = false;
26796
+ this.userEvents = new BehaviorSubject(undefined);
26797
+ this.subscriptions = new Subscription();
26798
+ }
26799
+ ngOnInit() {
26800
+ // Watch all user events
26801
+ this.subscriptions.add(this.userEventService
26802
+ .watchAll(0, 10, 'creationDate', "desc", undefined)
26803
+ .subscribe(result => {
26804
+ if (this.debug)
26805
+ console.debug(`[user-event-notification-list] receiving ${result.total} user events`, result.data);
26806
+ this.userEvents.next(result.data);
26807
+ this.markForCheck();
26808
+ }));
26809
+ // Listen changes
26810
+ this.subscriptions.add(this.userEventService.listenChanges(undefined)
26811
+ .subscribe(data => {
26812
+ if (this.debug)
26813
+ console.debug(`[user-event-notification-list] receiving ${data.length} new user events`, data);
26814
+ }));
26815
+ }
26816
+ ngOnDestroy() {
26817
+ this.subscriptions.unsubscribe();
26818
+ }
26819
+ read(event, userEvent) {
26820
+ var _a;
26821
+ if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
26822
+ return;
26823
+ (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
26824
+ }
26825
+ readAll(event) {
26826
+ var _a;
26827
+ const unreadUserEvents = (this.userEvents.value || []).filter(value => !value.readDate);
26828
+ if (!unreadUserEvents.length)
26829
+ return;
26830
+ (_a = this.readEvents) === null || _a === void 0 ? void 0 : _a.emit(unreadUserEvents);
26831
+ }
26832
+ executeAction(action, userEvent) {
26833
+ // Execute then close popover
26834
+ action.executeAction(userEvent);
26835
+ this.dismiss();
26836
+ }
26837
+ dismiss() {
26838
+ this.popoverController.dismiss();
26839
+ }
26840
+ markForCheck() {
26841
+ this.cd.markForCheck();
26842
+ }
26843
+ }
26844
+ UserEventNotificationList.decorators = [
26845
+ { type: Component, args: [{
26846
+ selector: 'app-user-event-notification-list',
26847
+ 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-col class=\"top-action\">\n <a (click)=\"readAll($event)\">{{'SOCIAL.USER_EVENT.NOTIFICATION.READ_ALL' | translate}}</a>\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 message\">\n <ion-row>\n <ion-col>\n <p [class.unread]=\"!userEvent.readDate\" [innerHTML]=\"userEvent.message\"></p>\n </ion-col>\n </ion-row>\n <ion-row *ngIf=\"userEvent.actions?.length\">\n <ion-col>\n <span *ngFor=\"let action of userEvent.actions\" class=\"action\">\n <a (click)=\"executeAction(action, userEvent)\">\n <app-icon *ngIf=\"action.iconRef\" slot=\"start\" height=\"20\" width=\"20\" [ref]=\"action.iconRef\"></app-icon>\n {{ action.name }}\n </a>\n </span>\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; margin-right: 3px\"\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-row class=\"ion-list-footer column\">\n </ion-row>\n\n</ion-list>\n",
26848
+ changeDetection: ChangeDetectionStrategy.OnPush,
26849
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}.message{font-size:.9em}.message p{margin-top:5px;margin-bottom:5px}.top-action{text-align:end;margin-right:8px}.top-action a{cursor:pointer;color:#f5f5f5;font-style:italic}.action a{margin-right:10px;cursor:pointer}.action app-icon{vertical-align:middle}"]
26850
+ },] }
26851
+ ];
26852
+ UserEventNotificationList.ctorParameters = () => [
26853
+ { type: ChangeDetectorRef },
26854
+ { type: PopoverController },
26855
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [UserEventServiceToken,] }] }
26856
+ ];
26857
+ UserEventNotificationList.propDecorators = {
26858
+ debug: [{ type: Input }],
26859
+ titleI18n: [{ type: Input }],
26860
+ readEvent: [{ type: Output }],
26861
+ readEvents: [{ type: Output }]
26862
+ };
26863
+
26864
+ class UserEventNotificationComponent {
26865
+ constructor(userEventService, accountService, popoverController) {
26866
+ this.userEventService = userEventService;
26867
+ this.accountService = accountService;
26868
+ this.popoverController = popoverController;
26869
+ this.debug = false;
26870
+ this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
26871
+ this.disabled = false;
26872
+ this._logPrefix = '[user-event-notification] ';
26873
+ this._readEvent = new EventEmitter();
26874
+ this._readEvents = new EventEmitter();
26875
+ }
26876
+ get count() {
26877
+ var _a;
26878
+ return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(map(value => value === 0 ? undefined : value));
26879
+ }
26880
+ ngOnInit() {
26881
+ return __awaiter(this, void 0, void 0, function* () {
26882
+ if (isNil(this.userEventService)) {
26883
+ console.warn(`${this._logPrefix}No service injected`);
26884
+ this.disabled = true;
26885
+ return;
26886
+ }
26887
+ // Wait service
26888
+ yield this.userEventService.ready();
26889
+ // Subscribe to read event
26890
+ this._readEvent.subscribe(value => {
26891
+ // default: mark event as read
26892
+ this.userEventService.markAsRead([value]);
26893
+ });
26894
+ this._readEvents.subscribe(value => {
26895
+ this.userEventService.markAsRead(value);
26896
+ });
26897
+ });
26898
+ }
26899
+ showList(event) {
26900
+ return __awaiter(this, void 0, void 0, function* () {
26901
+ // Reset count
26902
+ this.userEventService.resetCount();
26903
+ const popover = yield this.popoverController.create({
26904
+ component: UserEventNotificationList,
26905
+ componentProps: {
26906
+ debug: this.debug,
26907
+ titleI18n: this.titleI18n,
26908
+ readEvent: this._readEvent,
26909
+ readEvents: this._readEvents
26910
+ },
26911
+ backdropDismiss: true,
26912
+ keyboardClose: true,
26913
+ event,
26914
+ translucent: true,
26915
+ cssClass: 'popover-large'
26916
+ });
26917
+ yield popover.present();
26918
+ });
26919
+ }
26920
+ ngOnDestroy() {
26921
+ if (this.debug) {
26922
+ console.debug(`${this._logPrefix}Destroying`);
26923
+ }
26924
+ }
26925
+ }
26926
+ UserEventNotificationComponent.decorators = [
26927
+ { type: Component, args: [{
26928
+ selector: 'app-user-event-notification-component',
26929
+ 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",
26930
+ changeDetection: ChangeDetectionStrategy.OnPush,
26931
+ styles: [""]
26932
+ },] }
26933
+ ];
26934
+ UserEventNotificationComponent.ctorParameters = () => [
26935
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [UserEventServiceToken,] }] },
26936
+ { type: AccountService },
26937
+ { type: PopoverController }
26938
+ ];
26939
+ UserEventNotificationComponent.propDecorators = {
26940
+ debug: [{ type: Input }],
26941
+ titleI18n: [{ type: Input }],
26942
+ disabled: [{ type: Input }]
26943
+ };
26944
+
26945
+ class UserEventTestService extends AbstractUserEventService {
26946
+ constructor(graphql, accountService, network, translate, environment) {
26947
+ super(graphql, accountService, network, translate, undefined, undefined, undefined, environment);
26948
+ this.graphql = graphql;
26949
+ this.accountService = accountService;
26950
+ this.network = network;
26951
+ this.translate = translate;
26952
+ this.environment = environment;
26953
+ this.userEvents = [];
26954
+ }
26955
+ fromObject(source) {
26956
+ return UserEvent.fromObject(source);
26957
+ }
26958
+ add(entity) {
26959
+ entity = this.processUserEvent(entity);
26960
+ entity.id = this.userEvents.length + 1;
26961
+ this.userEvents.push(entity);
26962
+ this.count$.next(this.userEvents.length);
26963
+ }
26964
+ asFilter(filter) {
26965
+ return filter;
26966
+ }
26967
+ count(filter, options) {
26968
+ return Promise.resolve(this.userEvents.length);
26969
+ }
26970
+ delete(entity) {
26971
+ return Promise.resolve(undefined);
26972
+ }
26973
+ deleteAll(data, opts) {
26974
+ return Promise.resolve(undefined);
26975
+ }
26976
+ listenChanges(filter, options) {
26977
+ return of();
26978
+ }
26979
+ save(entity, options) {
26980
+ var _a;
26981
+ const toSave = (_a = this.userEvents) === null || _a === void 0 ? void 0 : _a.find(value => value.id == (entity === null || entity === void 0 ? void 0 : entity.id));
26982
+ Object.assign(toSave, entity);
26983
+ return entity;
26984
+ }
26985
+ saveAll(data, opts) {
26986
+ return __awaiter(this, void 0, void 0, function* () {
26987
+ for (const entity of (data || [])) {
26988
+ yield this.save(entity);
26989
+ }
26990
+ return Promise.resolve(this.userEvents);
26991
+ });
26992
+ }
26993
+ watchAll(offset, size, sortBy, sortDirection, filter, options) {
26994
+ return of({ data: this.userEvents });
26995
+ }
26996
+ }
26997
+ UserEventTestService.decorators = [
26998
+ { type: Injectable }
26999
+ ];
27000
+ UserEventTestService.ctorParameters = () => [
27001
+ { type: GraphqlService },
27002
+ { type: AccountService },
27003
+ { type: NetworkService },
27004
+ { type: TranslateService },
27005
+ { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
27006
+ ];
27007
+
27008
+ class UserEventModule {
27009
+ }
27010
+ UserEventModule.decorators = [
27011
+ { type: NgModule, args: [{
27012
+ imports: [
27013
+ CommonModule,
27014
+ CoreModule,
27015
+ SharedModule
27016
+ ],
27017
+ declarations: [
27018
+ UserEventsTable,
27019
+ UserEventNotificationComponent,
27020
+ UserEventNotificationList,
27021
+ ],
27022
+ exports: [
27023
+ UserEventsTable,
27024
+ UserEventNotificationComponent
27025
+ ],
27026
+ providers: [
27027
+ { provide: UserEventServiceToken, useClass: UserEventTestService }
27028
+ ]
27029
+ },] }
27030
+ ];
27031
+
26479
27032
  const MessageTypes = {
26480
27033
  INBOX_MESSAGE: 'INBOX_MESSAGE',
26481
27034
  EMAIL: 'EMAIL',
@@ -26687,9 +27240,9 @@ MessageForm.propDecorators = {
26687
27240
  canSelectType: [{ type: Input }]
26688
27241
  };
26689
27242
 
26690
- class SocialModule {
27243
+ class MessageModule {
26691
27244
  }
26692
- SocialModule.decorators = [
27245
+ MessageModule.decorators = [
26693
27246
  { type: NgModule, args: [{
26694
27247
  imports: [
26695
27248
  CommonModule,
@@ -26697,17 +27250,327 @@ SocialModule.decorators = [
26697
27250
  SharedModule
26698
27251
  ],
26699
27252
  declarations: [
26700
- UserEventsTable,
26701
27253
  MessageModal,
26702
27254
  MessageForm
26703
27255
  ],
26704
27256
  exports: [
26705
- UserEventsTable,
26706
27257
  MessageModal
26707
27258
  ]
26708
27259
  },] }
26709
27260
  ];
26710
27261
 
27262
+ var JobProgression_1;
27263
+ // todo use entity
27264
+ class Job {
27265
+ }
27266
+ // @dynamic
27267
+ let JobProgression = JobProgression_1 = class JobProgression extends Entity {
27268
+ constructor(id) {
27269
+ super(JobProgression_1.TYPENAME);
27270
+ this.id = id;
27271
+ }
27272
+ fromObject(source) {
27273
+ super.fromObject(source);
27274
+ this.name = source.name;
27275
+ this.message = source.message;
27276
+ this.current = source.current;
27277
+ this.total = source.total;
27278
+ }
27279
+ };
27280
+ JobProgression = JobProgression_1 = __decorate([
27281
+ EntityClass({ typename: 'JobProgressionVO' })
27282
+ ], JobProgression);
27283
+
27284
+ const JobProgressionServiceToken = new InjectionToken('JobProgressionService');
27285
+ const jobProgressionSubscription = gql `subscription UpdateJobProgression($id: Int!, $interval: Int){
27286
+ data: updateJobProgression(id: $id, interval: $interval) {
27287
+ id
27288
+ name
27289
+ message
27290
+ current
27291
+ total
27292
+ }
27293
+ }`;
27294
+ class JobProgressionService extends BaseGraphqlService {
27295
+ constructor(graphql, environment) {
27296
+ super(graphql, environment);
27297
+ this.graphql = graphql;
27298
+ this.environment = environment;
27299
+ this._logPrefix = '[job-progression-service] ';
27300
+ // For DEV only
27301
+ this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
27302
+ }
27303
+ listenChanges(id, options) {
27304
+ if (isNil(id))
27305
+ throw new Error(`${this._logPrefix}Missing argument 'id'`);
27306
+ if (this._debug)
27307
+ console.debug(`${this._logPrefix}[WS] Listening changes for job progression {${id}}...`);
27308
+ return this.graphql.subscribe({
27309
+ query: jobProgressionSubscription,
27310
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
27311
+ variables: { id, interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
27312
+ error: { code: SocialErrorCodes.SUBSCRIBE_JOB_PROGRESSION_ERROR, message: 'SOCIAL.ERROR.SUBSCRIBE_JOB_PROGRESSION_ERROR' }
27313
+ }).pipe(map(({ data }) => {
27314
+ const progression = data && JobProgression.fromObject(data);
27315
+ if (progression && this._debug)
27316
+ console.debug(`${this._logPrefix}Job progression ${id} updated on server`, progression);
27317
+ return progression;
27318
+ }));
27319
+ }
27320
+ }
27321
+ JobProgressionService.decorators = [
27322
+ { type: Injectable }
27323
+ ];
27324
+ JobProgressionService.ctorParameters = () => [
27325
+ { type: GraphqlService },
27326
+ { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
27327
+ ];
27328
+
27329
+ class JobProgressionList {
27330
+ constructor() {
27331
+ }
27332
+ ngOnInit() {
27333
+ }
27334
+ }
27335
+ JobProgressionList.decorators = [
27336
+ { type: Component, args: [{
27337
+ selector: 'app-job-progression-list',
27338
+ 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\" class=\"ion-item-job-progression\">\n <ion-grid class=\"ion-no-margin\">\n <ion-row class=\"name\">\n <ion-col>\n {{jobProgression.name}}\n </ion-col>\n </ion-row>\n <ion-row class=\"message\">\n <ion-col>\n {{jobProgression.message}}\n </ion-col>\n </ion-row>\n <ion-row class=\"progress-bar\">\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",
27339
+ styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ion-item-job-progression{font-size:.9em}.ion-item-job-progression .message{font-style:italic}.ion-item-job-progression .progress-bar{margin-top:5px;margin-bottom:5px}"]
27340
+ },] }
27341
+ ];
27342
+ JobProgressionList.ctorParameters = () => [];
27343
+ JobProgressionList.propDecorators = {
27344
+ titleI18n: [{ type: Input }],
27345
+ jobProgressions: [{ type: Input }]
27346
+ };
27347
+
27348
+ class JobProgressionComponent {
27349
+ constructor(jobProgressionService, popoverController, cd) {
27350
+ this.jobProgressionService = jobProgressionService;
27351
+ this.popoverController = popoverController;
27352
+ this.cd = cd;
27353
+ this.debug = false;
27354
+ this.titleI18n = 'SOCIAL.JOB.PROGRESSION.TITLE';
27355
+ this.jobFinished = new EventEmitter();
27356
+ this.disabled = true;
27357
+ this.color = 'accent';
27358
+ this.mode = 'determinate';
27359
+ this.value = 0;
27360
+ this.jobProgressions = [];
27361
+ this._subscriptions = new Subscription();
27362
+ this._subscriptionsById = {};
27363
+ this._logPrefix = '[job-progression] ';
27364
+ }
27365
+ ngOnInit() {
27366
+ var _a, _b, _c, _d;
27367
+ if (isNil(this.jobProgressionService)) {
27368
+ console.warn(`${this._logPrefix}No service injected`);
27369
+ }
27370
+ // parse options
27371
+ this.autoHide = toBoolean((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoHide, false);
27372
+ this.visible = !this.autoHide;
27373
+ this.autoHideDelay = toNumber((_b = this.options) === null || _b === void 0 ? void 0 : _b.autoHideDelay, 1000);
27374
+ this.autoRemove = toBoolean((_c = this.options) === null || _c === void 0 ? void 0 : _c.autoRemove, true);
27375
+ this.autoRemoveDelay = toNumber((_d = this.options) === null || _d === void 0 ? void 0 : _d.autoRemoveDelay, 1000);
27376
+ }
27377
+ addJob(id) {
27378
+ if (isNil(this.jobProgressionService)) {
27379
+ console.warn(`${this._logPrefix}No service injected. Can't add a job`);
27380
+ return;
27381
+ }
27382
+ if (!!this.getProgression(id)) {
27383
+ console.warn(`${this._logPrefix}Job (id=${id}) already present`);
27384
+ return;
27385
+ }
27386
+ if (this.debug) {
27387
+ console.debug(`${this._logPrefix}Add job id=${id}`);
27388
+ }
27389
+ // Adding empty job progression
27390
+ const progression = new JobProgression(id);
27391
+ this.jobProgressions.push(progression);
27392
+ this.disabled = false;
27393
+ const sub = this.jobProgressionService.listenChanges(id)
27394
+ .pipe(filter(progression => {
27395
+ if (id !== progression.id) {
27396
+ console.error(`${this._logPrefix}Job progression (id=${progression.id}) doesn't match expected job (id=${id})`);
27397
+ return false;
27398
+ }
27399
+ return true;
27400
+ }), map(progression => {
27401
+ // Ensure visible
27402
+ this.visible = true;
27403
+ // Get current progression object
27404
+ const currentProgression = this.getProgression(id);
27405
+ if (!currentProgression) {
27406
+ // add it if absent
27407
+ this.jobProgressions.push(progression);
27408
+ if (this.debug) {
27409
+ console.debug(`${this._logPrefix}Progression added id=${id}`, progression);
27410
+ }
27411
+ }
27412
+ else {
27413
+ // update current
27414
+ Object.assign(currentProgression, progression);
27415
+ if (this.debug) {
27416
+ console.debug(`${this._logPrefix}Progression updated id=${id}`, progression);
27417
+ }
27418
+ }
27419
+ return progression;
27420
+ }))
27421
+ .subscribe(progression => {
27422
+ // update value
27423
+ this.updateValue();
27424
+ // job finished
27425
+ if (progression.total > 0 && progression.current == progression.total) {
27426
+ if (this.debug) {
27427
+ console.debug(`${this._logPrefix}Finished job id=${progression.id}`);
27428
+ }
27429
+ // emit event
27430
+ this.jobFinished.emit(progression.id);
27431
+ if (this.autoRemove) {
27432
+ setTimeout(() => {
27433
+ var _a;
27434
+ this.removeJob(progression.id);
27435
+ // If last job
27436
+ if (this.autoHide && !((_a = this.jobProgressions) === null || _a === void 0 ? void 0 : _a.length)) {
27437
+ setTimeout(() => __awaiter(this, void 0, void 0, function* () {
27438
+ var _b;
27439
+ (_b = this._listPopover) === null || _b === void 0 ? void 0 : _b.dismiss();
27440
+ this.visible = false;
27441
+ this.markForCheck();
27442
+ }), this.autoHideDelay);
27443
+ }
27444
+ }, this.autoRemoveDelay);
27445
+ }
27446
+ }
27447
+ });
27448
+ this._subscriptionsById[id] = sub;
27449
+ this._subscriptions.add(sub);
27450
+ }
27451
+ removeJob(id) {
27452
+ if (this.debug) {
27453
+ console.debug(`${this._logPrefix}Remove job id=${id}`);
27454
+ }
27455
+ const sub = this._subscriptionsById[id];
27456
+ if (sub) {
27457
+ this._subscriptions.remove(sub);
27458
+ sub.unsubscribe();
27459
+ }
27460
+ const progression = this.getProgression(id);
27461
+ if (progression) {
27462
+ this.jobProgressions.splice(this.jobProgressions.indexOf(progression), 1);
27463
+ }
27464
+ this.updateValue();
27465
+ }
27466
+ getProgression(id) {
27467
+ return this.jobProgressions.find(progression => progression.id === id);
27468
+ }
27469
+ updateValue() {
27470
+ if (this.debug) {
27471
+ console.debug(`${this._logPrefix}Updating value`);
27472
+ }
27473
+ let value = 0;
27474
+ const nbProgression = arraySize(this.jobProgressions);
27475
+ let allIndeterminate = nbProgression > 0;
27476
+ this.jobProgressions.forEach(progression => {
27477
+ const indeterminate = progression.total === 0;
27478
+ allIndeterminate = allIndeterminate && indeterminate;
27479
+ if (!indeterminate) {
27480
+ value = value + progression.current * 100 / progression.total;
27481
+ }
27482
+ });
27483
+ this.value = nbProgression > 0 ? value / nbProgression : 0;
27484
+ this.mode = allIndeterminate ? 'indeterminate' : 'determinate';
27485
+ if (this.debug) {
27486
+ console.debug(`${this._logPrefix}Setting value=${this.value}, mode=${this.mode}`);
27487
+ }
27488
+ this.markForCheck();
27489
+ }
27490
+ showList(event) {
27491
+ return __awaiter(this, void 0, void 0, function* () {
27492
+ this._listPopover = yield this.popoverController.create({
27493
+ component: JobProgressionList,
27494
+ componentProps: {
27495
+ titleI18n: this.titleI18n,
27496
+ jobProgressions: this.jobProgressions
27497
+ },
27498
+ backdropDismiss: true,
27499
+ keyboardClose: true,
27500
+ event,
27501
+ translucent: true,
27502
+ cssClass: 'popover-large'
27503
+ });
27504
+ yield this._listPopover.present();
27505
+ yield this._listPopover.onDidDismiss();
27506
+ this._listPopover = undefined;
27507
+ });
27508
+ }
27509
+ markForCheck() {
27510
+ this.cd.markForCheck();
27511
+ }
27512
+ ngOnDestroy() {
27513
+ if (this.debug) {
27514
+ console.debug(`${this._logPrefix}Destroying`);
27515
+ }
27516
+ this._subscriptions.unsubscribe();
27517
+ }
27518
+ }
27519
+ JobProgressionComponent.decorators = [
27520
+ { type: Component, args: [{
27521
+ selector: 'app-job-progression',
27522
+ 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",
27523
+ changeDetection: ChangeDetectionStrategy.OnPush,
27524
+ styles: [".floating-spinner{position:absolute;top:6px;left:5px}"]
27525
+ },] }
27526
+ ];
27527
+ JobProgressionComponent.ctorParameters = () => [
27528
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [JobProgressionServiceToken,] }] },
27529
+ { type: PopoverController },
27530
+ { type: ChangeDetectorRef }
27531
+ ];
27532
+ JobProgressionComponent.propDecorators = {
27533
+ debug: [{ type: Input }],
27534
+ titleI18n: [{ type: Input }],
27535
+ options: [{ type: Input }],
27536
+ jobFinished: [{ type: Output }]
27537
+ };
27538
+
27539
+ class JobModule {
27540
+ }
27541
+ JobModule.decorators = [
27542
+ { type: NgModule, args: [{
27543
+ imports: [
27544
+ CommonModule,
27545
+ SharedModule,
27546
+ TranslateModule.forChild(),
27547
+ ],
27548
+ declarations: [
27549
+ JobProgressionComponent,
27550
+ JobProgressionList
27551
+ ],
27552
+ exports: [
27553
+ JobProgressionComponent
27554
+ ]
27555
+ },] }
27556
+ ];
27557
+
27558
+ const SocialModuleOptionsToken = new InjectionToken("SocialModuleOptions");
27559
+ class SocialModule {
27560
+ }
27561
+ SocialModule.decorators = [
27562
+ { type: NgModule, args: [{
27563
+ imports: [
27564
+ CommonModule,
27565
+ CoreModule,
27566
+ SharedModule,
27567
+ UserEventModule,
27568
+ JobModule,
27569
+ MessageModule,
27570
+ ],
27571
+ },] }
27572
+ ];
27573
+
26711
27574
  const Mutations = {
26712
27575
  send: gql `mutation SendMessage($data: MessageVOInput){
26713
27576
  done: sendMessage(message: $data)
@@ -27522,13 +28385,13 @@ LatLongTestPage.ctorParameters = () => [
27522
28385
  { type: FormBuilder }
27523
28386
  ];
27524
28387
 
27525
- const moment$6 = momentImported;
28388
+ const moment$7 = momentImported;
27526
28389
  class SwipeTestPage {
27527
28390
  constructor(formBuilder, dateFormatPipe) {
27528
28391
  this.formBuilder = formBuilder;
27529
28392
  this.dateFormatPipe = dateFormatPipe;
27530
28393
  this.$dates = new BehaviorSubject(undefined);
27531
- this._today = moment$6().startOf('day');
28394
+ this._today = moment$7().startOf('day');
27532
28395
  this.form = formBuilder.group({
27533
28396
  empty: [null, Validators.required],
27534
28397
  date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
@@ -27541,7 +28404,7 @@ class SwipeTestPage {
27541
28404
  ngOnInit() {
27542
28405
  const dates = [];
27543
28406
  for (let d = 0; d < 7; d++) {
27544
- dates[d] = moment$6(this._today).add(d - 3, 'day');
28407
+ dates[d] = moment$7(this._today).add(d - 3, 'day');
27545
28408
  }
27546
28409
  this.$dates.next(dates);
27547
28410
  this.loadData();
@@ -27582,7 +28445,7 @@ SwipeTestPage.ctorParameters = () => [
27582
28445
  { type: DateFormatPipe }
27583
28446
  ];
27584
28447
 
27585
- const moment$7 = momentImported;
28448
+ const moment$8 = momentImported;
27586
28449
  class DateTimeTestPage {
27587
28450
  constructor(platform, formBuilder, cd) {
27588
28451
  this.platform = platform;
@@ -27614,7 +28477,7 @@ class DateTimeTestPage {
27614
28477
  // Load the form with data
27615
28478
  loadData() {
27616
28479
  return __awaiter(this, void 0, void 0, function* () {
27617
- const now = moment$7();
28480
+ const now = moment$8();
27618
28481
  const data = {
27619
28482
  empty: null,
27620
28483
  emptyRequired: null,
@@ -27860,7 +28723,7 @@ NumpadTestPage.ctorParameters = () => [
27860
28723
  { type: FormBuilder }
27861
28724
  ];
27862
28725
 
27863
- const moment$8 = momentImported;
28726
+ const moment$9 = momentImported;
27864
28727
  class DateTestPage {
27865
28728
  constructor(formBuilder, cd) {
27866
28729
  this.formBuilder = formBuilder;
@@ -27893,7 +28756,7 @@ class DateTestPage {
27893
28756
  // Load the form with data
27894
28757
  loadData() {
27895
28758
  return __awaiter(this, void 0, void 0, function* () {
27896
- const now = moment$8();
28759
+ const now = moment$9();
27897
28760
  const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
27898
28761
  const data = {
27899
28762
  empty: null,
@@ -28639,5 +29502,5 @@ CoreTestingModule.decorators = [
28639
29502
  * Generated bundle index. Do not edit.
28640
29503
  */
28641
29504
 
28642
- export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, ResizableComponent, ResizableDirective, ResizableModule, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEvent, UserEventFilter, UserEventFragments, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moment$5 as moment, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, tz, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh, AppUpdateOfflineModeCard as ɵi, AppIconComponent as ɵj, DateTestPage as ɵk, NumpadTestPage as ɵl, MatBadgeIconTestPage as ɵm, ToastTestingModule as ɵn, ToastTestingPage as ɵo };
29505
+ export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, Job, JobModule, JobProgression, JobProgressionComponent, JobProgressionService, JobProgressionServiceToken, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, ResizableComponent, ResizableDirective, ResizableModule, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEvent, UserEventFilter, UserEventFragments, UserEventModule, UserEventNotificationComponent, UserEventService, UserEventServiceToken, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moment$5 as moment, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, tz, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh, AppUpdateOfflineModeCard as ɵi, AppIconComponent as ɵj, UserEventNotificationList as ɵk, UserEventTestService as ɵl, JobProgressionList as ɵm, DateTestPage as ɵn, NumpadTestPage as ɵo, MatBadgeIconTestPage as ɵp, ToastTestingModule as ɵq, ToastTestingPage as ɵr };
28643
29506
  //# sourceMappingURL=sumaris-net.ngx-components.js.map