@sumaris-net/ngx-components 1.21.0-beta2 → 1.21.0-beta20

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 (26) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +459 -152
  2. package/bundles/sumaris-net.ngx-components.umd.js.map +1 -1
  3. package/bundles/sumaris-net.ngx-components.umd.min.js +1 -1
  4. package/bundles/sumaris-net.ngx-components.umd.min.js.map +1 -1
  5. package/esm2015/src/app/core/menu/menu.component.js +2 -9
  6. package/esm2015/src/app/social/job/job.service.js +1 -2
  7. package/esm2015/src/app/social/user-event/notification/user-event-notification.component.js +23 -31
  8. package/esm2015/src/app/social/user-event/notification/user-event-notification.list.js +47 -8
  9. package/esm2015/src/app/social/user-event/testing/user-event.testing.service.js +73 -0
  10. package/esm2015/src/app/social/user-event/user-event.model.js +1 -1
  11. package/esm2015/src/app/social/user-event/user-event.module.js +6 -1
  12. package/esm2015/src/app/social/user-event/user-event.service.js +182 -59
  13. package/esm2015/sumaris-net.ngx-components.js +8 -7
  14. package/fesm2015/sumaris-net.ngx-components.js +309 -99
  15. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  16. package/package.json +1 -1
  17. package/src/app/social/user-event/notification/user-event-notification.component.d.ts +5 -8
  18. package/src/app/social/user-event/notification/user-event-notification.list.d.ts +18 -8
  19. package/src/app/social/user-event/testing/user-event.testing.service.d.ts +35 -0
  20. package/src/app/social/user-event/user-event.model.d.ts +1 -1
  21. package/src/app/social/user-event/user-event.service.d.ts +26 -10
  22. package/src/assets/i18n/en.json +2 -1
  23. package/src/assets/i18n/fr.json +2 -1
  24. package/src/theme/_ngx-components.scss +1 -0
  25. package/sumaris-net.ngx-components.d.ts +7 -6
  26. package/sumaris-net.ngx-components.metadata.json +1 -1
