@sumaris-net/ngx-components 1.21.8 → 1.22.0-rc1

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 (54) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +1299 -191
  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/esm2015/public_api.js +8 -1
  6. package/esm2015/src/app/core/icon/icon.component.js +5 -2
  7. package/esm2015/src/app/core/menu/menu.component.js +2 -2
  8. package/esm2015/src/app/shared/pipes/date-diff-duration.pipe.js +9 -5
  9. package/esm2015/src/app/shared/types.js +1 -1
  10. package/esm2015/src/app/social/job/job.model.js +26 -0
  11. package/esm2015/src/app/social/job/job.module.js +25 -0
  12. package/esm2015/src/app/social/job/job.service.js +54 -0
  13. package/esm2015/src/app/social/job/progression/job-progression.component.js +200 -0
  14. package/esm2015/src/app/social/job/progression/job-progression.list.js +20 -0
  15. package/esm2015/src/app/social/message/message.module.js +25 -0
  16. package/esm2015/src/app/social/social.errors.js +5 -2
  17. package/esm2015/src/app/social/social.module.js +10 -15
  18. package/esm2015/src/app/social/user-event/notification/user-event-notification.component.js +89 -0
  19. package/esm2015/src/app/social/user-event/notification/user-event-notification.list.js +78 -0
  20. package/esm2015/src/app/social/user-event/testing/user-event.testing.service.js +73 -0
  21. package/esm2015/src/app/social/user-event/user-event.model.js +58 -2
  22. package/esm2015/src/app/social/user-event/user-event.module.js +33 -0
  23. package/esm2015/src/app/social/user-event/user-event.service.js +412 -173
  24. package/esm2015/src/app/social/user-event/user-events.table.js +18 -13
  25. package/esm2015/sumaris-net.ngx-components.js +9 -6
  26. package/fesm2015/sumaris-net.ngx-components.js +1121 -254
  27. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  28. package/package.json +1 -1
  29. package/public_api.d.ts +7 -0
  30. package/src/app/core/icon/icon.component.d.ts +4 -4
  31. package/src/app/shared/material/badge/badge-icon.test.d.ts +1 -1
  32. package/src/app/shared/pipes/date-diff-duration.pipe.d.ts +6 -2
  33. package/src/app/shared/types.d.ts +4 -0
  34. package/src/app/social/job/job.model.d.ts +33 -0
  35. package/src/app/social/job/job.module.d.ts +2 -0
  36. package/src/app/social/job/job.service.d.ts +23 -0
  37. package/src/app/social/job/progression/job-progression.component.d.ts +44 -0
  38. package/src/app/social/job/progression/job-progression.list.d.ts +12 -0
  39. package/src/app/social/message/message.module.d.ts +2 -0
  40. package/src/app/social/social.errors.d.ts +3 -0
  41. package/src/app/social/social.module.d.ts +8 -0
  42. package/src/app/social/user-event/notification/user-event-notification.component.d.ts +22 -0
  43. package/src/app/social/user-event/notification/user-event-notification.list.d.ts +30 -0
  44. package/src/app/social/user-event/testing/user-event.testing.service.d.ts +35 -0
  45. package/src/app/social/user-event/user-event.model.d.ts +52 -8
  46. package/src/app/social/user-event/user-event.module.d.ts +2 -0
  47. package/src/app/social/user-event/user-event.service.d.ts +101 -51
  48. package/src/app/social/user-event/user-events.table.d.ts +6 -6
  49. package/src/assets/i18n/en-US.json +15 -2
  50. package/src/assets/i18n/en.json +16 -2
  51. package/src/assets/i18n/fr.json +15 -1
  52. package/src/theme/_ngx-components.scss +8 -0
  53. package/sumaris-net.ngx-components.d.ts +8 -5
  54. 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
 
