@sumaris-net/ngx-components 2.6.21 → 2.6.22

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 (27) hide show
  1. package/esm2020/src/app/admin/users/users.mjs +2 -2
  2. package/esm2020/src/app/core/account/new-token.modal.mjs +19 -13
  3. package/esm2020/src/app/core/account/token.table.mjs +22 -18
  4. package/esm2020/src/app/core/graphql/graphql.service.mjs +29 -31
  5. package/esm2020/src/app/core/services/account.service.mjs +1 -2
  6. package/esm2020/src/app/core/services/config.service.mjs +10 -8
  7. package/esm2020/src/app/core/services/model/token.model.mjs +6 -2
  8. package/esm2020/src/app/core/services/network.service.mjs +55 -38
  9. package/esm2020/src/app/core/services/network.types.mjs +1 -1
  10. package/esm2020/src/app/core/services/platform.service.mjs +2 -1
  11. package/esm2020/src/app/shared/http/http.utils.mjs +15 -11
  12. package/esm2020/src/app/shared/services/memory-entity-service.class.mjs +6 -6
  13. package/esm2020/src/environments/environment.class.mjs +1 -1
  14. package/fesm2015/sumaris-net.ngx-components.mjs +126 -92
  15. package/fesm2015/sumaris-net.ngx-components.mjs.map +1 -1
  16. package/fesm2020/sumaris-net.ngx-components.mjs +124 -92
  17. package/fesm2020/sumaris-net.ngx-components.mjs.map +1 -1
  18. package/package.json +1 -1
  19. package/src/app/core/account/new-token.modal.d.ts +1 -3
  20. package/src/app/core/account/token.table.d.ts +5 -3
  21. package/src/app/core/graphql/graphql.service.d.ts +20 -22
  22. package/src/app/core/services/model/token.model.d.ts +1 -0
  23. package/src/app/core/services/network.service.d.ts +11 -7
  24. package/src/app/shared/http/http.utils.d.ts +1 -0
  25. package/src/app/shared/services/memory-entity-service.class.d.ts +4 -2
  26. package/src/assets/manifest.json +1 -1
  27. package/src/environments/environment.class.d.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Directive, Injectable, EventEmitter, Output, Pipe, ChangeDetectorRef, forwardRef, Component, ChangeDetectionStrategy, Inject, Optional, Input, ViewChild, NgModule, HostBinding, HostListener, ElementRef, ViewChildren, CUSTOM_ELEMENTS_SCHEMA, ANIMATION_MODULE_TYPE, ViewEncapsulation, APP_INITIALIZER } from '@angular/core';
3
- import { firstValueFrom, shareReplay, tap, of, timer, merge, fromEvent, BehaviorSubject, Subscription, Subject, isObservable, from, noop as noop$9, Observable, forkJoin, defer, fromEventPattern, interval, combineLatest, mergeMap as mergeMap$1, EMPTY } from 'rxjs';
3
+ import { firstValueFrom, shareReplay, tap, of, timer, merge, fromEvent, BehaviorSubject, Subscription, Subject, isObservable, from, noop as noop$9, Observable, forkJoin, defer, timeout, fromEventPattern, interval, combineLatest, mergeMap as mergeMap$1, EMPTY } from 'rxjs';
4
4
  import { catchError, filter, map, takeUntil, first, switchMap, tap as tap$1, debounceTime, startWith, distinctUntilChanged, mergeMap, throttleTime, skip, bufferWhen, mapTo, distinctUntilKeyChanged, take } from 'rxjs/operators';
5
5
  import * as i2 from '@angular/common/http';
6
6
  import { HttpEventType, HttpClient, HttpHeaders, HttpResponse, HttpClientModule } from '@angular/common/http';
@@ -15155,14 +15155,12 @@ class HttpUtils {
15155
15155
  opts = opts || { responseType: 'text' };
15156
15156
  // Force no cache
15157
15157
  if (opts.nocache === true) {
15158
- opts.headers = (opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers));
15159
- opts.headers
15160
- .append('Cache-Control', 'no-cache')
15161
- .append('Pragma', 'no-cache');
15158
+ opts.headers = opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers);
15159
+ opts.headers.append('Cache-Control', 'no-cache').append('Pragma', 'no-cache');
15162
15160
  }
15163
15161
  // Use web http client
15164
15162
  try {
15165
- return (await http.get(uri, { ...opts, responseType: 'text' }).toPromise());
15163
+ return await firstValueFrom(http.get(uri, { ...opts, responseType: 'text' }));
15166
15164
  }
