@sumaris-net/ngx-components 1.7.3 → 1.8.2

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.
@@ -1995,7 +1995,7 @@
1995
1995
  { type: i0.Component, args: [{
1996
1996
  // eslint-disable-next-line @angular-eslint/component-selector
1997
1997
  selector: 'mat-autocomplete-field',
1998
- template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <!-- readonly -->\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Basic select -->\n <mat-select #matSelect\n *ngIf=\"!searchable; else searchableTemplate\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- header -->\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <!-- options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text>{{item | propertyGet: path }}</ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #searchableTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
1998
+ template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <!-- readonly -->\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Basic select -->\n <mat-select #matSelect\n *ngIf=\"!searchable; else searchableTemplate\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- header -->\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <!-- options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text>{{item | propertyGet: path }}</ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #searchableTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.showPanel && dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
1999
1999
  providers: [{
2000
2000
  provide: i1.NG_VALUE_ACCESSOR,
2001
2001
  multi: true,
@@ -15419,6 +15419,7 @@
15419
15419
  _this.onChange = new rxjs.Subject();
15420
15420
  _this.onAuthTokenChange = new rxjs.Subject();
15421
15421
  _this.onAuthBasicChange = new rxjs.Subject();
15422
+ _this._stopWatching$ = new rxjs.Subject();
15422
15423
  _this._cache = {
15423
15424
  loaded: false,
15424
15425
  keypair: null,
@@ -15945,6 +15946,7 @@
15945
15946
  if (hadAuthBasic)
15946
15947
  this.onAuthBasicChange.next(undefined);
15947
15948
  this.onChange.next(undefined);
15949
+ this._stopWatching$.next();
15948
15950
  return [2 /*return*/];
15949
15951
  }
15950
15952
  });
@@ -16104,13 +16106,18 @@
16104
16106
  });
16105
16107
  });
16106
16108
  };