@@ -25919,7 +25926,10 @@ AppInMemoryTable.propDecorators = {
25919
25926
  const SocialErrorCodes = {
25920
25927
  LOAD_USER_EVENTS_ERROR: 50000,
25921
25928
  SAVE_USER_EVENT_ERROR: 50001,
25922
- 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
25923
25933
  };
25924
25934
 
25925
25935
  var UserEvent_1;
@@ -25934,16 +25944,23 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25934
25944
  }
25935
25945
  asObject(opts) {
25936
25946
  const target = super.asObject(opts);
25947
+ target.creationDate = toDateISOString(this.creationDate);
25948
+ target.readDate = toDateISOString(this.readDate);
25937
25949
  // Serialize content
25938
25950
  if (typeof target.content === 'object') {
25939
25951
  target.content = JSON.stringify(target.content);
25940
25952
  }
25953
+ delete target.avatar;
25954
+ delete target.avatarIcon;
25955
+ delete target.icon;
25956
+ delete target.actions;
25941
25957
  return target;
25942
25958
  }
25943
25959
  fromObject(source) {
25944
25960
  Object.assign(this, source); // Copy all properties
25945
25961
  super.fromObject(source);
25946
25962
  this.creationDate = fromDateISOString(source.creationDate);
25963
+ this.readDate = fromDateISOString(source.readDate);
25947
25964
  try {
25948
25965
  // Deserialize content
25949
25966
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -25962,6 +25979,52 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25962
25979
  UserEvent = UserEvent_1 = __decorate([
25963
25980
  EntityClass({ typename: 'UserEventVO' })
25964
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);
25965
26028
 
25966
26029
  const UserEventFragments = {
25967
26030
  userEvent: gql `fragment UserEventFragment on UserEventVO {
@@ -25989,179 +26052,206 @@ const UserEventFragments = {
25989
26052
  }`
25990
26053
  };
25991
26054
 
25992
- // @dynamic
25993
- let UserEventFilter = class UserEventFilter extends EntityFilter {
25994
- constructor() {
25995
- super(...arguments);
25996
- this.issuer = null;
25997
- this.recipient = null;
25998
- }
25999
- fromObject(source, opts) {
26000
- super.fromObject(source, opts);
26001
- this.issuer = source.issuer;
26002
- this.recipient = source.recipient;
26003
- }
26004
- buildFilter() {
26005
- const filterFns = super.buildFilter();
26006
- // issuer
26007
- if (this.issuer) {
26008
- filterFns.push(t => (t.issuer === this.issuer));
26009
- }
26010
- if (this.recipient) {
26011
- filterFns.push(t => (t.recipient === this.recipient));
26012
- }
26013
- return filterFns;
26014
- }
26015
- };
26016
- UserEventFilter = __decorate([
26017
- EntityClass({ typename: 'UserEventFilterVO' })
26018
- ], UserEventFilter);
26019
- const SaveQuery = gql `
26020
- mutation SaveUserEvent($data: UserEventVOInput){
26021
- data: saveUserEvent(userEvent: $data){
26022
- ...UserEventFragment
26023
- }
26024
- }
26025
- ${UserEventFragments.userEvent}
26026
- `;
26027
- const LoadAllQuery = gql `
26028
- query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26029
- data: userEvents(filter: $filter, page: $page){
26030
- ...LightUserEventFragment
26031
- }
26032
- }
26033
- ${UserEventFragments.lightUserEvent}
26034
- `;
26035
- const DeleteByIdsMutation = gql `
26036
- mutation DeleteUserEvents($ids:[Int]){
26037
- deleteUserEvents(ids: $ids)
26038
- }
26039
- `;
26040
- const LoadAllWithContentQuery = gql `
26041
- query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26042
- data: userEvents(filter: $filter, page: $page){
26043
- ...UserEventFragment
26044
- }
26045
- }
26046
- ${UserEventFragments.userEvent}
26047
- `;
26048
- class UserEventService extends BaseGraphqlService {
26049
- 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) {
26050
26059
  super(graphql, environment);
26051
26060
  this.graphql = graphql;
26052
26061
  this.accountService = accountService;
26053
26062
  this.network = network;
26054
26063
  this.translate = translate;
26055
- this.toastController = toastController;
26064
+ this.queries = queries;
26065
+ this.mutations = mutations;
26066
+ this.subscriptions = subscriptions;
26056
26067
  this.environment = environment;
26057
- this._userEventActions = [];
26068
+ this.count$ = new BehaviorSubject(0);
26069
+ this.listeners = [];
26070
+ this._subscriptions = new Subscription();
26071
+ this._logPrefix = '[user-event-service] ';
26058
26072
  // For DEV only
26059
- 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();
26060
26102
  }
26061
- /**
26062
- *
26063
- * @param offset
26064
- * @param size
26065
- * @param sortBy
26066
- * @param sortDirection
26067
- * @param filter
26068
- * @param options
26069
- * @deprecated use watchPage() instead
26070
- */
26071
26103
  watchAll(offset, size, sortBy, sortDirection, filter, options) {
26072
26104
  return this.watchPage({ offset, size, sortBy, sortDirection }, filter, options);
26073
26105
  }
26074
26106
  watchPage(page, filter, options) {
26107
+ var _a;
26075
26108
  let now = this._debug && Date.now();
26076
- //if (this._debug)
26077
- 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);
26078
26113
  filter = this.asFilter(filter);
26079
26114
  // Force recipient to current issuer, if not admin and not specified
26080
- if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
26081
- const recipient = this.accountService.account.pubkey;
26082
- 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))) {
26083
26118
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
26084
- filter.recipient = recipient;
26119
+ filter.recipients = [recipient];
26085
26120
  }
