@sumaris-net/ngx-components 1.21.6 → 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 (56) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +1321 -201
  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/form/editor.class.js +19 -12
  7. package/esm2015/src/app/core/icon/icon.component.js +5 -2
  8. package/esm2015/src/app/core/menu/menu.component.js +2 -2
  9. package/esm2015/src/app/shared/pipes/date-diff-duration.pipe.js +9 -5
  10. package/esm2015/src/app/shared/types.js +1 -1
  11. package/esm2015/src/app/social/job/job.model.js +26 -0
  12. package/esm2015/src/app/social/job/job.module.js +25 -0
  13. package/esm2015/src/app/social/job/job.service.js +54 -0
  14. package/esm2015/src/app/social/job/progression/job-progression.component.js +200 -0
  15. package/esm2015/src/app/social/job/progression/job-progression.list.js +20 -0
  16. package/esm2015/src/app/social/message/message.module.js +25 -0
  17. package/esm2015/src/app/social/social.errors.js +5 -2
  18. package/esm2015/src/app/social/social.module.js +10 -15
  19. package/esm2015/src/app/social/user-event/notification/user-event-notification.component.js +89 -0
  20. package/esm2015/src/app/social/user-event/notification/user-event-notification.list.js +78 -0
  21. package/esm2015/src/app/social/user-event/testing/user-event.testing.service.js +73 -0
  22. package/esm2015/src/app/social/user-event/user-event.model.js +58 -2
  23. package/esm2015/src/app/social/user-event/user-event.module.js +33 -0
  24. package/esm2015/src/app/social/user-event/user-event.service.js +412 -173
  25. package/esm2015/src/app/social/user-event/user-events.table.js +18 -13
  26. package/esm2015/sumaris-net.ngx-components.js +9 -6
  27. package/fesm2015/sumaris-net.ngx-components.js +1104 -230
  28. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  29. package/package.json +1 -1
  30. package/public_api.d.ts +7 -0
  31. package/src/app/core/form/editor.class.d.ts +3 -1
  32. package/src/app/core/icon/icon.component.d.ts +4 -4
  33. package/src/app/shared/material/badge/badge-icon.test.d.ts +1 -1
  34. package/src/app/shared/pipes/date-diff-duration.pipe.d.ts +6 -2
  35. package/src/app/shared/types.d.ts +4 -0
  36. package/src/app/social/job/job.model.d.ts +33 -0
  37. package/src/app/social/job/job.module.d.ts +2 -0
  38. package/src/app/social/job/job.service.d.ts +23 -0
  39. package/src/app/social/job/progression/job-progression.component.d.ts +44 -0
  40. package/src/app/social/job/progression/job-progression.list.d.ts +12 -0
  41. package/src/app/social/message/message.module.d.ts +2 -0
  42. package/src/app/social/social.errors.d.ts +3 -0
  43. package/src/app/social/social.module.d.ts +8 -0
  44. package/src/app/social/user-event/notification/user-event-notification.component.d.ts +22 -0
  45. package/src/app/social/user-event/notification/user-event-notification.list.d.ts +30 -0
  46. package/src/app/social/user-event/testing/user-event.testing.service.d.ts +35 -0
  47. package/src/app/social/user-event/user-event.model.d.ts +52 -8
  48. package/src/app/social/user-event/user-event.module.d.ts +2 -0
  49. package/src/app/social/user-event/user-event.service.d.ts +101 -51
  50. package/src/app/social/user-event/user-events.table.d.ts +6 -6
  51. package/src/assets/i18n/en-US.json +15 -2
  52. package/src/assets/i18n/en.json +16 -2
  53. package/src/assets/i18n/fr.json +15 -1
  54. package/src/theme/_ngx-components.scss +8 -0
  55. package/sumaris-net.ngx-components.d.ts +8 -5
  56. package/sumaris-net.ngx-components.metadata.json +1 -1
@@ -1966,17 +1966,21 @@ class DateDiffDurationPipe {
1966
1966
  return '';
1967
1967
  const startDate = this.dateAdapter.parse(value.startValue, DATE_ISO_PATTERN);
1968
1968
  const endDate = this.dateAdapter.parse(value.endValue, DATE_ISO_PATTERN);
1969
- return this.format(startDate, endDate);
1969
+ return this.format(startDate, endDate, args);
1970
1970
  }
1971
- format(startDate, endDate) {
1971
+ format(startDate, endDate, args) {
1972
1972
  const duration = moment.duration(endDate.diff(startDate));
1973
1973
  if (duration.asMinutes() < 0)
1974
1974
  return '';
1975
+ const withSeconds = args === null || args === void 0 ? void 0 : args.seconds;
1975
1976
  const timeDuration = moment(0)
1976
1977
  .hour(duration.hours())
1977
1978
  .minute(duration.minutes());
1979
+ if (withSeconds) {
1980
+ timeDuration.second(duration.seconds());
1981
+ }
1978
1982
  const days = Math.floor(duration.asDays());
1979
- return (days > 0 ? days.toString() + (this.dayUnit + ' ') : '') + timeDuration.format('HH:mm');
1983
+ return (days > 0 ? days.toString() + (this.dayUnit + ' ') : '') + timeDuration.format(withSeconds ? 'HH:mm:ss' : 'HH:mm');
1980
1984
  }
1981
1985
  }