15167
15165
  catch (err) {
15168
15166
  if (err && err.message) {
@@ -15179,14 +15177,19 @@ class HttpUtils {
15179
15177
  opts = opts || {};
15180
15178
  // Force no cache
15181
15179
  if (opts.nocache === true) {
15182
- opts.headers = (opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers));
15183
- opts.headers
15184
- .append('Cache-Control', 'no-cache')
15185
- .append('Pragma', 'no-cache');
15180
+ opts.headers = opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers);
15181
+ opts.headers.append('Cache-Control', 'no-cache').append('Pragma', 'no-cache');
15186
15182
  }
15187
15183
  // Use web http client
15188
15184
  try {
15189
- return (await http.get(uri, { ...opts, responseType: 'json' }).toPromise());
15185
+ let result;
15186
+ if (opts.timeout) {
15187
+ result = http.get(uri, { ...opts, responseType: 'json' }).pipe(timeout(opts?.timeout));
15188
+ }
15189
+ else {
15190
+ result = http.get(uri, { ...opts, responseType: 'json' });
15191
+ }
15192
+ return await firstValueFrom(result);
15190
15193
  }
15191
15194
  catch (err) {
15192
15195
  if (err && err.message) {
@@ -15646,20 +15649,19 @@ const NetworkRefreshTimerPeriod = {
15646
15649
  DESKTOP: 1000 * 60 * 5 /* every 5 min */,
15647
15650
  };
15648
15651
  const PEER_URL_REGEXP = /^(http|https):\/\/[^ "?#@]+$/;
15652
+ const NETWORK_DEFAULT_CONNECTION_TIMEOUT = 10000; // 10s - /!\ should be high (e.g. for poor connection)
15649
15653
  /* -- DEV only (to debug refresh timer)
15650
- const NetworkRefreshTimerPeriod = {
15651
- MOBILE: 1000,
15652
- DESKTOP: 1000
15653
- }*/
15654
+ NetworkRefreshTimerPeriod.MOBILE = 1000;
15655
+ NetworkRefreshTimerPeriod.DESKTOP = 1000; */
15654
15656
  class NetworkService extends StartableObservableService {
15655
- constructor(platform, modalCtrl, storage, settings, cache, http, _document, environment, loggingService, network, translate, toastController) {
15657
+ constructor(_document, platform, modalCtrl, storage, settings, cache, http, environment, loggingService, network, translate, toastController) {
15656
15658
  super(platform);
15659
+ this._document = _document;
15657
15660
  this.modalCtrl = modalCtrl;
15658
15661
  this.storage = storage;
15659
15662
  this.settings = settings;
15660
15663
  this.cache = cache;
15661
15664
  this.http = http;
15662
- this._document = _document;
15663
15665
  this.environment = environment;
15664
15666
  this.loggingService = loggingService;
15665
15667
  this.translate = translate;
@@ -15669,6 +15671,7 @@ class NetworkService extends StartableObservableService {
15669
15671
  this.onResetNetworkCache = new EventEmitter(true);
15670
15672
  this._listeners = {};
15671
15673
  this._mobile = this.settings.mobile;
15674
+ this._connectionTimeout = environment.connectionTimeout || NETWORK_DEFAULT_CONNECTION_TIMEOUT;
15672
15675
  this._logger = this.loggingService?.getLogger('network');
15673
15676
  if (this._mobile) {
15674
15677
  this._timerRefreshPeriod = NetworkRefreshTimerPeriod.MOBILE;
@@ -15694,9 +15697,9 @@ class NetworkService extends StartableObservableService {
15694
15697
  }
15695
15698
  get connectionType() {
15696
15699
  // If force offline: return 'none'
15697
- return this._forceOffline && 'none'
15700
+ return this._forceOffline ? 'none'
15698
15701
  // Else, return device connection type (or unknown)
15699
- || (this.started && this._deviceConnectionType || 'unknown');
15702
+ : (this.started && this._deviceConnectionType || 'unknown');
15700
15703
  }
15701
15704
  get peer() {
15702
15705
  return this.dataSubject.value?.clone();
@@ -15704,6 +15707,9 @@ class NetworkService extends StartableObservableService {
15704
15707
  set peer(peer) {
15705
15708
  this.restart(peer);
15706
15709
  }
15710
+ get connectionTimeout() {
15711
+ return this._connectionTimeout;
15712
+ }
15707
15713
  /**
15708
15714
  * Register to network event
15709
15715
  *
@@ -15836,7 +15842,7 @@ class NetworkService extends StartableObservableService {
15836
15842
  * @param peer
15837
15843
  * @param opts
15838
15844
  */
15839
- async checkPeerAlive(peer, opts) {
15845
+ async checkPeerAlive(peer) {
15840
15846
  peer = peer || this.peer;
15841
15847
  if (!peer) {
15842
15848
  const settings = await this.settings.ready();
@@ -15844,13 +15850,15 @@ class NetworkService extends StartableObservableService {
15844
15850
  return undefined; // No peer define. Skip
15845
15851
  peer = Peer.parseUrl(settings.peerUrl);
15846
15852
  }
15847
- return this.getNodeInfo(peer);
15853
+ return this.getNodeInfo(peer, { nocache: true, timeout: this._connectionTimeout });
15848
15854
  }
15849
15855
  async checkPeerCompatible(peerInfo, opts) {
15856
+ if (!peerInfo)
15857
+ return false; // Peer cannot be reached
15850
15858
  if (!this.environment.peerMinVersion)
15851
15859
  return true; // Skip compatibility check
15852
15860
  // Check the min pod version, defined by the app
15853
- const isCompatible = peerInfo && peerInfo.softwareVersion && VersionUtils.isCompatible(this.environment.peerMinVersion, peerInfo.softwareVersion);
15861
+ const isCompatible = peerInfo.softwareVersion && VersionUtils.isCompatible(this.environment.peerMinVersion, peerInfo.softwareVersion);
15854
15862
  // Display toast, if not compatible
15855
15863
  if (!isCompatible && (!opts || opts.showToast !== false)) {
15856
15864
  await this.showToast({
@@ -15864,17 +15872,17 @@ class NetworkService extends StartableObservableService {
15864
15872
  }
15865
15873
  return isCompatible;
15866
15874
  }
15867
- async getNodeInfo(peer) {
15875
+ async getNodeInfo(peer, opts) {
15868
15876
  const path = this.computePeerPath(peer, '/api/node/info');
15869
- this._logger?.debug('checkPeerAlive', `Getting '${path}' ...`);
15877
+ this._logger?.debug('getNodeInfo', `Getting '${path}' ...`);
15870
15878
  try {
15871
- const data = await this.get(path);
15872
- this._logger?.debug('checkPeerAlive', `Response of '${path}':\n${JSON.stringify(data)}`);
15879
+ const data = await this.get(path, opts);
15880
+ this._logger?.debug('getNodeInfo', `Response of '${path}':\n${JSON.stringify(data)}`);
15873
15881
  return data;
15874
15882
  }
15875
15883
  catch (err) {
15876
15884
  console.debug(`[network] Error while getting '${path}': ${err && err.message || err}`, err);
15877
- this._logger?.error('checkPeerAlive', `Error while getting '${path}': ${err?.message || ''}`);
15885
+ this._logger?.error('getNodeInfo', `Error while getting '${path}': ${err?.message || ''}`);
15878
15886
  return undefined;
15879
15887
  }
15880
15888
  }
@@ -15992,13 +16000,30 @@ class NetworkService extends StartableObservableService {
15992
16000
  console.info('[network] Starting network...');
15993
16001
  // Restoring local settings
15994
16002
  peer = peer || (await this.restoreLocally());
15995
- // Make sure to hide the splashscreen, before open the modal
15996
- if (!peer)
16003
+ if (!peer) {
16004
+ // Make sure to hide the splashscreen, before open the modal
15997
16005
  await SplashScreen.hide();
15998
- // No peer in settings: ask user to choose
15999
- while (!peer) {
16000
- console.debug('[network] No peer defined. Asking user to choose a peer.');
16001
- peer = await this.showSelectPeerModal({ allowSelectDownPeer: false });
16006
+ // No peer in settings: ask user to choose
16007
+ while (!peer) {
16008
+ console.debug('[network] No peer defined. Asking user to choose a peer.');
16009
+ peer = await this.showSelectPeerModal({ allowSelectDownPeer: false });
16010
+ }
16011
+ }
16012
+ else if (this.online) {
16013
+ // Check if alive. If not, force offline mode
16014
+ const alive = await this.checkPeerAlive(peer);
16015
+ if (!alive) {
16016
+ // Peer not alive, but should be at the same URL, retrying each 1s
16017
+ if (this.environment.sameUrlPeer) {
16018
+ const retryMs = this._connectionTimeout > 0 ? this._connectionTimeout : 1000;
16019
+ await firstValueFrom(timer(retryMs, retryMs)
16020
+ .pipe(takeUntil(this.stopSubject), tap$1(() => console.warn(`[network-service] Waiting peer be be alive, at {${peer.url}} ...`)), mergeMap(() => this.checkPeerAlive(peer)), filter(alive => !!alive), first()));
16021
+ }
16022
+ else {
16023
+ // Continue, in offline mode
16024
+ this.setForceOffline(true);
16025
+ }
16026
+ }
16002
16027
  }
16003
16028
  console.info(`[network] Starting service [OK] {peer: '${peer.url}', online: ${this.online}}`);
16004
16029
  return peer;
@@ -16036,19 +16061,14 @@ class NetworkService extends StartableObservableService {
16036
16061
  if (this.environment.defaultPeer) {
16037
16062
  return Peer.fromObject(this.environment.defaultPeer);
16038
16063
  }
16039
- // Else, if App is hosted, try the web site as a peer
16040
- const location = this._document && this._document.location;
16041
- if (location && location.protocol && location.protocol.startsWith('http')) {
16064
+ // Else, if App is hosted, try the website as a peer
16065
+ const location = this._document?.location;
16066
+ if (location?.protocol?.startsWith('http')) {
16042
16067
  const hostname = this._document.location.host;
16043
16068
  const detectedPeer = Peer.parseUrl(`${this._document.location.protocol}${hostname}${this.environment.baseUrl}`);
16044
- if (await this.checkPeerAlive(detectedPeer)) {
16069
+ if (this.environment.sameUrlPeer || await this.checkPeerAlive(detectedPeer)) {
16045
16070
  return detectedPeer;
16046
16071
  }
16047
- // Peer not alive, but should be at the same URL, retrying each 1s
16048
- if (this.environment.sameUrlPeer) {
16049
- return await timer(1000, 1000)
16050
- .pipe(takeUntil(this.stopSubject), tap$1(() => console.warn(`[network-service] Waiting peer be be alive, at {${detectedPeer.url}} ...`)), mergeMap(() => this.checkPeerAlive(detectedPeer)), filter(alive => !!alive), map(() => detectedPeer), first()).toPromise();
16051
- }
16052
16072
  }
16053
16073
  return undefined;
16054
16074
  }
@@ -16080,7 +16100,7 @@ class NetworkService extends StartableObservableService {
16080
16100
  // Checkin if peer alive
16081
16101
  tap$1(() => console.debug('[network] Checking connection to pod...')), mergeMap(() => this.checkPeerAlive(this.peer)),
16082
16102
  // Filter to keep only changes
16083
- filter(info => !!info !== !!lastInfo), tap$1(info => lastInfo = info),
16103
+ filter(info => !equals(info, lastInfo)), tap$1(info => lastInfo = info),
16084
16104
  // Check compatibility
16085
16105
  mergeMap((info) => this.checkPeerCompatible(info, { showToast: true })))
16086
16106
  .subscribe(alive => {
@@ -16182,15 +16202,15 @@ class NetworkService extends StartableObservableService {
16182
16202
  }
16183
16203
  }
16184
16204
  }
16185
- NetworkService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NetworkService, deps: [{ token: i2$1.Platform }, { token: i2$1.ModalController }, { token: i2$3.Storage }, { token: LocalSettingsService }, { token: i4$1.CacheService }, { token: i2.HttpClient }, { token: DOCUMENT }, { token: ENVIRONMENT }, { token: APP_LOGGING_SERVICE, optional: true }, { token: i6$4.Network, optional: true }, { token: i1$1.TranslateService, optional: true }, { token: i2$1.ToastController, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
16205
+ NetworkService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NetworkService, deps: [{ token: DOCUMENT }, { token: i2$1.Platform }, { token: i2$1.ModalController }, { token: i2$3.Storage }, { token: LocalSettingsService }, { token: i4$1.CacheService }, { token: i2.HttpClient }, { token: ENVIRONMENT }, { token: APP_LOGGING_SERVICE, optional: true }, { token: i6$4.Network, optional: true }, { token: i1$1.TranslateService, optional: true }, { token: i2$1.ToastController, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
16186
16206
  NetworkService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NetworkService, providedIn: 'root' });
16187
16207
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NetworkService, decorators: [{
16188
16208
  type: Injectable,
16189
16209
  args: [{ providedIn: 'root' }]
16190
- }], ctorParameters: function () { return [{ type: i2$1.Platform }, { type: i2$1.ModalController }, { type: i2$3.Storage }, { type: LocalSettingsService }, { type: i4$1.CacheService }, { type: i2.HttpClient }, { type: undefined, decorators: [{
16210
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
16191
16211
  type: Inject,
16192
16212
  args: [DOCUMENT]
16193
- }] }, { type: Environment, decorators: [{
16213
+ }] }, { type: i2$1.Platform }, { type: i2$1.ModalController }, { type: i2$3.Storage }, { type: LocalSettingsService }, { type: i4$1.CacheService }, { type: i2.HttpClient }, { type: Environment, decorators: [{
16194
16214
  type: Inject,
16195
16215
  args: [ENVIRONMENT]
16196
16216
  }] }, { type: undefined, decorators: [{
@@ -16609,6 +16629,10 @@ let UserToken = UserToken_1 = class UserToken extends Entity {
16609
16629
  this.lastUsedDate = null;
16610
16630
  this.creationDate = null;
16611
16631
  }
16632
+ static equals(t1, t2) {
16633
+ return (isNotNil(t1.id) && t1.id === t2?.id)
16634
+ || (t1 && (t1.pubkey && t1.pubkey === t2?.pubkey) && (t1.name === t2?.name));
16635
+ }
16612
16636
  asObject(opts) {
16613
16637
  const target = super.asObject(opts);
16614
16638
  target.expirationDate = toDateISOString(this.expirationDate);
@@ -17013,14 +17037,13 @@ const loggerLink = unwrapESModule(loggerLinkImported);
17013
17037
  const APP_GRAPHQL_TYPE_POLICIES = new InjectionToken('graphqlTypePolicies');
17014
17038
  const APP_GRAPHQL_FRAGMENTS = new InjectionToken('graphqlFragments');
17015
17039
  class GraphqlService extends StartableService {
17016
- constructor(platform, apollo, httpLink, network, storage, cryptoService, environment, typePolicies, fragments) {
17040
+ constructor(platform, apollo, httpLink, network, storage, environment, typePolicies, fragments) {
17017
17041
  super(platform); // Wait platform
17018
17042
  this.platform = platform;
17019
17043
  this.apollo = apollo;
17020
17044
  this.httpLink = httpLink;
17021
17045
  this.network = network;
17022
17046
  this.storage = storage;
17023
- this.cryptoService = cryptoService;
17024
17047
  this.environment = environment;
17025
17048
  this.typePolicies = typePolicies;
17026
17049
  this.fragments = fragments;
@@ -17144,14 +17167,14 @@ class GraphqlService extends StartableService {
17144
17167
  return res.data;
17145
17168
  }
17146
17169
  }
17147
- const res = await this.apollo.mutate({
17170
+ const res = await firstValueFrom(this.apollo.mutate({
17148
17171
  mutation: opts.mutation,
17149
17172
  variables: opts.variables,
17150
17173
  context: opts.context,
17151
17174
  optimisticResponse: opts.optimisticResponse,
17152
17175
  update: opts.update
17153
17176
  })
17154
- .pipe(catchError(error => this.onApolloError(error, opts.error)), first()).toPromise();
17177
+ .pipe(catchError(error => this.onApolloError(error, opts.error)), first()));
17155
17178
  if (Array.isArray(res.errors)) {
17156
17179
  throw res.errors[0];
17157
17180
  }
@@ -17647,7 +17670,7 @@ class GraphqlService extends StartableService {
17647
17670
  || (err.graphQLErrors && err.graphQLErrors[0])
17648
17671
  || err;
17649
17672
  console.error('[graphql] ' + (error && error.message || error), error.stack || '');
17650
- if (error && error.code === ErrorCodes.UNKNOWN_NETWORK_ERROR && err.networkError && err.networkError.message) {
17673
+ if (error?.code === ErrorCodes.UNKNOWN_NETWORK_ERROR && err.networkError?.message) {
17651
17674
  console.error('[graphql] original error: ' + err.networkError.message);
17652
17675
  this.onNetworkError.next(error);
17653
17676
  }
@@ -17733,14 +17756,14 @@ class GraphqlService extends StartableService {
17733
17756
  return undefined;
17734
17757
  }
17735
17758
  }
17736
- GraphqlService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GraphqlService, deps: [{ token: i2$1.Platform }, { token: i2$6.Apollo }, { token: i3$1.HttpLink }, { token: NetworkService }, { token: StorageService }, { token: CryptoService }, { token: ENVIRONMENT }, { token: APP_GRAPHQL_TYPE_POLICIES, optional: true }, { token: APP_GRAPHQL_FRAGMENTS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
17759
+ GraphqlService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GraphqlService, deps: [{ token: i2$1.Platform }, { token: i2$6.Apollo }, { token: i3$1.HttpLink }, { token: NetworkService }, { token: StorageService }, { token: ENVIRONMENT }, { token: APP_GRAPHQL_TYPE_POLICIES, optional: true }, { token: APP_GRAPHQL_FRAGMENTS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
17737
17760
  GraphqlService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GraphqlService, providedIn: 'root' });
17738
17761
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GraphqlService, decorators: [{
17739
17762
  type: Injectable,
17740
17763
  args: [{
17741
17764
  providedIn: 'root'
17742
17765
  }]
17743
- }], ctorParameters: function () { return [{ type: i2$1.Platform }, { type: i2$6.Apollo }, { type: i3$1.HttpLink }, { type: NetworkService }, { type: StorageService }, { type: CryptoService }, { type: Environment, decorators: [{
17766
+ }], ctorParameters: function () { return [{ type: i2$1.Platform }, { type: i2$6.Apollo }, { type: i3$1.HttpLink }, { type: NetworkService }, { type: StorageService }, { type: Environment, decorators: [{
17744
17767
  type: Inject,
17745
17768
  args: [ENVIRONMENT]
17746
17769
  }] }, { type: undefined, decorators: [{
@@ -18091,7 +18114,6 @@ const Fragments = {
18091
18114
  token: gql `fragment UserTokenFragment on UserTokenVO {
18092
18115
  id
18093
18116
  pubkey
18094
- token
18095
18117
  name
18096
18118
  flags
18097
18119
  expirationDate
@@ -19522,13 +19544,15 @@ class ConfigService extends BaseGraphqlService {
19522
19544
  async loadOrRestoreLocally() {
19523
19545
  let data;
19524
19546
  let wasJustLoaded = false;
19525
- try {
19526
- data = await this.loadDefault({ fetchPolicy: 'network-only' });
19527
- wasJustLoaded = true;
19528
- }
19529
- catch (err) {
19530
- // Log, then continue
19531
- console.error(err && err.message || err, err);
19547
+ if (this.network.online) {
19548
+ try {
19549
+ data = await this.loadDefault({ fetchPolicy: 'network-only' });
19550
+ wasJustLoaded = true;
19551
+ }
19552
+ catch (err) {
19553
+ // Log, then continue
19554
+ console.error(err && err.message || err, err);
19555
+ }
19532
19556
  }
19533
19557
  // Save it into local storage, for next startup
19534
19558
  if (data) {
@@ -19819,6 +19843,7 @@ class PlatformService extends StartableService {
19819
19843
  )
19820
19844
  .subscribe(type => this.configureCache(type !== 'none')));
19821
19845
  console.info(`[platform] Starting platform [OK] {mobile: ${this._mobile}, capacitor: ${this._capacitor}, web: ${this.isWeb()}, downloader: ${this.canDownload}} in ${Date.now() - now}ms`);
19846
+ // Pass auth token
19822
19847
  this.registerSubscription(this.configService.config
19823
19848
  .subscribe(config => {
19824
19849
  if (!config)
@@ -23053,7 +23078,7 @@ class InMemoryEntitiesService extends StartableObservableService {
23053
23078
  return undefined;
23054
23079
  });
23055
23080
  this._startByReadyFunction = false; // Need setValue() to be called, to start the service
23056
- this._sortByReplacement = {
23081
+ this.sortByReplacement = {
23057
23082
  ...options.sortByReplacement
23058
23083
  };
23059
23084
  }
@@ -23158,9 +23183,9 @@ class InMemoryEntitiesService extends StartableObservableService {
23158
23183
  else {
23159
23184
  excludedDataByPagination = (size > 0 && ((offset + size) < data.length))
23160
23185
  // Slice using limit to size
23161
- ? data.slice(0, offset - 1).concat(data.slice(offset + size))
23186
+ ? data.slice(0, offset).concat(data.slice(offset + size))
23162
23187
  // Slice without limit
23163
- : data.slice(0, offset - 1);
23188
+ : data.slice(0, offset);
23164
23189
  data = (size > 0 && ((offset + size) < data.length))
23165
23190
  // Slice using limit to size
23166
23191
  ? data.slice(offset, offset + size)
@@ -23258,7 +23283,7 @@ class InMemoryEntitiesService extends StartableObservableService {
23258
23283
  // Make sure to fill sortBy BEFORE checking in the replacement map
23259
23284
  sortBy = sortBy || 'id';
23260
23285
  // Replace sortBy, using the replacement map
23261
- sortBy = this._sortByReplacement[sortBy] || sortBy;
23286
+ sortBy = this.sortByReplacement[sortBy] || sortBy;
23262
23287
  // Execute the sort
23263
23288
  return EntityUtils.sort(data, sortBy, sortDirection);
23264
23289
  }
@@ -23266,7 +23291,7 @@ class InMemoryEntitiesService extends StartableObservableService {
23266
23291
  return EntityFilterUtils.fromObject(source, this.filterType);
23267
23292
  }
23268
23293
  addSortByReplacement(source, target) {
23269
- this._sortByReplacement[source] = target;
23294
+ this.sortByReplacement[source] = target;
23270
23295
  }
23271
23296
  equals(d1, d2) {
23272
23297
  if (this._equalsFn)
@@ -31467,12 +31492,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
31467
31492
  }] } });
31468
31493
 
31469
31494
  class NewTokenModal extends AppEntityEditorModal {
31470
- constructor(injector, translate, validator, accountService) {
31495
+ constructor(injector, validator, accountService) {
31471
31496
  super(injector, UserToken, { tabCount: 1 });
31472
31497
  this.injector = injector;
31473
- this.translate = translate;
31474
31498
  this.validator = validator;
31475
31499
  this.accountService = accountService;
31500
+ this.translate = injector.get(TranslateService);
31501
+ this.toastController = injector.get(ToastController);
31476
31502
  this.tokenForm = validator.getFormGroup();
31477
31503
  this.tokenAppForm = new AppForm(this.injector, this.tokenForm);
31478
31504
  }
@@ -31535,7 +31561,9 @@ class NewTokenModal extends AppEntityEditorModal {
31535
31561
  async copy(event) {
31536
31562
  event?.stopPropagation();
31537
31563
  await Clipboard.write({ string: this.form.value.token });
31538
- this.copiedLabel = 'ACCOUNT.TOKENS.CREATE.COPIED';
31564
+ await Toasts.show(this.toastController, this.translate, {
31565
+ type: 'info', message: 'ACCOUNT.TOKENS.CREATE.COPIED'
31566
+ });
31539
31567
  }
31540
31568
  getFlags(scopes) {
31541
31569
  let flags = 0;
@@ -31545,29 +31573,31 @@ class NewTokenModal extends AppEntityEditorModal {
31545
31573
  return flags;
31546
31574
  }
31547
31575
  }
31548
- NewTokenModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NewTokenModal, deps: [{ token: i0.Injector }, { token: i1$1.TranslateService }, { token: UserTokenValidatorService }, { token: AccountService }], target: i0.ɵɵFactoryTarget.Component });
31549
- NewTokenModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NewTokenModal, selector: "app-new-token-modal", inputs: { tokenScopes: "tokenScopes", existingNames: "existingNames" }, usesInheritance: true, ngImport: i0, template: "<app-modal-toolbar modalName=\"NewTokenModal\"\n [title]=\"$title | async\"\n [color]=\"'secondary'\"\n [showSpinner]=\"loading\"\n [canValidate]=\"!loading && valid\"\n (cancel)=\"close($event)\"\n (validate)=\"saveAndClose($event)\"\n></app-modal-toolbar>\n\n<ion-content>\n\n <!-- error -->\n <ion-item *ngIf=\"error\" lines=\"none\" class=\"ion-padding\">\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 <h6 class=\"ion-padding\">{{ 'ACCOUNT.TOKENS.CREATE.DESCRIPTION' | translate }}</h6>\n\n <form class=\"form-container ion-no-padding\" [formGroup]=\"tokenForm\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\"\n [autofocusDelay]=\"500\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.NAME'|translate\"\n formControlName=\"name\"\n autocomplete=\"off\"\n required\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n >\n <mat-error *ngIf=\"form.controls.name.hasError('required') && form.controls.name.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.name.hasError('notAlreadyExists') && form.controls.name.dirty\" translate>ACCOUNT.TOKENS.CREATE.NAME_ALREADY_EXISTS</mat-error>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-chips-field\n formControlName=\"scopes\"\n appearance=\"legacy\"\n chipColor=\"primary\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.SCOPES' | translate\"\n [config]=\"tokenConfig\"\n [mobile]=\"mobile\"\n [debug]=\"false\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n ></mat-chips-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-date-field\n formControlName=\"expirationDate\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.EXPIRATION_DATE' | translate\"\n [mobile]=\"mobile\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n ></mat-date-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <ion-button\n *ngIf=\"tokenForm | formGetValue: 'token' | isNilOrBlank; else showToken\"\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_GENERATE_TITLE' | translate\"\n (click)=\"generate($event)\"\n [disabled]=\"tokenForm.invalid\"\n >\n {{ 'ACCOUNT.TOKENS.CREATE.BTN_GENERATE' | translate}}\n </ion-button>\n <ng-template #showToken>\n <h6>{{ 'ACCOUNT.TOKENS.CREATE.COPY_HELP' | translate }}</h6>\n <ion-text style=\"display: block; background-color: lightgray\">{{ tokenForm | formGetValue: 'token' }}</ion-text>\n <button\n mat-icon-button\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_COPY_TITLE' | translate\"\n (click)=\"copy($event)\"\n >\n <mat-icon>content_copy</mat-icon>\n </button>\n <ion-text>{{ copiedLabel | translate }}</ion-text>\n </ng-template>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </form>\n\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n <ng-content></ng-content>\n </ion-col>\n\n <ion-col size=\"auto\">\n\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"close($event)\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button [fill]=\"invalid ? 'clear' : 'solid'\"\n [disabled]=\"disabled || loading || invalid\"\n (click)=\"saveAndClose($event)\"\n (keyup.enter)=\"saveAndClose($event)\"\n color=\"tertiary\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: MatDate, selector: "mat-date-field", inputs: ["mobile", "formControl", "formControlName", "placeholder", "floatLabel", "appearance", "required", "compact", "placeholderChar", "autofocus", "startDate", "clearable", "timezone", "datePickerFilter", "readonly", "tabindex"] }, { kind: "component", type: MatChipsField, selector: "mat-chips-field", inputs: ["equals", "logPrefix", "formControl", "formControlName", "floatLabel", "appearance", "placeholder", "suggestFn", "required", "mobile", "readonly", "clearable", "debounceTime", "displayWith", "displayAttributes", "displayColumnSizes", "displayColumnNames", "highlightAccent", "showAllOnFocus", "showPanelOnFocus", "autofocus", "config", "i18nPrefix", "noResultMessage", "class", "panelWidth", "matAutocompletePosition", "itemSize", "fetchMoreThreshold", "suggestLengthThreshold", "showLoadingSpinner", "chipColor", "debug", "filter", "tabindex", "items"], outputs: ["click", "blur", "focus", "dropButtonClick", "keydown.escape", "keyup.enter"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "component", type: ModalToolbarComponent, selector: "app-modal-toolbar", inputs: ["modalName", "title", "color", "showSpinner", "canValidate", "validateIcon"], outputs: ["cancel", "validate"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: IsNilOrBlankPipe, name: "isNilOrBlank" }, { kind: "pipe", type: IsNotNilOrBlankPipe, name: "isNotNilOrBlank" }, { kind: "pipe", type: FormGetValuePipe, name: "formGetValue" }] });
31576
+ NewTokenModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NewTokenModal, deps: [{ token: i0.Injector }, { token: UserTokenValidatorService }, { token: AccountService }], target: i0.ɵɵFactoryTarget.Component });
31577
+ NewTokenModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NewTokenModal, selector: "app-new-token-modal", inputs: { tokenScopes: "tokenScopes", existingNames: "existingNames" }, usesInheritance: true, ngImport: i0, template: "<app-modal-toolbar modalName=\"NewTokenModal\"\n [title]=\"$title | async\"\n [color]=\"'secondary'\"\n [showSpinner]=\"loading\"\n [canValidate]=\"!loading && valid\"\n (cancel)=\"close($event)\"\n (validate)=\"saveAndClose($event)\"\n></app-modal-toolbar>\n\n<ion-content class=\"ion-padding\">\n\n <!-- error -->\n <ion-item *ngIf=\"error\" 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 <p><b translate>ACCOUNT.TOKENS.CREATE.DESCRIPTION</b></p>\n\n <form class=\"form-container\" [formGroup]=\"tokenForm\">\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\"\n [autofocusDelay]=\"500\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.NAME'|translate\"\n formControlName=\"name\"\n autocomplete=\"off\"\n required\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n >\n <mat-error *ngIf=\"form.controls.name.hasError('required') && form.controls.name.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.name.hasError('notAlreadyExists') && form.controls.name.touched\" translate>ACCOUNT.TOKENS.CREATE.NAME_ALREADY_EXISTS</mat-error>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-chips-field\n formControlName=\"scopes\"\n appearance=\"legacy\"\n chipColor=\"primary\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.SCOPES' | translate\"\n [config]=\"tokenConfig\"\n [mobile]=\"mobile\"\n [debug]=\"false\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n >\n <mat-error *ngIf=\"form.controls.name.hasError('notEmptyArray') && form.controls.name.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-chips-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-date-field\n formControlName=\"expirationDate\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.EXPIRATION_DATE' | translate\"\n [mobile]=\"mobile\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n ></mat-date-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <ion-button\n *ngIf=\"tokenForm | formGetValue: 'token' | isNilOrBlank; else showToken\"\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_GENERATE_TITLE' | translate\"\n (click)=\"generate($event)\"\n [disabled]=\"tokenForm.invalid\"\n >\n {{ 'ACCOUNT.TOKENS.CREATE.BTN_GENERATE' | translate}}\n </ion-button>\n <ng-template #showToken>\n <p><b translate>ACCOUNT.TOKENS.CREATE.COPY_HELP</b></p>\n <mat-form-field>\n <textarea matInput formControlName=\"token\" readonly style=\"height: auto; background-color: lightgray;\" rows=\"4\"></textarea>\n <button matSuffix\n mat-icon-button\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_COPY_TITLE' | translate\"\n (click)=\"copy($event)\"\n >\n <mat-icon>content_copy</mat-icon>\n </button>\n </mat-form-field>\n </ng-template>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </form>\n\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n <ng-content></ng-content>\n </ion-col>\n\n <ion-col size=\"auto\">\n\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"close($event)\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button [fill]=\"invalid ? 'clear' : 'solid'\"\n [disabled]=\"disabled || loading || invalid\"\n (click)=\"saveAndClose($event)\"\n (keyup.enter)=\"saveAndClose($event)\"\n color=\"tertiary\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6$1.MatSuffix, selector: "[matSuffix]" }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: MatDate, selector: "mat-date-field", inputs: ["mobile", "formControl", "formControlName", "placeholder", "floatLabel", "appearance", "required", "compact", "placeholderChar", "autofocus", "startDate", "clearable", "timezone", "datePickerFilter", "readonly", "tabindex"] }, { kind: "component", type: MatChipsField, selector: "mat-chips-field", inputs: ["equals", "logPrefix", "formControl", "formControlName", "floatLabel", "appearance", "placeholder", "suggestFn", "required", "mobile", "readonly", "clearable", "debounceTime", "displayWith", "displayAttributes", "displayColumnSizes", "displayColumnNames", "highlightAccent", "showAllOnFocus", "showPanelOnFocus", "autofocus", "config", "i18nPrefix", "noResultMessage", "class", "panelWidth", "matAutocompletePosition", "itemSize", "fetchMoreThreshold", "suggestLengthThreshold", "showLoadingSpinner", "chipColor", "debug", "filter", "tabindex", "items"], outputs: ["click", "blur", "focus", "dropButtonClick", "keydown.escape", "keyup.enter"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "component", type: ModalToolbarComponent, selector: "app-modal-toolbar", inputs: ["modalName", "title", "color", "showSpinner", "canValidate", "validateIcon"], outputs: ["cancel", "validate"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: IsNilOrBlankPipe, name: "isNilOrBlank" }, { kind: "pipe", type: IsNotNilOrBlankPipe, name: "isNotNilOrBlank" }, { kind: "pipe", type: FormGetValuePipe, name: "formGetValue" }] });
31550
31578
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NewTokenModal, decorators: [{
31551
31579
  type: Component,
31552
- args: [{ selector: 'app-new-token-modal', template: "<app-modal-toolbar modalName=\"NewTokenModal\"\n [title]=\"$title | async\"\n [color]=\"'secondary'\"\n [showSpinner]=\"loading\"\n [canValidate]=\"!loading && valid\"\n (cancel)=\"close($event)\"\n (validate)=\"saveAndClose($event)\"\n></app-modal-toolbar>\n\n<ion-content>\n\n <!-- error -->\n <ion-item *ngIf=\"error\" lines=\"none\" class=\"ion-padding\">\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 <h6 class=\"ion-padding\">{{ 'ACCOUNT.TOKENS.CREATE.DESCRIPTION' | translate }}</h6>\n\n <form class=\"form-container ion-no-padding\" [formGroup]=\"tokenForm\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\"\n [autofocusDelay]=\"500\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.NAME'|translate\"\n formControlName=\"name\"\n autocomplete=\"off\"\n required\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n >\n <mat-error *ngIf=\"form.controls.name.hasError('required') && form.controls.name.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.name.hasError('notAlreadyExists') && form.controls.name.dirty\" translate>ACCOUNT.TOKENS.CREATE.NAME_ALREADY_EXISTS</mat-error>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-chips-field\n formControlName=\"scopes\"\n appearance=\"legacy\"\n chipColor=\"primary\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.SCOPES' | translate\"\n [config]=\"tokenConfig\"\n [mobile]=\"mobile\"\n [debug]=\"false\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n ></mat-chips-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-date-field\n formControlName=\"expirationDate\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.EXPIRATION_DATE' | translate\"\n [mobile]=\"mobile\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n ></mat-date-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <ion-button\n *ngIf=\"tokenForm | formGetValue: 'token' | isNilOrBlank; else showToken\"\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_GENERATE_TITLE' | translate\"\n (click)=\"generate($event)\"\n [disabled]=\"tokenForm.invalid\"\n >\n {{ 'ACCOUNT.TOKENS.CREATE.BTN_GENERATE' | translate}}\n </ion-button>\n <ng-template #showToken>\n <h6>{{ 'ACCOUNT.TOKENS.CREATE.COPY_HELP' | translate }}</h6>\n <ion-text style=\"display: block; background-color: lightgray\">{{ tokenForm | formGetValue: 'token' }}</ion-text>\n <button\n mat-icon-button\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_COPY_TITLE' | translate\"\n (click)=\"copy($event)\"\n >\n <mat-icon>content_copy</mat-icon>\n </button>\n <ion-text>{{ copiedLabel | translate }}</ion-text>\n </ng-template>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </form>\n\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n <ng-content></ng-content>\n </ion-col>\n\n <ion-col size=\"auto\">\n\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"close($event)\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button [fill]=\"invalid ? 'clear' : 'solid'\"\n [disabled]=\"disabled || loading || invalid\"\n (click)=\"saveAndClose($event)\"\n (keyup.enter)=\"saveAndClose($event)\"\n color=\"tertiary\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n\n</ion-footer>\n" }]
31553
- }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$1.TranslateService }, { type: UserTokenValidatorService }, { type: AccountService }]; }, propDecorators: { tokenScopes: [{
31580
+ args: [{ selector: 'app-new-token-modal', template: "<app-modal-toolbar modalName=\"NewTokenModal\"\n [title]=\"$title | async\"\n [color]=\"'secondary'\"\n [showSpinner]=\"loading\"\n [canValidate]=\"!loading && valid\"\n (cancel)=\"close($event)\"\n (validate)=\"saveAndClose($event)\"\n></app-modal-toolbar>\n\n<ion-content class=\"ion-padding\">\n\n <!-- error -->\n <ion-item *ngIf=\"error\" 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 <p><b translate>ACCOUNT.TOKENS.CREATE.DESCRIPTION</b></p>\n\n <form class=\"form-container\" [formGroup]=\"tokenForm\">\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\"\n [autofocusDelay]=\"500\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.NAME'|translate\"\n formControlName=\"name\"\n autocomplete=\"off\"\n required\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n >\n <mat-error *ngIf=\"form.controls.name.hasError('required') && form.controls.name.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.name.hasError('notAlreadyExists') && form.controls.name.touched\" translate>ACCOUNT.TOKENS.CREATE.NAME_ALREADY_EXISTS</mat-error>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-chips-field\n formControlName=\"scopes\"\n appearance=\"legacy\"\n chipColor=\"primary\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.SCOPES' | translate\"\n [config]=\"tokenConfig\"\n [mobile]=\"mobile\"\n [debug]=\"false\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n >\n <mat-error *ngIf=\"form.controls.name.hasError('notEmptyArray') && form.controls.name.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-chips-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-date-field\n formControlName=\"expirationDate\"\n [placeholder]=\"'ACCOUNT.TOKENS.CREATE.EXPIRATION_DATE' | translate\"\n [mobile]=\"mobile\"\n [required]=\"true\"\n [readonly]=\"tokenForm | formGetValue: 'token' | isNotNilOrBlank\"\n ></mat-date-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <ion-button\n *ngIf=\"tokenForm | formGetValue: 'token' | isNilOrBlank; else showToken\"\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_GENERATE_TITLE' | translate\"\n (click)=\"generate($event)\"\n [disabled]=\"tokenForm.invalid\"\n >\n {{ 'ACCOUNT.TOKENS.CREATE.BTN_GENERATE' | translate}}\n </ion-button>\n <ng-template #showToken>\n <p><b translate>ACCOUNT.TOKENS.CREATE.COPY_HELP</b></p>\n <mat-form-field>\n <textarea matInput formControlName=\"token\" readonly style=\"height: auto; background-color: lightgray;\" rows=\"4\"></textarea>\n <button matSuffix\n mat-icon-button\n [title]=\"'ACCOUNT.TOKENS.CREATE.BTN_COPY_TITLE' | translate\"\n (click)=\"copy($event)\"\n >\n <mat-icon>content_copy</mat-icon>\n </button>\n </mat-form-field>\n </ng-template>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </form>\n\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n <ng-content></ng-content>\n </ion-col>\n\n <ion-col size=\"auto\">\n\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"close($event)\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button [fill]=\"invalid ? 'clear' : 'solid'\"\n [disabled]=\"disabled || loading || invalid\"\n (click)=\"saveAndClose($event)\"\n (keyup.enter)=\"saveAndClose($event)\"\n color=\"tertiary\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n\n</ion-footer>\n" }]
31581
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: UserTokenValidatorService }, { type: AccountService }]; }, propDecorators: { tokenScopes: [{
31554
31582
  type: Input
31555
31583
  }], existingNames: [{
31556
31584
  type: Input
31557
31585
  }] } });
31558
31586
 
31559
31587
  class UserTokenTable extends AppInMemoryTable {
31560
- constructor(injector, formBuilder, validatorService, environment, tokenScopes) {
31561
- super(injector, [...RESERVED_START_COLUMNS, 'name', /*'flags',*/ 'scopes', 'lastUsedDate', 'expirationDate', 'creationDate', 'updateDate', ...RESERVED_END_COLUMNS], UserToken, new InMemoryEntitiesService(UserToken, undefined, {
31562
- filterFnFactory: () => () => true
31588
+ constructor(injector, formBuilder, validatorService, cd, environment, tokenScopes) {
31589
+ super(injector, [...RESERVED_START_COLUMNS, 'name', 'scopes', 'lastUsedDate', 'expirationDate', 'creationDate', ...RESERVED_END_COLUMNS], UserToken, new InMemoryEntitiesService(UserToken, undefined, {
31590
+ filterFnFactory: () => () => true,
31591
+ equals: UserToken.equals,
31563
31592
  }), validatorService);
31564
31593
  this.injector = injector;
31565
31594
  this.formBuilder = formBuilder;
31566
31595
  this.validatorService = validatorService;
31596
+ this.cd = cd;
31567
31597
  this.tokenScopes = tokenScopes;
31568
31598
  this.useSticky = false;
31569
31599
  // this.readOnly = true;
31570
- this.inlineEdition = true;
31600
+ this.inlineEdition = false;
31571
31601
  this.defaultSortBy = 'creationDate';
31572
31602
  this.defaultSortDirection = 'asc';
31573
31603
  this.i18nColumnPrefix = 'ACCOUNT.TOKENS.TABLE.';
@@ -31590,10 +31620,10 @@ class UserTokenTable extends AppInMemoryTable {
31590
31620
  }
31591
31621
  setValue(value, opts) {
31592
31622
  // Set scopes from flags
31593
- value?.forEach(userToken => {
31623
+ value?.forEach((userToken) => {
31594
31624
  const scopes = [];
31595
31625
  if (userToken.flags) {
31596
- this.tokenScopes.forEach(scope => {
31626
+ this.tokenScopes.forEach((scope) => {
31597
31627
  // eslint-disable-next-line no-bitwise
31598
31628
  if (userToken.flags & scope.flag) {
31599
31629
  scopes.push(scope);
@@ -31605,6 +31635,9 @@ class UserTokenTable extends AppInMemoryTable {
31605
31635
  super.setValue(value, opts);
31606
31636
  }
31607
31637
  async addToken(event) {
31638
+ if (event?.defaultPrevented)
31639
+ return; // Avoid multiple call
31640
+ event?.preventDefault();
31608
31641
  event?.stopPropagation();
31609
31642
  const modal = await this.modalCtrl.create({
31610
31643
  component: NewTokenModal,
@@ -31613,9 +31646,9 @@ class UserTokenTable extends AppInMemoryTable {
31613
31646
  isNew: true,
31614
31647
  data: new UserToken(),
31615
31648
  tokenScopes: this.tokenScopes || [],
31616
- existingNames: this.value?.map(v => v.name)
31649
+ existingNames: this.value?.map((v) => v.name),
31617
31650
  },
31618
- backdropDismiss: false
31651
+ backdropDismiss: false,
31619
31652
  });
31620
31653
  await modal.present();
31621
31654
  const { data } = await modal.onDidDismiss();
@@ -31642,19 +31675,18 @@ class UserTokenTable extends AppInMemoryTable {
31642
31675
  // // this.markAsDirty();
31643
31676
  // }
31644
31677
  display(scopes) {
31645
- return scopes?.map(value => this.translate.instant(value.name)).join(', ');
31678
+ return scopes?.map((value) => this.translate.instant(value.name)).join(', ');
31679
+ }
31680
+ markForCheck() {
31681
+ this.cd.markForCheck();
31646
31682
  }
31647
31683
  }
31648
- UserTokenTable.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: UserTokenTable, deps: [{ token: i0.Injector }, { token: i1$2.UntypedFormBuilder }, { token: i2$8.ValidatorService }, { token: ENVIRONMENT }, { token: APP_USER_TOKEN_SCOPES, optional: true }], target: i0.ɵɵFactoryTarget.Component });
31649
- UserTokenTable.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: UserTokenTable, selector: "app-user-token-table", inputs: { useSticky: "useSticky" }, providers: [
31650
- { provide: ValidatorService, useClass: UserTokenValidatorService }
31651
- ], usesInheritance: true, ngImport: i0, template: "<mat-toolbar>\n\n <!-- Refresh -->\n <button mat-icon-button *ngIf=\"!mobile\"\n [title]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"onRefresh.emit()\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n <ion-item *ngIf=\"!mobile && error; let error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <div class=\"toolbar-spacer\"></div>\n\n <ng-container *ngIf=\"selection.isEmpty(); else hasSelection\">\n\n <button mat-icon-button\n *ngIf=\"canEdit && !mobile\"\n [title]=\"'COMMON.BTN_ADD'|translate\"\n (click)=\"addToken($event)\">\n <mat-icon>add</mat-icon>\n </button>\n\n </ng-container>\n\n <ng-template #hasSelection>\n\n <button mat-icon-button\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n\n </ng-template>\n\n</mat-toolbar>\n\n<ion-content class=\"ion-no-padding\">\n\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- table -->\n <div class=\"table-container\">\n <table #table mat-table matSort matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\">\n\n <ng-container matColumnDef=\"select\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!inlineEdition\">\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\">\n </mat-checkbox>\n </th>\n <td mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!inlineEdition\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(row) : null\" [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td>\n </ng-container>\n\n <!-- Id Column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">{{ row.currentData.id }}</td>\n </ng-container>\n\n <!-- name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'NAME' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ (row.currentData | propertyGet : 'name') || (i18nColumnPrefix + 'UNKNOWN' | translate) }}\n </td>\n </ng-container>\n\n<!-- <ng-container matColumnDef=\"flags\">-->\n<!-- <th mat-header-cell *matHeaderCellDef mat-sort-header>-->\n<!-- <ion-label>{{ i18nColumnPrefix + 'FLAGS' | translate }}</ion-label>-->\n<!-- </th>-->\n<!-- <td mat-cell *matCellDef=\"let row\">-->\n<!-- {{ row.currentData | propertyGet : 'flags' }}-->\n<!-- </td>-->\n<!-- </ng-container>-->\n\n <ng-container matColumnDef=\"scopes\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'SCOPES' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ display(row.currentData | propertyGet : 'scopes') }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"creationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'CREATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'creationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expirationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'EXPIRATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'expirationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastUsedDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'LAST_USED_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'lastUsedDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"updateDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'UPDATE_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'updateDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column [stickyEnd]=\"useSticky\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [canCancel]=\"false\">\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"\n [class.mat-row-selected]=\"row.editing\"\n [class.mat-row-error]=\"row.validator?.invalid\"\n [class.mat-row-dirty]=\"row.validator?.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.validator?.invalid\"></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject|async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n </div>\n</ion-content>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addToken($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".mat-cell-date-time{width:180px}.mat-column-id{width:90px}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonFab, selector: "ion-fab", inputs: ["activated", "edge", "horizontal", "vertical"] }, { kind: "component", type: i2$1.IonFabButton, selector: "ion-fab-button", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: i2$1.IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: i2$1.IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i6$6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6$6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6$6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6$6.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i6$6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6$6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6$6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6$6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6$6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6$6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i7$3.MatSort, selector: "[matSort]", inputs: ["matSortDisabled", "matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7$3.MatSortHeader, selector: "[mat-sort-header]", inputs: ["disabled", "mat-sort-header", "arrowPosition", "start", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: i6$2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i8$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$3.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ActionsColumnComponent, selector: "app-actions-column", inputs: ["stickyEnd", "canCancel", "canConfirm", "canDelete", "canBackward", "canForward", "canConfirmAndAdd", "dirtyIcon", "optionsTitle", "class", "cellTemplate"], outputs: ["optionsClick", "cancelOrDeleteClick", "confirmEditCreateClick", "confirmAndAddClick", "backward", "forward"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: PropertyGetPipe, name: "propertyGet" }, { kind: "pipe", type: DateFormatPipe, name: "dateFormat" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
31684
+ UserTokenTable.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: UserTokenTable, deps: [{ token: i0.Injector }, { token: i1$2.UntypedFormBuilder }, { token: i2$8.ValidatorService }, { token: i0.ChangeDetectorRef }, { token: ENVIRONMENT }, { token: APP_USER_TOKEN_SCOPES, optional: true }], target: i0.ɵɵFactoryTarget.Component });
31685
+ UserTokenTable.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: UserTokenTable, selector: "app-user-token-table", inputs: { useSticky: "useSticky" }, providers: [{ provide: ValidatorService, useClass: UserTokenValidatorService }], usesInheritance: true, ngImport: i0, template: "<mat-toolbar>\n\n <!-- Refresh -->\n <button mat-icon-button *ngIf=\"!mobile\"\n [title]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"onRefresh.emit()\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n <ion-item *ngIf=\"!mobile && error; let error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <div class=\"toolbar-spacer\"></div>\n\n <ng-container *ngIf=\"selection.isEmpty(); else hasSelection\">\n\n <button mat-icon-button\n *ngIf=\"canEdit && !mobile\"\n [title]=\"'COMMON.BTN_ADD'|translate\"\n (click)=\"addToken($event)\">\n <mat-icon>add</mat-icon>\n </button>\n\n </ng-container>\n\n <ng-template #hasSelection>\n\n <button mat-icon-button\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n\n </ng-template>\n\n</mat-toolbar>\n\n<ion-content class=\"ion-no-padding\">\n\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- table -->\n <div class=\"table-container\">\n <table #table mat-table matSort matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\">\n\n <ng-container matColumnDef=\"select\" [sticky]=\"useSticky\">\n <th 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 </th>\n <td 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 </td>\n </ng-container>\n\n <!-- Id Column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"cdk-visually-hidden\">\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"cdk-visually-hidden\">{{ row.currentData.id }}</td>\n </ng-container>\n\n <!-- name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'NAME' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ (row.currentData | propertyGet : 'name') || (i18nColumnPrefix + 'UNKNOWN' | translate) }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"scopes\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'SCOPES' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ display(row.currentData | propertyGet : 'scopes') }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"creationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'CREATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'creationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expirationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'EXPIRATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'expirationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastUsedDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'LAST_USED_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'lastUsedDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column [stickyEnd]=\"useSticky\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [canCancel]=\"false\">\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"\n [class.mat-row-selected]=\"row.editing\"\n [class.mat-row-error]=\"row.validator?.invalid\"\n [class.mat-row-dirty]=\"row.validator?.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.validator?.invalid\"></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject|async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n </div>\n</ion-content>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addToken($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".mat-cell-date-time{width:180px}.mat-column-id{width:90px}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonFab, selector: "ion-fab", inputs: ["activated", "edge", "horizontal", "vertical"] }, { kind: "component", type: i2$1.IonFabButton, selector: "ion-fab-button", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: i2$1.IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: i2$1.IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i6$6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6$6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6$6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6$6.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i6$6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6$6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6$6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6$6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6$6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6$6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i7$3.MatSort, selector: "[matSort]", inputs: ["matSortDisabled", "matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7$3.MatSortHeader, selector: "[mat-sort-header]", inputs: ["disabled", "mat-sort-header", "arrowPosition", "start", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: i6$2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i8$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$3.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ActionsColumnComponent, selector: "app-actions-column", inputs: ["stickyEnd", "canCancel", "canConfirm", "canDelete", "canBackward", "canForward", "canConfirmAndAdd", "dirtyIcon", "optionsTitle", "class", "cellTemplate"], outputs: ["optionsClick", "cancelOrDeleteClick", "confirmEditCreateClick", "confirmAndAddClick", "backward", "forward"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: PropertyGetPipe, name: "propertyGet" }, { kind: "pipe", type: DateFormatPipe, name: "dateFormat" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
31652
31686
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: UserTokenTable, decorators: [{
31653
31687
  type: Component,
31654
- args: [{ selector: 'app-user-token-table', providers: [
31655
- { provide: ValidatorService, useClass: UserTokenValidatorService }
31656
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mat-toolbar>\n\n <!-- Refresh -->\n <button mat-icon-button *ngIf=\"!mobile\"\n [title]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"onRefresh.emit()\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n <ion-item *ngIf=\"!mobile && error; let error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <div class=\"toolbar-spacer\"></div>\n\n <ng-container *ngIf=\"selection.isEmpty(); else hasSelection\">\n\n <button mat-icon-button\n *ngIf=\"canEdit && !mobile\"\n [title]=\"'COMMON.BTN_ADD'|translate\"\n (click)=\"addToken($event)\">\n <mat-icon>add</mat-icon>\n </button>\n\n </ng-container>\n\n <ng-template #hasSelection>\n\n <button mat-icon-button\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n\n </ng-template>\n\n</mat-toolbar>\n\n<ion-content class=\"ion-no-padding\">\n\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- table -->\n <div class=\"table-container\">\n <table #table mat-table matSort matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\">\n\n <ng-container matColumnDef=\"select\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!inlineEdition\">\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\">\n </mat-checkbox>\n </th>\n <td mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!inlineEdition\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(row) : null\" [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td>\n </ng-container>\n\n <!-- Id Column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">{{ row.currentData.id }}</td>\n </ng-container>\n\n <!-- name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'NAME' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ (row.currentData | propertyGet : 'name') || (i18nColumnPrefix + 'UNKNOWN' | translate) }}\n </td>\n </ng-container>\n\n<!-- <ng-container matColumnDef=\"flags\">-->\n<!-- <th mat-header-cell *matHeaderCellDef mat-sort-header>-->\n<!-- <ion-label>{{ i18nColumnPrefix + 'FLAGS' | translate }}</ion-label>-->\n<!-- </th>-->\n<!-- <td mat-cell *matCellDef=\"let row\">-->\n<!-- {{ row.currentData | propertyGet : 'flags' }}-->\n<!-- </td>-->\n<!-- </ng-container>-->\n\n <ng-container matColumnDef=\"scopes\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'SCOPES' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ display(row.currentData | propertyGet : 'scopes') }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"creationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'CREATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'creationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expirationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'EXPIRATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'expirationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastUsedDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'LAST_USED_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'lastUsedDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"updateDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'UPDATE_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'updateDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column [stickyEnd]=\"useSticky\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [canCancel]=\"false\">\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"\n [class.mat-row-selected]=\"row.editing\"\n [class.mat-row-error]=\"row.validator?.invalid\"\n [class.mat-row-dirty]=\"row.validator?.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.validator?.invalid\"></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject|async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n </div>\n</ion-content>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addToken($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".mat-cell-date-time{width:180px}.mat-column-id{width:90px}\n"] }]
31657
- }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$2.UntypedFormBuilder }, { type: i2$8.ValidatorService }, { type: Environment, decorators: [{
31688
+ args: [{ selector: 'app-user-token-table', providers: [{ provide: ValidatorService, useClass: UserTokenValidatorService }], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mat-toolbar>\n\n <!-- Refresh -->\n <button mat-icon-button *ngIf=\"!mobile\"\n [title]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"onRefresh.emit()\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n <ion-item *ngIf=\"!mobile && error; let error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <div class=\"toolbar-spacer\"></div>\n\n <ng-container *ngIf=\"selection.isEmpty(); else hasSelection\">\n\n <button mat-icon-button\n *ngIf=\"canEdit && !mobile\"\n [title]=\"'COMMON.BTN_ADD'|translate\"\n (click)=\"addToken($event)\">\n <mat-icon>add</mat-icon>\n </button>\n\n </ng-container>\n\n <ng-template #hasSelection>\n\n <button mat-icon-button\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n\n </ng-template>\n\n</mat-toolbar>\n\n<ion-content class=\"ion-no-padding\">\n\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- table -->\n <div class=\"table-container\">\n <table #table mat-table matSort matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\">\n\n <ng-container matColumnDef=\"select\" [sticky]=\"useSticky\">\n <th 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 </th>\n <td 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 </td>\n </ng-container>\n\n <!-- Id Column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"cdk-visually-hidden\">\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"cdk-visually-hidden\">{{ row.currentData.id }}</td>\n </ng-container>\n\n <!-- name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'NAME' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ (row.currentData | propertyGet : 'name') || (i18nColumnPrefix + 'UNKNOWN' | translate) }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"scopes\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>{{ i18nColumnPrefix + 'SCOPES' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n {{ display(row.currentData | propertyGet : 'scopes') }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"creationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'CREATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'creationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expirationDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'EXPIRATION_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'expirationDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastUsedDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header class=\"mat-cell-date-time\">\n <ion-label>{{ i18nColumnPrefix + 'LAST_USED_DATE' | translate }}</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\">\n {{ row.currentData | propertyGet : 'lastUsedDate' | dateFormat : {time: true} }}\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column [stickyEnd]=\"useSticky\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [canCancel]=\"false\">\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"\n [class.mat-row-selected]=\"row.editing\"\n [class.mat-row-error]=\"row.validator?.invalid\"\n [class.mat-row-dirty]=\"row.validator?.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.validator?.invalid\"></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject|async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n </div>\n</ion-content>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addToken($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".mat-cell-date-time{width:180px}.mat-column-id{width:90px}\n"] }]
31689
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$2.UntypedFormBuilder }, { type: i2$8.ValidatorService }, { type: i0.ChangeDetectorRef }, { type: Environment, decorators: [{
31658
31690
  type: Inject,
31659
31691
  args: [ENVIRONMENT]
31660
31692
  }] }, { type: undefined, decorators: [{
@@ -36829,7 +36861,7 @@ class UsersPage extends AppTable {
36829
36861
  console.warn('[users] Unknown action=' + action);
36830
36862
  break;
36831
36863
  }
36832
- // Mark as consummed
36864
+ // Mark as consumed
36833
36865
  this.router.navigate(['.'], {
36834
36866
  relativeTo: this.route,
36835
36867
  queryParams: { ...queryParams, action: undefined },
@@ -40118,5 +40150,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
40118
40150
  * Generated bundle index. Do not edit.
40119
40151
  */
40120
40152
 
40121
- export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_DEBUG_DATA_SERVICE, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_FRAGMENTS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_JOB_PROGRESSION_SERVICE, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_LOGGING_SERVICE, APP_MENU_ITEMS, APP_MENU_OPTIONS, APP_NAMED_FILTER_SERVICE, APP_PROGRESS_BAR_SERVICE, APP_SETTINGS_MENU_ITEMS, APP_STORAGE, APP_STORAGE_EXPLORER_PROTECTED_KEYS, APP_TESTING_PAGES, APP_USER_EVENT_LIST_INFINITE_SCROLL_THRESHOLD, APP_USER_EVENT_SERVICE, APP_USER_SETTINGS_OPTIONS, APP_USER_TOKEN_SCOPES, AboutModal, AbstractDateFormat, AbstractNamedFilterService, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, AccountUtils, ActionsColumnComponent, AdminModule, AdminRoutingModule, AdminUsersModule, Alerts, AndroidOsEnvironment, AnimationState, AppAboutModalModule, AppAccountModule, AppAsyncTable, AppAuthForm, AppAuthModal, AppAuthModule, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppEntityFormModule, AppForm, AppFormArray, AppFormButtonsBarModule, AppFormField, AppFormModule, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppHomePageModule, AppIconComponent, AppIconModule, AppImageGalleryComponent, AppInMemoryTable, AppInstallUpgradeCard, AppInstallUpgradeCardModule, AppListForm, AppListFormModule, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppPropertiesFormModule, AppPropertiesTable, AppRegisterModule, AppSelectPeerModule, AppSettingsPageModule, AppTabEditor, AppTabEditorOptions, AppTable, AppTableModule, AppTableUtils, AppTextPopoverModule, AppUpdateOfflineModeCard, AppUpdateOfflineModeCardModule, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayJoinPipe, ArrayLengthPipe, ArrayPluckPipe, AsAnyPipe, AsArrayPipe, AsObservablePipe, AudioProvider, AudioTestingModule, AudioTestingPage, AuthGuardService, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, BadgeDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigFragments, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_MATCH_REGEXP, DATE_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, DateFormatService, DateFromNowPipe, DateShortTestPage, DateTestPage, DateTimeTestPage, DateUtils, DebugComponent, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ED25519_SEED_LENGTH, EMPTY_PLACEHOLDER_CHAR, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesAsyncTableDataSource, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EnvironmentHttpLoader, EnvironmentLoader, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, GalleryTestPage, GeolocationUtils, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, IMAGE_DEFAULTS, IPosition, ImageAttachment, ImageAttachmentFilter, ImageAttachmentService, ImageGalleryModule, ImageGalleryTestingModule, ImageModule, ImageService, ImagesUtils, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNilOrNaNPipe, IsNilPipe, IsNotNilOrBlankPipe, IsNotNilOrNaNPipe, IsNotNilPipe, IsOnDeskPipe, IsOnFieldPipe, JobModule, JobProgression, JobProgressionComponent, JobProgressionIcon, JobProgressionList, JobProgressionService, JobProgressionTestService, JobProgressionTestingPage, JobTestingModule, JobUtils, JsonUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LogLevel, LogUtils, Logger, LoggingService, LoggingServiceModule, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MOMENT_NO_TIME_PROPERTY, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatAutocompleteFieldUtils, MatBooleanField, MatChipsField, MatColorPipe, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItem, MenuItems, MenuOptions, MenuService, MenuTestingModule, MenuTestingPage, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NamedFilter, NamedFilterFilter, NamedFilterSelector, NetworkService, NewTokenModal, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, NumpadTestPage, ObservableTestPage, OddPipe, OtherMenuTestingPage, PEER_URL_REGEXP, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertiesFormTestPage, PropertiesFormTestingModule, PropertyEntity, PropertyEntityFilter, PropertyEntityValidator, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, RegisterForm, RegisterModal, ResizableComponent, ResizableDirective, ResizableModule, SCRYPT_PARAMS, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_STORAGE_TESTING_PAGES, SHARED_TESTING_PAGES, SOCIAL_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedBadgeModule, SharedDebugModule, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedNamedFilterModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedTextFormModule, SharedToolbarModule, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, SocialTestingModule, Software, StartableService, StatusById, StatusIds, StatusList, StorageDrivers, StorageExplorerComponent, StorageExplorerModule, StorageExplorerTestingModule, StorageExplorerTestingRoutingModule, StorageService, StrIncludesPipe, StrLengthPipe, SubMenuTabDirective, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TableValidatorService, TextForm, TextFormTestingPage, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, ToastTestingModule, ToastTestingPage, Toasts, TokenScope, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, TreeItemEntityUtils, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEventModule, UserEventNotificationIcon, UserEventNotificationList, UserEventTestService, UserEventTestingModule, UserEventTestingPage, UserSettings, UserToken, UserTokenTable, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, collectByProperty, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, fadeInSlowAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, findParentWithClass, 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, initArrayControlsFromValues, isAndroid, isBlankString, isCapacitor, isControlHasInput, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isStartableService, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, 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, setPropertyByPath, setTabIndex, sleep, slideInAnimation, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, undefinedIfNull, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
40153
+ export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_DEBUG_DATA_SERVICE, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_FRAGMENTS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_JOB_PROGRESSION_SERVICE, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_LOGGING_SERVICE, APP_MENU_ITEMS, APP_MENU_OPTIONS, APP_NAMED_FILTER_SERVICE, APP_PROGRESS_BAR_SERVICE, APP_SETTINGS_MENU_ITEMS, APP_STORAGE, APP_STORAGE_EXPLORER_PROTECTED_KEYS, APP_TESTING_PAGES, APP_USER_EVENT_LIST_INFINITE_SCROLL_THRESHOLD, APP_USER_EVENT_SERVICE, APP_USER_SETTINGS_OPTIONS, APP_USER_TOKEN_SCOPES, AboutModal, AbstractDateFormat, AbstractNamedFilterService, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, AccountUtils, ActionsColumnComponent, AdminModule, AdminRoutingModule, AdminUsersModule, Alerts, AndroidOsEnvironment, AnimationState, AppAboutModalModule, AppAccountModule, AppAsyncTable, AppAuthForm, AppAuthModal, AppAuthModule, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppEntityFormModule, AppForm, AppFormArray, AppFormButtonsBarModule, AppFormField, AppFormModule, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppHomePageModule, AppIconComponent, AppIconModule, AppImageGalleryComponent, AppInMemoryTable, AppInstallUpgradeCard, AppInstallUpgradeCardModule, AppListForm, AppListFormModule, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppPropertiesFormModule, AppPropertiesTable, AppRegisterModule, AppSelectPeerModule, AppSettingsPageModule, AppTabEditor, AppTabEditorOptions, AppTable, AppTableModule, AppTableUtils, AppTextPopoverModule, AppUpdateOfflineModeCard, AppUpdateOfflineModeCardModule, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayJoinPipe, ArrayLengthPipe, ArrayPluckPipe, AsAnyPipe, AsArrayPipe, AsObservablePipe, AudioProvider, AudioTestingModule, AudioTestingPage, AuthGuardService, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, BadgeDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigFragments, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_MATCH_REGEXP, DATE_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, DateFormatService, DateFromNowPipe, DateShortTestPage, DateTestPage, DateTimeTestPage, DateUtils, DebugComponent, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ED25519_SEED_LENGTH, EMPTY_PLACEHOLDER_CHAR, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesAsyncTableDataSource, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EnvironmentHttpLoader, EnvironmentLoader, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, GalleryTestPage, GeolocationUtils, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, IMAGE_DEFAULTS, IPosition, ImageAttachment, ImageAttachmentFilter, ImageAttachmentService, ImageGalleryModule, ImageGalleryTestingModule, ImageModule, ImageService, ImagesUtils, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNilOrNaNPipe, IsNilPipe, IsNotNilOrBlankPipe, IsNotNilOrNaNPipe, IsNotNilPipe, IsOnDeskPipe, IsOnFieldPipe, JobModule, JobProgression, JobProgressionComponent, JobProgressionIcon, JobProgressionList, JobProgressionService, JobProgressionTestService, JobProgressionTestingPage, JobTestingModule, JobUtils, JsonUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LogLevel, LogUtils, Logger, LoggingService, LoggingServiceModule, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MOMENT_NO_TIME_PROPERTY, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatAutocompleteFieldUtils, MatBooleanField, MatChipsField, MatColorPipe, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItem, MenuItems, MenuOptions, MenuService, MenuTestingModule, MenuTestingPage, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NETWORK_DEFAULT_CONNECTION_TIMEOUT, NamedFilter, NamedFilterFilter, NamedFilterSelector, NetworkService, NewTokenModal, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, NumpadTestPage, ObservableTestPage, OddPipe, OtherMenuTestingPage, PEER_URL_REGEXP, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertiesFormTestPage, PropertiesFormTestingModule, PropertyEntity, PropertyEntityFilter, PropertyEntityValidator, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, RegisterForm, RegisterModal, ResizableComponent, ResizableDirective, ResizableModule, SCRYPT_PARAMS, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_STORAGE_TESTING_PAGES, SHARED_TESTING_PAGES, SOCIAL_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedBadgeModule, SharedDebugModule, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedNamedFilterModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedTextFormModule, SharedToolbarModule, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, SocialTestingModule, Software, StartableService, StatusById, StatusIds, StatusList, StorageDrivers, StorageExplorerComponent, StorageExplorerModule, StorageExplorerTestingModule, StorageExplorerTestingRoutingModule, StorageService, StrIncludesPipe, StrLengthPipe, SubMenuTabDirective, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TableValidatorService, TextForm, TextFormTestingPage, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, ToastTestingModule, ToastTestingPage, Toasts, TokenScope, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, TreeItemEntityUtils, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEventModule, UserEventNotificationIcon, UserEventNotificationList, UserEventTestService, UserEventTestingModule, UserEventTestingPage, UserSettings, UserToken, UserTokenTable, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, collectByProperty, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, fadeInSlowAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, findParentWithClass, 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, initArrayControlsFromValues, isAndroid, isBlankString, isCapacitor, isControlHasInput, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isStartableService, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, 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, setPropertyByPath, setTabIndex, sleep, slideInAnimation, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, undefinedIfNull, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
40122
40154
  //# sourceMappingURL=sumaris-net.ngx-components.mjs.map