16107
- AccountService.prototype.listenChanges = function () {
16109
+ AccountService.prototype.watch = function () {
16108
16110
  var _this = this;
16109
16111
  if (!this._cache.pubkey)
16110
- return rxjs.Subscription.EMPTY;
16111
- var self = this;
16112
- console.debug('[account] [WS] Listening changes');
16113
- var subscription = this.graphql.subscribe({
16112
+ throw new Error('Not logged in');
16113
+ if (!this.started) {
16114
+ // Wait service ready, then loop
16115
+ return rxjs.from(this.ready())
16116
+ .pipe(operators.switchMap(function () { return _this.watch(); }));
16117
+ }
16118
+ this._stopWatching$.next(); // Stop previous listening
16119
+ console.debug('[account] [WS] Watching changes');
16120
+ return this.graphql.subscribe({
16114
16121
  query: AccountSubscriptions.listenChanges,
16115
16122
  variables: {
16116
16123
  interval: 10
@@ -16119,57 +16126,40 @@
16119
16126
  code: ErrorCodes$2.SUBSCRIBE_ACCOUNT_ERROR,
16120
16127
  message: 'ERROR.ACCOUNT.SUBSCRIBE_ACCOUNT_ERROR'
16121
16128
  }
16122
- }).subscribe({
16123
- next: function (_b) {
16124
- var data = _b.data;
16125
- return __awaiter(_this, void 0, void 0, function () {
16126
- var _a, existingUpdateDate;
16127
- return __generator(this, function (_b) {
16128
- switch (_b.label) {
16129
- case 0:
16130
- if (!data)
16131
- return [2 /*return*/];
16132
- existingUpdateDate = toDateISOString((_a = self._data) === null || _a === void 0 ? void 0 : _a.updateDate);
16133
- if (!(existingUpdateDate !== data.updateDate)) return [3 /*break*/, 2];
16134
- console.debug("[account] [WS] Detected update on {" + data.updateDate + "}");
16135
- return [4 /*yield*/, self.refresh()];
16136
- case 1:
16137
- _b.sent();
16138
- _b.label = 2;
16139
- case 2: return [2 /*return*/];
16140
- }
16141
- });
16142
- });
16143
- },
16144
- error: function (err) { return __awaiter(_this, void 0, void 0, function () {
16145
- return __generator(this, function (_b) {
16146
- switch (_b.label) {
16147
- case 0:
16148
- if (!(err && +err.code === ServerErrorCodes.NOT_FOUND)) return [3 /*break*/, 2];
16149
- console.info('[account] Account not exists anymore: force user to logout...', err);
16150
- return [4 /*yield*/, self.logout()];
16151
- case 1:
16152
- _b.sent();
16153
- return [3 /*break*/, 5];
16154
- case 2:
16155
- if (!(err && +err.code === ServerErrorCodes.UNAUTHORIZED)) return [3 /*break*/, 4];
16156
- console.info('[account] Account not authorized: force user to logout...', err);
16157
- return [4 /*yield*/, self.logout()];
16158
- case 3:
16159
- _b.sent();
16160
- return [3 /*break*/, 5];
16161
- case 4:
16162
- console.warn('[account] [WS] Received error:', err);
16163
- _b.label = 5;
16164
- case 5: return [2 /*return*/];
16165
- }
16166
- });
16167
- }); },
16168
- complete: function () {
16169
- console.debug('[account] [WS] Completed');
16129
+ })
16130
+ .pipe(
16131
+ // Stop this pipe next time we call watch()
16132
+ operators.takeUntil(this._stopWatching$), operators.map(function (_b) {
16133
+ var data = _b.data;
16134
+ var _a;
16135
+ if (!data)
16136
+ return;
16137
+ var existingUpdateDate = toDateISOString((_a = _this._data) === null || _a === void 0 ? void 0 : _a.updateDate);
16138
+ if (existingUpdateDate === data.updateDate)
16139
+ return;
16140
+ console.debug("[account] [WS] Detected update on {" + data.updateDate + "}");
16141
+ return exports.Account.fromObject(data);
16142
+ }), operators.filter(isNotNil));
16143
+ };
16144
+ AccountService.prototype.listenChanges = function () {
16145
+ var self = this;
16146
+ var subscription = this.watch()
16147
+ .subscribe({
16148
+ next: function (data) { return self.refresh(); },
16149
+ error: function (err) {
16150
+ if (err && +err.code === ServerErrorCodes.NOT_FOUND) {
16151
+ console.info('[account] Account not exists anymore: force user to logout...', err);
16152
+ self.logout();
16153
+ }
16154
+ else if (err && +err.code === ServerErrorCodes.UNAUTHORIZED) {
16155
+ console.info('[account] Account not authorized: force user to logout...', err);
16156
+ self.logout();
16157
+ }
16158
+ else {
16159
+ console.warn('[account] [WS] Received error:', err);
16160
+ }
16170
16161
  }
16171
16162
  });
16172
- // Add log when closing WS
16173
16163
  subscription.add(function () { return console.debug('[account] [WS] Stop listening changes'); });
16174
16164
  return subscription;
16175
16165
  };
@@ -16891,7 +16881,7 @@
16891
16881
  var APP_CONFIG_OPTIONS = new i0.InjectionToken('defaultOptions');
16892
16882
  var ConfigService = /** @class */ (function (_super) {
16893
16883
  __extends(ConfigService, _super);
16894
- function ConfigService(platform, graphql, storage, network, file, toastController, translate, environment, defaultOptionsMap) {
16884
+ function ConfigService(platform, graphql, storage, network, file, toastController, translate, accountService, environment, defaultOptionsMap) {
16895
16885
  var _this = _super.call(this, graphql, environment) || this;
16896
16886
  _this.platform = platform;
16897
16887
  _this.graphql = graphql;
@@ -16900,6 +16890,7 @@
16900
16890
  _this.file = file;
16901
16891
  _this.toastController = toastController;
16902
16892
  _this.translate = translate;
16893
+ _this.accountService = accountService;
16903
16894
  _this.environment = environment;
16904
16895
  _this.$data = new rxjs.BehaviorSubject(null);
16905
16896
  _this._debug = !environment.production;
@@ -16970,6 +16961,9 @@
16970
16961
  });
16971
16962
  });
16972
16963
  };
16964
+ ConfigService.prototype.canUserWrite = function (data, opts) {
16965
+ return this.accountService.isAdmin();
16966
+ };
16973
16967
  /**
16974
16968
  * Save a configuration
16975
16969
  *
@@ -17248,7 +17242,7 @@
17248
17242
  };
17249
17243
  return ConfigService;
17250
17244
  }(BaseGraphqlService));
17251
- ConfigService.ɵprov = i0__namespace.ɵɵdefineInjectable({ factory: function ConfigService_Factory() { return new ConfigService(i0__namespace.ɵɵinject(i1__namespace$4.Platform), i0__namespace.ɵɵinject(GraphqlService), i0__namespace.ɵɵinject(i3__namespace$1.Storage), i0__namespace.ɵɵinject(NetworkService), i0__namespace.ɵɵinject(FileService), i0__namespace.ɵɵinject(i1__namespace$4.ToastController), i0__namespace.ɵɵinject(i1__namespace$1.TranslateService), i0__namespace.ɵɵinject(ENVIRONMENT), i0__namespace.ɵɵinject(APP_CONFIG_OPTIONS, 8)); }, token: ConfigService, providedIn: "root" });
17245
+ ConfigService.ɵprov = i0__namespace.ɵɵdefineInjectable({ factory: function ConfigService_Factory() { return new ConfigService(i0__namespace.ɵɵinject(i1__namespace$4.Platform), i0__namespace.ɵɵinject(GraphqlService), i0__namespace.ɵɵinject(i3__namespace$1.Storage), i0__namespace.ɵɵinject(NetworkService), i0__namespace.ɵɵinject(FileService), i0__namespace.ɵɵinject(i1__namespace$4.ToastController), i0__namespace.ɵɵinject(i1__namespace$1.TranslateService), i0__namespace.ɵɵinject(AccountService), i0__namespace.ɵɵinject(ENVIRONMENT), i0__namespace.ɵɵinject(APP_CONFIG_OPTIONS, 8)); }, token: ConfigService, providedIn: "root" });
17252
17246
  ConfigService.decorators = [
17253
17247
  { type: i0.Injectable, args: [{
17254
17248
  providedIn: 'root',
@@ -17263,6 +17257,7 @@
17263
17257
  { type: FileService },
17264
17258
  { type: i1$5.ToastController },
17265
17259
  { type: i1$2.TranslateService },
17260
+ { type: AccountService },
17266
17261
  { type: undefined, decorators: [{ type: i0.Inject, args: [ENVIRONMENT,] }] },
17267
17262
  { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [APP_CONFIG_OPTIONS,] }] }
17268
17263
  ]; };
@@ -23820,6 +23815,9 @@
23820
23815
  });
23821
23816
  });
23822
23817
  };
23818
+ BaseEntityService.prototype.canUserWrite = function (data, opts) {
23819
+ return !!data;
23820
+ };
23823
23821
  BaseEntityService.prototype.saveAll = function (entities, opts) {
23824
23822
  return __awaiter(this, void 0, void 0, function () {
23825
23823
  var hasNewEntities, json, now;
@@ -27734,6 +27732,10 @@
27734
27732
  if (!opts || opts.emitEvent !== false)
27735
27733
  this.markForCheck();
27736
27734
  };
27735
+ /* -- public abstract methods (to override) -- */
27736
+ AppEntityEditor.prototype.canUserWrite = function (data, opts) {
27737
+ return this.dataService.canUserWrite(data, opts);
27738
+ };
27737
27739
  /* -- protected methods -- */
27738
27740
  /**
27739
27741
  * Return undefined to keep same tab