@@ -21172,9 +21172,6 @@ class MenuComponent {
21172
21172
  this._subscription = new Subscription();
21173
21173
  this.loading = true;
21174
21174
  this.isLogin = false;
21175
- // showUserEventNotification: boolean;
21176
- // showJobProgression: boolean;
21177
- // jobProgressionOptions: JobProgressionOptions;
21178
21175
  this.$items = new BehaviorSubject(undefined);
21179
21176
  this.id = 'menu';
21180
21177
  this.menuId = 'left';
@@ -21188,10 +21185,6 @@ class MenuComponent {
21188
21185
  this.splitPane.when = yield firstNotNilPromise(this.menuService.splitPaneWhen);
21189
21186
  // Wait platform started
21190
21187
  yield this.platformService.ready();
21191
- // Init social options
21192
- // this.showUserEventNotification = toBoolean(this.socialModuleOptions?.showUserEventNotification, false);
21193
- // this.showJobProgression = toBoolean(this.socialModuleOptions?.showJobProgression, false);
21194
- // this.jobProgressionOptions = this.socialModuleOptions?.jobProgressionOptions;
21195
21188
  // Listen to menu service event
21196
21189
  this.menuService.splitPaneWhen
21197
21190
  .subscribe((value) => this.setSplitPaneWhen(value));
@@ -21438,7 +21431,7 @@ class MenuComponent {
21438
21431
  MenuComponent.decorators = [
21439
21432
  { type: Component, args: [{
21440
21433
  selector: 'app-menu',
21441
- 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",
21434
+ 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",
21442
21435
  animations: [fadeInAnimation],
21443
21436
  changeDetection: ChangeDetectionStrategy.OnPush,
21444
21437
  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)}}"]
@@ -25959,13 +25952,12 @@ const UserEventFragments = {
25959
25952
  const moment$6 = momentImported;
25960
25953
  const UserEventServiceToken = new InjectionToken('UserEventService');
25961
25954
  class AbstractUserEventService extends BaseGraphqlService {
25962
- constructor(graphql, accountService, network, translate, toastController, queries, mutations, subscriptions, environment) {
25955
+ constructor(graphql, accountService, network, translate, queries, mutations, subscriptions, environment) {
25963
25956
  super(graphql, environment);
25964
25957
  this.graphql = graphql;
25965
25958
  this.accountService = accountService;
25966
25959
  this.network = network;
25967
25960
  this.translate = translate;
25968
- this.toastController = toastController;
25969
25961
  this.queries = queries;
25970
25962
  this.mutations = mutations;
25971
25963
  this.subscriptions = subscriptions;
@@ -25976,18 +25968,32 @@ class AbstractUserEventService extends BaseGraphqlService {
25976
25968
  this._logPrefix = '[user-event-service] ';
25977
25969
  // For DEV only
25978
25970
  this._debug = !(environment === null || environment === void 0 ? void 0 : environment.production);
25979
- // listen login/logout
25980
- this._subscriptions.add(accountService.onLogin.subscribe(() => __awaiter(this, void 0, void 0, function* () {
25981
- const count = yield this.count(this.defaultFilter());
25982
- if (count && this._debug) {
25983
- console.debug(`${this._logPrefix}Received ${count} unread notifications`);
25984
- }
25985
- this._count$.next(count);
25986
- })));
25987
25971
  }
25988
25972
  get userEventCount() {
25989
25973
  return this._count$.asObservable();
25990
25974
  }
25975
+ ngOnStart() {
25976
+ return __awaiter(this, void 0, void 0, function* () {
25977
+ // Update component when refresh is need (=login events)
25978
+ this._subscriptions.add(merge(this.accountService.onLogin, this.accountService.onLogout)
25979
+ .pipe(
25980
+ // Wait account service ready (can be restarted)
25981
+ mergeMap(() => this.accountService.ready()), map(() => this.accountService.isLogin()), distinctUntilChanged())
25982
+ .subscribe(login => {
25983
+ if (login) {
25984
+ this.onLogin();
25985
+ }
25986
+ else {
25987
+ this.onLogout();
25988
+ }
25989
+ }));
25990
+ // First attempt if account is ready
25991
+ yield this.accountService.ready();
25992
+ if (this.accountService.isLogin()) {
25993
+ setTimeout(() => this.onLogin());
25994
+ }
25995
+ });
25996
+ }
25991
25997
  ngOnDestroy() {
25992
25998
  this._subscriptions.unsubscribe();
25993
25999
  }
@@ -25997,13 +26003,15 @@ class AbstractUserEventService extends BaseGraphqlService {
25997
26003
  watchPage(page, filter, options) {
25998
26004
  var _a;
25999
26005
  let now = this._debug && Date.now();
26000
- //if (this._debug)
26006
+ if (!filter) {
26007
+ filter = this.defaultFilter();
26008
+ }
26001
26009
  console.debug(`${this._logPrefix}Loading user events...`, filter);
26002
26010
  filter = this.asFilter(filter);
26003
26011
  // Force recipient to current issuer, if not admin and not specified
26004
- if (isEmptyArray(filter.recipients) || !this.accountService.isAdmin()) {
26012
+ if (isEmptyArray(filter === null || filter === void 0 ? void 0 : filter.recipients) || !this.accountService.isAdmin()) {
26005
26013
  const recipient = this.defaultRecipient();
26006
- if (!((_a = filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
26014
+ if (!((_a = filter === null || filter === void 0 ? void 0 : filter.recipients) === null || _a === void 0 ? void 0 : _a.includes(recipient))) {
26007
26015
  console.warn('[user-events-service] Force user event filter.recipient=' + recipient);
26008
26016
  filter.recipients = [recipient];
26009
26017
  }
@@ -26013,23 +26021,26 @@ class AbstractUserEventService extends BaseGraphqlService {
26013
26021
  queryName: withContent ? 'LoadAllWithContent' : 'LoadAll',
26014
26022
  query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26015
26023
  variables: {
26016
- page: Object.assign({ sortBy: 'updateDate', sortDirection: 'desc' }, page),
26024
+ page: Object.assign(Object.assign({ sortBy: 'creationDate' }, page), {
26025
+ // @ts-ignore
26026
+ sortDirection: (page.sortDirection || 'desc').toUpperCase() }),
26017
26027
  filter: filter && filter.asPodObject()
26018
26028
  },
26019
26029
  arrayFieldName: 'data',
26020
26030
  error: { code: SocialErrorCodes.LOAD_USER_EVENTS_ERROR, message: 'SOCIAL.ERROR.LOAD_USER_EVENTS_ERROR' },
26021
- fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || "cache-first"
26031
+ fetchPolicy: (options === null || options === void 0 ? void 0 : options.fetchPolicy) || 'cache-first'
26022
26032
  })
26023
26033
  .pipe(map(res => {
26024
- const data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(this.processUserEvent);
26034
+ let data = ((res === null || res === void 0 ? void 0 : res.data) || []).map(value => this.processUserEvent(value, this));
26025
26035
  if (now) {
26026
26036
  console.debug(`${this._logPrefix}${data.length} user events loaded in ${Date.now() - now}ms`);
26027
26037
  now = null;
26028
26038
  }
26029
- const unreadCount = this.unreadEvents(data);
26039
+ // Must re-order because of listenChanges result will add new event at the end
26040
+ data = EntityUtils.sort(data, page.sortBy, page.sortDirection);
26030
26041
  return {
26031
26042
  data,
26032
- total: toNumber(res === null || res === void 0 ? void 0 : res.total, unreadCount)
26043
+ total: toNumber(res === null || res === void 0 ? void 0 : res.total, data.length)
26033
26044
  };
26034
26045
  }));
26035
26046
  }
@@ -26053,7 +26064,7 @@ class AbstractUserEventService extends BaseGraphqlService {
26053
26064
  return undefined;
26054
26065
  }
26055
26066
  if (!filter)
26056
- throw new Error(`Missing argument 'filter'`);
26067
+ filter = this.defaultFilter();
26057
26068
  filter = this.asFilter(filter);
26058
26069
  if (this._debug)
26059
26070
  console.debug(`${this._logPrefix}Counting user events with filter:`, filter);
@@ -26068,6 +26079,32 @@ class AbstractUserEventService extends BaseGraphqlService {
26068
26079
  return res.total;
26069
26080
  });
26070
26081
  }
26082
+ listenCountChanges(filter, options) {
26083
+ if (!this.subscriptions.listenCountChanges) {
26084
+ console.warn(`${this._logPrefix}Subscription query 'listenCountChanges' not provided, skip.`);
26085
+ return of();
26086
+ }
26087
+ if (!filter)
26088
+ filter = this.defaultFilter();
26089
+ filter = this.asFilter(filter);
26090
+ if (this._debug)
26091
+ console.debug(`${this._logPrefix}[WS] Listening count changes for user events with filter:`, filter);
26092
+ return this.graphql.subscribe({
26093
+ query: this.subscriptions.listenCountChanges,
26094
+ fetchPolicy: options === null || options === void 0 ? void 0 : options.fetchPolicy,
26095
+ variables: { filter: filter.asPodObject(), interval: toNumber(options === null || options === void 0 ? void 0 : options.interval, 10) },
26096
+ error: {
26097
+ code: SocialErrorCodes.SUBSCRIBE_USER_EVENTS_ERROR,
26098
+ message: 'SOCIAL.ERROR.SUBSCRIBE_USER_EVENTS_ERROR'
26099
+ }
26100
+ }).pipe(map(({ total }) => {
26101
+ if (total && this._debug)
26102
+ console.debug(`${this._logPrefix}Received new user events count:`, total);
26103
+ // update count
26104
+ this._count$.next(total);
26105
+ return total;
26106
+ }));
26107
+ }
26071
26108
  listenChanges(filter, options) {
26072
26109
  var _a;
26073
26110
  if (!((_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.listenChanges)) {
@@ -26075,7 +26112,7 @@ class AbstractUserEventService extends BaseGraphqlService {
26075
26112
  return of();
26076
26113
  }
26077
26114
  if (!filter)
26078
- throw new Error(`Missing argument 'filter'`);
26115
+ filter = this.defaultFilter();
26079
26116
  filter = this.asFilter(filter);
26080
26117
  const withContent = (options === null || options === void 0 ? void 0 : options.withContent) === true;
26081
26118
  if (this._debug)
@@ -26091,14 +26128,12 @@ class AbstractUserEventService extends BaseGraphqlService {
26091
26128
  }).pipe(map(({ data }) => {
26092
26129
  if (data && this._debug)
26093
26130
  console.debug(`${this._logPrefix}Received new user events:`, data);
26094
- const updatedData = data === null || data === void 0 ? void 0 : data.map(this.processUserEvent);
26131
+ const updatedData = data === null || data === void 0 ? void 0 : data.map(value => this.processUserEvent(value, this));
26095
26132
  // Update cache
26096
26133
  this.insertIntoMutableCachedQueries(this.graphql.cache, {
26097
26134
  query: withContent ? this.queries.loadAllWithContent : this.queries.loadAll,
26098
26135
  data: updatedData
26099
26136
  });
26100
- // update count
26101
- this._count$.next(this.unreadEvents(updatedData));
26102
26137
  return updatedData;
26103
26138
  }));
26104
26139
  }
@@ -26141,9 +26176,15 @@ class AbstractUserEventService extends BaseGraphqlService {
26141
26176
  }
26142
26177
  save(entity, options) {
26143
26178
  return __awaiter(this, void 0, void 0, function* () {
26179
+ if (!this.mutations.save) {
26180
+ if (!this.mutations.saveAll)
26181
+ throw new Error('Not implemented');
26182
+ const allData = yield this.saveAll([entity], options);
26183
+ return allData === null || allData === void 0 ? void 0 : allData[0];
26184
+ }
26144
26185
  this.fillDefaultProperties(entity);
26145
26186
  // Transform into json
26146
- const isNew = isNil(entity.id);
26187
+ const withContent = !!entity.content;
26147
26188
  const json = entity.asObject();
26148
26189
  const now = Date.now();
26149
26190
  if (this._debug)
@@ -26162,39 +26203,87 @@ class AbstractUserEventService extends BaseGraphqlService {
26162
26203
  console.debug(`${this._logPrefix}User event saved in ${Date.now() - now}ms`, entity);
26163
26204
  this.copyIdAndUpdateDate(savedEntity, entity);
26164
26205
  // Add to cache
26165
- if (isNew) {
26166
- this.insertIntoMutableCachedQueries(proxy, {
26167
- query: this.queries.loadAll,
26168
- data: Object.assign(Object.assign({}, savedEntity), { content: null })
26169
- });
26206
+ if (withContent) {
26170
26207
  this.insertIntoMutableCachedQueries(proxy, {
26171
26208
  query: this.queries.loadAllWithContent,
26172
26209
  data: savedEntity
26173
26210
  });
26174
26211
  }
26212
+ else {
26213
+ this.insertIntoMutableCachedQueries(proxy, {
26214
+ query: this.queries.loadAll,
26215
+ data: Object.assign(Object.assign({}, savedEntity), { content: null })
26216
+ });
26217
+ }
26175
26218
  }
26176
26219
  }
26177
26220
  });
26178
26221
  return entity;
26179
26222
  });
26180
26223
  }
26181
- saveAll(data, opts) {
26182
- return Promise.all(data
26183
- .map(entity => this.save(entity, opts)));
26224
+ saveAll(entities, opts) {
26225
+ return __awaiter(this, void 0, void 0, function* () {
26226
+ if (isEmptyArray(entities))
26227
+ return entities;
26228
+ if (!this.mutations.saveAll) {
26229
+ if (!this.mutations.save)
26230
+ throw new Error('Not implemented');
26231
+ // Save one by one
26232
+ return chainPromises(entities.map((entity) => () => this.save(entity, opts)));
26233
+ }
26234
+ // Transform into json
26235
+ const json = entities.map(entity => {
26236
+ this.fillDefaultProperties(entity);
26237
+ return entity.asObject();
26238
+ });
26239
+ const now = Date.now();
26240
+ if (this._debug)
26241
+ console.debug(`${this._logPrefix}Saving user events...`, json);
26242
+ yield this.graphql.mutate({
26243
+ mutation: this.mutations.saveAll,
26244
+ variables: {
26245
+ data: json
26246
+ },
26247
+ error: { code: SocialErrorCodes.SAVE_USER_EVENT_ERROR, message: 'SOCIAL.ERROR.SAVE_USER_EVENT_ERROR' },
26248
+ update: (proxy, { data }) => {
26249
+ // Update entity
26250
+ const savedEntities = (data === null || data === void 0 ? void 0 : data.data) || [];
26251
+ if (savedEntities.length) {
26252
+ if (this._debug)
26253
+ console.debug(`${this._logPrefix}User events saved in ${Date.now() - now}ms`, savedEntities);
26254
+ entities.forEach(entity => {
26255
+ const savedEntity = savedEntities.find((e) => EntityUtils.equals(e, entity, 'id'));
26256
+ this.copyIdAndUpdateDate(savedEntity, entity);
26257
+ });
26258
+ // Add to cache (assuming all with content)
26259
+ this.insertIntoMutableCachedQueries(proxy, {
26260
+ query: this.queries.loadAllWithContent,
26261
+ data: savedEntities
26262
+ });
26263
+ }
26264
+ }
26265
+ });
26266
+ return entities;
26267
+ });
26184
26268
  }
26185
- markAsRead(entity) {
26269
+ markAsRead(entities) {
26186
26270
  return __awaiter(this, void 0, void 0, function* () {
26187
- // Get onRead listeners
26188
- const onReadListeners = (this.listeners || []).filter(listener => !!listener.onRead).filter(listener => listener.accept(entity));
26189
- if (onReadListeners.length) {
26190
- for (const listener of onReadListeners) {
26191
- yield listener.onRead(entity);
26271
+ const userEventWithoutReadListeners = [];
26272
+ for (const entity of (entities || [])) {
26273
+ // Get onRead listeners
26274
+ const onReadListeners = (this.listeners || []).filter(listener => !!listener.onRead).filter(listener => listener.accept(entity));
26275
+ if (onReadListeners.length) {
26276
+ for (const listener of onReadListeners) {
26277
+ yield listener.onRead(entity);
26278
+ }
26279
+ }
26280
+ else {
26281
+ // Add to this list for default operation
26282
+ userEventWithoutReadListeners.push(entity);
26192
26283
  }
26193
26284
  }
26194
- else {
26195
- // Use default
26196
- yield this.defaultMarkAsRead(entity);
26197
- }
26285
+ // Use default
26286
+ yield this.defaultMarkAsRead(userEventWithoutReadListeners);
26198
26287
  });
26199
26288
  }
26200
26289
  registerListener(listener) {
@@ -26202,37 +26291,64 @@ class AbstractUserEventService extends BaseGraphqlService {
26202
26291
  this.listeners = [];
26203
26292
  this.listeners.push(listener);
26204
26293
  }
26294
+ resetCount() {
26295
+ this._count$.next(undefined);
26296
+ }
26205
26297
  /* -- protected methods -- */
26206
- processUserEvent(source) {
26298
+ onLogin() {
26299
+ return __awaiter(this, void 0, void 0, function* () {
26300
+ // Get first count
26301
+ const count = yield this.count(undefined);
26302
+ if (this._debug)
26303
+ console.debug(`${this._logPrefix}Receiving user events count`, count);
26304
+ // Update count
26305
+ this._count$.next(count);
26306
+ // Then listen changes
26307
+ this._listenSubscription = this.listenCountChanges(undefined).subscribe();
26308
+ });
26309
+ }
26310
+ onLogout() {
26311
+ var _a;
26312
+ (_a = this._listenSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
26313
+ }
26314
+ processUserEvent(source, that) {
26315
+ that = that || this;
26207
26316
  // Convert json source to IUserEvent
26208
- let target = this.fromObject(source);
26317
+ let target = that.fromObject(source);
26209
26318
  // Get listeners
26210
- const listeners = (this.listeners || []).filter(listener => listener.onReceived).filter(listener => listener.accept(target));
26319
+ const listeners = (that.listeners || []).filter(listener => listener.onReceived).filter(listener => listener.accept(target));
26211
26320
  for (const listener of listeners) {
26212
26321
  if (target) {
26213
26322
  target = listener.onReceived(target);
26214
26323
  }
26215
26324
  else {
26216
- if (this._debug)
26217
- console.debug(`${this._logPrefix}Event has been rejected by a listener`, source);
26325
+ if (that._debug)
26326
+ console.debug(`${that._logPrefix}Event has been rejected by a listener`, source);
26218
26327
  break;
26219
26328
  }
26220
26329
  }
26221
26330
  return target;
26222
26331
  }
26223
- defaultMarkAsRead(userEvent) {
26332
+ defaultMarkAsRead(userEvents) {
26224
26333
  return __awaiter(this, void 0, void 0, function* () {
26225
- if (!userEvent)
26334
+ if (!userEvents)
26226
26335
  throw new Error(`${this._logPrefix}Invalid event to save`);
26336
+ if (!userEvents.length)
26337
+ return;
26227
26338
  // set read date
26228
- userEvent.readDate = moment$6();
26229
- if (!userEvent.id || userEvent.id < 0) {
26339
+ userEvents.forEach(userEvent => userEvent.readDate = moment$6());
26340
+ // split local/remote entities
26341
+ const localEntities = userEvents.filter(userEvent => !userEvent.id || userEvent.id < 0);
26342
+ const remoteEntities = userEvents.filter(userEvent => userEvent.id > 0);
26343
+ // save local entities
26344
+ if (localEntities.length) {
26230
26345
  if (this._debug)
26231
26346
  console.debug(`${this._logPrefix}Save local user event`);
26232
26347
  // TODO !!!!!!!!!!!!!
26233
26348
  }
26234
- else {
26235
- yield this.save(userEvent);
26349
+ // save remote entities
26350
+ if (remoteEntities.length) {
26351
+ yield this.saveAll(remoteEntities);
26236
26352
  }
26237
26353
  });
26238
26354
  }
@@ -26269,7 +26385,6 @@ AbstractUserEventService.ctorParameters = () => [
26269
26385
  { type: AccountService },
26270
26386
  { type: NetworkService },
26271
26387
  { type: TranslateService },
26272
- { type: ToastController },
26273
26388
  { type: undefined },
26274
26389
  { type: undefined },
26275
26390
  { type: undefined },
@@ -26310,7 +26425,7 @@ const userEventMutations = {
26310
26425
  };
26311
26426
  class UserEventService extends AbstractUserEventService {
26312
26427
  constructor(graphql, accountService, network, translate, toastController, environment) {
26313
- super(graphql, accountService, network, translate, toastController, userEventQueries, userEventMutations, undefined, environment);
26428
+ super(graphql, accountService, network, translate, userEventQueries, userEventMutations, undefined, environment);
26314
26429
  this.graphql = graphql;
26315
26430
  this.accountService = accountService;
26316
26431
  this.network = network;
@@ -26581,17 +26696,47 @@ UserEventsTable.propDecorators = {
26581
26696
  };
26582
26697
 
26583
26698
  class UserEventNotificationList {
26584
- constructor(popoverController) {
26699
+ constructor(cd, popoverController, userEventService) {
26700
+ this.cd = cd;
26585
26701
  this.popoverController = popoverController;
26702
+ this.userEventService = userEventService;
26703
+ this.debug = false;
26704
+ this.userEvents = new BehaviorSubject(undefined);
26705
+ this.subscriptions = new Subscription();
26586
26706
  }
26587
26707
  ngOnInit() {
26708
+ // Watch all user events
26709
+ this.subscriptions.add(this.userEventService
26710
+ .watchAll(0, 10, 'creationDate', "desc", undefined)
26711
+ .subscribe(result => {
26712
+ if (this.debug)
26713
+ console.debug(`[user-event-notification-list] receiving ${result.total} user events`, result.data);
26714
+ this.userEvents.next(result.data);
26715
+ this.markForCheck();
26716
+ }));
26717
+ // Listen changes
26718
+ this.subscriptions.add(this.userEventService.listenChanges(undefined)
26719
+ .subscribe(data => {
26720
+ if (this.debug)
26721
+ console.debug(`[user-event-notification-list] receiving ${data.length} new user events`, data);
26722
+ }));
26723
+ }
26724
+ ngOnDestroy() {
26725
+ this.subscriptions.unsubscribe();
26588
26726
  }
26589
- read($event, userEvent) {
26727
+ read(event, userEvent) {
26590
26728
  var _a;
26591
26729
  if (userEvent === null || userEvent === void 0 ? void 0 : userEvent.readDate)
26592
26730
  return;
26593
26731
  (_a = this.readEvent) === null || _a === void 0 ? void 0 : _a.emit(userEvent);
26594
26732
  }
26733
+ readAll(event) {
26734
+ var _a;
26735
+ const unreadUserEvents = (this.userEvents.value || []).filter(value => !value.readDate);
26736
+ if (!unreadUserEvents.length)
26737
+ return;
26738
+ (_a = this.readEvents) === null || _a === void 0 ? void 0 : _a.emit(unreadUserEvents);
26739
+ }
26595
26740
  executeAction(action, userEvent) {
26596
26741
  // Execute then close popover
26597
26742
  action.executeAction(userEvent);
@@ -26600,69 +26745,74 @@ class UserEventNotificationList {
26600
26745
  dismiss() {
26601
26746
  this.popoverController.dismiss();
26602
26747
  }
26748
+ markForCheck() {
26749
+ this.cd.markForCheck();
26750
+ }
26603
26751
  }
26604
26752
  UserEventNotificationList.decorators = [
26605
26753
  { type: Component, args: [{
26606
26754
  selector: 'app-user-event-notification-list',
26607
- template: "\n<ion-list class=\"ion-list-popover\">\n\n <ion-row class=\"ion-list-header column\">\n <ion-col>\n <ion-label>{{titleI18n | translate}}</ion-label>\n </ion-col>\n </ion-row>\n\n <ion-item *ngIf=\"!(userEvents | async)?.length\">\n {{'SOCIAL.USER_EVENT.NOTIFICATION.EMPTY' | translate}}\n </ion-item>\n <ion-item\n *ngFor=\"let userEvent of userEvents | async\"\n (click)=\"read($event, userEvent)\"\n >\n\n <ion-avatar slot=\"start\">\n\n <img *ngIf=\"userEvent.avatar; else avatarIcon\" src=\"{{ userEvent.avatar }}\">\n\n <ng-template #avatarIcon>\n <app-icon\n *ngIf=\"userEvent.avatarIcon\"\n [ref]=\"userEvent.avatarIcon\"\n height=\"40\"\n width=\"40\"\n ></app-icon>\n </ng-template>\n\n </ion-avatar>\n\n <ion-grid class=\"ion-no-margin ion-no-padding\">\n <ion-row>\n <ion-col>\n <p [class.unread]=\"!userEvent.readDate\">\n {{userEvent.message}}\n </p>\n </ion-col>\n </ion-row>\n <ion-row *ngIf=\"userEvent.actions?.length\">\n <ion-col>\n <p>\n <span *ngFor=\"let action of userEvent.actions\">\n <a\n [style.margin-right.px]=\"8\"\n [style.cursor]=\"'pointer'\"\n (click)=\"executeAction(action, userEvent)\"\n >\n {{ '&#10142;&nbsp;' + action.name}}\n </a>\n </span>\n </p>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <app-icon\n *ngIf=\"userEvent.icon\"\n [ref]=\"userEvent.icon\"\n height=\"16\"\n width=\"16\"\n [style.vertical-align]=\"'sub'\"\n ></app-icon>\n <small>\n <span>{{userEvent.creationDate|dateFromNow}}</span>\n <span [style.color]=\"'gray'\">{{ ' | ' + (userEvent.creationDate|dateFormat:{time:true}) }}</span>\n </small>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-item>\n\n</ion-list>\n",
26755
+ template: "\n<ion-list class=\"ion-list-popover\">\n\n <ion-row class=\"ion-list-header column\">\n <ion-col>\n <ion-label>{{titleI18n | translate}}</ion-label>\n </ion-col>\n </ion-row>\n\n <ion-item *ngIf=\"!(userEvents | async)?.length\">\n {{'SOCIAL.USER_EVENT.NOTIFICATION.EMPTY' | translate}}\n </ion-item>\n <ion-item\n *ngFor=\"let userEvent of userEvents | async\"\n (click)=\"read($event, userEvent)\"\n >\n\n <ion-avatar slot=\"start\">\n\n <img *ngIf=\"userEvent.avatar; else avatarIcon\" src=\"{{ userEvent.avatar }}\">\n\n <ng-template #avatarIcon>\n <app-icon\n *ngIf=\"userEvent.avatarIcon\"\n [ref]=\"userEvent.avatarIcon\"\n height=\"40\"\n width=\"40\"\n ></app-icon>\n </ng-template>\n\n </ion-avatar>\n\n <ion-grid class=\"ion-no-margin ion-no-padding\">\n <ion-row>\n <ion-col>\n <p [class.unread]=\"!userEvent.readDate\">\n {{userEvent.message}}\n </p>\n </ion-col>\n </ion-row>\n <ion-row *ngIf=\"userEvent.actions?.length\">\n <ion-col>\n <p>\n <span *ngFor=\"let action of userEvent.actions\">\n <a\n [style.margin-right.px]=\"8\"\n [style.cursor]=\"'pointer'\"\n (click)=\"executeAction(action, userEvent)\"\n >\n {{ '&#10142;&nbsp;' + action.name}}\n </a>\n </span>\n </p>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <app-icon\n *ngIf=\"userEvent.icon\"\n [ref]=\"userEvent.icon\"\n height=\"16\"\n width=\"16\"\n [style.vertical-align]=\"'sub'\"\n ></app-icon>\n <small>\n <span>{{userEvent.creationDate|dateFromNow}}</span>\n <span [style.color]=\"'gray'\">{{ ' | ' + (userEvent.creationDate|dateFormat:{time:true}) }}</span>\n </small>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-item>\n\n <ion-row class=\"ion-list-footer column\">\n <ion-col>\n <a style=\"cursor: pointer\" (click)=\"readAll($event)\">{{'SOCIAL.USER_EVENT.NOTIFICATION.READ_ALL' | translate}}</a>\n </ion-col>\n </ion-row>\n\n</ion-list>\n",
26756
+ changeDetection: ChangeDetectionStrategy.OnPush,
26608
26757
  styles: [":host(.popover-viewport){overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.unread{font-weight:700}"]
26609
26758
  },] }
26610
26759
  ];
26611
26760
  UserEventNotificationList.ctorParameters = () => [
26612
- { type: PopoverController }
26761
+ { type: ChangeDetectorRef },
26762
+ { type: PopoverController },
26763
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [UserEventServiceToken,] }] }
26613
26764
  ];
26614
26765
  UserEventNotificationList.propDecorators = {
26766
+ debug: [{ type: Input }],
26615
26767
  titleI18n: [{ type: Input }],
26616
- userEvents: [{ type: Input }],
26617
- readEvent: [{ type: Output }]
26768
+ readEvent: [{ type: Output }],
26769
+ readEvents: [{ type: Output }]
26618
26770
  };
26619
26771
 
26620
26772
  class UserEventNotificationComponent {
26621
- constructor(userEventService, accountService, popoverController, cd) {
26773
+ constructor(userEventService, accountService, popoverController) {
26622
26774
  this.userEventService = userEventService;
26623
26775
  this.accountService = accountService;
26624
26776
  this.popoverController = popoverController;
26625
- this.cd = cd;
26626
26777
  this.debug = false;
26627
26778
  this.titleI18n = 'SOCIAL.USER_EVENT.NOTIFICATION.TITLE';
26628
26779
  this.disabled = false;
26629
- this.userEventsSubject = new BehaviorSubject(undefined);
26630
- this._subscriptions = new Subscription();
26631
26780
  this._logPrefix = '[user-event-notification] ';
26632
26781
  this._readEvent = new EventEmitter();
26782
+ this._readEvents = new EventEmitter();
26633
26783
  }
26634
26784
  get count() {
26635
26785
  var _a;
26636
26786
  return (_a = this.userEventService) === null || _a === void 0 ? void 0 : _a.userEventCount.pipe(map(value => value === 0 ? undefined : value));
26637
26787
  }
26638
26788
  ngOnInit() {
26639
- var _a;
26640
- if (isNil(this.userEventService)) {
26641
- console.warn(`${this._logPrefix}No service injected`);
26642
- this.disabled = true;
26643
- return;
26644
- }
26645
- this._subscriptions.add(this.userEventService.watchAll(0, 10, 'creationDate', "desc", {
26646
- recipients: [(_a = this.accountService.person) === null || _a === void 0 ? void 0 : _a.pubkey]
26647
- }).subscribe(value => {
26648
- const data = value.data;
26649
- if (this.debug) {
26650
- console.debug(`${this._logPrefix}Receiving user events`, data);
26789
+ return __awaiter(this, void 0, void 0, function* () {
26790
+ if (isNil(this.userEventService)) {
26791
+ console.warn(`${this._logPrefix}No service injected`);
26792
+ this.disabled = true;
26793
+ return;
26651
26794
  }
26652
- this.userEventsSubject.next(data);
26653
- }));
26654
- this._readEvent.subscribe(value => {
26655
- this.userEventService.markAsRead(value);
26795
+ // Subscribe to read event
26796
+ this._readEvent.subscribe(value => {
26797
+ // default: mark event as read
26798
+ this.userEventService.markAsRead([value]);
26799
+ });
26800
+ this._readEvents.subscribe(value => {
26801
+ this.userEventService.markAsRead(value);
26802
+ });
26656
26803
  });
26657
26804
  }
26658
26805
  showList(event) {
26659
26806
  return __awaiter(this, void 0, void 0, function* () {
26807
+ // Reset count
26808
+ this.userEventService.resetCount();
26660
26809
  const popover = yield this.popoverController.create({
26661
26810
  component: UserEventNotificationList,
26662
26811
  componentProps: {
26812
+ debug: this.debug,
26663
26813
  titleI18n: this.titleI18n,
26664
- userEvents: this.userEventsSubject,
26665
- readEvent: this._readEvent
26814
+ readEvent: this._readEvent,
26815
+ readEvents: this._readEvents
26666
26816
  },
26667
26817
  backdropDismiss: true,
26668
26818
  keyboardClose: true,
@@ -26673,14 +26823,10 @@ class UserEventNotificationComponent {
26673
26823
  yield popover.present();
26674
26824
  });
26675
26825
  }
26676
- markForCheck() {
26677
- this.cd.markForCheck();
26678
- }
26679
26826
  ngOnDestroy() {
26680
26827
  if (this.debug) {
26681
26828
  console.debug(`${this._logPrefix}Destroying`);
26682
26829
  }
26683
- this._subscriptions.unsubscribe();
26684
26830
  }
26685
26831
  }
26686
26832
  UserEventNotificationComponent.decorators = [
@@ -26694,8 +26840,7 @@ UserEventNotificationComponent.decorators = [
26694
26840
  UserEventNotificationComponent.ctorParameters = () => [
26695
26841
  { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [UserEventServiceToken,] }] },
26696
26842
  { type: AccountService },
26697
- { type: PopoverController },
26698
- { type: ChangeDetectorRef }
26843
+ { type: PopoverController }
26699
26844
  ];
26700
26845
  UserEventNotificationComponent.propDecorators = {
26701
26846
  debug: [{ type: Input }],
@@ -26703,6 +26848,69 @@ UserEventNotificationComponent.propDecorators = {
26703
26848
  disabled: [{ type: Input }]
26704
26849
  };
26705
26850
 
26851
+ class UserEventTestService extends AbstractUserEventService {
26852
+ constructor(graphql, accountService, network, translate, environment) {
26853
+ super(graphql, accountService, network, translate, undefined, undefined, undefined, environment);
26854
+ this.graphql = graphql;
26855
+ this.accountService = accountService;
26856
+ this.network = network;
26857
+ this.translate = translate;
26858
+ this.environment = environment;
26859
+ this.userEvents = [];
26860
+ }
26861
+ fromObject(source) {
26862
+ return UserEvent.fromObject(source);
26863
+ }
26864
+ add(entity) {
26865
+ entity = this.processUserEvent(entity);
26866
+ entity.id = this.userEvents.length + 1;
26867
+ this.userEvents.push(entity);
26868
+ this._count$.next(this.userEvents.length);
26869
+ }
26870
+ asFilter(filter) {
26871
+ return filter;
26872
+ }
26873
+ count(filter, options) {
26874
+ return Promise.resolve(this.userEvents.length);
26875
+ }
26876
+ delete(entity) {
26877
+ return Promise.resolve(undefined);
26878
+ }
26879
+ deleteAll(data, opts) {
26880
+ return Promise.resolve(undefined);
26881
+ }
26882
+ listenChanges(filter, options) {
26883
+ return of();
26884
+ }
26885
+ save(entity, options) {
26886
+ var _a;
26887
+ 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));
26888
+ Object.assign(toSave, entity);
26889
+ return entity;
26890
+ }
26891
+ saveAll(data, opts) {
26892
+ return __awaiter(this, void 0, void 0, function* () {
26893
+ for (const entity of (data || [])) {
26894
+ yield this.save(entity);
26895
+ }
26896
+ return Promise.resolve(this.userEvents);
26897
+ });
26898
+ }
26899
+ watchAll(offset, size, sortBy, sortDirection, filter, options) {
26900
+ return of({ data: this.userEvents });
26901
+ }
26902
+ }
26903
+ UserEventTestService.decorators = [
26904
+ { type: Injectable }
26905
+ ];
26906
+ UserEventTestService.ctorParameters = () => [
26907
+ { type: GraphqlService },
26908
+ { type: AccountService },
26909
+ { type: NetworkService },
26910
+ { type: TranslateService },
26911
+ { type: Environment, decorators: [{ type: Optional }, { type: Inject, args: [ENVIRONMENT,] }] }
26912
+ ];
26913
+
26706
26914
  class UserEventModule {
26707
26915
  }
26708
26916
  UserEventModule.decorators = [
@@ -26720,6 +26928,9 @@ UserEventModule.decorators = [
26720
26928
  exports: [
26721
26929
  UserEventsTable,
26722
26930
  UserEventNotificationComponent
26931
+ ],
26932
+ providers: [
26933
+ { provide: UserEventServiceToken, useClass: UserEventTestService }
26723
26934
  ]
26724
26935
  },] }
26725
26936
  ];
@@ -26981,7 +27192,6 @@ const jobProgressionSubscription = gql `subscription UpdateJobProgression($id: I
26981
27192
  message
26982
27193
  current
26983
27194
  total
26984
- updateDate
26985
27195
  }
26986
27196
  }`;
26987
27197
  class JobProgressionService extends BaseGraphqlService {
@@ -29186,5 +29396,5 @@ CoreTestingModule.decorators = [
29186
29396
  * Generated bundle index. Do not edit.
29187
29397
  */
29188
29398
 
29189
- 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, 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, JobProgressionList as ɵl, DateTestPage as ɵm, NumpadTestPage as ɵn, MatBadgeIconTestPage as ɵo, ToastTestingModule as ɵp, ToastTestingPage as ɵq };
29399
+ 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, 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 };
29190
29400
  //# sourceMappingURL=sumaris-net.ngx-components.js.map