1982
1986
  DateDiffDurationPipe.ɵprov = ɵɵdefineInjectable({ factory: function DateDiffDurationPipe_Factory() { return new DateDiffDurationPipe(ɵɵinject(DateAdapter), ɵɵinject(TranslateService)); }, token: DateDiffDurationPipe, providedIn: "root" });
@@ -21477,7 +21481,7 @@ class MenuComponent {
21477
21481
  MenuComponent.decorators = [
21478
21482
  { type: Component, args: [{
21479
21483
  selector: 'app-menu',
21480
- template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
21484
+ template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n<!-- todo ajouter ici les 2 composants du module social ??? -->\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '&#xab;' : '&#xbb;'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
21481
21485
  animations: [fadeInAnimation],
21482
21486
  changeDetection: ChangeDetectionStrategy.OnPush,
21483
21487
  styles: ["ion-menu{--ion-item-background:transparent;--ion-item-divider-background:transparent;--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint);--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-text-color-selected:var(--ion-color-primary);--ion-item-icon-color-selected:var(--ion-color-primary);--ion-item-text-color-disable:var(--ion-color-medium);--ion-item-icon-color-disable:var(--ion-color-medium)}ion-menu ion-header ion-text{color:var(--ion-color-primary)}ion-menu ion-header .user-avatar{background-size:cover;background-repeat:no-repeat;background-position:50%;background-color:var(--ion-color-secondary);border:1px solid var(--ion-color-primary);overflow:hidden!important;font-size:var(--avatar-size,60px)!important;line-height:var(--avatar-size,60px);height:var(--avatar-size,60px)!important;width:var(--avatar-size,60px)!important;border-radius:50%;display:inline-block}ion-menu ion-header .user-logo{text-align:right}ion-menu ion-header .user-logo img{max-width:120px;max-height:var(--avatar-size,60px);width:auto}ion-menu ion-header .username{padding-top:0;margin-top:0;margin-bottom:0;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-menu ion-header button[mat-button]{padding:0;text-align:start!important;width:100%}ion-menu .scroll-content{margin-top:79px!important}ion-menu .has-user-header .scroll-content{margin-top:188px!important}ion-menu ion-content.has-profile-header{--offset-top:188px}ion-menu ion-content.no-profile-header{--offset-top:79px}ion-menu ion-content ion-list{min-height:100%;display:flex;flex-direction:column;justify-content:flex-start}ion-menu ion-content ion-list ion-menu-toggle.flex-spacer{flex:1 1 auto;display:flex;flex-direction:column;justify-content:flex-end}ion-menu ion-content ion-list ion-item.primary{--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint)}ion-menu ion-content ion-list ion-item.secondary{--ion-item-icon-color:var(--ion-color-secondary-tint);--ion-item-text-color:var(--ion-color-secondary-tint)}ion-menu ion-content ion-list ion-item.tertiary{--ion-item-icon-color:var(--ion-color-tertiary-tint);--ion-item-text-color:var(--ion-color-tertiary-tint)}ion-menu ion-content ion-list ion-item.danger{--ion-item-icon-color:var(--ion-color-danger-tint);--ion-item-text-color:var(--ion-color-danger-tint)}ion-menu ion-content ion-list ion-item.medium{--ion-item-icon-color:var(--ion-color-medium-shade);--ion-item-text-color:var(--ion-color-medium-shade)}ion-menu ion-content ion-list ion-item.dark{--ion-item-icon-color:var(--ion-color-dark-tint);--ion-item-text-color:var(--ion-color-dark-tint)}ion-menu ion-content ion-list ion-item ion-icon,ion-menu ion-content ion-list ion-item mat-icon{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item ion-label,ion-menu ion-content ion-list ion-item ion-text{color:var(--ion-item-text-color)!important}ion-menu ion-content ion-list ion-item.selected{background-color:var(--ion-item-background-selected)!important;--color-hover:var(--ion-item-background-selected)!important}ion-menu ion-content ion-list ion-item.selected ion-icon,ion-menu ion-content ion-list ion-item.selected mat-icon{color:var(--ion-item-icon-color-selected)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item.selected ion-label,ion-menu ion-content ion-list ion-item.selected ion-text{color:var(--ion-item-text-color-selected)!important}ion-menu ion-content ion-list ion-item.selected:hover{--color-hover:var(--ion-item-background-selected)!important;--ion-item-icon-color-selected:var(--ion-item-icon-color)!important;--ion-item-text-color-selected:var(--ion-item-text-color)!important}ion-menu ion-footer{display:block!important}ion-menu ion-footer ion-toolbar ion-title{cursor:pointer;font-size:12pt;font-weight:400;text-align:center;padding:0 8px}ion-menu ion-footer ion-toolbar ion-button{--width:40px}@media screen and (max-width:767px){ion-menu ion-footer{display:none!important;visibility:hidden!important}}@media screen and (min-width:768px){ion-menu ion-scroll{overflow-y:auto!important}ion-menu .user-avatar{font-size:var(--avatar-size,80px)!important;line-height:var(--avatar-size,80px);height:var(--avatar-size,80px)!important;width:var(--avatar-size,80px)!important}ion-menu .user-logo img{max-height:var(--avatar-size,80px)}}"]
@@ -21541,13 +21545,14 @@ class AppIconComponent {
21541
21545
  this.icon = value.icon;
21542
21546
  this.matIcon = value.matIcon;
21543
21547
  this.matSvgIcon = value.matSvgIcon;
21548
+ this.color = value.color;
21544
21549
  }
21545
21550
  ;
21546
21551
  }
21547
21552
  AppIconComponent.decorators = [
21548
21553
  { type: Component, args: [{
21549
21554
  selector: 'app-icon',
21550
- template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\">{{matIcon}}</mat-icon>\n</ng-template>\n\n"
21555
+ template: "<ion-icon *ngIf=\"icon; else matIconTemplate\" slot=\"icon-only\"\n [color]=\"color\"\n [name]=\"icon\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n></ion-icon>\n<ng-template #matIconTemplate>\n <mat-icon [svgIcon]=\"matSvgIcon\"\n [style.color]=\"'var(--ion-color-'+color+')'\"\n [style.height.px]=\"height\"\n [style.width.px]=\"width\"\n [style.font-size.px]=\"height || width\"\n >{{matIcon}}</mat-icon>\n</ng-template>\n\n"
21551
21556
  },] }
21552
21557
  ];
21553
21558
  AppIconComponent.propDecorators = {
@@ -21555,6 +21560,8 @@ AppIconComponent.propDecorators = {
21555
21560
  matIcon: [{ type: Input }],
21556
21561
  matSvgIcon: [{ type: Input }],
21557
21562
  color: [{ type: Input }],
21563
+ height: [{ type: Input }],
21564
+ width: [{ type: Input }],
21558
21565
  ref: [{ type: Input }]
21559
21566
  };
21560
21567
 
@@ -24225,9 +24232,11 @@ class AppEditor {
24225
24232
  get forms() {
24226
24233
  return this._children && this._children.filter(c => c instanceof AppForm);
24227
24234
  }
24235
+ get editors() {
24236
+ return this._children && this._children.filter(c => c instanceof AppEditor);
24237
+ }
24228
24238
  get dirty() {
24229
- var _a;
24230
- return this._dirty || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.dirty)) !== -1) || false;
24239
+ return this._dirty || (this._children && this._children.findIndex(c => c.enabled && c.dirty) !== -1) || false;
24231
24240
  }
24232
24241
  /**
24233
24242
  * Is valid (tables and forms)
@@ -24237,16 +24246,13 @@ class AppEditor {
24237
24246
  return !this._children || this._children.findIndex(c => c.enabled && !c.valid) === -1;
24238
24247
  }
24239
24248
  get invalid() {
24240
- var _a;
24241
- return (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.invalid)) !== -1) || false;
24249
+ return (this._children && this._children.findIndex(c => c.enabled && c.invalid) !== -1) || false;
24242
24250
  }
24243
24251
  get pending() {
24244
- var _a;
24245
- return (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.pending)) !== -1) || false;
24252
+ return (this._children && this._children.findIndex(c => c.enabled && c.pending) !== -1) || false;
24246
24253
  }
24247
24254
  get loading() {
24248
- var _a;
24249
- return this.loadingSubject.value || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
24255
+ return this.loadingSubject.value || (this._children && this._children.findIndex(c => c.enabled && c.loading) !== -1) || false;
24250
24256
  }
24251
24257
  get enabled() {
24252
24258
  return this._enabled;
@@ -24288,7 +24294,15 @@ class AppEditor {
24288
24294
  }
24289
24295
  addChildForms(forms) {
24290
24296
  (forms || []).forEach(form => this.addChildForm(form));
24291
- return this;
24297
+ }
24298
+ removeChildForm(form) {
24299
+ if (!form)
24300
+ throw new Error('Trying to remove an undefined child form');
24301
+ const index = (this._children || []).findIndex(c => c === form);
24302
+ if (index !== -1) {
24303
+ return this._children.splice(index, 1)[0];
24304
+ }
24305
+ return undefined;
24292
24306
  }
24293
24307
  disable(opts) {
24294
24308
  var _a;
@@ -24392,10 +24406,11 @@ class AppEditor {
24392
24406
  * @param opts
24393
24407
  */
24394
24408
  unload(opts) {
24409
+ var _a;
24395
24410
  return __awaiter(this, void 0, void 0, function* () {
24396
24411
  console.debug('[tab-page] Unloading data...');
24397
24412
  this.markAsLoading();
24398
- this._children.forEach(f => {
24413
+ (_a = this._children) === null || _a === void 0 ? void 0 : _a.forEach(f => {
24399
24414
  if (f instanceof AppForm) {
24400
24415
  f.reset(null, opts);
24401
24416
  }
@@ -24403,7 +24418,6 @@ class AppEditor {
24403
24418
  f.dataSource.disconnect();
24404
24419
  }
24405
24420
  });
24406
- // TODO: find a way to remove current page from the navigation history
24407
24421
  });
24408
24422
  }
24409
24423
  reloadWithConfirmation(confirm) {
@@ -25912,7 +25926,10 @@ AppInMemoryTable.propDecorators = {
25912
25926
  const SocialErrorCodes = {
25913
25927
  LOAD_USER_EVENTS_ERROR: 50000,
25914
25928
  SAVE_USER_EVENT_ERROR: 50001,
25915
- 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
25916
25933
  };
25917
25934
 
25918
25935
  var UserEvent_1;
@@ -25927,16 +25944,23 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25927
25944
  }
25928
25945
  asObject(opts) {
25929
25946
  const target = super.asObject(opts);
25947
+ target.creationDate = toDateISOString(this.creationDate);
25948
+ target.readDate = toDateISOString(this.readDate);
25930
25949
  // Serialize content
25931
25950
  if (typeof target.content === 'object') {
25932
25951
  target.content = JSON.stringify(target.content);
25933
25952
  }
25953
+ delete target.avatar;
25954
+ delete target.avatarIcon;
25955
+ delete target.icon;
25956
+ delete target.actions;
25934
25957
  return target;
25935
25958
  }
25936
25959
  fromObject(source) {
25937
25960
  Object.assign(this, source); // Copy all properties
25938
25961
  super.fromObject(source);
25939
25962
  this.creationDate = fromDateISOString(source.creationDate);
25963
+ this.readDate = fromDateISOString(source.readDate);
25940
25964
  try {
25941
25965
  // Deserialize content
25942
25966
  if (typeof source.content === 'string' && source.content.startsWith('{')) {
@@ -25955,6 +25979,52 @@ let UserEvent = UserEvent_1 = class UserEvent extends Entity {
25955
25979
  UserEvent = UserEvent_1 = __decorate([
25956
25980
  EntityClass({ typename: 'UserEventVO' })
25957
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);
25958
26028
 
25959
26029
  const UserEventFragments = {
25960
26030
  userEvent: gql `fragment UserEventFragment on UserEventVO {
@@ -25982,179 +26052,206 @@ const UserEventFragments = {
25982
26052
  }`
25983
26053
  };
25984
26054
 
25985
- // @dynamic
25986
- let UserEventFilter = class UserEventFilter extends EntityFilter {
25987
- constructor() {
25988
- super(...arguments);
25989
- this.issuer = null;
25990
- this.recipient = null;
25991
- }
25992
- fromObject(source, opts) {
25993
- super.fromObject(source, opts);
25994
- this.issuer = source.issuer;
25995
- this.recipient = source.recipient;
25996
- }
25997
- buildFilter() {
25998
- const filterFns = super.buildFilter();
25999
- // issuer
26000
- if (this.issuer) {
26001
- filterFns.push(t => (t.issuer === this.issuer));
26002
- }
26003
- if (this.recipient) {
26004
- filterFns.push(t => (t.recipient === this.recipient));
26005
- }
26006
- return filterFns;
26007
- }
26008
- };
26009
- UserEventFilter = __decorate([
26010
- EntityClass({ typename: 'UserEventFilterVO' })
26011
- ], UserEventFilter);
26012
- const SaveQuery = gql `
26013
- mutation SaveUserEvent($data: UserEventVOInput){
26014
- data: saveUserEvent(userEvent: $data){
26015
- ...UserEventFragment
26016
- }
26017
- }
26018
- ${UserEventFragments.userEvent}
26019
- `;
26020
- const LoadAllQuery = gql `
26021
- query UserEvents($filter: UserEventFilterVOInput, $page: PageInput){
26022
- data: userEvents(filter: $filter, page: $page){
26023
- ...LightUserEventFragment
26024
- }
26025
- }
26026
- ${UserEventFragments.lightUserEvent}
26027
- `;
26028
- const DeleteByIdsMutation = gql `
26029
- mutation DeleteUserEvents($ids:[Int]){
26030
- deleteUserEvents(ids: $ids)
26031
- }
26032
- `;
26033
- const LoadAllWithContentQuery = gql `
26034
- query UserEventsWithContent($filter: UserEventFilterVOInput, $page: PageInput){
26035
- data: userEvents(filter: $filter, page: $page){
26036
- ...UserEventFragment
26037
- }
26038
- }
26039
- ${UserEventFragments.userEvent}
26040
- `;
26041
- class UserEventService extends BaseGraphqlService {
26042
- 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) {
26043
26059
  super(graphql, environment);
26044
26060
  this.graphql = graphql;
26045
26061
  this.accountService = accountService;
26046
26062
  this.network = network;
26047
26063
  this.translate = translate;
26048
- this.toastController = toastController;
26064
+ this.queries = queries;
26065
+ this.mutations = mutations;
26066
+ this.subscriptions = subscriptions;
26049
26067
  this.environment = environment;
26050
- this._userEventActions = [];
26068
+ this.count$ = new BehaviorSubject(0);
26069
+ this.listeners = [];
26070
+ this._subscriptions = new Subscription();
26071
+ this._logPrefix = '[user-event-service] ';
26051
26072
  // For DEV only
26052
- 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();
26053
26102
  }
26054
- /**
26055
- *
26056
- * @param offset
26057
- * @param size
26058
- * @param sortBy
26059
- * @param sortDirection
26060
- * @param filter
26061
- * @param options
26062
- * @deprecated use watchPage() instead
26063
- */
26064
26103
  watchAll(offset, size, sortBy, sortDirection, filter, options) {
26065
26104
  return this.watchPage({ offset, size, sortBy, sortDirection }, filter, options);
26066
26105
  }
26067
26106
  watchPage(page, filter, options) {
26107
+ var _a;
26068
26108
  let now = this._debug && Date.now();
26069
- //if (this._debug)
26070
- 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);
26071
26113
  filter = this.asFilter(filter);
26072
26114
  // Force recipient to current issuer, if not admin and not specified
26073
- if (isNilOrBlank(filter.recipient) || !this.accountService.isAdmin()) {
26074
- const recipient = this.accountService.account.pubkey;
26075
- 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))) {
26076
26118
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
26077
- filter.recipient = recipient;
26119
+ filter.recipients = [recipient];
26078
26120
  }
26079
26121
  }
26080
- const withContent = options && options.withContent === true;
26122
+ const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26081
26123
  return this.mutableWatchQuery({
26082
26124
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
26083
- query: withContent ? LoadAllWithContentQuery : LoadAllQuery,
26125
+ query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26084
26126
  variables: {
26085
- 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() }),
26086
26130
  filter: filter && filter.asPodObject()
26087
26131
  },
26088
26132
  arrayFieldName: 'data',
26089
26133
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
26090
- fetchPolicy: options && options.fetchPolicy || undefined
26134
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'cache-first'
26091
26135
  })
26092
26136
  .pipe(map(res => {
26093
- 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));
26094
26138
  if (now) {
26095
- 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`);
26096
26140
  now = null;
26097
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);
26098
26144
  return {
26099
26145
  data,
26100
- total: res && toNumber(res.total, data.length)
26146
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, data.length)
26101
26147
  };
26102
26148
  }));
26103
26149
  }
26104
- saveAll(data, options) {
26105
- return Promise.all(data
26106
- .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);
26107
26161
  }
26108
- /**
26109
- * Save a userEvent entity
26110
- *
26111
- * @param entity
26112
- */
26113
- save(entity, options) {
26162
+ count(filter, options) {
26163
+ var _a;
26114
26164
  return __awaiter(this, void 0, void 0, function* () {
26115
- this.fillDefaultProperties(entity);
26116
- // Transform into json
26117
- const isNew = isNil(entity.id);
26118
- const json = entity.asObject();
26119
- 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);
26120
26174
  if (this._debug)
26121
- console.debug(`[user-event-service] Saving user event...`, json);
26122
- yield this.graphql.mutate({
26123
- 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,
26124
26178
  variables: {
26125
- data: json
26179
+ filter: filter.asPodObject()
26126
26180
  },
26127
- error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
26128
- update: (proxy, { data }) => {
26129
- // Update entity
26130
- const savedEntity = data && data.data;
26131
- if (savedEntity) {
26132
- if (this._debug)
26133
- console.debug(`[user-event-service] User event saved in ${Date.now() - now}ms`, entity);
26134
- this.copyIdAndUpdateDate(savedEntity, entity);
26135
- // Add to cache
26136
- if (isNew) {
26137
- this.insertIntoMutableCachedQueries(proxy, {
26138
- query: LoadAllQuery,
26139
- data: Object.assign(Object.assign({}, savedEntity), { content: null })
26140
- });
26141
- this.insertIntoMutableCachedQueries(proxy, {
26142
- query: LoadAllWithContentQuery,
26143
- data: savedEntity
26144
- });
26145
- }
26146
- }
26147
- }
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'
26148
26183
  });
26149
- 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]);
26150
26253
  });
26151
26254
  }
26152
- /**
26153
- * Save many trips
26154
- *
26155
- * @param entities
26156
- * @param opts
26157
- */
26158
26255
  deleteAll(entities, opts) {
26159
26256
  return __awaiter(this, void 0, void 0, function* () {
26160
26257
  const ids = entities && entities
@@ -26163,90 +26260,311 @@ class UserEventService extends BaseGraphqlService {
26163
26260
  return; // stop, if nothing else to do
26164
26261
  const now = Date.now();
26165
26262
  if (this._debug)
26166
- console.debug('[user-event-service] Deleting events... ids:', ids);
26263
+ console.debug(`${this._logPrefix}Deleting events... ids:`, ids);
26167
26264
  yield this.graphql.mutate({
26168
- mutation: DeleteByIdsMutation,
26265
+ mutation: this.mutations.deleteByIds,
26169
26266
  variables: {
26170
26267
  ids
26171
26268
  },
26172
26269
  update: (proxy) => {
26173
26270
  // Remove from caches
26174
26271
  this.removeFromMutableCachedQueriesByIds(proxy, {
26175
- query: LoadAllQuery,
26272
+ query: this.queries.loadAll,
26176
26273
  ids
26177
26274
  });
26178
26275
  this.removeFromMutableCachedQueriesByIds(proxy, {
26179
- query: LoadAllWithContentQuery,
26276
+ query: this.queries.loadAllWithContent,
26180
26277
  ids
26181
26278
  });
26182
26279
  if (this._debug)
26183
- console.debug(`[user-event-service] Events deleted in ${Date.now() - now}ms`);
26280
+ console.debug(`${this._logPrefix}Events deleted in ${Date.now() - now}ms`);
26184
26281
  }
26185
26282
  });
26186
26283
  });
26187
26284
  }
26188
- /**
26189
- * Delete userEvent entities
26190
- */
26191
- delete(data) {
26285
+ save(entity, options) {
26192
26286
  return __awaiter(this, void 0, void 0, function* () {
26193
- if (!data)
26194
- return; // skip
26195
- 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;
26196
26324
  });
26197
26325
  }
26198
- listenChanges(id, options) {
26199
- // TODO
26200
- console.warn('TODO: implement listen changes on user events');
26201
- return of();
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
+ });
26331
+ }
26332
+ markAsRead(entities) {
26333
+ return __awaiter(this, void 0, void 0, function* () {
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
+ }
26342
+ }
26343
+ else {
26344
+ // Add to this list for default operation
26345
+ userEventWithoutReadListeners.push(entity);
26346
+ }
26347
+ }
26348
+ // Use default
26349
+ yield this.defaultMarkAsRead(userEventWithoutReadListeners);
26350
+ });
26202
26351
  }
26203
- registerAction(definition) {
26204
- console.info(`[user-event-service] Registering action ${definition.name} for ${definition.__typename}`);
26205
- this._userEventActions.push(definition);
26352
+ registerListener(listener) {
26353
+ if (!this.listeners)
26354
+ this.listeners = [];
26355
+ this.listeners.push(listener);
26206
26356
  }
26207
- getActionsByTypename(typename) {
26208
- return this._userEventActions.filter(def => def.__typename === typename);
26357
+ resetCount() {
26358
+ this.count$.next(undefined);
26359
+ this.resetCountDate = moment$6();
26360
+ // restart listening count changes
26361
+ this.startListenCountChanges();
26209
26362
  }
26210
- showToastErrorWithContext(opts) {
26363
+ /* -- protected methods -- */
26364
+ onLogin() {
26211
26365
  return __awaiter(this, void 0, void 0, function* () {
26212
- let message = opts.message || (opts.error && opts.error.message || opts.error);
26213
- // Make sure message a string
26214
- if (!message || typeof message !== 'string') {
26215
- message = 'ERROR.UNKNOWN_TECHNICAL_ERROR';
26216
- }
26217
- // If offline, display a simple alert
26218
- if (this.network.offline) {
26219
- this.showToast({ message, type: 'error' });
26220
- return;
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);
26221
26397
  }
26222
- // Translate the message (to be able to extract details content)
26223
- message = this.translate.instant(message);
26224
- // Clean details parts
26225
- if (message && message.indexOf('<small>') !== -1) {
26226
- message = message.substr(0, message.indexOf('<small>') - 1);
26398
+ else {
26399
+ if (that._debug)
26400
+ console.debug(`${that._logPrefix}Event has been rejected by a listener`, source);
26401
+ break;
26227
26402
  }
26228
- const res = yield this.showToast({
26229
- type: 'error',
26230
- duration: 15000,
26231
- message: message + '<br/><br/><b>' + this.translate.instant('CONFIRM.SEND_DEBUG_DATA') + '</b>',
26232
- buttons: [{
26233
- icon: 'bug',
26234
- text: this.translate.instant('COMMON.BTN_SEND'),
26235
- role: 'send'
26236
- }]
26237
- });
26238
- if (!res || res.role !== 'send')
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)
26239
26412
  return;
26240
- // Send debug data
26241
- try {
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) {
26242
26420
  if (this._debug)
26243
- console.debug('Sending debug data...');
26244
- // Call content factory
26245
- let context = opts && opts.context;
26246
- if (typeof context === 'function') {
26247
- context = context();
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;
26248
26429
  }
26249
- if (context instanceof Promise) {
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) {
26250
26568
  context = yield context;
26251
26569
  }
26252
26570
  // Send the message
@@ -26269,13 +26587,16 @@ class UserEventService extends BaseGraphqlService {
26269
26587
  }
26270
26588
  sendDataForDebug(data) {
26271
26589
  const userEvent = new UserEvent();
26272
- userEvent.eventType = UserEventTypes.DEBUG_DATA;
26590
+ userEvent.type = UserEventTypes.DEBUG_DATA;
26273
26591
  userEvent.content = this.convertObjectToString(data);
26274
26592
  return this.save(userEvent);
26275
26593
  }
26276
26594
  asFilter(filter) {
26277
26595
  return UserEventFilter.fromObject(filter);
26278
26596
  }
26597
+ fromObject(source) {
26598
+ return UserEvent.fromObject(source);
26599
+ }
26279
26600
  /* -- protected methods -- */
26280
26601
  convertObjectToString(data) {
26281
26602
  if (typeof data === 'string') {
@@ -26304,13 +26625,9 @@ class UserEventService extends BaseGraphqlService {
26304
26625
  // TODO: compute sign
26305
26626
  console.warn('TODO: sign user event before sending');
26306
26627
  }
26307
- copyIdAndUpdateDate(source, target) {
26308
- EntityUtils.copyIdAndUpdateDate(source, target);
26309
- }
26310
26628
  }
26311
- 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" });
26312
26629
  UserEventService.decorators = [
26313
- { type: Injectable, args: [{ providedIn: 'root' },] }
26630
+ { type: Injectable }
26314
26631
  ];
26315
26632
  UserEventService.ctorParameters = () => [
26316
26633
  { type: GraphqlService },
@@ -26323,7 +26640,7 @@ UserEventService.ctorParameters = () => [
26323
26640
 
26324
26641
  const ICONS_MAP = {
26325
26642
  DEBUG_DATA: { matIcon: 'bug_report' },
26326
- INBOX_MESSAGE: { matIcon: 'mail' },
26643
+ INBOX_MESSAGE: { matIcon: 'mail' }
26327
26644
  };
26328
26645
  // TODO: refactor with a registration done by data service:
26329
26646
  // - userEventService.registerEventAction({__typename: 'TripVO', ...})
@@ -26389,7 +26706,7 @@ class UserEventsTable extends AppTable {
26389
26706
  }
26390
26707
  }));
26391
26708
  const filter = this.filter || new UserEventFilter();
26392
- filter.recipient = this.recipient;
26709
+ filter.recipients = [this.recipient];
26393
26710
  this.setFilter(filter, { emitEvent: true });
26394
26711
  }
26395
26712
  start() {
@@ -26402,17 +26719,17 @@ class UserEventsTable extends AppTable {
26402
26719
  });
26403
26720
  }
26404
26721
  getIcon(source) {
26405
- return ICONS_MAP[source.eventType];
26722
+ return ICONS_MAP[source.type];
26406
26723
  }
26407
26724
  getDetail(source) {
26408
26725
  if (!source)
26409
26726
  return undefined;
26410
- if (source.content && source.eventType === UserEventTypes.DEBUG_DATA) {
26727
+ if (source.content && source.type === UserEventTypes.DEBUG_DATA) {
26411
26728
  const context = source.content.context;
26412
26729
  if (context && context.__typename) {
26413
- const actions = this.service.getActionsByTypename(context.__typename);
26730
+ // const actions = this.service.getActionsByTypename(context.__typename);
26414
26731
  return {
26415
- actions,
26732
+ // actions,
26416
26733
  title: source.content.error && source.content.error.message || source.content.message,
26417
26734
  description: source.content.error && source.content.error.details || undefined
26418
26735
  };
@@ -26424,11 +26741,11 @@ class UserEventsTable extends AppTable {
26424
26741
  doAction(action, row) {
26425
26742
  return __awaiter(this, void 0, void 0, function* () {
26426
26743
  const event = row.currentData;
26427
- const context = event.content && event.content.context;
26744
+ // const context = event.content && event.content.context;
26428
26745
  this.markAsLoading();
26429
26746
  if (action && typeof action.executeAction === 'function') {
26430
26747
  try {
26431
- let res = action.executeAction(event, context);
26748
+ let res = action.executeAction(event /*, context*/);
26432
26749
  res = (res instanceof Promise) ? yield res : res;
26433
26750
  }
26434
26751
  catch (err) {
@@ -26445,15 +26762,20 @@ class UserEventsTable extends AppTable {
26445
26762
  UserEventsTable.decorators = [
26446
26763
  { type: Component, args: [{
26447
26764
  selector: 'app-user-events-table',
26448
- 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",
26449
26766
  changeDetection: ChangeDetectionStrategy.OnPush,
26767
+ providers: [
26768
+ {
26769
+ provide: UserEventServiceToken, useClass: UserEventService
26770
+ }
26771
+ ],
26450
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}"]
26451
26773
  },] }
26452
26774
  ];
26453
26775
  UserEventsTable.ctorParameters = () => [
26454
26776
  { type: Injector },
26455
26777
  { type: AccountService },
26456
- { type: UserEventService },
26778
+ { type: undefined, decorators: [{ type: Inject, args: [UserEventServiceToken,] }] },
26457
26779
  { type: EntitiesStorage },
26458
26780
  { type: ChangeDetectorRef },
26459
26781
  { type: undefined, decorators: [{ type: Inject, args: [ENVIRONMENT,] }] }
@@ -26465,6 +26787,248 @@ UserEventsTable.propDecorators = {
26465
26787
  defaultSortDirection: [{ type: Input }]
26466
26788
  };
26467
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
+
26468
27032
  const MessageTypes = {
26469
27033
  INBOX_MESSAGE: 'INBOX_MESSAGE',
26470
27034
  EMAIL: 'EMAIL',
@@ -26676,9 +27240,9 @@ MessageForm.propDecorators = {
26676
27240
  canSelectType: [{ type: Input }]
26677
27241
  };
26678
27242
 
26679
- class SocialModule {
27243
+ class MessageModule {
26680
27244
  }
26681
- SocialModule.decorators = [
27245
+ MessageModule.decorators = [
26682
27246
  { type: NgModule, args: [{
26683
27247
  imports: [
26684
27248
  CommonModule,
@@ -26686,17 +27250,327 @@ SocialModule.decorators = [
26686
27250
  SharedModule
26687
27251
  ],
26688
27252
  declarations: [
26689
- UserEventsTable,
26690
27253
  MessageModal,
26691
27254
  MessageForm
26692
27255
  ],
26693
27256
  exports: [
26694
- UserEventsTable,
26695
27257
  MessageModal
26696
27258
  ]
26697
27259
  },] }
26698
27260
  ];
26699
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
+
26700
27574
  const Mutations = {
26701
27575
  send: gql `mutation SendMessage($data: MessageVOInput){
26702
27576
  done: sendMessage(message: $data)
@@ -27511,13 +28385,13 @@ LatLongTestPage.ctorParameters = () => [
27511
28385
  { type: FormBuilder }
27512
28386
  ];
27513
28387
 
27514
- const moment$6 = momentImported;
28388
+ const moment$7 = momentImported;
27515
28389
  class SwipeTestPage {
27516
28390
  constructor(formBuilder, dateFormatPipe) {
27517
28391
  this.formBuilder = formBuilder;
27518
28392
  this.dateFormatPipe = dateFormatPipe;
27519
28393
  this.$dates = new BehaviorSubject(undefined);
27520
- this._today = moment$6().startOf('day');
28394
+ this._today = moment$7().startOf('day');
27521
28395
  this.form = formBuilder.group({
27522
28396
  empty: [null, Validators.required],
27523
28397
  date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
@@ -27530,7 +28404,7 @@ class SwipeTestPage {
27530
28404
  ngOnInit() {
27531
28405
  const dates = [];
27532
28406
  for (let d = 0; d < 7; d++) {
27533
- dates[d] = moment$6(this._today).add(d - 3, 'day');
28407
+ dates[d] = moment$7(this._today).add(d - 3, 'day');
27534
28408
  }
27535
28409
  this.$dates.next(dates);
27536
28410
  this.loadData();
@@ -27571,7 +28445,7 @@ SwipeTestPage.ctorParameters = () => [
27571
28445
  { type: DateFormatPipe }
27572
28446
  ];
27573
28447
 
27574
- const moment$7 = momentImported;
28448
+ const moment$8 = momentImported;
27575
28449
  class DateTimeTestPage {
27576
28450
  constructor(platform, formBuilder, cd) {
27577
28451
  this.platform = platform;
@@ -27603,7 +28477,7 @@ class DateTimeTestPage {
27603
28477
  // Load the form with data
27604
28478
  loadData() {
27605
28479
  return __awaiter(this, void 0, void 0, function* () {
27606
- const now = moment$7();
28480
+ const now = moment$8();
27607
28481
  const data = {
27608
28482
  empty: null,
27609
28483
  emptyRequired: null,
@@ -27849,7 +28723,7 @@ NumpadTestPage.ctorParameters = () => [
27849
28723
  { type: FormBuilder }
27850
28724
  ];
27851
28725
 
27852
- const moment$8 = momentImported;
28726
+ const moment$9 = momentImported;
27853
28727
  class DateTestPage {
27854
28728
  constructor(formBuilder, cd) {
27855
28729
  this.formBuilder = formBuilder;
@@ -27882,7 +28756,7 @@ class DateTestPage {
27882
28756
  // Load the form with data
27883
28757
  loadData() {
27884
28758
  return __awaiter(this, void 0, void 0, function* () {
27885
- const now = moment$8();
28759
+ const now = moment$9();
27886
28760
  const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
27887
28761
  const data = {
27888
28762
  empty: null,
@@ -28628,5 +29502,5 @@ CoreTestingModule.decorators = [
28628
29502
  * Generated bundle index. Do not edit.
28629
29503
  */
28630
29504
 
28631
- 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 };
28632
29506
  //# sourceMappingURL=sumaris-net.ngx-components.js.map