26086
26121
  }
26087
- const withContent = options && options.withContent === true;
26122
+ const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26088
26123
  return this.mutableWatchQuery({
26089
26124
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
26090
- query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
26125
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26091
26126
  variables: {
26092
- 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() }),
26093
26130
  filter: filter && filter.asPodObject()
26094
26131
  },
26095
26132
  arrayFieldName: 'data',
26096
26133
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
26097
- fetchPolicy: options && options.fetchPolicy || undefined
26134
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'cache-first'
26098
26135
  })
26099
26136
  .pipe(map(res => {
26100
- 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));
26101
26138
  if (now) {
26102
- 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`);
26103
26140
  now = null;
26104
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);
26105
26144
  return {
26106
26145
  data,
26107
- total: res && toNumber(res.total, data.length)
26146
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, data.length)
26108
26147
  };
26109
26148
  }));
26110
26149
  }
26111
- saveAll(data, options) {
26112
- return Promise.all(data
26113
- .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);
26114
26161
  }
26115
- /**
26116
- * Save a userEvent entity
26117
- *
26118
- * @param entity
26119
- */
26120
- save(entity, options) {
26162
+ count(filter, options) {
26163
+ var _a;
26121
26164
  return __awaiter(this, void 0, void 0, function* () {
26122
- this.fillDefaultProperties(entity);
26123
- // Transform into json
26124
- const isNew = isNil(entity.id);
26125
- const json = entity.asObject();
26126
- 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);
26127
26174
  if (this._debug)
26128
- console.debug(`[user-event-service] Saving user event...`, json);
26129
- yield this.graphql.mutate({
26130
- 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,
26131
26178
  variables: {
26132
- data: json
26179
+ filter: filter.asPodObject()
26133
26180
  },
26134
- error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
26135
- update: (proxy, { data }) => {
26136
- // Update entity
26137
- const savedEntity = data && data.data;
26138
- if (savedEntity) {
26139
- if (this._debug)
26140
- console.debug(`[user-event-service] User event saved in ${Date.now() - now}ms`, entity);
26141
- this.copyIdAndUpdateDate(savedEntity, entity);
26142
- // Add to cache
26143
- if (isNew) {
26144
- this.insertIntoMutableCachedQueries(proxy, {
26145
- query: LoadAllQuery,
26146
- data: Object.assign(Object.assign({}, savedEntity), { content: null })
26147
- });
26148
- this.insertIntoMutableCachedQueries(proxy, {
26149
- query: LoadAllWithContentQuery,
26150
- data: savedEntity
26151
- });
26152
- }
26153
- }
26154
- }
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'
26155
26183
  });
26156
- 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]);
26157
26253
  });
26158
26254
  }
26159
- /**
26160
- * Save many trips
26161
- *
26162
- * @param entities
26163
- * @param opts
26164
- */
26165
26255
  deleteAll(entities, opts) {
26166
26256
  return __awaiter(this, void 0, void 0, function* () {
26167
26257
  const ids = entities && entities
@@ -26170,127 +26260,351 @@ class UserEventService extends BaseGraphqlService {
26170
26260
  return; // stop, if nothing else to do
26171
26261
  const now = Date.now();
26172
26262
  if (this._debug)
26173
- console.debug('[user-event-service] Deleting events... ids:', ids);
26263
+ console.debug(`${this._logPrefix}Deleting events... ids:`, ids);
26174
26264
  yield this.graphql.mutate({
26175
- mutation: DeleteByIdsMutation,
26265
+ mutation: this.mutations.deleteByIds,
26176
26266
  variables: {
26177
26267
  ids
26178
26268
  },
26179
26269
  update: (proxy) => {
26180
26270
  // Remove from caches
26181
26271
  this.removeFromMutableCachedQueriesByIds(proxy, {
26182
- query: LoadAllQuery,
26272
+ query: this.queries.loadAll,
26183
26273
  ids
26184
26274
  });
26185
26275
  this.removeFromMutableCachedQueriesByIds(proxy, {
26186
- query: LoadAllWithContentQuery,
26276
+ query: this.queries.loadAllWithContent,
26187
26277
  ids
26188
26278
  });
26189
26279
  if (this._debug)
26190
- console.debug(`[user-event-service] Events deleted in ${Date.now() - now}ms`);
26280
+ console.debug(`${this._logPrefix}Events deleted in ${Date.now() - now}ms`);
26191
26281
  }
26192
26282
  });
26193
26283
  });
26194
26284
  }
26195
- /**
26196
- * Delete userEvent entities
26197
- */
26198
- delete(data) {
26285
+ save(entity, options) {
26199
26286
  return __awaiter(this, void 0, void 0, function* () {
26200
- if (!data)
26201
- return; // skip
26202
- 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;
26203
26324
  });
26204
26325
  }
26205
- listenChanges(id, options) {
26206
- // TODO
26207
- console.warn('TODO: implement listen changes on user events');
26208
- return of();
26209
- }
26210
- registerAction(definition) {
26211
- console.info(`[user-event-service] Registering action ${definition.name} for ${definition.__typename}`);
26212
- this._userEventActions.push(definition);
26213
- }
26214
- getActionsByTypename(typename) {
26215
- 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
+ });
26216
26331
  }
26217
- showToastErrorWithContext(opts) {
26332
+ markAsRead(entities) {
26218
26333
  return __awaiter(this, void 0, void 0, function* () {
26219
- let message = opts.message || (opts.error && opts.error.message || opts.error);
26220
- // Make sure message a string
26221
- if (!message || typeof message !== 'string') {
26222
- message = 'ERROR.UNKNOWN_TECHNICAL_ERROR';
26223
- }
26224
- // If offline, display a simple alert
26225
- if (this.network.offline) {
26226
- this.showToast({ message, type: 'error' });
26227
- return;
26228
- }
26229
- // Translate the message (to be able to extract details content)
26230
- message = this.translate.instant(message);
26231
- // Clean details parts
26232
- if (message && message.indexOf('<small>') !== -1) {
26233
- message = message.substr(0, message.indexOf('<small>') - 1);
26234
- }
26235
- const res = yield this.showToast({
26236
- type: 'error',
26237
- duration: 15000,
26238
- message: message + '<br/><br/><b>' + this.translate.instant('CONFIRM.SEND_DEBUG_DATA') + '</b>',
26239
- buttons: [{
26240
- icon: 'bug',
26241
- text: this.translate.instant('COMMON.BTN_SEND'),
26242
- role: 'send'
26243
- }]
26244
- });
26245
- if (!res || res.role !== 'send')
26246
- return;
26247
- // Send debug data
26248
- try {
26249
- if (this._debug)
26250
- console.debug('Sending debug data...');
26251
- // Call content factory
26252
- let context = opts && opts.context;
26253
- if (typeof context === 'function') {
26254
- 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
+ }
26255
26342
  }
26256
- if (context instanceof Promise) {
26257
- context = yield context;
26343
+ else {
26344
+ // Add to this list for default operation
26345
+ userEventWithoutReadListeners.push(entity);
26258
26346
  }
26259
- // Send the message
26260
- const userEvent = yield this.sendDataForDebug({
26261
- message,
26262
- error: opts.error || undefined,
26263
- context: this.convertObjectToString(context)
26264
- });
26265
- console.info('Debug data successfully sent to admin', userEvent);
26266
- this.showToast({
26267
- type: 'info',
26268
- message: 'INFO.DEBUG_DATA_SEND',
26269
- showCloseButton: true
26270
- });
26271
- }
26272
- catch (err) {
26273
- console.error('Error while sending debug data:', err);
26274
26347
  }
26348
+ // Use default
26349
+ yield this.defaultMarkAsRead(userEventWithoutReadListeners);
26275
26350
  });
26276
26351
  }
26277
- sendDataForDebug(data) {
26278
- const userEvent = new UserEvent();
26279
- userEvent.eventType = UserEventTypes.DEBUG_DATA;
26280
- userEvent.content = this.convertObjectToString(data);
26281
- return this.save(userEvent);
26352
+ registerListener(listener) {
26353
+ if (!this.listeners)
26354
+ this.listeners = [];
26355
+ this.listeners.push(listener);
26282
26356
  }
26283
- asFilter(filter) {
26284
- return UserEventFilter.fromObject(filter);
26357
+ resetCount() {
26358
+ this.count$.next(undefined);
26359
+ this.resetCountDate = moment$6();
26360
+ // restart listening count changes
26361
+ this.startListenCountChanges();
26285
26362
  }
26286
26363
  /* -- protected methods -- */
26287
- convertObjectToString(data) {
26288
- if (typeof data === 'string') {
26289
- return data;
26290
- }
26291
- // Serialize content into string
26292
- else if (typeof data === 'object') {
26293
- if (data instanceof Entity) {
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') {
26603
+ return data;
26604
+ }
26605
+ // Serialize content into string
26606
+ else if (typeof data === 'object') {
26607
+ if (data instanceof Entity) {
26294
26608
  return JSON.stringify(data.asObject({ keepTypename: true, keepLocalId: true, minify: false }));
26295
26609
  }
26296
26610
  else {
@@ -26311,13 +26625,9 @@ class UserEventService extends BaseGraphqlService {
26311
26625
  // TODO: compute sign
26312
26626
  console.warn('TODO: sign user event before sending');
26313
26627
  }
26314
- copyIdAndUpdateDate(source, target) {
26315
- EntityUtils.copyIdAndUpdateDate(source, target);
26316
- }
26317
26628
  }
26318
- 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" });
26319
26629
  UserEventService.decorators = [
26320
- { type: Injectable, args: [{ providedIn: 'root' },] }
26630
+ { type: Injectable }
26321
26631
  ];
26322
26632
  UserEventService.ctorParameters = () => [
26323
26633
  { type: GraphqlService },
@@ -26330,7 +26640,7 @@ UserEventService.ctorParameters = () => [
26330
26640
 
26331
26641
  const ICONS_MAP = {
26332
26642
  DEBUG_DATA: { matIcon: 'bug_report' },
26333
- INBOX_MESSAGE: { matIcon: 'mail' },
26643
+ INBOX_MESSAGE: { matIcon: 'mail' }
26334
26644
  };
26335
26645
  // TODO: refactor with a registration done by data service:
26336
26646
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -26396,7 +26706,7 @@ class UserEventsTable extends AppTable {
26396
26706
  }
26397
26707
  }));
26398
26708
  const filter = this.filter || new UserEventFilter();
26399
- filter.recipient = this.recipient;
26709
+ filter.recipients = [this.recipient];
26400
26710
  this.setFilter(filter, { emitEvent: true });
26401
26711
  }
26402
26712
  start() {
@@ -26409,17 +26719,17 @@ class UserEventsTable extends AppTable {
26409
26719
  });
26410
26720
  }
26411
26721
  getIcon(source) {
26412
- return ICONS_MAP[source.eventType];
26722
+ return ICONS_MAP[source.type];
26413
26723
  }
26414
26724
  getDetail(source) {
26415
26725
  if (!source)
26416
26726
  return undefined;
26417
- if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
26727
+ if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
26418
26728
  const context = source.content.context;
26419
26729
  if (context && context.__typename) {
26420
- const actions = this.service.getActionsByTypename(context.__typename);
26730
+ // const actions = this.service.getActionsByTypename(context.__typename);
26421
26731
  return {
26422
- actions,
26732
+ // actions,
26423
26733
  title: source.content.error && source.content.error.message || source.content.message,
26424
26734
  description: source.content.error && source.content.error.details || undefined
26425
26735
  };
@@ -26431,11 +26741,11 @@ class UserEventsTable extends AppTable {
26431
26741
  doAction(action, row) {
26432
26742
  return __awaiter(this, void 0, void 0, function* () {
26433
26743
  const event = row.currentData;
26434
- const context = event.content && event.content.context;
26744
+ // const context = event.content && event.content.context;
26435
26745
  this.markAsLoading();
26436
26746
  if (action && typeof action.executeAction === 'function') {
26437
26747
  try {
26438
- let res = action.executeAction(event, context);
26748
+ let res = action.executeAction(event /*, context*/);
26439
26749
  res = (res instanceof Promise) ? yield res : res;
26440
26750
  }
26441
26751
  catch (err) {
@@ -26452,15 +26762,20 @@ class UserEventsTable extends AppTable {
26452
26762
  UserEventsTable.decorators = [
26453
26763
  { type: Component, args: [{
26454
26764
  selector: 'app-user-events-table',
26455
- 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",
26456
26766
  changeDetection: ChangeDetectionStrategy.OnPush,
26767
+ providers: [
26768
+ {
26769
+ provide: UserEventServiceToken, useClass: UserEventService
26770
+ }
26771
+ ],
26457
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}"]
26458
26773
  },] }
26459
26774
  ];
26460
26775
  UserEventsTable.ctorParameters = () => [
26461
26776
  { type: Injector },
26462
26777
  { type: AccountService },
26463
- { type: UserEventService },
26778
+ { type: undefined, decorators: [{ type: Inject, args: [UserEventServiceToken,] }] },
26464
26779
  { type: EntitiesStorage },
26465
26780
  { type: ChangeDetectorRef },
26466
26781
  { type: undefined, decorators: [{ type: Inject, args: [ENVIRONMENT,] }] }
@@ -26472,6 +26787,248 @@ UserEventsTable.propDecorators = {
26472
26787
  defaultSortDirection: [{ type: Input }]
26473
26788
  };
26474
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
+
26475
27032
  const MessageTypes = {
26476
27033
  INBOX_MESSAGE: 'INBOX_MESSAGE',
26477
27034
  EMAIL: 'EMAIL',
@@ -26683,9 +27240,9 @@ MessageForm.propDecorators = {
26683
27240
  canSelectType: [{ type: Input }]
26684
27241
  };
26685
27242
 
26686
- class SocialModule {
27243
+ class MessageModule {
26687
27244
  }
26688
- SocialModule.decorators = [
27245
+ MessageModule.decorators = [
26689
27246
  { type: NgModule, args: [{
26690
27247
  imports: [
26691
27248
  CommonModule,
@@ -26693,17 +27250,327 @@ SocialModule.decorators = [
26693
27250
  SharedModule
26694
27251
  ],
26695
27252
  declarations: [
26696
- UserEventsTable,
26697
27253
  MessageModal,
26698
27254
  MessageForm
26699
27255
  ],
26700
27256
  exports: [
26701
- UserEventsTable,
26702
27257
  MessageModal
26703
27258
  ]
26704
27259
  },] }
26705
27260
  ];
26706
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
+
26707
27574
  const Mutations = {
26708
27575
  send: gql `mutation SendMessage($data: MessageVOInput){
26709
27576
  done: sendMessage(message: $data)
@@ -27518,13 +28385,13 @@ LatLongTestPage.ctorParameters = () => [
27518
28385
  { type: FormBuilder }
27519
28386
  ];
27520
28387
 
27521
- const moment$6 = momentImported;
28388
+ const moment$7 = momentImported;
27522
28389
  class SwipeTestPage {
27523
28390
  constructor(formBuilder, dateFormatPipe) {
27524
28391
  this.formBuilder = formBuilder;
27525
28392
  this.dateFormatPipe = dateFormatPipe;
27526
28393
  this.$dates = new BehaviorSubject(undefined);
27527
- this._today = moment$6().startOf('day');
28394
+ this._today = moment$7().startOf('day');
27528
28395
  this.form = formBuilder.group({
27529
28396
  empty: [null, Validators.required],
27530
28397
  date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
@@ -27537,7 +28404,7 @@ class SwipeTestPage {
27537
28404
  ngOnInit() {
27538
28405
  const dates = [];
27539
28406
  for (let d = 0; d < 7; d++) {
27540
- dates[d] = moment$6(this._today).add(d - 3, 'day');
28407
+ dates[d] = moment$7(this._today).add(d - 3, 'day');
27541
28408
  }
27542
28409
  this.$dates.next(dates);
27543
28410
  this.loadData();
@@ -27578,7 +28445,7 @@ SwipeTestPage.ctorParameters = () => [
27578
28445
  { type: DateFormatPipe }
27579
28446
  ];
27580
28447
 
27581
- const moment$7 = momentImported;
28448
+ const moment$8 = momentImported;
27582
28449
  class DateTimeTestPage {
27583
28450
  constructor(platform, formBuilder, cd) {
27584
28451
  this.platform = platform;
@@ -27610,7 +28477,7 @@ class DateTimeTestPage {
27610
28477
  // Load the form with data
27611
28478
  loadData() {
27612
28479
  return __awaiter(this, void 0, void 0, function* () {
27613
- const now = moment$7();
28480
+ const now = moment$8();
27614
28481
  const data = {
27615
28482
  empty: null,
27616
28483
  emptyRequired: null,
@@ -27856,7 +28723,7 @@ NumpadTestPage.ctorParameters = () => [
27856
28723
  { type: FormBuilder }
27857
28724
  ];
27858
28725
 
27859
- const moment$8 = momentImported;
28726
+ const moment$9 = momentImported;
27860
28727
  class DateTestPage {
27861
28728
  constructor(formBuilder, cd) {
27862
28729
  this.formBuilder = formBuilder;
@@ -27889,7 +28756,7 @@ class DateTestPage {
27889
28756
  // Load the form with data
27890
28757
  loadData() {
27891
28758
  return __awaiter(this, void 0, void 0, function* () {
27892
- const now = moment$8();
28759
+ const now = moment$9();
27893
28760
  const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
27894
28761
  const data = {
27895
28762
  empty: null,
@@ -28635,5 +29502,5 @@ CoreTestingModule.decorators = [
28635
29502
  * Generated bundle index. Do not edit.
28636
29503
  */
28637
29504
 
28638
- 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 };
28639
29506
  //# sourceMappingURL=sumaris-net.ngx-components.js.map