http-request-manager 0.0.20 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +44 -253
  2. package/esm2022/lib/http-request-manager.module.mjs +145 -0
  3. package/esm2022/lib/http-request-services-demo/http-request-services-demo.component.mjs +41 -0
  4. package/esm2022/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.mjs +175 -0
  5. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.mjs +80 -0
  6. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.mjs +42 -0
  7. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.mjs +85 -0
  8. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.mjs +11 -0
  9. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.mjs +29 -0
  10. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.mjs +9 -0
  11. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.mjs +12 -0
  12. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.mjs +10 -0
  13. package/esm2022/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.mjs +276 -0
  14. package/esm2022/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.mjs +268 -0
  15. package/esm2022/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.mjs +75 -0
  16. package/esm2022/lib/index.mjs +4 -0
  17. package/esm2022/lib/interceptors/proxy-debugger.interceptor.mjs +47 -0
  18. package/esm2022/lib/interceptors/request-error.interceptor.mjs +5 -5
  19. package/esm2022/lib/models/config-http-options.model.mjs +18 -0
  20. package/esm2022/lib/models/config-local-storage-options.model.mjs +12 -0
  21. package/esm2022/lib/models/config-options.model.mjs +12 -0
  22. package/esm2022/lib/models/config-token.model.mjs +8 -0
  23. package/esm2022/lib/models/index.mjs +4 -1
  24. package/esm2022/lib/models/retry-options.model.mjs +3 -3
  25. package/esm2022/lib/services/index.mjs +1 -1
  26. package/esm2022/lib/services/local-storage-manager-service/local-storage-manager.service.mjs +34 -9
  27. package/esm2022/lib/services/local-storage-manager-service/models/index.mjs +1 -2
  28. package/esm2022/lib/services/local-storage-manager-service/models/setting-options.model.mjs +2 -2
  29. package/esm2022/lib/services/local-storage-manager-service/models/storage-option.model.mjs +3 -3
  30. package/esm2022/lib/services/request-manager-services/http-manager.service.mjs +87 -51
  31. package/esm2022/lib/services/request-manager-services/request.service.mjs +70 -28
  32. package/esm2022/lib/services/request-manager-services/rxjs-operators/delay-retry.mjs +7 -5
  33. package/esm2022/lib/services/request-manager-services/rxjs-operators/request-streaming.mjs +1 -1
  34. package/esm2022/lib/services/request-manager-state-service/http-manager-state.store.mjs +6 -39
  35. package/esm2022/lib/services/utils/app.service.mjs +7 -1
  36. package/esm2022/lib/services/utils/object-merger.service.mjs +34 -0
  37. package/esm2022/lib/services/utils/path-query.service.mjs +2 -1
  38. package/esm2022/lib/services/utils/utils.service.mjs +23 -2
  39. package/esm2022/public-api.mjs +4 -4
  40. package/fesm2022/http-request-manager.mjs +1782 -435
  41. package/fesm2022/http-request-manager.mjs.map +1 -1
  42. package/http-request-manager-4.1.2.tgz +0 -0
  43. package/lib/http-request-manager.module.d.ts +33 -0
  44. package/lib/http-request-services-demo/http-request-services-demo.component.d.ts +24 -0
  45. package/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.d.ts +56 -0
  46. package/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.d.ts +26 -0
  47. package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.d.ts +13 -0
  48. package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.d.ts +26 -0
  49. package/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.d.ts +12 -0
  50. package/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.d.ts +16 -0
  51. package/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.d.ts +8 -0
  52. package/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.d.ts +14 -0
  53. package/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.d.ts +10 -0
  54. package/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.d.ts +98 -0
  55. package/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.d.ts +110 -0
  56. package/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.d.ts +16 -0
  57. package/lib/index.d.ts +3 -0
  58. package/lib/interceptors/proxy-debugger.interceptor.d.ts +12 -0
  59. package/lib/interceptors/request-error.interceptor.d.ts +1 -1
  60. package/lib/models/config-http-options.model.d.ts +21 -0
  61. package/lib/models/config-local-storage-options.model.d.ts +13 -0
  62. package/lib/models/config-options.model.d.ts +12 -0
  63. package/lib/models/config-token.model.d.ts +8 -0
  64. package/lib/models/index.d.ts +3 -0
  65. package/lib/services/local-storage-manager-service/local-storage-manager.service.d.ts +7 -2
  66. package/lib/services/local-storage-manager-service/models/index.d.ts +0 -1
  67. package/lib/services/local-storage-manager-service/models/setting-options.model.d.ts +2 -2
  68. package/lib/services/local-storage-manager-service/models/storage-option.model.d.ts +4 -4
  69. package/lib/services/request-manager-services/http-manager.service.d.ts +12 -7
  70. package/lib/services/request-manager-services/request.service.d.ts +1 -0
  71. package/lib/services/request-manager-services/rxjs-operators/delay-retry.d.ts +1 -1
  72. package/lib/services/request-manager-state-service/http-manager-state.store.d.ts +11 -15
  73. package/lib/services/utils/object-merger.service.d.ts +7 -0
  74. package/lib/services/utils/utils.service.d.ts +1 -1
  75. package/package.json +27 -18
  76. package/public-api.d.ts +3 -3
  77. package/esm2022/lib/services/local-storage-manager-service/models/storage-option-settings.model.mjs +0 -13
  78. package/http-request-manager-0.0.20.tgz +0 -0
  79. package/lib/services/local-storage-manager-service/models/storage-option-settings.model.d.ts +0 -15
@@ -1,13 +1,47 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, APP_ID, Inject, Injector, InjectionToken } from '@angular/core';
2
+ import { inject, Injectable, APP_ID, Inject, InjectionToken, Injector, Optional, EventEmitter, Component, ViewEncapsulation, Input, Output, NgModule, ViewChild } from '@angular/core';
3
3
  import { ComponentStore } from '@ngrx/component-store';
4
- import { withLatestFrom, map, tap, catchError, filter, finalize, takeWhile, retryWhen, delay, mergeMap, startWith, takeUntil, switchMap, concatMap, scan, expand } from 'rxjs/operators';
5
- import { HttpClient, HttpHeaders, HttpEventType, HttpErrorResponse } from '@angular/common/http';
4
+ import { map, catchError, filter, finalize, takeWhile, retry, startWith, tap, mergeMap, takeUntil, withLatestFrom, switchMap, concatMap, scan, distinctUntilChanged } from 'rxjs/operators';
5
+ import { HttpClient, HttpHeaders, HttpEventType, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
6
6
  import * as CryptoJS from 'crypto-js';
7
- import { interval, from, BehaviorSubject, EMPTY, defer, of, throwError, Subject, Subscription, catchError as catchError$1 } from 'rxjs';
8
- import { ToastDisplay, ToastColors, ToastMessageService as ToastMessageService$1 } from 'toast-message';
9
- import { ToastMessageService } from 'toast-message-display';
7
+ import { from, BehaviorSubject, EMPTY, throwError, defer, interval, timer, Subject, of, Subscription, catchError as catchError$1 } from 'rxjs';
8
+ import { ToastMessageService, ToastDisplay, ToastColors, ToastMessageModule } from 'toast-message-display';
10
9
  import * as i1 from '@ngx-translate/core';
10
+ import { TranslateModule } from '@ngx-translate/core';
11
+ import * as i1$1 from '@angular/common';
12
+ import { CommonModule } from '@angular/common';
13
+ import * as i2 from '@angular/forms';
14
+ import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
15
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
16
+ import * as i3$1 from '@angular/material/button';
17
+ import { MatButtonModule } from '@angular/material/button';
18
+ import { MatChipsModule } from '@angular/material/chips';
19
+ import * as i11 from '@angular/material/divider';
20
+ import { MatDividerModule } from '@angular/material/divider';
21
+ import * as i4 from '@angular/material/form-field';
22
+ import { MatFormFieldModule } from '@angular/material/form-field';
23
+ import * as i7 from '@angular/material/icon';
24
+ import { MatIconModule } from '@angular/material/icon';
25
+ import * as i12 from '@angular/material/input';
26
+ import { MatInputModule } from '@angular/material/input';
27
+ import * as i9 from '@angular/material/progress-bar';
28
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
29
+ import * as i5 from '@angular/material/select';
30
+ import { MatSelectModule } from '@angular/material/select';
31
+ import { MatSidenavModule } from '@angular/material/sidenav';
32
+ import * as i10$1 from '@angular/material/slide-toggle';
33
+ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
34
+ import * as i3$2 from '@angular/material/menu';
35
+ import { MatMenuModule } from '@angular/material/menu';
36
+ import * as i4$1 from '@angular/material/toolbar';
37
+ import { MatToolbarModule } from '@angular/material/toolbar';
38
+ import * as i8 from '@angular/material/table';
39
+ import { MatTableModule } from '@angular/material/table';
40
+ import * as i10 from '@angular/material/button-toggle';
41
+ import { MatButtonToggleModule } from '@angular/material/button-toggle';
42
+ import * as i3 from '@angular/material/progress-spinner';
43
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
44
+ import * as i6 from '@angular/material/core';
11
45
 
12
46
  var StorageType;
13
47
  (function (StorageType) {
@@ -16,15 +50,15 @@ var StorageType;
16
50
  StorageType[StorageType["DB"] = 2] = "DB";
17
51
  })(StorageType || (StorageType = {}));
18
52
 
19
- class StorageOptionSettings {
20
- constructor(storage = StorageType.GLOBAL, expires, expiresIn, encrypted) {
53
+ class SettingOptions {
54
+ constructor(storage, expires, expiresIn, encrypted) {
21
55
  this.storage = storage;
22
56
  this.expires = expires;
23
57
  this.expiresIn = expiresIn;
24
58
  this.encrypted = encrypted;
25
59
  }
26
60
  static adapt(item) {
27
- return new StorageOptionSettings((item?.storage) ? item.storage : StorageType.GLOBAL, (item?.expires) ? item.expires : 0, (item?.expiresIn) ? item.expiresIn : '', (item?.encrypted) ? item.encrypted : false);
61
+ return new SettingOptions((item?.storage) ? item.storage : StorageType.GLOBAL, (item?.expires) ? item.expires : 0, (item?.expiresIn) ? item.expiresIn : '', (item?.encrypted) ? item?.encrypted : false);
28
62
  }
29
63
  }
30
64
 
@@ -35,7 +69,7 @@ class StorageOption {
35
69
  this.options = options;
36
70
  }
37
71
  static adapt(item) {
38
- return new StorageOption((item?.id) ? item.id : crypto.randomUUID(), item?.name, (item?.options) ? StorageOptionSettings.adapt(item.options) : StorageOptionSettings.adapt());
72
+ return new StorageOption((item?.id) ? item.id : crypto.randomUUID(), item?.name, (item?.options) ? SettingOptions.adapt(item.options) : SettingOptions.adapt());
39
73
  }
40
74
  }
41
75
 
@@ -51,18 +85,6 @@ class GlobalStoreOptions {
51
85
  }
52
86
  }
53
87
 
54
- class SettingOptions {
55
- constructor(storage = StorageType.GLOBAL, expires, expiresIn, encrypted) {
56
- this.storage = storage;
57
- this.expires = expires;
58
- this.expiresIn = expiresIn;
59
- this.encrypted = encrypted;
60
- }
61
- static adapt(item) {
62
- return new SettingOptions((item?.storage) ? item.storage : StorageType.GLOBAL, (item?.expires) ? item.expires : 0, (item?.expiresIn) ? item.expiresIn : '', (item?.encrypted) ? item?.encrypted : false);
63
- }
64
- }
65
-
66
88
  class StorageData {
67
89
  constructor(id, data) {
68
90
  this.id = id;
@@ -140,6 +162,7 @@ class UtilsService {
140
162
  return hex.padStart(32, '0').substr(0, 32);
141
163
  }
142
164
  // y = years, m = months, w = weeks, d = days, hr = hours, mn = minutes else seconds
165
+ // returns epoch time corresponding to the expiry type
143
166
  expires(str) {
144
167
  if (!str)
145
168
  return;
@@ -192,7 +215,27 @@ class UtilsService {
192
215
  if (!expiryDate)
193
216
  return;
194
217
  const now = Math.floor(new Date().getTime() / 1000);
195
- return expiryDate - now;
218
+ let diff = expiryDate - now;
219
+ if (diff <= 0)
220
+ return "Expired";
221
+ const units = [
222
+ { label: 'y', seconds: 31536000 },
223
+ { label: 'm', seconds: 2592000 },
224
+ { label: 'w', seconds: 604800 },
225
+ { label: 'd', seconds: 86400 },
226
+ { label: 'h', seconds: 3600 },
227
+ { label: 'min', seconds: 60 },
228
+ { label: '', seconds: 1 },
229
+ ];
230
+ let result = [];
231
+ for (const unit of units) {
232
+ if (diff >= unit.seconds) {
233
+ const value = Math.floor(diff / unit.seconds);
234
+ diff %= unit.seconds;
235
+ result.push(`${value}${unit.label}${value > 1 ? 's' : ''}`);
236
+ }
237
+ }
238
+ return result.join(', ');
196
239
  }
197
240
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
198
241
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, providedIn: 'root' }); }
@@ -256,6 +299,12 @@ const UUID = () => {
256
299
  return self.crypto.randomUUID();
257
300
  };
258
301
 
302
+ // Must provide a value for APP_ID in AppModule->Providers
303
+ // providers: [
304
+ // {
305
+ // provide: APP_ID,
306
+ // useValue: "056991ac-3537-43ab-b5b9-83edf6554eff",
307
+ // },
259
308
  class AppService {
260
309
  constructor(id) {
261
310
  this.id = id;
@@ -379,273 +428,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
379
428
  }]
380
429
  }], ctorParameters: function () { return []; } });
381
430
 
382
- const storage = {
383
- localStores: [],
384
- sessionStores: [],
385
- settings: [],
386
- };
387
- class LocalStorageManagerService extends ComponentStore {
388
- startTimer() {
389
- const timer$ = interval(1000 * 3).pipe(withLatestFrom(this.data$), map(([_, state]) => state), tap((state) => {
390
- const expired = this.expired(state) ? this.expired(state) : [];
391
- if (expired.length > 0) {
392
- const ids = expired.map((item) => item.id);
393
- const updatedState = {
394
- ...state,
395
- localStores: state.localStores.filter((item) => !ids.includes(item.id)),
396
- sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
397
- settings: state.settings.filter((item) => !ids.includes(item.id)),
398
- };
399
- this.persistState(updatedState);
400
- this.updateState(updatedState);
401
- }
402
- }));
403
- timer$.subscribe();
404
- }
405
- constructor() {
406
- super(storage);
407
- this.storageName = 'storage';
408
- this.storageSettingsName = 'global-storage';
409
- this.stateRetrieved = false;
410
- this.encrypted = false;
411
- this.app = inject(AppService);
412
- this.utils = inject(UtilsService);
413
- this.encryption = inject(SymmetricalEncryptionService);
414
- this.encryptionTest = inject(EncryptionTestService);
415
- // SELECTORS
416
- this.data$ = this.select((state) => state);
417
- this.stores$ = this.select((state) => state.settings);
418
- this.storeExists$ = (store) => this.select(this.data$, (data) => data.settings.find(item => item.name === store) ? true : false);
419
- this.store$ = (store) => this.select(this.data$, (data) => {
420
- const foundStore = data.settings.find(item => item.name === store);
421
- if (foundStore) {
422
- const options = SettingOptions.adapt(foundStore.options);
423
- const found = foundStore.options?.storage === StorageType.GLOBAL
424
- ? data.localStores.find(item => item.id === foundStore.id)
425
- : data.sessionStores.find(item => item.id === foundStore.id);
426
- if (!found) {
427
- this.deleteStore({ name: store });
428
- return;
429
- }
430
- const storageData = (options.encrypted) ? this.encryption.decrypt(found.data, this.app.appID) : found.data;
431
- return (this.isString(storageData)) ? JSON.parse(storageData) : storageData;
432
- }
433
- else {
434
- return null;
435
- }
436
- });
437
- this.settings$ = this.select((state) => state.settings);
438
- this.setting$ = (store) => this.select(this.data$, (state) => {
439
- const foundSetting = state.settings.find(item => item.name === store);
440
- return (foundSetting) ? foundSetting : null;
441
- });
442
- this.persistence$ = this.data$
443
- .subscribe(data => {
444
- if (this.stateRetrieved)
445
- this.persistState(data);
446
- });
447
- this.updateState = this.updater((state, updatedState) => ({
448
- ...updatedState,
449
- }));
450
- this.setStore = this.updater((state, store) => {
451
- const settings = StorageOption.adapt(store);
452
- const type = store.options.storage;
453
- const hasStore = this.hasGlobalStorage(type, store.id);
454
- store.name = this.validStoreName(store.name);
455
- if (!hasStore) {
456
- console.warn(`No such Store: ${store.name}`);
457
- return state;
458
- }
459
- else {
460
- const str = this.encryptionTest.isEncrypted(store.data) ? store.data : JSON.stringify(store.data);
461
- const dataStr = (this.isObjectOrArray(str)) ? (store.options.encrypted) ? this.encryption.encrypt(str, this.app.appID) : store.data : store.data;
462
- const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
463
- const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
464
- return {
465
- ...state,
466
- localStores: [...state.localStores, ...localData],
467
- sessionStores: [...state.sessionStores, ...sessionData],
468
- settings: [...state.settings, ...[settings]],
469
- };
470
- }
471
- });
472
- this.createStore = this.updater((state, store) => {
473
- const settings = StorageOption.adapt(store);
474
- const foundStore = state?.settings.some(item => item.name === store.name);
475
- const expires = (settings.options?.expiresIn) ? this.utils.expires(settings.options?.expiresIn) : 0;
476
- if (settings.options)
477
- settings.options.expires = expires;
478
- store.name = this.validStoreName(store.name);
479
- if (foundStore) {
480
- return state;
481
- }
482
- else {
483
- if (!this.isObjectOrArray(store.data)) {
484
- console.warn('Data must ba an Object or Array');
485
- return;
486
- }
487
- store.data = (this.isString(store.data)) ? JSON.parse(store.data) : store.data;
488
- const dataStr = (store.options.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
489
- const localData = (settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
490
- const sessionData = (settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
491
- return {
492
- ...state,
493
- localStores: [...state.localStores, ...localData],
494
- sessionStores: [...state.sessionStores, ...sessionData],
495
- settings: [...state.settings, ...[settings]],
496
- };
497
- }
498
- });
499
- this.updateStore = this.updater((state, store) => {
500
- store.name = this.validStoreName(store.name);
501
- const settings = state.settings.find(item => item.name === store.name);
502
- if (settings) {
503
- const type = settings.options?.storage;
504
- const hasStore = this.hasGlobalStorage(type, settings.id || '');
505
- if (!hasStore) {
506
- console.warn(`No such Store: ${store.name}`);
507
- }
508
- else {
509
- const dataStr = (settings.options?.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
510
- const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
511
- const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
512
- state.localStores = state.localStores.filter(item => item.id !== settings.id);
513
- state.sessionStores = state.sessionStores.filter(item => item.id !== settings.id);
514
- return {
515
- ...state,
516
- localStores: [...state.localStores, ...localData],
517
- sessionStores: [...state.sessionStores, ...sessionData],
518
- };
431
+ /**
432
+ * An injection token that provides the configuration settings for the application.
433
+ * This token can be used to inject the `ConfigSettings` instance into components or services
434
+ * that require access to the application configuration.
435
+ */
436
+ const CONFIG_SETTINGS_TOKEN = new InjectionToken('http.config');
437
+
438
+ class ObjectMergerService {
439
+ mergeOptions(options, configForRoot) {
440
+ const merged = configForRoot ? { ...configForRoot } : {};
441
+ for (const key in options) {
442
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
443
+ const value = options[key];
444
+ if (value !== null &&
445
+ value !== undefined &&
446
+ !(typeof value === 'number') &&
447
+ !(typeof value === 'boolean') &&
448
+ !(this.isNonEmptyString(value)) &&
449
+ !(Array.isArray(value) && value.length === 0) &&
450
+ !(typeof value === 'object' && !Array.isArray(value))) {
451
+ merged[key] = value;
519
452
  }
520
453
  }
521
- return state;
522
- });
523
- this.deleteStore = this.updater((state, store) => {
524
- store.name = this.validStoreName(store.name);
525
- const id = state.settings.find(item => item.name === store.name)?.id;
526
- if (id) {
527
- const settings = state.settings.filter(item => item.id !== id);
528
- const localData = state.localStores.filter(item => item.id !== id);
529
- const sessionData = state.sessionStores.filter(item => item.id !== id);
530
- return {
531
- ...state,
532
- localStores: [...localData],
533
- sessionStores: [...sessionData],
534
- settings: [...settings],
535
- };
536
- }
537
- else {
538
- console.warn(`No such Store: ${store.name}`);
539
- return state;
540
- }
541
- });
542
- this.isObjectOrArray = (obj) => {
543
- try {
544
- //obj = (Object.prototype.toString.call(obj) === '[object Object]') ? JSON.parse(obj) : obj
545
- return typeof obj === 'object' || Array.isArray(obj);
546
- }
547
- catch (error) {
548
- return false;
549
- }
550
- };
551
- this.retrieveState();
552
- this.startTimer();
454
+ }
455
+ return merged;
553
456
  }
554
- resetStore() {
555
- const newState = {
556
- localStores: [],
557
- sessionStores: [],
558
- settings: [],
559
- };
560
- this.updateState(newState);
561
- this.persistState(newState);
457
+ isNonEmptyString(value) {
458
+ return typeof value === 'string' && value.length === 0;
562
459
  }
563
- persistState(state) {
564
- if (!state)
565
- return;
566
- const strLocal = JSON.stringify(state.localStores);
567
- localStorage.setItem(this.storageName, strLocal);
568
- const strSession = JSON.stringify(state.sessionStores);
569
- sessionStorage.setItem(this.storageName, strSession);
570
- const settingsStr = this.encryption.encrypt(state.settings, this.app.appID);
571
- localStorage.setItem(this.storageSettingsName, settingsStr || '');
460
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ObjectMergerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
461
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ObjectMergerService, providedIn: 'root' }); }
462
+ }
463
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ObjectMergerService, decorators: [{
464
+ type: Injectable,
465
+ args: [{
466
+ providedIn: 'root'
467
+ }]
468
+ }] });
469
+
470
+ class ApiRequest {
471
+ constructor(server = '', path = [], headers = {}, adapter, mapper, polling, retry = RetryOptions.adapt(), stream = false, displayError = false) {
472
+ this.server = server;
473
+ this.path = path;
474
+ this.headers = headers;
475
+ this.adapter = adapter;
476
+ this.mapper = mapper;
477
+ this.polling = polling;
478
+ this.retry = retry;
479
+ this.stream = stream;
480
+ this.displayError = displayError;
572
481
  }
573
- expired(state) {
574
- if (!state)
575
- return [];
576
- return state.settings?.filter(item => (item.options?.expires || 0) > 0 && this.utils.hasExpired(item.options?.expires || 0));
482
+ static adapt(item) {
483
+ const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
484
+ const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
485
+ return new ApiRequest(server, item?.path, (item?.headers) ? item.headers : {}, item?.adapter, item?.mapper, item?.polling ? Math.floor(item.polling) : 0, retryOptions, item?.stream, item?.displayError);
577
486
  }
578
- retrieveState() {
579
- const str = localStorage.getItem(this.storageSettingsName);
580
- const localStr = localStorage.getItem(this.storageName);
581
- const sessionStr = sessionStorage.getItem(this.storageName);
582
- const localData = (localStr) ? JSON.parse(localStr) : null;
583
- const sessionData = (sessionStr) ? JSON.parse(sessionStr) : null;
584
- const decryptedStr = str ? this.encryption.decrypt(str, this.app.appID) : null;
585
- const settings = (decryptedStr && decryptedStr !== null) ? JSON.parse(decryptedStr) : [];
586
- settings.forEach(store => {
587
- const expired = (store.options?.expires || 0) > 0 && this.utils.hasExpired(store.options?.expires || 0);
588
- if (!expired) {
589
- const hasStorage = this.hasGlobalStorage(store.options?.storage, store.id || '');
590
- if (!hasStorage) {
591
- this.createStore({ id: store.id, name: store.name, data: [], options: SettingOptions.adapt(store.options) });
592
- }
593
- else {
594
- const storeData = (store.options?.storage === StorageType.GLOBAL) ? localData.find(item => item.id === store.id) : sessionData.find(item => item.id === store.id);
595
- this.setStore({ id: store.id || '', name: store.name, data: storeData?.data, options: SettingOptions.adapt(store.options) });
596
- }
597
- }
598
- });
599
- this.stateRetrieved = true;
600
- }
601
- isString(obj) {
602
- return (Object.prototype.toString.call(obj) === '[object String]');
603
- }
604
- fixAndParseJSON(jsonString) {
605
- const fixedString = jsonString
606
- .replace(/'/g, '"')
607
- .replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
608
- .replace(/,\s*(\}|\])/g, '$1');
609
- try {
610
- return JSON.parse(fixedString);
611
- }
612
- catch (error) {
613
- throw new Error('Failed to parse JSON: ' + error.message);
614
- }
615
- }
616
- validStoreName(str) {
617
- return str
618
- .toLowerCase() // Convert to lowercase
619
- .replace(/\s+/g, '_') // Replace spaces with underscores
620
- .replace(/[^ -~]/g, ''); // Remove non-ASCII characters
621
- }
622
- hasGlobalStorage(type = StorageType.GLOBAL, id) {
623
- const strData = [];
624
- if (type === StorageType.GLOBAL) {
625
- const str = localStorage.getItem(this.storageName);
626
- strData.push(...(str ? JSON.parse(str) : []));
627
- }
628
- else {
629
- const str = sessionStorage.getItem(this.storageName);
630
- strData.push(...(str ? JSON.parse(str) : []));
631
- }
632
- const found = strData.find(store => store.id === id);
633
- return (found) ? true : false;
634
- }
635
- ngOnDestroy() {
636
- this.persistence$.unsubscribe();
637
- }
638
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
639
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, providedIn: 'root' }); }
640
- }
641
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, decorators: [{
642
- type: Injectable,
643
- args: [{ providedIn: 'root' }]
644
- }], ctorParameters: function () { return []; } });
645
-
646
- class HeadersService {
647
- constructor() {
648
- this.headers = {};
487
+ }
488
+
489
+ class HeadersService {
490
+ constructor() {
491
+ this.headers = {};
649
492
  }
650
493
  generateHeaders(headers) {
651
494
  const allHeaders = headers ? { ...this.headers, ...headers } : {};
@@ -681,6 +524,7 @@ class PathQueryService {
681
524
  return (Object.keys(query).length > 0) ? path + '?' + this.buildQueryPath(query) : path;
682
525
  }
683
526
  buildRestPath(server, params) {
527
+ server = (server) ? server : '';
684
528
  server = (server.charAt(0) === '/') ? server.substring(1) : server;
685
529
  return this.cleanUrlPath(server + '/' + params.join('/'));
686
530
  }
@@ -922,32 +766,32 @@ class RequestService {
922
766
  this.progress$ = this.progress.asObservable();
923
767
  }
924
768
  getRecordRequest(options) {
925
- this.isPending.next(true);
926
769
  const urlPath = this.buildUrlPath(options);
927
770
  const headers = this.buildCombinedHeaders(options);
771
+ this.isPending.next(true);
928
772
  return (options.stream)
929
773
  ? this.http.get(urlPath, headers).pipe(requestStreaming(), this.handleFinalize())
930
- : this.http.get(urlPath, headers).pipe(this.request(options), this.handleFinalize());
774
+ : this.http.get(urlPath, headers).pipe(this.request(options));
931
775
  }
932
776
  createRecordRequest(options, data) {
933
- this.isPending.next(true);
934
777
  const urlPath = this.buildUrlPath(options);
935
778
  const headers = this.buildCombinedHeaders(options);
779
+ this.isPending.next(true);
936
780
  return (options.stream)
937
781
  ? this.http.post(urlPath, data, headers).pipe(requestStreaming(), this.handleFinalize())
938
- : this.http.post(urlPath, data, headers).pipe(this.request(options), this.handleFinalize());
782
+ : this.http.post(urlPath, data, headers).pipe(this.request(options));
939
783
  }
940
784
  updateRecordRequest(options, data) {
941
- this.isPending.next(true);
942
785
  const urlPath = this.buildUrlPath(options);
943
786
  const headers = this.buildHeaders(options);
944
- return this.http.put(urlPath, data, headers).pipe(this.request(options), this.handleFinalize());
787
+ this.isPending.next(true);
788
+ return this.http.put(urlPath, data, headers).pipe(this.request(options));
945
789
  }
946
790
  deleteRecordRequest(options) {
947
- this.isPending.next(true);
948
791
  const urlPath = this.buildUrlPath(options);
949
792
  const headers = this.buildHeaders(options);
950
- return this.http.delete(urlPath, headers).pipe(this.handleFinalize());
793
+ this.isPending.next(true);
794
+ return this.http.delete(urlPath, headers).pipe(this.request(options));
951
795
  }
952
796
  // Helper functions
953
797
  buildUrlPath(options) {
@@ -957,13 +801,13 @@ class RequestService {
957
801
  return this.headersService.generateHeaders(options.headers);
958
802
  }
959
803
  buildCombinedHeaders(options) {
960
- const headers = this.headersService.generateHeaders(options.headers);
961
- return this.combineHeaders(headers, options.stream);
804
+ const headers = this.combineHeaders(options.headers, options.stream);
805
+ return this.headersService.generateHeaders(headers);
962
806
  }
963
807
  request(options) {
964
808
  return (source$) => {
965
809
  return source$.pipe(map(data => {
966
- if (options.adapter) {
810
+ if (options?.adapter) {
967
811
  return Array.isArray(data)
968
812
  ? data.map((item) => options.adapter(item))
969
813
  : options.adapter(data);
@@ -978,23 +822,62 @@ class RequestService {
978
822
  return this.http.get(urlPath, { responseType: 'blob', observe: 'events', reportProgress: true })
979
823
  .pipe(map((event) => {
980
824
  this.isPending.next(true);
825
+ const info = event;
981
826
  switch (event.type) {
982
827
  case HttpEventType.DownloadProgress:
983
- const status = (event.total) ? Math.round(event.loaded / (event.total || 1) * 100) : 100;
984
- this.progress.next(status);
985
- return status;
828
+ if (info.status !== 200) {
829
+ this.isPending.next(false);
830
+ throw new Error('Download failed');
831
+ return 0;
832
+ }
833
+ else {
834
+ const status = (event.total) ? Math.round(event.loaded / (event.total || 1) * 100) : 100;
835
+ this.progress.next(status);
836
+ return status;
837
+ }
986
838
  case HttpEventType.Response:
987
- const header_content = event.headers.get('Content-Disposition') || '';
988
- const file = header_content.split('=')[1].substring(0, header_content.split('=')[1].length);
989
- this.downloadFile(file, event.body);
990
- this.isPending.next(false);
991
- return 100;
839
+ try {
840
+ const header_content = event.headers.get('Content-Disposition') || '';
841
+ const fd = this.fileDetails(options.path);
842
+ if (!fd) {
843
+ this.isPending.next(false);
844
+ throw new Error('Save File: (file name and extension) not found in Headers or Path');
845
+ }
846
+ // checks if header_content is not empty and splits the header_content to get the file name
847
+ // otherwise, it will use the fileDownload - contains the file name and extension
848
+ const file = (header_content) ? header_content.split('=')[1].substring(0, header_content.split('=')[1].length) : `${fd.file}.${fd.ext}`;
849
+ this.downloadFile(file, event.body);
850
+ this.isPending.next(false);
851
+ return 100;
852
+ }
853
+ catch (error) {
854
+ throw new Error('Download failed');
855
+ }
992
856
  default:
993
857
  this.isPending.next(false);
994
858
  return 0;
995
859
  }
860
+ }), catchError(err => {
861
+ return throwError(() => err);
996
862
  }));
997
863
  }
864
+ fileDetails(path) {
865
+ const combinedPath = Array.isArray(path) ? path.join('/') : path;
866
+ if (!combinedPath || combinedPath.trim() === '') {
867
+ return;
868
+ }
869
+ const segments = combinedPath.split('/');
870
+ const fileNameWithExt = segments.pop() || '';
871
+ if (!fileNameWithExt.includes('.'))
872
+ return;
873
+ const dotIndex = fileNameWithExt.lastIndexOf('.');
874
+ if (fileNameWithExt.lastIndexOf('.') < 1)
875
+ return;
876
+ return {
877
+ file: fileNameWithExt.substring(0, dotIndex),
878
+ ext: fileNameWithExt.substring(dotIndex + 1),
879
+ };
880
+ }
998
881
  handleFinalize() {
999
882
  return finalize(() => this.isPending.next(false));
1000
883
  }
@@ -1046,12 +929,15 @@ class RequestService {
1046
929
  return fileType;
1047
930
  }
1048
931
  combineHeaders(headers, isStreaming) {
1049
- const options = {
1050
- observe: 'events',
1051
- responseType: 'text',
1052
- reportProgress: true,
1053
- };
1054
- return (isStreaming) ? { ...headers, ...options } : headers;
932
+ return (isStreaming) ?
933
+ {
934
+ ...headers,
935
+ observe: 'events',
936
+ responseType: 'text',
937
+ reportProgress: true,
938
+ Accept: 'text/event-stream'
939
+ }
940
+ : headers;
1055
941
  }
1056
942
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1057
943
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, providedIn: 'root' }); }
@@ -1072,8 +958,10 @@ function countdown(duration) {
1072
958
 
1073
959
  const DEFAULT_MAX_RETRIES = 3;
1074
960
  function delayedRetry(delayMs, maxRetry = DEFAULT_MAX_RETRIES) {
1075
- let retries = maxRetry;
1076
- return (src) => src.pipe(retryWhen((errors) => errors.pipe(delay(delayMs), mergeMap(error => retries-- > 0 ? of(error) : throwError(error)))));
961
+ return (src) => src.pipe(retry({
962
+ count: maxRetry,
963
+ delay: () => timer(delayMs)
964
+ }));
1077
965
  }
1078
966
 
1079
967
  /**
@@ -1088,11 +976,78 @@ function requestPolling(pollInterval, stopCondition$, isPending$) {
1088
976
  };
1089
977
  }
1090
978
 
979
+ class DatabaseStorage {
980
+ constructor(table = '', expiresIn) {
981
+ this.table = table;
982
+ this.expiresIn = expiresIn;
983
+ }
984
+ static adapt(item) {
985
+ return new DatabaseStorage(item?.table, item?.expiresIn);
986
+ }
987
+ }
988
+
989
+ class RetryOptions {
990
+ constructor(times = 0, delay = 3) {
991
+ this.times = times;
992
+ this.delay = delay;
993
+ }
994
+ static adapt(item) {
995
+ return new RetryOptions(item?.times, item?.delay);
996
+ }
997
+ }
998
+
999
+ var DataType;
1000
+ (function (DataType) {
1001
+ DataType[DataType["ANY"] = 0] = "ANY";
1002
+ DataType[DataType["ARRAY"] = 1] = "ARRAY";
1003
+ DataType[DataType["OBJECT"] = 2] = "OBJECT";
1004
+ })(DataType || (DataType = {}));
1005
+
1006
+ class ConfigHTTPOptions {
1007
+ constructor(server = '', path, headers, polling, retry, stream, displayError) {
1008
+ this.server = server;
1009
+ this.path = path;
1010
+ this.headers = headers;
1011
+ this.polling = polling;
1012
+ this.retry = retry;
1013
+ this.stream = stream;
1014
+ this.displayError = displayError;
1015
+ }
1016
+ static adapt(item) {
1017
+ const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
1018
+ const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
1019
+ return new ConfigHTTPOptions(server, (item?.path) ? item.path : [], (item?.headers) ? item.headers : {}, item?.polling ? Math.floor(item.polling) : 0, retryOptions, (item?.stream) ? item.stream : false, (item?.displayError) ? item.displayError : false);
1020
+ }
1021
+ }
1022
+
1023
+ class LocalStorageOptions {
1024
+ constructor(storageName, storageSettingsName, options) {
1025
+ this.storageName = storageName;
1026
+ this.storageSettingsName = storageSettingsName;
1027
+ this.options = options;
1028
+ }
1029
+ static adapt(item) {
1030
+ return new LocalStorageOptions((item?.storageName) ? item.storageName : 'storage', (item?.storageSettingsName) ? item.storageSettingsName : 'global-storage', (item?.options) ? SettingOptions.adapt(item.options) : SettingOptions.adapt());
1031
+ }
1032
+ }
1033
+
1034
+ class ConfigOptions {
1035
+ constructor(httpRequestOptions, LocalStorageOptions) {
1036
+ this.httpRequestOptions = httpRequestOptions;
1037
+ this.LocalStorageOptions = LocalStorageOptions;
1038
+ }
1039
+ static adapt(item) {
1040
+ return new ConfigOptions((item?.httpRequestOptions) ? ConfigHTTPOptions.adapt(item.httpRequestOptions) : undefined, (item?.LocalStorageOptions) ? LocalStorageOptions.adapt(item.LocalStorageOptions) : undefined);
1041
+ }
1042
+ }
1043
+
1091
1044
  class HTTPManagerService extends RequestService {
1092
- constructor() {
1045
+ constructor(configOptions) {
1093
1046
  super();
1047
+ this.configOptions = configOptions;
1094
1048
  this.toastMessage = inject(ToastMessageService);
1095
1049
  this.ng_injector = inject(Injector);
1050
+ this.objectMergerService = inject(ObjectMergerService);
1096
1051
  this.countdown = new BehaviorSubject(0);
1097
1052
  this.countdown$ = this.countdown.asObservable();
1098
1053
  this.error = new BehaviorSubject(false);
@@ -1100,62 +1055,87 @@ class HTTPManagerService extends RequestService {
1100
1055
  this.data = new BehaviorSubject(null);
1101
1056
  this.data$ = this.data.asObservable();
1102
1057
  this.polling$ = new Subject();
1058
+ this.config = ConfigOptions.adapt();
1059
+ this.config = (configOptions) ? ConfigOptions.adapt(configOptions) : ConfigOptions.adapt();
1103
1060
  }
1104
1061
  // REQUESTS
1105
1062
  getRequest(options, params) {
1063
+ this.isPending.next(true);
1106
1064
  this.data.next(null);
1107
- const updatedOptions = {
1108
- ...options,
1109
- path: params ? [...options.path, ...params] : options.path,
1110
- };
1065
+ options = (options) ? options : ApiRequest.adapt();
1066
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1111
1067
  const func = this.getRecordRequest;
1112
1068
  const requests = this.createRequest(func, updatedOptions);
1113
- return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1069
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1070
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1071
+ if (updatedOptions.displayError)
1072
+ this.handleErrorWithSnackBar(err);
1073
+ this.isPending.next(false);
1074
+ return this.handleError(err);
1075
+ }));
1114
1076
  }
1115
1077
  postRequest(data, options, params) {
1078
+ this.isPending.next(true);
1116
1079
  this.data.next(null);
1117
- const updatedOptions = {
1118
- ...options,
1119
- path: params ? [...options.path, ...params] : options.path,
1120
- };
1080
+ options = (options) ? options : ApiRequest.adapt();
1081
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1121
1082
  const func = this.createRecordRequest;
1122
1083
  const requests = this.createRequest(func, updatedOptions, data);
1123
- return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1084
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1085
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1086
+ if (updatedOptions.displayError)
1087
+ this.handleErrorWithSnackBar(err);
1088
+ this.isPending.next(false);
1089
+ return this.handleError(err);
1090
+ }));
1124
1091
  }
1125
1092
  putRequest(data, options, params) {
1093
+ this.isPending.next(true);
1126
1094
  this.data.next(null);
1127
- const updatedOptions = {
1128
- ...options,
1129
- path: params ? [...options.path, ...params] : options.path,
1130
- };
1095
+ options = (options) ? options : ApiRequest.adapt();
1096
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1131
1097
  const func = this.updateRecordRequest;
1132
1098
  const requests = this.createRequest(func, updatedOptions, data);
1133
- return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1099
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1100
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1101
+ if (updatedOptions.displayError)
1102
+ this.handleErrorWithSnackBar(err);
1103
+ this.isPending.next(false);
1104
+ return this.handleError(err);
1105
+ }));
1134
1106
  }
1135
1107
  deleteRequest(options, params) {
1108
+ this.isPending.next(true);
1136
1109
  this.data.next(null);
1137
- const updatedOptions = {
1138
- ...options,
1139
- path: params ? [...options.path, ...params] : options.path,
1140
- };
1110
+ options = (options) ? options : ApiRequest.adapt();
1111
+ const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1141
1112
  const func = this.deleteRecordRequest;
1142
1113
  const requests = this.createRequest(func, updatedOptions);
1143
- return this.createObservable(options, requests, func.name).pipe(tap(data => this.data.next(data)));
1114
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.next(data)))
1115
+ .pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
1116
+ if (updatedOptions.displayError)
1117
+ this.handleErrorWithSnackBar(err);
1118
+ this.isPending.next(false);
1119
+ return this.handleError(err);
1120
+ }));
1144
1121
  }
1145
1122
  downloadRequest(options, params) {
1123
+ this.isPending.next(true);
1124
+ options = (options) ? options : ApiRequest.adapt();
1125
+ const mergedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
1146
1126
  const updatedOptions = {
1147
- ...options,
1127
+ ...mergedOptions,
1148
1128
  path: params ? [...options.path, ...params] : options.path,
1149
1129
  };
1150
1130
  const func = this.downloadFileRequest;
1151
1131
  const requests = this.createRequest(func, updatedOptions);
1152
- return this.createObservable(options, requests, func.name)
1153
- .pipe(tap(() => this.error.next(false)), catchError((err) => {
1132
+ return this.createObservable(updatedOptions, requests, func.name)
1133
+ .pipe(catchError((err) => {
1154
1134
  this.error.next(true);
1155
- return EMPTY;
1135
+ this.isPending.next(false);
1136
+ return this.handleError(err);
1156
1137
  }));
1157
1138
  }
1158
- // UTILS
1159
1139
  createObservable(options, request$, funcName) {
1160
1140
  const polling = options.polling ? (options.polling > 0 ? true : false) : false;
1161
1141
  const isPolling = polling &&
@@ -1168,36 +1148,35 @@ class HTTPManagerService extends RequestService {
1168
1148
  if (!options.polling)
1169
1149
  return;
1170
1150
  const count = options.polling ? options.polling : 0;
1171
- console.log('COUNT:', count);
1151
+ // console.log('COUNT:', count);
1172
1152
  countdown(count)
1173
1153
  .pipe(map((x) => {
1174
- console.log('XX:', count, x);
1154
+ // console.log('XX:', count, x);
1175
1155
  const pollingInSec = options.polling || 0;
1176
1156
  const percentageCompleted = ((pollingInSec - x) / pollingInSec) * 100;
1177
1157
  return Math.round(percentageCompleted);
1178
1158
  }))
1179
1159
  .subscribe((countDownValue) => {
1180
- console.log(this.countdown.value, countDownValue);
1160
+ // console.log(this.countdown.value, countDownValue);
1181
1161
  this.countdown.next(countDownValue);
1182
1162
  });
1183
1163
  }))
1184
1164
  : request$.pipe(catchError((err) => {
1185
1165
  if (err instanceof HttpErrorResponse) {
1186
1166
  this.error.next(true);
1187
- if (options.displayError)
1188
- this.handleErrorWithSnackBar(err);
1189
1167
  return this.handleError(err);
1190
1168
  }
1191
1169
  return throwError(() => err);
1192
- }), finalize(() => this.isPending.next(false)));
1170
+ }));
1193
1171
  return polling$.pipe(catchError((err, caught) => {
1194
1172
  if (err instanceof HttpErrorResponse) {
1195
1173
  this.error.next(true);
1196
- this.stopPolling();
1174
+ if (isPolling)
1175
+ this.stopPolling();
1197
1176
  return this.handleError(err);
1198
1177
  }
1199
1178
  return throwError(() => err);
1200
- }), options.retry.times > 0
1179
+ }), options.retry?.times > 0
1201
1180
  ? delayedRetry((options?.retry.delay || 3) * 1000, (options?.retry.times || 0) - 1)
1202
1181
  : (source) => source);
1203
1182
  }
@@ -1207,24 +1186,25 @@ class HTTPManagerService extends RequestService {
1207
1186
  }
1208
1187
  prepareRequestData(options, data, funcName) {
1209
1188
  if ((options.mapper && funcName === 'updateRecordRequest') || funcName === 'createRecordRequest') {
1210
- data = options.mapper
1211
- ? Array.isArray(data)
1212
- ? map((item) => options.mapper(item))
1213
- : options.mapper(data)
1214
- : data;
1189
+ if (options?.mapper) {
1190
+ data = options.mapper
1191
+ ? Array.isArray(data)
1192
+ ? map((item) => options.mapper(item))
1193
+ : options.mapper(data)
1194
+ : data;
1195
+ }
1215
1196
  }
1216
1197
  else {
1217
- data = options.adapter
1218
- ? Array.isArray(data)
1198
+ if (options?.adapter) {
1199
+ data = Array.isArray(data)
1219
1200
  ? map((item) => options.adapter(item))
1220
- : options.adapter(data)
1221
- : data;
1201
+ : options.adapter(data);
1202
+ }
1222
1203
  }
1223
1204
  return { options: options, data: data };
1224
1205
  }
1225
1206
  // MISC
1226
1207
  handleError(error) {
1227
- this.isPending.next(false);
1228
1208
  return throwError(() => error);
1229
1209
  }
1230
1210
  handleErrorWithSnackBar(error) {
@@ -1241,7 +1221,7 @@ class HTTPManagerService extends RequestService {
1241
1221
  this.isPending.next(false);
1242
1222
  this.polling$.next();
1243
1223
  }
1244
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1224
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, deps: [{ token: CONFIG_SETTINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1245
1225
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, providedIn: 'root' }); }
1246
1226
  }
1247
1227
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, decorators: [{
@@ -1249,53 +1229,298 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1249
1229
  args: [{
1250
1230
  providedIn: 'root',
1251
1231
  }]
1252
- }], ctorParameters: function () { return []; } });
1232
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
1233
+ type: Optional
1234
+ }, {
1235
+ type: Inject,
1236
+ args: [CONFIG_SETTINGS_TOKEN]
1237
+ }] }]; } });
1253
1238
 
1254
- class DatabaseStorage {
1255
- constructor(table = '', expiresIn) {
1256
- this.table = table;
1257
- this.expiresIn = expiresIn;
1239
+ const storage = {
1240
+ localStores: [],
1241
+ sessionStores: [],
1242
+ settings: [],
1243
+ };
1244
+ class LocalStorageManagerService extends ComponentStore {
1245
+ startTimer() {
1246
+ const timer$ = interval(1000 * 3).pipe(withLatestFrom(this.data$), map(([_, state]) => state), tap((state) => {
1247
+ const expired = this.expired(state) ? this.expired(state) : [];
1248
+ if (expired.length > 0) {
1249
+ const ids = expired.map((item) => item.id);
1250
+ const updatedState = {
1251
+ ...state,
1252
+ localStores: state.localStores.filter((item) => !ids.includes(item.id)),
1253
+ sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
1254
+ settings: state.settings.filter((item) => !ids.includes(item.id)),
1255
+ };
1256
+ this.persistState(updatedState);
1257
+ this.updateState(updatedState);
1258
+ }
1259
+ }));
1260
+ timer$.subscribe();
1258
1261
  }
1259
- static adapt(item) {
1260
- return new DatabaseStorage(item?.table, item?.expiresIn);
1262
+ constructor(config) {
1263
+ super(storage);
1264
+ this.config = config;
1265
+ this.storageName = 'storage';
1266
+ this.storageSettingsName = 'global-storage';
1267
+ this.defaultOptions = SettingOptions.adapt();
1268
+ this.stateRetrieved = false;
1269
+ this.encrypted = false;
1270
+ this.app = inject(AppService);
1271
+ this.utils = inject(UtilsService);
1272
+ this.objectMergerService = inject(ObjectMergerService);
1273
+ this.encryption = inject(SymmetricalEncryptionService);
1274
+ this.encryptionTest = inject(EncryptionTestService);
1275
+ // SELECTORS
1276
+ this.data$ = this.select((state) => state);
1277
+ this.stores$ = this.select((state) => state.settings);
1278
+ this.storeExists$ = (store) => this.select(this.data$, (data) => data.settings.find(item => item.name === store) ? true : false);
1279
+ this.store$ = (store) => this.select(this.data$, (data) => {
1280
+ const foundStore = data.settings.find(item => item.name === store);
1281
+ if (foundStore) {
1282
+ const options = SettingOptions.adapt(foundStore.options);
1283
+ const found = foundStore.options?.storage === StorageType.GLOBAL
1284
+ ? data.localStores.find(item => item.id === foundStore.id)
1285
+ : data.sessionStores.find(item => item.id === foundStore.id);
1286
+ if (!found) {
1287
+ this.deleteStore({ name: store });
1288
+ return;
1289
+ }
1290
+ if (!this.app?.appID) {
1291
+ console.warn('No App ID found - AppId not Provided');
1292
+ return;
1293
+ }
1294
+ const storageData = (options.encrypted) ? this.encryption.decrypt(found.data, this.app.appID) : found.data;
1295
+ return (this.isString(storageData)) ? JSON.parse(storageData) : storageData;
1296
+ }
1297
+ else {
1298
+ return null;
1299
+ }
1300
+ });
1301
+ this.settings$ = this.select(state => (state) ? state.settings : storage.settings);
1302
+ this.setting$ = (store) => this.select(this.data$, (state) => {
1303
+ const foundSetting = state.settings.find(item => item.name === store);
1304
+ return (foundSetting) ? foundSetting : null;
1305
+ });
1306
+ this.persistence$ = this.data$
1307
+ .subscribe(data => {
1308
+ if (this.stateRetrieved)
1309
+ this.persistState(data);
1310
+ });
1311
+ this.updateState = this.updater((state, updatedState) => ({
1312
+ ...updatedState,
1313
+ }));
1314
+ this.setStore = this.updater((state, store) => {
1315
+ const settings = StorageOption.adapt(store);
1316
+ settings.options = this.objectMergerService.mergeOptions(settings.options || this.defaultOptions, this.defaultOptions);
1317
+ const type = store.options.storage;
1318
+ const hasStore = this.hasGlobalStorage(type, store.id);
1319
+ store.name = this.validStoreName(store.name);
1320
+ if (!hasStore) {
1321
+ console.warn(`No such Store: ${store.name}`);
1322
+ return state;
1323
+ }
1324
+ else {
1325
+ const str = this.encryptionTest.isEncrypted(store.data) ? store.data : JSON.stringify(store.data);
1326
+ const dataStr = (this.isObjectOrArray(str)) ? (store.options.encrypted) ? this.encryption.encrypt(str, this.app.appID) : store.data : store.data;
1327
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
1328
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
1329
+ return {
1330
+ ...state,
1331
+ localStores: [...state.localStores, ...localData],
1332
+ sessionStores: [...state.sessionStores, ...sessionData],
1333
+ settings: [...state.settings, ...[settings]],
1334
+ };
1335
+ }
1336
+ });
1337
+ this.createStore = this.updater((state, store) => {
1338
+ const settings = StorageOption.adapt(store);
1339
+ settings.options = this.objectMergerService.mergeOptions(settings.options || this.defaultOptions, this.defaultOptions);
1340
+ const foundStore = state?.settings.some(item => item.name === store.name);
1341
+ const expires = (settings.options?.expiresIn) ? this.utils.expires(settings.options?.expiresIn) : 0;
1342
+ if (settings.options)
1343
+ settings.options.expires = expires;
1344
+ store.name = this.validStoreName(store.name);
1345
+ if (foundStore) {
1346
+ return state;
1347
+ }
1348
+ else {
1349
+ if (!this.isObjectOrArray(store.data)) {
1350
+ console.warn('Data must ba an Object or Array');
1351
+ return;
1352
+ }
1353
+ store.data = (this.isString(store.data)) ? JSON.parse(store.data) : store.data;
1354
+ const dataStr = (store.options.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
1355
+ const localData = (settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
1356
+ const sessionData = (settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
1357
+ return {
1358
+ ...state,
1359
+ localStores: [...state.localStores, ...localData],
1360
+ sessionStores: [...state.sessionStores, ...sessionData],
1361
+ settings: [...state.settings, ...[settings]],
1362
+ };
1363
+ }
1364
+ });
1365
+ this.updateStore = this.updater((state, store) => {
1366
+ store.name = this.validStoreName(store.name);
1367
+ const settings = state.settings.find(item => item.name === store.name);
1368
+ if (settings) {
1369
+ const type = settings.options?.storage;
1370
+ const hasStore = this.hasGlobalStorage(type, settings.id || '');
1371
+ if (!hasStore) {
1372
+ console.warn(`No such Store: ${store.name}`);
1373
+ }
1374
+ else {
1375
+ const dataStr = (settings.options?.encrypted) ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
1376
+ const localData = (dataStr && settings.options?.storage === StorageType.GLOBAL) ? [{ data: dataStr, id: settings.id }] : [];
1377
+ const sessionData = (dataStr && settings.options?.storage === StorageType.SESSION) ? [{ data: dataStr, id: settings.id }] : [];
1378
+ state.localStores = state.localStores.filter(item => item.id !== settings.id);
1379
+ state.sessionStores = state.sessionStores.filter(item => item.id !== settings.id);
1380
+ return {
1381
+ ...state,
1382
+ localStores: [...state.localStores, ...localData],
1383
+ sessionStores: [...state.sessionStores, ...sessionData],
1384
+ };
1385
+ }
1386
+ }
1387
+ return state;
1388
+ });
1389
+ this.deleteStore = this.updater((state, store) => {
1390
+ store.name = this.validStoreName(store.name);
1391
+ const id = state.settings.find(item => item.name === store.name)?.id;
1392
+ if (id) {
1393
+ const settings = state.settings.filter(item => item.id !== id);
1394
+ const localData = state.localStores.filter(item => item.id !== id);
1395
+ const sessionData = state.sessionStores.filter(item => item.id !== id);
1396
+ return {
1397
+ ...state,
1398
+ localStores: [...localData],
1399
+ sessionStores: [...sessionData],
1400
+ settings: [...settings],
1401
+ };
1402
+ }
1403
+ else {
1404
+ console.warn(`No such Store: ${store.name}`);
1405
+ return state;
1406
+ }
1407
+ });
1408
+ this.isObjectOrArray = (obj) => {
1409
+ let parsed;
1410
+ try {
1411
+ parsed = JSON.parse(obj);
1412
+ }
1413
+ catch (e) {
1414
+ return false;
1415
+ }
1416
+ if (Array.isArray(parsed)) {
1417
+ const allStringsOrObjectsOrNumbers = parsed.every(item => typeof item === 'string' ||
1418
+ typeof item === 'object' && item !== null ||
1419
+ typeof item === 'number');
1420
+ return allStringsOrObjectsOrNumbers;
1421
+ }
1422
+ return typeof parsed === 'object' && parsed !== null;
1423
+ };
1424
+ this.storageName = config.LocalStorageOptions?.storageName || this.storageName;
1425
+ this.storageSettingsName = config.LocalStorageOptions?.storageSettingsName || this.storageSettingsName;
1426
+ this.defaultOptions = config.LocalStorageOptions?.options || this.defaultOptions;
1427
+ this.retrieveState();
1428
+ this.startTimer();
1261
1429
  }
1262
- }
1263
-
1264
- class RetryOptions {
1265
- constructor(times = 0, delay = 0) {
1266
- this.times = times;
1267
- this.delay = delay;
1430
+ resetStore() {
1431
+ const newState = {
1432
+ localStores: [],
1433
+ sessionStores: [],
1434
+ settings: [],
1435
+ };
1436
+ this.updateState(newState);
1437
+ this.persistState(newState);
1268
1438
  }
1269
- static adapt(item) {
1270
- return new RetryOptions(item?.times ? Math.floor(item.times) : 0, item?.delay ? Math.floor(item.delay) : 0);
1439
+ persistState(state) {
1440
+ if (!state)
1441
+ return;
1442
+ const strLocal = JSON.stringify(state.localStores);
1443
+ localStorage.setItem(this.storageName, strLocal);
1444
+ const strSession = JSON.stringify(state.sessionStores);
1445
+ sessionStorage.setItem(this.storageName, strSession);
1446
+ const settingsStr = this.encryption.encrypt(state.settings, this.app.appID);
1447
+ localStorage.setItem(this.storageSettingsName, settingsStr || '');
1271
1448
  }
1272
- }
1273
-
1274
- var DataType;
1275
- (function (DataType) {
1276
- DataType[DataType["ANY"] = 0] = "ANY";
1277
- DataType[DataType["ARRAY"] = 1] = "ARRAY";
1278
- DataType[DataType["OBJECT"] = 2] = "OBJECT";
1279
- })(DataType || (DataType = {}));
1280
-
1281
- class ApiRequest {
1282
- constructor(server = '', path = [], headers = {}, adapter, mapper, polling, retry = RetryOptions.adapt(), stream = false, displayError = false) {
1283
- this.server = server;
1284
- this.path = path;
1285
- this.headers = headers;
1286
- this.adapter = adapter;
1287
- this.mapper = mapper;
1288
- this.polling = polling;
1289
- this.retry = retry;
1290
- this.stream = stream;
1291
- this.displayError = displayError;
1449
+ expired(state) {
1450
+ if (!state)
1451
+ return [];
1452
+ return state.settings?.filter(item => (item.options?.expires || 0) > 0 && this.utils.hasExpired(item.options?.expires || 0));
1453
+ }
1454
+ retrieveState() {
1455
+ const str = localStorage.getItem(this.storageSettingsName);
1456
+ const localStr = localStorage.getItem(this.storageName);
1457
+ const sessionStr = sessionStorage.getItem(this.storageName);
1458
+ const localData = (localStr) ? JSON.parse(localStr) : null;
1459
+ const sessionData = (sessionStr) ? JSON.parse(sessionStr) : null;
1460
+ const decryptedStr = str ? this.encryption.decrypt(str, this.app.appID) : null;
1461
+ const settings = (decryptedStr && decryptedStr !== null) ? JSON.parse(decryptedStr) : [];
1462
+ settings.forEach(store => {
1463
+ const expired = (store.options?.expires || 0) > 0 && this.utils.hasExpired(store.options?.expires || 0);
1464
+ if (!expired) {
1465
+ const hasStorage = this.hasGlobalStorage(store.options?.storage, store.id || '');
1466
+ if (!hasStorage) {
1467
+ this.createStore({ id: store.id, name: store.name, data: [], options: SettingOptions.adapt(store.options) });
1468
+ }
1469
+ else {
1470
+ const storeData = (store.options?.storage === StorageType.GLOBAL) ? localData.find(item => item.id === store.id) : sessionData.find(item => item.id === store.id);
1471
+ this.setStore({ id: store.id || '', name: store.name, data: storeData?.data, options: SettingOptions.adapt(store.options) });
1472
+ }
1473
+ }
1474
+ });
1475
+ this.stateRetrieved = true;
1476
+ }
1477
+ isString(obj) {
1478
+ return (Object.prototype.toString.call(obj) === '[object String]');
1479
+ }
1480
+ fixAndParseJSON(jsonString) {
1481
+ const fixedString = jsonString
1482
+ .replace(/'/g, '"')
1483
+ .replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
1484
+ .replace(/,\s*(\}|\])/g, '$1');
1485
+ try {
1486
+ return JSON.parse(fixedString);
1487
+ }
1488
+ catch (error) {
1489
+ throw new Error('Failed to parse JSON: ' + error.message);
1490
+ }
1491
+ }
1492
+ validStoreName(str) {
1493
+ return str
1494
+ .toLowerCase() // Convert to lowercase
1495
+ .replace(/\s+/g, '_') // Replace spaces with underscores
1496
+ .replace(/[^ -~]/g, ''); // Remove non-ASCII characters
1497
+ }
1498
+ hasGlobalStorage(type = StorageType.GLOBAL, id) {
1499
+ const strData = [];
1500
+ if (type === StorageType.GLOBAL) {
1501
+ const str = localStorage.getItem(this.storageName);
1502
+ strData.push(...(str ? JSON.parse(str) : []));
1503
+ }
1504
+ else {
1505
+ const str = sessionStorage.getItem(this.storageName);
1506
+ strData.push(...(str ? JSON.parse(str) : []));
1507
+ }
1508
+ const found = strData.find(store => store.id === id);
1509
+ return (found) ? true : false;
1292
1510
  }
1293
- static adapt(item) {
1294
- const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
1295
- const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
1296
- return new ApiRequest(server, item?.path, (item?.headers) ? item.headers : {}, item?.adapter, item?.mapper, item?.polling ? Math.floor(item.polling) : 0, retryOptions, item?.stream, item?.displayError);
1511
+ ngOnDestroy() {
1512
+ this.persistence$.unsubscribe();
1297
1513
  }
1514
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable }); }
1515
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, providedIn: 'root' }); }
1298
1516
  }
1517
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageManagerService, decorators: [{
1518
+ type: Injectable,
1519
+ args: [{ providedIn: 'root' }]
1520
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
1521
+ type: Inject,
1522
+ args: [CONFIG_SETTINGS_TOKEN]
1523
+ }] }]; } });
1299
1524
 
1300
1525
  class RequestOptions {
1301
1526
  constructor(path = [], headers = {}) {
@@ -1313,7 +1538,7 @@ const defaultState = {
1313
1538
  dataObject: null,
1314
1539
  };
1315
1540
  class HTTPManagerStateService extends ComponentStore {
1316
- constructor(apiOptions, dataType, database) {
1541
+ constructor(apiOptions = ApiRequest.adapt(), dataType, database) {
1317
1542
  super(defaultState);
1318
1543
  this.apiOptions = apiOptions;
1319
1544
  this.dataType = dataType;
@@ -1347,9 +1572,6 @@ class HTTPManagerStateService extends ComponentStore {
1347
1572
  });
1348
1573
  // --------------------------------------------------------------------------------------------------
1349
1574
  // UPDATERS
1350
- this.resetData$ = this.updater((state) => {
1351
- return { ...state, data: [], dataObject: null };
1352
- });
1353
1575
  this.setData$ = this.updater((state, data) => {
1354
1576
  if (!data)
1355
1577
  return state;
@@ -1498,35 +1720,6 @@ class HTTPManagerStateService extends ComponentStore {
1498
1720
  }
1499
1721
  }));
1500
1722
  })));
1501
- // FETCH PAGINATION
1502
- this.fetchPaginationCancel$ = new Subject();
1503
- this.fetchPaginationRecords = (size = 10, options) => this.effect(() => {
1504
- this.fetchPaginationCancel$.next();
1505
- return of(RequestOptions.adapt(options)).pipe(switchMap(() => {
1506
- this.resetData$();
1507
- const requestOptions = this.updateRequestOptions(options?.headers);
1508
- const updatedPath = [...(options?.path ?? []), { size, page: 1 }];
1509
- const firstRequestObservable = this.httpManagerService.getRequest(requestOptions, updatedPath).pipe(takeUntil(this.fetchPaginationCancel$), tap(() => this.httpManagerService.isPending.next(true)), tap((data) => {
1510
- data = !data ? (this.dataType === DataType.ARRAY ? [] : {}) : data;
1511
- this.setData$(data.results);
1512
- }));
1513
- return firstRequestObservable.pipe(takeUntil(this.fetchPaginationCancel$), expand((data) => {
1514
- this.httpManagerService.isPending.next(true);
1515
- const totalPages = data?.totalPages || 1;
1516
- const currentPage = data?.page || 1;
1517
- if (currentPage < totalPages) {
1518
- const nextPage = currentPage + 1;
1519
- const updatedPathWithNextPage = [...(options?.path ?? []), { size, page: nextPage }];
1520
- const nextRequestObservable = this.httpManagerService.getRequest(requestOptions, updatedPathWithNextPage).pipe(takeUntil(this.fetchPaginationCancel$), tap(() => this.httpManagerService.isPending.next(true)), tap((nextData) => {
1521
- nextData = !nextData ? (this.dataType === DataType.ARRAY ? [] : {}) : nextData;
1522
- this.setData$(nextData.results);
1523
- }));
1524
- return nextRequestObservable;
1525
- }
1526
- return EMPTY;
1527
- }), takeUntil(this.fetchPaginationCancel$), tap(() => this.httpManagerService.isPending.next(false)));
1528
- }));
1529
- });
1530
1723
  this.setApiRequestOptions(apiOptions, dataType, database);
1531
1724
  }
1532
1725
  setApiRequestOptions(apiOptions, dataType, database) {
@@ -1535,7 +1728,7 @@ class HTTPManagerStateService extends ComponentStore {
1535
1728
  this.hasDatabase = this.database?.table === "" ? false : true;
1536
1729
  this.database = (this.hasDatabase) ? DatabaseStorage.adapt(database) : undefined;
1537
1730
  }
1538
- get apiRequestOptions() {
1731
+ get ApiRequestOptions() {
1539
1732
  return this.apiOptions;
1540
1733
  }
1541
1734
  initStorage() {
@@ -1586,7 +1779,7 @@ class HTTPManagerStateService extends ComponentStore {
1586
1779
  }
1587
1780
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService, decorators: [{
1588
1781
  type: Injectable
1589
- }], ctorParameters: function () { return [{ type: ApiRequest, decorators: [{
1782
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1590
1783
  type: Inject,
1591
1784
  args: [API_OPTS]
1592
1785
  }] }, { type: undefined, decorators: [{
@@ -1660,7 +1853,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1660
1853
 
1661
1854
  class RequestErrorInterceptor {
1662
1855
  constructor() {
1663
- this.toastMessage = inject(ToastMessageService$1);
1856
+ this.toastMessage = inject(ToastMessageService);
1664
1857
  }
1665
1858
  intercept(req, next) {
1666
1859
  return next.handle(req).pipe(catchError$1((error) => {
@@ -1672,8 +1865,8 @@ class RequestErrorInterceptor {
1672
1865
  duration: 5 * 1000, //5 seconds
1673
1866
  });
1674
1867
  if (error.status >= 400 && error.status < 500) {
1675
- displayError.color = ToastColors.ERROR;
1676
- displayError.message = `${error.status}: ${error.statusText}`;
1868
+ displayError.color = ToastColors.WARN;
1869
+ displayError.message = error.error || `${error.status}: ${error.statusText}`;
1677
1870
  console.error('Client Error:', {
1678
1871
  status: error.status,
1679
1872
  message: error.message,
@@ -1684,7 +1877,7 @@ class RequestErrorInterceptor {
1684
1877
  }
1685
1878
  else if (error.status >= 500) {
1686
1879
  displayError.color = ToastColors.ERROR;
1687
- displayError.message = `${error.status}: ${error.statusText}`;
1880
+ displayError.message = error.error || `${error.status}: ${error.statusText}`;
1688
1881
  console.error('Server Error:', {
1689
1882
  status: error.status,
1690
1883
  message: error.message,
@@ -1703,6 +1896,1160 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1703
1896
  type: Injectable
1704
1897
  }] });
1705
1898
 
1899
+ const PROXY_CONFIG = new InjectionToken('PROXY_CONFIG');
1900
+ class ProxyDebuggerInterceptor {
1901
+ constructor(proxyConfig) {
1902
+ this.proxyConfig = proxyConfig;
1903
+ }
1904
+ intercept(req, next) {
1905
+ if (!this.proxyConfig) {
1906
+ return next.handle(req);
1907
+ }
1908
+ const headers = req.headers.keys().reduce((acc, key) => {
1909
+ acc[key] = req.headers.get(key) || '';
1910
+ return acc;
1911
+ }, {});
1912
+ for (const proxyPath in this.proxyConfig) {
1913
+ if (this.proxyConfig.hasOwnProperty(proxyPath)) {
1914
+ const proxyDetails = this.proxyConfig[proxyPath];
1915
+ const regex = new RegExp('^' + proxyPath.replace('/', '').replace('*', '(.*)'));
1916
+ if (regex.test(req.url)) {
1917
+ const target = proxyDetails.target;
1918
+ const endpoint = req.url.replace(regex, '$1');
1919
+ const actualPath = target + '/' + endpoint;
1920
+ console.log('Request Proxied:', {
1921
+ requestUrl: req.url,
1922
+ requestPayload: req.body,
1923
+ headers: headers,
1924
+ proxyPath: proxyPath,
1925
+ actualPath: actualPath,
1926
+ });
1927
+ }
1928
+ }
1929
+ }
1930
+ return next.handle(req);
1931
+ }
1932
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProxyDebuggerInterceptor, deps: [{ token: PROXY_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1933
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProxyDebuggerInterceptor }); }
1934
+ }
1935
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ProxyDebuggerInterceptor, decorators: [{
1936
+ type: Injectable
1937
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1938
+ type: Optional
1939
+ }, {
1940
+ type: Inject,
1941
+ args: [PROXY_CONFIG]
1942
+ }] }]; } });
1943
+
1944
+ class DownloadFileComponent {
1945
+ constructor() {
1946
+ this.subscriptions = new Subscription();
1947
+ this.displayError = 3; // seconds
1948
+ this.diameter = 32;
1949
+ this.mode = 'determinate';
1950
+ this.isPending = false;
1951
+ this.active = false;
1952
+ this.disabled = false;
1953
+ this.error = new EventEmitter();
1954
+ this._progress = 0;
1955
+ this._hasError = false;
1956
+ this.errorTimerActive = false;
1957
+ }
1958
+ set progress(value) {
1959
+ this._progress = value ?? 0;
1960
+ }
1961
+ get progress() {
1962
+ return this._progress;
1963
+ }
1964
+ set hasError(value) {
1965
+ this._hasError = !!value;
1966
+ if (this._hasError && !this.errorTimerActive) {
1967
+ this.errorTimerActive = true;
1968
+ this.active = false;
1969
+ this.error.emit();
1970
+ this.subscriptions.add(timer(this.displayError * 1000)
1971
+ .subscribe((err) => {
1972
+ this._hasError = false;
1973
+ this.errorTimerActive = false;
1974
+ }));
1975
+ }
1976
+ }
1977
+ get hasError() {
1978
+ return this._hasError;
1979
+ }
1980
+ ngOnInit() { }
1981
+ onAction() {
1982
+ this.isPending = false;
1983
+ if (this.event)
1984
+ this.event();
1985
+ }
1986
+ ngOnDestroy() {
1987
+ this.subscriptions.unsubscribe();
1988
+ }
1989
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DownloadFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1990
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DownloadFileComponent, selector: "app-download-file", inputs: { event: "event", displayError: "displayError", diameter: "diameter", mode: "mode", isPending: "isPending", active: "active", disabled: "disabled", progress: "progress", hasError: "hasError" }, outputs: { error: "error" }, ngImport: i0, template: "<ng-container *ngIf=\"!isPending; else DOWNLOADING\">\n <ng-container *ngIf=\"hasError; else NORMAL\">\n <div class=\"width center-txt\" style=\"margin-bottom: 4px;\">\n <mat-icon color=\"warn\" class=\"warn-icon\">warning</mat-icon>\n </div>\n </ng-container>\n <ng-template #NORMAL>\n <ng-container *ngIf=\"active; else ACTION\">\n\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n\n </ng-container>\n <ng-template #ACTION>\n <button data-tracking=\"export-btn\" mat-icon-button (click)=\"onAction()\" class=\"icon-button\" [disabled]=\"disabled\">\n <mat-icon class=\"custom-icon\">file_download</mat-icon>\n </button>\n </ng-template>\n </ng-template>\n</ng-container>\n\n<ng-template #DOWNLOADING>\n <div\n class=\"spinner-container\"\n *ngIf=\"(progress > 0 && progress < 100); else INDETERMINATE\"\n >\n <div class=\"spinner-background\">\n {{progress}}%\n </div>\n <mat-progress-spinner\n color=\"primary\"\n [mode]=\"mode\"\n [value]=\"progress\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n <ng-template #INDETERMINATE>\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n </ng-template>\n\n</ng-template>\n\n\n\n", styles: [":not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:44px;height:44px;font-size:12px;line-height:32px;text-align:center;overflow:hidden;border-radius:50%;border:solid 5px whitesmoke}.center-txt{align-content:center;text-align:-webkit-center}.width{width:48px;height:48px}.icon-button{display:flex;align-items:center;justify-content:center;width:48px;height:48px;padding:0}.container-obj{display:flex;justify-content:center;align-items:center;width:48px;height:48px}.centered-obj-div{text-align:center}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], encapsulation: i0.ViewEncapsulation.None }); }
1991
+ }
1992
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DownloadFileComponent, decorators: [{
1993
+ type: Component,
1994
+ args: [{ selector: 'app-download-file', encapsulation: ViewEncapsulation.None, template: "<ng-container *ngIf=\"!isPending; else DOWNLOADING\">\n <ng-container *ngIf=\"hasError; else NORMAL\">\n <div class=\"width center-txt\" style=\"margin-bottom: 4px;\">\n <mat-icon color=\"warn\" class=\"warn-icon\">warning</mat-icon>\n </div>\n </ng-container>\n <ng-template #NORMAL>\n <ng-container *ngIf=\"active; else ACTION\">\n\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n\n </ng-container>\n <ng-template #ACTION>\n <button data-tracking=\"export-btn\" mat-icon-button (click)=\"onAction()\" class=\"icon-button\" [disabled]=\"disabled\">\n <mat-icon class=\"custom-icon\">file_download</mat-icon>\n </button>\n </ng-template>\n </ng-template>\n</ng-container>\n\n<ng-template #DOWNLOADING>\n <div\n class=\"spinner-container\"\n *ngIf=\"(progress > 0 && progress < 100); else INDETERMINATE\"\n >\n <div class=\"spinner-background\">\n {{progress}}%\n </div>\n <mat-progress-spinner\n color=\"primary\"\n [mode]=\"mode\"\n [value]=\"progress\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n <ng-template #INDETERMINATE>\n <div class=\"container-obj\">\n <div class=\"centered-obj-div\">\n <mat-progress-spinner\n color=\"primary\"\n mode=\"indeterminate\"\n [diameter]=\"44\"\n ></mat-progress-spinner>\n </div>\n </div>\n </ng-template>\n\n</ng-template>\n\n\n\n", styles: [":not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:44px;height:44px;font-size:12px;line-height:32px;text-align:center;overflow:hidden;border-radius:50%;border:solid 5px whitesmoke}.center-txt{align-content:center;text-align:-webkit-center}.width{width:48px;height:48px}.icon-button{display:flex;align-items:center;justify-content:center;width:48px;height:48px;padding:0}.container-obj{display:flex;justify-content:center;align-items:center;width:48px;height:48px}.centered-obj-div{text-align:center}\n"] }]
1995
+ }], propDecorators: { event: [{
1996
+ type: Input
1997
+ }], displayError: [{
1998
+ type: Input
1999
+ }], diameter: [{
2000
+ type: Input
2001
+ }], mode: [{
2002
+ type: Input
2003
+ }], isPending: [{
2004
+ type: Input
2005
+ }], active: [{
2006
+ type: Input
2007
+ }], disabled: [{
2008
+ type: Input
2009
+ }], error: [{
2010
+ type: Output
2011
+ }], progress: [{
2012
+ type: Input
2013
+ }], hasError: [{
2014
+ type: Input
2015
+ }] } });
2016
+
2017
+ class DownloadLabels {
2018
+ constructor(error = '', action = '', icon = 'error') {
2019
+ this.error = error;
2020
+ this.action = action;
2021
+ this.icon = icon;
2022
+ }
2023
+ static adapt(item) {
2024
+ return new DownloadLabels(item?.error, item?.action, item?.icon);
2025
+ }
2026
+ }
2027
+
2028
+ class FileDownloaderComponent extends HTTPManagerService {
2029
+ set labels(value) {
2030
+ this._labels = (value) ? DownloadLabels.adapt(value) : DownloadLabels.adapt();
2031
+ }
2032
+ get labels() {
2033
+ return this._labels;
2034
+ }
2035
+ constructor() {
2036
+ super();
2037
+ this.delayError = 3;
2038
+ this.apiRequest = ApiRequest.adapt();
2039
+ this.displayErrorMessage = false;
2040
+ this._labels = DownloadLabels.adapt();
2041
+ this.active = false;
2042
+ this.subscription = new Subscription();
2043
+ this.completed = new EventEmitter();
2044
+ this.failed = new EventEmitter();
2045
+ this.disabled = false;
2046
+ }
2047
+ ngOnInit() {
2048
+ }
2049
+ onDownloadStreaming() {
2050
+ if (this.active)
2051
+ return;
2052
+ this.active = true;
2053
+ return this.downloadRequest(this.apiRequest)
2054
+ .pipe(distinctUntilChanged(), catchError((err) => {
2055
+ this.onError(err.message);
2056
+ this.active = false;
2057
+ this.failed.emit(err);
2058
+ return err;
2059
+ })).subscribe((res) => {
2060
+ if (res === 100) {
2061
+ this.active = false;
2062
+ this.completed.emit();
2063
+ }
2064
+ });
2065
+ }
2066
+ onError(message) {
2067
+ if (!message || !this.displayErrorMessage)
2068
+ return;
2069
+ const display = ToastDisplay.adapt({
2070
+ message,
2071
+ action: 'Ok',
2072
+ color: ToastColors.ERROR,
2073
+ icon: 'error',
2074
+ });
2075
+ this.active = false;
2076
+ this.toastMessage.toastMessage(display);
2077
+ }
2078
+ OnDestroy() {
2079
+ this.subscription.unsubscribe();
2080
+ }
2081
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2082
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: FileDownloaderComponent, selector: "app-file-downloader", inputs: { delayError: "delayError", apiRequest: "apiRequest", displayErrorMessage: "displayErrorMessage", labels: "labels", disabled: "disabled" }, outputs: { completed: "completed", failed: "failed" }, usesInheritance: true, ngImport: i0, template: "<app-download-file\n [disabled]=\"disabled\"\n [displayError]=\"3\"\n [event]=\"onDownloadStreaming.bind(this)\"\n [isPending]=\"(isPending$ | async) || false\"\n [progress]=\"(progress$ | async)\"\n [hasError]=\"(error$ | async)\"\n (error)=\"onError(labels.error)\"\n [active]=\"active\"\n></app-download-file>\n", styles: [".snackBarInfo{background-color:#f44336;color:#fff}.mat-simple-snackbar>span{font-weight:700}.mat-simple-snackbar-action .mat-button .mat-button-wrapper{color:#fff}.cdk-overlay-pane>.mat-snack-bar-container{width:100%}.mat-snack-bar-container{max-width:100%!important;width:100%}\n"], dependencies: [{ kind: "component", type: DownloadFileComponent, selector: "app-download-file", inputs: ["event", "displayError", "diameter", "mode", "isPending", "active", "disabled", "progress", "hasError"], outputs: ["error"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None }); }
2083
+ }
2084
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderComponent, decorators: [{
2085
+ type: Component,
2086
+ args: [{ selector: 'app-file-downloader', encapsulation: ViewEncapsulation.None, template: "<app-download-file\n [disabled]=\"disabled\"\n [displayError]=\"3\"\n [event]=\"onDownloadStreaming.bind(this)\"\n [isPending]=\"(isPending$ | async) || false\"\n [progress]=\"(progress$ | async)\"\n [hasError]=\"(error$ | async)\"\n (error)=\"onError(labels.error)\"\n [active]=\"active\"\n></app-download-file>\n", styles: [".snackBarInfo{background-color:#f44336;color:#fff}.mat-simple-snackbar>span{font-weight:700}.mat-simple-snackbar-action .mat-button .mat-button-wrapper{color:#fff}.cdk-overlay-pane>.mat-snack-bar-container{width:100%}.mat-snack-bar-container{max-width:100%!important;width:100%}\n"] }]
2087
+ }], ctorParameters: function () { return []; }, propDecorators: { delayError: [{
2088
+ type: Input
2089
+ }], apiRequest: [{
2090
+ type: Input
2091
+ }], displayErrorMessage: [{
2092
+ type: Input
2093
+ }], labels: [{
2094
+ type: Input
2095
+ }], completed: [{
2096
+ type: Output
2097
+ }], failed: [{
2098
+ type: Output
2099
+ }], disabled: [{
2100
+ type: Input
2101
+ }] } });
2102
+
2103
+ class SpinnerComponent {
2104
+ constructor() {
2105
+ this.value = 0;
2106
+ }
2107
+ ngOnInit() {
2108
+ }
2109
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2110
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SpinnerComponent, selector: "app-spinner", inputs: { color: "color", diameter: "diameter", display: "display", mode: "mode", strokeWidth: "strokeWidth", value: "value" }, ngImport: i0, template: "<div class=\"spinner-background\">{{display}}</div>\n<mat-progress-spinner\n [color]=\"color\"\n [diameter]=\"diameter\"\n [mode]=\"mode || 'indeterminate'\"\n [strokeWidth]=\"strokeWidth\"\n [value]=\"value\">\n</mat-progress-spinner>\n", styles: [".example-h2{margin:24px 0}:not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:80px;height:80px;line-height:80px;text-align:center;overflow:hidden;border-color:#673ab71f;border-radius:50%;border-style:solid;border-width:10px}\n"], dependencies: [{ kind: "component", type: i3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
2111
+ }
2112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpinnerComponent, decorators: [{
2113
+ type: Component,
2114
+ args: [{ selector: 'app-spinner', template: "<div class=\"spinner-background\">{{display}}</div>\n<mat-progress-spinner\n [color]=\"color\"\n [diameter]=\"diameter\"\n [mode]=\"mode || 'indeterminate'\"\n [strokeWidth]=\"strokeWidth\"\n [value]=\"value\">\n</mat-progress-spinner>\n", styles: [".example-h2{margin:24px 0}:not(spinner-container).spinner-container{position:relative}:not(spinner-container).spinner-container .spinner-background{position:absolute;width:80px;height:80px;line-height:80px;text-align:center;overflow:hidden;border-color:#673ab71f;border-radius:50%;border-style:solid;border-width:10px}\n"] }]
2115
+ }], ctorParameters: function () { return []; }, propDecorators: { color: [{
2116
+ type: Input
2117
+ }], diameter: [{
2118
+ type: Input
2119
+ }], display: [{
2120
+ type: Input
2121
+ }], mode: [{
2122
+ type: Input
2123
+ }], strokeWidth: [{
2124
+ type: Input
2125
+ }], value: [{
2126
+ type: Input
2127
+ }] } });
2128
+
2129
+ class FileDownloaderModule {
2130
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2131
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, declarations: [SpinnerComponent,
2132
+ DownloadFileComponent,
2133
+ FileDownloaderComponent], imports: [CommonModule,
2134
+ MatIconModule,
2135
+ MatProgressSpinnerModule,
2136
+ MatButtonModule], exports: [FileDownloaderComponent] }); }
2137
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, imports: [CommonModule,
2138
+ MatIconModule,
2139
+ MatProgressSpinnerModule,
2140
+ MatButtonModule] }); }
2141
+ }
2142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileDownloaderModule, decorators: [{
2143
+ type: NgModule,
2144
+ args: [{
2145
+ imports: [
2146
+ CommonModule,
2147
+ MatIconModule,
2148
+ MatProgressSpinnerModule,
2149
+ MatButtonModule,
2150
+ ],
2151
+ declarations: [
2152
+ SpinnerComponent,
2153
+ DownloadFileComponent,
2154
+ FileDownloaderComponent,
2155
+ ],
2156
+ exports: [
2157
+ FileDownloaderComponent
2158
+ ]
2159
+ }]
2160
+ }] });
2161
+
2162
+ class LocalStorageDemoComponent {
2163
+ get type() {
2164
+ return (this.typeControl.value) ? +this.typeControl.value : 0;
2165
+ }
2166
+ get isValid() {
2167
+ return this.newStoreForm.valid;
2168
+ }
2169
+ get isValidData() {
2170
+ return this.storageForm.valid;
2171
+ }
2172
+ constructor(configOptions) {
2173
+ this.configOptions = configOptions;
2174
+ this.fb = inject(FormBuilder);
2175
+ this.utils = inject(UtilsService);
2176
+ this.type$ = new BehaviorSubject(StorageType.GLOBAL);
2177
+ this.typeControl = this.fb.control(StorageType.GLOBAL.toString());
2178
+ this.localStorageManagerService = inject(LocalStorageManagerService);
2179
+ this.settings$ = this.localStorageManagerService.settings$;
2180
+ this.setting$ = (store) => this.localStorageManagerService.setting$(store);
2181
+ this.storageForm = this.fb.group({
2182
+ store: this.fb.control(null),
2183
+ type: 'local',
2184
+ settingType: 'local',
2185
+ encrypted: false,
2186
+ data: this.fb.control('', Validators.required),
2187
+ });
2188
+ this.newStoreForm = this.fb.group({
2189
+ name: this.fb.control(null, Validators.required),
2190
+ storage: 'local',
2191
+ encrypted: false,
2192
+ data: this.fb.control('', Validators.required),
2193
+ expiresIn: this.fb.control('0')
2194
+ });
2195
+ this.storeData$ = this.storageForm.get('store')?.valueChanges
2196
+ .pipe(switchMap((data) => {
2197
+ return data
2198
+ ? this.localStorageManagerService.store$(data.name)
2199
+ : of('');
2200
+ }), tap(data => {
2201
+ this.storageForm.get('data')?.patchValue(data, { emitEvent: false });
2202
+ }));
2203
+ this.expiresIn = (epoch) => this.utils.expiresIn(epoch);
2204
+ this.isValidJSON = (str) => {
2205
+ try {
2206
+ JSON.parse(str);
2207
+ return true;
2208
+ }
2209
+ catch (e) {
2210
+ return false;
2211
+ }
2212
+ };
2213
+ this.displayedColumns = ['name', 'id', 'encrypted', 'expires', "option"];
2214
+ this.filterData = (values) => {
2215
+ if (!values)
2216
+ return [];
2217
+ return values.filter((item) => item.options.storage === +this.type);
2218
+ };
2219
+ this.create = false;
2220
+ }
2221
+ ngOnInit() {
2222
+ this.storeProps = this.configOptions?.LocalStorageOptions;
2223
+ this.options = this.storeProps?.options;
2224
+ if (this.options?.storage) {
2225
+ this.typeControl.patchValue(this.options.storage.toString());
2226
+ this.typeControl.disable();
2227
+ }
2228
+ else {
2229
+ this.typeControl.enable();
2230
+ }
2231
+ if (this.options?.expiresIn) {
2232
+ this.newStoreForm.get('expiresIn')?.patchValue(this.options.expiresIn);
2233
+ this.newStoreForm.get('expiresIn')?.disable();
2234
+ }
2235
+ else {
2236
+ this.newStoreForm.get('expiresIn')?.enable();
2237
+ }
2238
+ if (this.options?.encrypted) {
2239
+ this.newStoreForm.get('encrypted')?.patchValue(this.options.encrypted);
2240
+ this.newStoreForm.get('encrypted')?.disable();
2241
+ }
2242
+ else {
2243
+ this.newStoreForm.get('encrypted')?.enable();
2244
+ }
2245
+ }
2246
+ onCreateStore() {
2247
+ if (!this.isValid)
2248
+ return;
2249
+ const store = this.newStoreForm.value;
2250
+ if (!store.name || store.name === '')
2251
+ return;
2252
+ const options = { storage: this.type, encrypted: store.encrypted, expiresIn: store.expiresIn };
2253
+ this.localStorageManagerService.createStore({
2254
+ name: store.name,
2255
+ data: store.data,
2256
+ options: SettingOptions.adapt(options)
2257
+ });
2258
+ this.newStoreForm.reset();
2259
+ this.create = false;
2260
+ }
2261
+ onUpdateStore(store) {
2262
+ if (!this.storageForm.valid)
2263
+ return;
2264
+ const storeData = this.storageForm.value;
2265
+ const data = JSON.parse(storeData.data || '');
2266
+ const type = (storeData.type === 'local') ? StorageType.GLOBAL : StorageType.SESSION;
2267
+ const options = { storage: type, encrypted: storeData.encrypted };
2268
+ this.localStorageManagerService.updateStore({
2269
+ name: store.name,
2270
+ data
2271
+ });
2272
+ }
2273
+ onSelectedRow(store) {
2274
+ this.store = store;
2275
+ this.data$ = this.localStorageManagerService.store$(store.name).pipe(map(item => JSON.stringify(item)));
2276
+ this.create = false;
2277
+ }
2278
+ onCreate() {
2279
+ this.onCancel();
2280
+ this.create = true;
2281
+ }
2282
+ onDelete(store) {
2283
+ console.log('DELETED STORE:', store);
2284
+ this.localStorageManagerService.deleteStore({
2285
+ name: store.name,
2286
+ });
2287
+ this.onCancel();
2288
+ }
2289
+ onCancel() {
2290
+ this.data$ = EMPTY;
2291
+ this.store = null;
2292
+ this.create = false;
2293
+ }
2294
+ onUpdate(store, data) {
2295
+ this.localStorageManagerService.updateStore({
2296
+ name: store.name,
2297
+ data: JSON.parse(data)
2298
+ });
2299
+ this.onCancel();
2300
+ }
2301
+ onReset() {
2302
+ this.localStorageManagerService.resetStore();
2303
+ }
2304
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
2305
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LocalStorageDemoComponent, selector: "app-local-storage-demo", ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <div style=\"display: flex; gap: 1rem\">\n <h2 style=\"padding-top: .5rem; display: flex;\">\n <div style=\"padding-top: .5rem;\">Local Storage Manager</div>\n <div>\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>info</mat-icon>\n </button>\n </div>\n </h2>\n <span style=\"flex:1\"></span>\n <div style=\"padding-top: .25rem;\">\n <mat-button-toggle-group name=\"storage\" [formControl]=\"typeControl\" (change)=\"onCancel()\">\n <mat-button-toggle value=\"0\">Local Storage</mat-button-toggle>\n <mat-button-toggle value=\"1\">Session Storage</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"margin-top: .25rem;\">\n <button mat-icon-button (click)=\"onCreate()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"storeProps?.storageName || storeProps?.storageSettingsName\">\n <div style=\"display: flex; gap: .5rem; flex-direction: column; border: gray solid thin; background-color: whitesmoke; padding: 1rem;\"\n >\n <div style=\"display: flex;\">\n <div *ngIf=\"storeProps?.storageSettingsName\" style=\"flex:1\">\n Database: <b>{{ storeProps?.storageSettingsName }}</b>\n </div>\n <div *ngIf=\"storeProps?.storageName\" style=\"flex:1\">\n Data: <b>{{ storeProps?.storageName }}</b>\n </div>\n </div>\n </div>\n </ng-container>\n\n <div style=\"margin-top: 2rem;\" [formGroup]=\"newStoreForm\" *ngIf=\"create; else LIST\">\n\n <h2>Create Store</h2>\n\n <div style=\"display: flex; gap: 1rem;\">\n <div style=\"flex:1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Store Name</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"name\">\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In...</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"0\">None</mat-option>\n <mat-option value=\"30s\">30 Seconds</mat-option>\n <mat-option value=\"1mn\">1 Minute</mat-option>\n <mat-option value=\"1hr\">1 Hour</mat-option>\n <mat-option value=\"1d\">1 Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"margin-top: 1rem;\">\n <mat-slide-toggle formControlName=\"encrypted\">Encrypted</mat-slide-toggle>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" formControlName=\"data\" #json></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCreateStore()\" [disabled]=\"!(isValid && isValidJSON(json.value))\">\n Save Store\n </button>\n </div>\n\n </div>\n\n <ng-template #LIST>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n{{ settings$ | async | json }}\n <div *ngIf=\"filterData(settings$ | async) as data\">\n <ng-container *ngIf=\"data.length > 0; else NO_DATA\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> Store </th>\n <td mat-cell *matCellDef=\"let element\" style=\"font-weight: bold; text-transform: uppercase;\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"encrypted\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Encrypted </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.encrypted; else NO\">YES</ng-container>\n <ng-template #NO><span style=\"color:gray\">NO</span></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expires\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Expires </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.expires !== 0; else NO_DATA\">\n {{expiresIn(element.options.expires)}}\n </ng-container>\n <ng-template #NO_DATA>\n \u221E\n </ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"option\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let element\" style=\"padding-right: 0;\">\n <div style=\"display: flex;justify-content: flex-end;\">\n <button mat-icon-button color=\"warn\" (click)=\"onDelete(element); $event.stopPropagation()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"onSelectedRow(row)\"></tr>\n </table>\n </ng-container>\n\n <ng-template #NO_DATA>\n <h3 style=\"margin-top: 1rem;\">No Data</h3>\n </ng-template>\n\n <div *ngIf=\"(data$ | async) as data\" style=\"margin-top: 2rem;\">\n <div style=\"margin-bottom: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <h3>STORE: <span style=\"font-weight: bold;\">{{ store.name | uppercase }}</span></h3>\n <h3>SETTINGS: {{ setting$(store.name) | async | json }}</h3>\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" #json [value]=\"data\"></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex; gap: .5rem;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCancel()\">Cancel</button>\n <button mat-stroked-button (click)=\"onUpdate(store, json.value)\" [disabled]=\"!(isValidJSON(json.value))\">Update</button>\n </div>\n </div>\n </div>\n\n </ng-template>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <button mat-stroked-button (click)=\"onReset()\">Delete All Stores</button>\n </div>\n\n</div>\n\n\n<mat-menu #menu=\"matMenu\">\n <div style=\"padding: 1rem;\">\n <p>Please note that the LocalStorage (encryption) and management of data is dependant on initializing the APP_ID</p>\n <p>Must provide a value for <b>APP_ID</b> in AppModule->Providers</p>\n <mat-divider></mat-divider>\n <div style=\"font-size: smaller; margin-top: .5rem;\">\n <p>Example: UUID (self.crypto.randomUUID() to generate)</p>\n <div style=\"background-color: whitesmoke; padding: 1rem;\">\n &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i3$2.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "directive", type: i3$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i10.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i10.MatButtonToggle, selector: "mat-button-toggle", inputs: ["disableRipple", "aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "appearance", "checked", "disabled"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i10$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i12.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: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }], encapsulation: i0.ViewEncapsulation.None }); }
2306
+ }
2307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalStorageDemoComponent, decorators: [{
2308
+ type: Component,
2309
+ args: [{ selector: 'app-local-storage-demo', encapsulation: ViewEncapsulation.None, template: "<div style=\"margin: 2rem;\">\n\n <div style=\"display: flex; gap: 1rem\">\n <h2 style=\"padding-top: .5rem; display: flex;\">\n <div style=\"padding-top: .5rem;\">Local Storage Manager</div>\n <div>\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>info</mat-icon>\n </button>\n </div>\n </h2>\n <span style=\"flex:1\"></span>\n <div style=\"padding-top: .25rem;\">\n <mat-button-toggle-group name=\"storage\" [formControl]=\"typeControl\" (change)=\"onCancel()\">\n <mat-button-toggle value=\"0\">Local Storage</mat-button-toggle>\n <mat-button-toggle value=\"1\">Session Storage</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"margin-top: .25rem;\">\n <button mat-icon-button (click)=\"onCreate()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"storeProps?.storageName || storeProps?.storageSettingsName\">\n <div style=\"display: flex; gap: .5rem; flex-direction: column; border: gray solid thin; background-color: whitesmoke; padding: 1rem;\"\n >\n <div style=\"display: flex;\">\n <div *ngIf=\"storeProps?.storageSettingsName\" style=\"flex:1\">\n Database: <b>{{ storeProps?.storageSettingsName }}</b>\n </div>\n <div *ngIf=\"storeProps?.storageName\" style=\"flex:1\">\n Data: <b>{{ storeProps?.storageName }}</b>\n </div>\n </div>\n </div>\n </ng-container>\n\n <div style=\"margin-top: 2rem;\" [formGroup]=\"newStoreForm\" *ngIf=\"create; else LIST\">\n\n <h2>Create Store</h2>\n\n <div style=\"display: flex; gap: 1rem;\">\n <div style=\"flex:1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Store Name</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"name\">\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In...</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"0\">None</mat-option>\n <mat-option value=\"30s\">30 Seconds</mat-option>\n <mat-option value=\"1mn\">1 Minute</mat-option>\n <mat-option value=\"1hr\">1 Hour</mat-option>\n <mat-option value=\"1d\">1 Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"margin-top: 1rem;\">\n <mat-slide-toggle formControlName=\"encrypted\">Encrypted</mat-slide-toggle>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" formControlName=\"data\" #json></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCreateStore()\" [disabled]=\"!(isValid && isValidJSON(json.value))\">\n Save Store\n </button>\n </div>\n\n </div>\n\n <ng-template #LIST>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n{{ settings$ | async | json }}\n <div *ngIf=\"filterData(settings$ | async) as data\">\n <ng-container *ngIf=\"data.length > 0; else NO_DATA\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> Store </th>\n <td mat-cell *matCellDef=\"let element\" style=\"font-weight: bold; text-transform: uppercase;\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"encrypted\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Encrypted </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.encrypted; else NO\">YES</ng-container>\n <ng-template #NO><span style=\"color:gray\">NO</span></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expires\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Expires </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.expires !== 0; else NO_DATA\">\n {{expiresIn(element.options.expires)}}\n </ng-container>\n <ng-template #NO_DATA>\n \u221E\n </ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"option\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let element\" style=\"padding-right: 0;\">\n <div style=\"display: flex;justify-content: flex-end;\">\n <button mat-icon-button color=\"warn\" (click)=\"onDelete(element); $event.stopPropagation()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"onSelectedRow(row)\"></tr>\n </table>\n </ng-container>\n\n <ng-template #NO_DATA>\n <h3 style=\"margin-top: 1rem;\">No Data</h3>\n </ng-template>\n\n <div *ngIf=\"(data$ | async) as data\" style=\"margin-top: 2rem;\">\n <div style=\"margin-bottom: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <h3>STORE: <span style=\"font-weight: bold;\">{{ store.name | uppercase }}</span></h3>\n <h3>SETTINGS: {{ setting$(store.name) | async | json }}</h3>\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" #json [value]=\"data\"></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex; gap: .5rem;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCancel()\">Cancel</button>\n <button mat-stroked-button (click)=\"onUpdate(store, json.value)\" [disabled]=\"!(isValidJSON(json.value))\">Update</button>\n </div>\n </div>\n </div>\n\n </ng-template>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <button mat-stroked-button (click)=\"onReset()\">Delete All Stores</button>\n </div>\n\n</div>\n\n\n<mat-menu #menu=\"matMenu\">\n <div style=\"padding: 1rem;\">\n <p>Please note that the LocalStorage (encryption) and management of data is dependant on initializing the APP_ID</p>\n <p>Must provide a value for <b>APP_ID</b> in AppModule->Providers</p>\n <mat-divider></mat-divider>\n <div style=\"font-size: smaller; margin-top: .5rem;\">\n <p>Example: UUID (self.crypto.randomUUID() to generate)</p>\n <div style=\"background-color: whitesmoke; padding: 1rem;\">\n &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"] }]
2310
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
2311
+ type: Inject,
2312
+ args: [CONFIG_SETTINGS_TOKEN]
2313
+ }] }]; } });
2314
+
2315
+ class ClientInfo {
2316
+ constructor(domain = '', service = '', id = 0, name = '') {
2317
+ this.domain = domain;
2318
+ this.service = service;
2319
+ this.id = id;
2320
+ this.name = name;
2321
+ }
2322
+ static adapt(item) {
2323
+ return new ClientInfo(item?.domain, item?.service, item?.id, item?.name);
2324
+ }
2325
+ }
2326
+
2327
+ class ClientInfoMapper {
2328
+ constructor(id = 0, name = '') {
2329
+ this.id = id;
2330
+ this.name = name;
2331
+ }
2332
+ static adapt(item) {
2333
+ return new ClientInfoMapper(item?.id, item?.name);
2334
+ }
2335
+ }
2336
+
2337
+ class AIPrompt {
2338
+ constructor(response = '') {
2339
+ this.response = response;
2340
+ }
2341
+ static adapt(item) {
2342
+ return new AIPrompt(item?.response);
2343
+ }
2344
+ }
2345
+
2346
+ class RequestManagerDemoComponent {
2347
+ get retry() {
2348
+ return this.requestForm.get('retry')?.value;
2349
+ }
2350
+ get headers() {
2351
+ return this.requestForm.get('headers');
2352
+ }
2353
+ get isValid() {
2354
+ this.requestForm.markAllAsTouched();
2355
+ return this.requestForm.valid;
2356
+ }
2357
+ constructor() {
2358
+ this.displayedColumns = ['id', 'name', 'lastName', 'age'];
2359
+ this.fb = inject(FormBuilder);
2360
+ this.toastMessage = inject(ToastMessageService);
2361
+ this.httpManagerService = inject(HTTPManagerService);
2362
+ this.isPending$ = this.httpManagerService.isPending$;
2363
+ this.countdown$ = this.httpManagerService.countdown$;
2364
+ this.GET_error$ = new BehaviorSubject('');
2365
+ this.POST_error$ = new BehaviorSubject('');
2366
+ this.PUT_error$ = new BehaviorSubject('');
2367
+ this.DELETE_error$ = new BehaviorSubject('');
2368
+ this.STREAM_error$ = new BehaviorSubject('');
2369
+ this.STREAM_AI_error$ = new BehaviorSubject('');
2370
+ this.requestParams = {
2371
+ GET: ApiRequest.adapt(),
2372
+ POST: ApiRequest.adapt(),
2373
+ PUT: ApiRequest.adapt(),
2374
+ DELETE: ApiRequest.adapt(),
2375
+ STREAM: ApiRequest.adapt(),
2376
+ };
2377
+ this.questionControl = this.fb.control("", [Validators.required]);
2378
+ this.downloadRequest = ApiRequest.adapt({
2379
+ server: 'http://localhost:4200/assets',
2380
+ path: ['icons1.svg']
2381
+ });
2382
+ this.sampleClientData = {
2383
+ id: 0,
2384
+ name: "Old School Dates",
2385
+ domain: "osd.com",
2386
+ service: "osd",
2387
+ spiffe: "osd.com/osd",
2388
+ secret: "SMOPECXP-OS4P-USOG-X2II-3XMD1FQDR3IJX",
2389
+ created: 1693003138,
2390
+ modified: 1693003138,
2391
+ icon: "",
2392
+ imageFile: "",
2393
+ };
2394
+ this.requestForm = this.fb.group({
2395
+ path: this.fb.control(""),
2396
+ headers: this.fb.array([]),
2397
+ adapter: [null],
2398
+ retry: this.fb.group({
2399
+ times: [3],
2400
+ delay: [3],
2401
+ }),
2402
+ polling: [3],
2403
+ });
2404
+ this.sampleAdaptors = [
2405
+ { label: "ClientInfo Basic", value: ClientInfo.adapt },
2406
+ { label: "AI Prompt", value: AIPrompt.adapt },
2407
+ ];
2408
+ this.sampleMappers = [
2409
+ { label: "Mapper Basic", value: ClientInfoMapper.adapt },
2410
+ { label: "AI Prompt", value: AIPrompt.adapt },
2411
+ ];
2412
+ // server = `http://sample-endpoint/as/authorization.oauth2`
2413
+ this.arrayObjectsToObjects = (arr) => {
2414
+ return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
2415
+ };
2416
+ }
2417
+ ngOnInit() {
2418
+ // const reqGet2 = ApiRequest.adapt({
2419
+ // server,
2420
+ // path: ['clients'],
2421
+ // headers: { authentication: "Bearer <KEY>" },
2422
+ // adapter: ClientInfo,
2423
+ // dataType: DataType.OBJECT,
2424
+ // // concurrent: false,
2425
+ // // polling: 3, //seconds
2426
+ // });
2427
+ // const req2 = [1024,1025,1026].map(item => {
2428
+ // return this.httpManagerService.getRequest<ClientInfo[]>(reqGet2, [item])
2429
+ // .pipe(
2430
+ // catchError(error => {
2431
+ // return throwError(() => new Error(error.error.message));
2432
+ // })
2433
+ // )
2434
+ // })
2435
+ // forkJoin(req2)
2436
+ // .subscribe(res => console.log(res))
2437
+ }
2438
+ addHeader() {
2439
+ const header = this.fb.group({
2440
+ key: ['', Validators.required],
2441
+ value: ['']
2442
+ });
2443
+ this.headers.push(header);
2444
+ }
2445
+ removeHeader(index) {
2446
+ this.headers.removeAt(index);
2447
+ }
2448
+ compileRequest() {
2449
+ const requestParams = this.requestForm.value;
2450
+ requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
2451
+ const pathReq = (requestParams.path === "") ? [] : (requestParams.path || "").split("/");
2452
+ if (!this.pollingState.checked)
2453
+ requestParams.polling = 0;
2454
+ if (!this.failedState.checked) {
2455
+ requestParams.retry = { times: 0, delay: 0 };
2456
+ }
2457
+ return ApiRequest.adapt({
2458
+ ...requestParams,
2459
+ // ...{ path: pathReq, server: this.server },
2460
+ ...{ path: pathReq },
2461
+ });
2462
+ }
2463
+ onGetRequest() {
2464
+ if (!this.isValid)
2465
+ return;
2466
+ const reqParams = this.compileRequest();
2467
+ this.requestParams.GET = reqParams;
2468
+ this.GET$ = EMPTY; //Cancels Previous
2469
+ this.GET_error$.next('');
2470
+ this.GET$ = this.httpManagerService.getRequest(reqParams)
2471
+ .pipe(
2472
+ // tap((data) => console.log("API GET response", data)),
2473
+ catchError(error => {
2474
+ return throwError(() => this.errorHandling(error, 'GET'));
2475
+ }));
2476
+ }
2477
+ onCreateRequest() {
2478
+ if (!this.isValid)
2479
+ return;
2480
+ const reqParams = this.compileRequest();
2481
+ this.requestParams.POST = reqParams;
2482
+ this.POST$ = EMPTY; //Cancels Previous
2483
+ this.POST_error$.next('');
2484
+ this.POST$ = this.httpManagerService.postRequest(this.sampleClientData, reqParams)
2485
+ .pipe(
2486
+ // tap((data) => console.log("API POST response", data)),
2487
+ catchError(error => {
2488
+ return throwError(() => this.errorHandling(error, 'POST'));
2489
+ }));
2490
+ }
2491
+ onUpdateRequest() {
2492
+ if (!this.isValid)
2493
+ return;
2494
+ const reqParams = this.compileRequest();
2495
+ this.sampleClientData.id = reqParams.path[reqParams.path.length - 1];
2496
+ this.requestParams.PUT = reqParams;
2497
+ this.PUT$ = EMPTY; //Cancels Previous
2498
+ this.PUT_error$.next('');
2499
+ this.PUT$ = this.httpManagerService.putRequest(this.sampleClientData, reqParams)
2500
+ .pipe(
2501
+ // tap((data) => console.log("API PUT response", data)),
2502
+ catchError(error => {
2503
+ return throwError(() => this.errorHandling(error, 'PUT'));
2504
+ }));
2505
+ }
2506
+ onDeleteRequest() {
2507
+ if (!this.isValid)
2508
+ return;
2509
+ const reqParams = this.compileRequest();
2510
+ this.requestParams.DELETE = reqParams;
2511
+ this.DELETE$ = EMPTY; //Cancels Previous
2512
+ this.DELETE_error$.next('');
2513
+ this.DELETE$ = this.httpManagerService.deleteRequest(reqParams)
2514
+ .pipe(
2515
+ // tap((data) => console.log("API DELETE response", data)),
2516
+ catchError(error => {
2517
+ return throwError(() => this.errorHandling(error, 'DELETE'));
2518
+ }));
2519
+ }
2520
+ onStreamPostRequest() {
2521
+ if (!this.isValid)
2522
+ return;
2523
+ const reqParams = this.compileRequest();
2524
+ reqParams.server = "http://localhost:11434/api";
2525
+ reqParams.path = ["generate"];
2526
+ reqParams.stream = true;
2527
+ const payload = {
2528
+ model: "mistral",
2529
+ prompt: this.questionControl.value,
2530
+ stream: reqParams.stream
2531
+ };
2532
+ this.requestParams.STREAM = reqParams;
2533
+ this.STREAM_AI$ = EMPTY;
2534
+ this.STREAM_AI_error$.next('');
2535
+ this.STREAM_AI$ = this.httpManagerService.postRequest(payload, reqParams)
2536
+ .pipe(map(items => items.map((word) => word.response).flat().join('')), tap(() => this.questionControl.reset()), catchError(error => {
2537
+ return throwError(() => this.errorHandling(error, 'STREAM'));
2538
+ }));
2539
+ }
2540
+ onStreamRequest() {
2541
+ if (!this.isValid)
2542
+ return;
2543
+ const reqParams = this.compileRequest();
2544
+ reqParams.server = "oidc";
2545
+ reqParams.stream = true;
2546
+ this.STREAM$ = this.httpManagerService.getRequest(reqParams)
2547
+ .pipe(
2548
+ // tap((data) => console.log("API STREAM response", data)),
2549
+ catchError(error => {
2550
+ return throwError(() => this.errorHandling(error, 'STREAM'));
2551
+ }));
2552
+ }
2553
+ onDownloadCompleted() {
2554
+ const message = "Download Completed";
2555
+ const display = ToastDisplay.adapt({
2556
+ message,
2557
+ action: 'Ok',
2558
+ color: ToastColors.SUCCESS,
2559
+ icon: 'sentiment_satisfied_alt',
2560
+ });
2561
+ this.toastMessage.toastMessage(display);
2562
+ }
2563
+ onDownloadFailed(err) {
2564
+ const message = "Download Failed";
2565
+ const display = ToastDisplay.adapt({
2566
+ message,
2567
+ action: 'Ok',
2568
+ color: ToastColors.ERROR,
2569
+ icon: 'warning',
2570
+ });
2571
+ this.toastMessage.toastMessage(display);
2572
+ }
2573
+ errorHandling(err, type) {
2574
+ if (type === 'GET')
2575
+ this.GET_error$.next(err.message);
2576
+ if (type === 'POST')
2577
+ this.POST_error$.next(err.message);
2578
+ if (type === 'PUT')
2579
+ this.PUT_error$.next(err.message);
2580
+ if (type === 'DELETE')
2581
+ this.DELETE_error$.next(err.message);
2582
+ if (type === 'STREAM')
2583
+ this.STREAM_error$.next(err.message);
2584
+ }
2585
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2586
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: RequestManagerDemoComponent, selector: "app-request-manager-demo", viewQueries: [{ propertyName: "failedState", first: true, predicate: ["failedState"], descendants: true, static: true }, { propertyName: "pollingState", first: true, predicate: ["pollingState"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\" class=\"btn\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\"\n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !(isPending$ | async)\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(GET$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(POST$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(PUT$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(DELETE$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_AI_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div>\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; margin-bottom: 0; padding-top: .5rem; display: flex;\">\n <div>\n Download File\n </div>\n <div style=\"flex:1; margin-left: 1rem;\">\n <mat-slide-toggle #disable>\n <span *ngIf=\"disable.checked; else DISABLE\">\n Enable\n </span>\n <ng-template #DISABLE>Disable</ng-template>\n </mat-slide-toggle>\n </div>\n </h2>\n <div>\n <app-file-downloader\n [disabled]=\"disable.checked\"\n [delayError]=\"3\"\n [apiRequest]=\"downloadRequest\"\n (completed)=\"onDownloadCompleted()\"\n (failed)=\"onDownloadFailed($event)\"\n ></app-file-downloader>\n </div>\n </div>\n </div>\n\n</div>\n", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i9.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i10$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i12.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: FileDownloaderComponent, selector: "app-file-downloader", inputs: ["delayError", "apiRequest", "displayErrorMessage", "labels", "disabled"], outputs: ["completed", "failed"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
2587
+ }
2588
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerDemoComponent, decorators: [{
2589
+ type: Component,
2590
+ args: [{ selector: 'app-request-manager-demo', template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\" class=\"btn\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\"\n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !(isPending$ | async)\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(GET$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(POST$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(PUT$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(DELETE$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_AI_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div>\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; margin-bottom: 0; padding-top: .5rem; display: flex;\">\n <div>\n Download File\n </div>\n <div style=\"flex:1; margin-left: 1rem;\">\n <mat-slide-toggle #disable>\n <span *ngIf=\"disable.checked; else DISABLE\">\n Enable\n </span>\n <ng-template #DISABLE>Disable</ng-template>\n </mat-slide-toggle>\n </div>\n </h2>\n <div>\n <app-file-downloader\n [disabled]=\"disable.checked\"\n [delayError]=\"3\"\n [apiRequest]=\"downloadRequest\"\n (completed)=\"onDownloadCompleted()\"\n (failed)=\"onDownloadFailed($event)\"\n ></app-file-downloader>\n </div>\n </div>\n </div>\n\n</div>\n", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"] }]
2591
+ }], ctorParameters: function () { return []; }, propDecorators: { failedState: [{
2592
+ type: ViewChild,
2593
+ args: ["failedState", { static: true }]
2594
+ }], pollingState: [{
2595
+ type: ViewChild,
2596
+ args: ["pollingState", { static: true }]
2597
+ }] } });
2598
+
2599
+ class StateManagerDemoService extends HTTPManagerStateService {
2600
+ constructor() {
2601
+ super(ApiRequest.adapt({
2602
+ server: "",
2603
+ path: [],
2604
+ headers: {},
2605
+ adapter: ClientInfo.adapt,
2606
+ mapper: ClientInfoMapper.adapt,
2607
+ stream: false,
2608
+ }), DataType.ARRAY, DatabaseStorage.adapt());
2609
+ }
2610
+ setAPIOptions(apiOptions, dataType, database) {
2611
+ this.setApiRequestOptions(apiOptions, dataType, database);
2612
+ }
2613
+ getClients() {
2614
+ // const headers = {
2615
+ // auth: "sample-auth-token"
2616
+ // }
2617
+ // const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
2618
+ this.fetchRecords();
2619
+ }
2620
+ createClient(data) {
2621
+ // const headers = {
2622
+ // auth: "sample-auth-token"
2623
+ // }
2624
+ // const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
2625
+ this.createRecord(data);
2626
+ }
2627
+ updateClient(data) {
2628
+ // const headers = {
2629
+ // auth: "sample-auth-token"
2630
+ // }
2631
+ data.id = 1031;
2632
+ const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2633
+ this.updateRecord(data, sampleOptions);
2634
+ }
2635
+ deleteClient(data) {
2636
+ // const headers = {
2637
+ // auth: "sample-auth-token"
2638
+ // }
2639
+ data.id = 1031;
2640
+ const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2641
+ this.deleteRecord(sampleOptions);
2642
+ }
2643
+ streamRequest() {
2644
+ const headers = {
2645
+ auth: "sample-auth-token"
2646
+ };
2647
+ // const sampleOptions = RequestOptions.adapt({ path: [1], headers })
2648
+ this.fetchStream();
2649
+ }
2650
+ streamAIRequest(data) {
2651
+ const headers = {
2652
+ auth: "sample-auth-token"
2653
+ };
2654
+ const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2655
+ this.createStream(data, sampleOptions);
2656
+ // this.fetchStream(sampleOptions)
2657
+ }
2658
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: StateManagerDemoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2659
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: StateManagerDemoService, providedIn: 'root' }); }
2660
+ }
2661
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: StateManagerDemoService, decorators: [{
2662
+ type: Injectable,
2663
+ args: [{
2664
+ providedIn: 'root'
2665
+ }]
2666
+ }], ctorParameters: function () { return []; } });
2667
+
2668
+ class RequestManagerStateDemoComponent {
2669
+ get dataObservable$() {
2670
+ switch (this.requestType) {
2671
+ case 'GET':
2672
+ return this.GET$;
2673
+ case 'PUT':
2674
+ return this.PUT$;
2675
+ case 'POST':
2676
+ return this.POST$;
2677
+ case 'DELETE':
2678
+ return this.DELETE$;
2679
+ case 'STREAM':
2680
+ return this.STREAM;
2681
+ case 'STREAM_AI':
2682
+ return this.STREAM_AI;
2683
+ default:
2684
+ return this.GET$;
2685
+ break;
2686
+ }
2687
+ }
2688
+ get hasChanged() {
2689
+ return this.requestForm.dirty;
2690
+ }
2691
+ get dataType() {
2692
+ return this.requestForm.get("datatype")?.value;
2693
+ }
2694
+ get database() {
2695
+ return this.requestForm.get("database")?.value;
2696
+ }
2697
+ get retry() {
2698
+ return this.requestForm.get("retry")?.value;
2699
+ }
2700
+ get headers() {
2701
+ return this.requestForm.get('headers');
2702
+ }
2703
+ get isValid() {
2704
+ this.requestForm.markAllAsTouched();
2705
+ return this.requestForm.valid;
2706
+ }
2707
+ constructor() {
2708
+ this.stateManagerDemoService = inject(StateManagerDemoService);
2709
+ this.displayedColumns = ['id', 'name', 'lastName', 'age'];
2710
+ this.fb = inject(FormBuilder);
2711
+ this.httpManagerService = inject(HTTPManagerService);
2712
+ this.isPending$ = this.stateManagerDemoService.isPending$;
2713
+ this.error$ = this.stateManagerDemoService.error$;
2714
+ this.countdown$ = this.httpManagerService.countdown$;
2715
+ this.GET_error$ = new BehaviorSubject('');
2716
+ this.POST_error$ = new BehaviorSubject('');
2717
+ this.PUT_error$ = new BehaviorSubject('');
2718
+ this.DELETE_error$ = new BehaviorSubject('');
2719
+ this.STREAM_error$ = new BehaviorSubject('');
2720
+ this.GET$ = new BehaviorSubject(null);
2721
+ this.POST$ = new BehaviorSubject(null);
2722
+ this.PUT$ = new BehaviorSubject(null);
2723
+ this.DELETE$ = new BehaviorSubject(null);
2724
+ this.STREAM = new BehaviorSubject(null);
2725
+ this.STREAM$ = this.STREAM.asObservable();
2726
+ this.STREAM_AI = new BehaviorSubject(null);
2727
+ this.STREAM_AI$ = this.STREAM_AI.asObservable()
2728
+ .pipe(map((items) => (items) ? items.map((item) => item.response) : []), map((items) => items.join('').trim()));
2729
+ this.questionControl = this.fb.control("", [Validators.required]);
2730
+ this.requestType = '';
2731
+ this.sampleClientData = {
2732
+ id: 0,
2733
+ name: "Old School Dates",
2734
+ domain: "osd.com",
2735
+ service: "osd",
2736
+ spiffe: "osd.com/osd",
2737
+ secret: "SMOPECXP-OS4P-USOG-X2II-3XMD1FQDR3IJX",
2738
+ created: 1693003138,
2739
+ modified: 1693003138,
2740
+ icon: "",
2741
+ imageFile: "",
2742
+ };
2743
+ this.selectedRecord = this.fb.control(null);
2744
+ this.requestForm = this.fb.group({
2745
+ datatype: this.fb.control('ARRAY'),
2746
+ path: this.fb.control(""),
2747
+ headers: this.fb.array([]),
2748
+ adapter: [null],
2749
+ mapper: [null],
2750
+ retry: this.fb.group({
2751
+ times: [3],
2752
+ delay: [3],
2753
+ }),
2754
+ polling: [3],
2755
+ database: this.fb.group({
2756
+ table: [''],
2757
+ expiresIn: ['1m'],
2758
+ })
2759
+ });
2760
+ this.sampleAdaptors = [
2761
+ { label: "ClientInfo Basic", value: ClientInfo.adapt },
2762
+ { label: "AI Prompt", value: AIPrompt.adapt },
2763
+ ];
2764
+ this.sampleMappers = [
2765
+ { label: "Mapper Basic", value: ClientInfoMapper.adapt },
2766
+ { label: "AI Prompt", value: AIPrompt.adapt },
2767
+ ];
2768
+ // server = `http://sample-endpoint/as/authorization.oauth2`
2769
+ this.arrayObjectsToObjects = (arr) => {
2770
+ return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
2771
+ };
2772
+ }
2773
+ ngOnInit() {
2774
+ this.selectedRecord.valueChanges
2775
+ .subscribe((data) => {
2776
+ this.selectedRecord$ = (data) ? this.stateManagerDemoService.selectRecord$(data.id) : EMPTY;
2777
+ });
2778
+ this.stateManagerDemoService.data$
2779
+ .pipe(tap((data) => {
2780
+ switch (this.requestType) {
2781
+ case 'GET':
2782
+ this.GET$.next(data);
2783
+ break;
2784
+ case 'PUT':
2785
+ this.PUT$.next(data);
2786
+ break;
2787
+ case 'POST':
2788
+ this.POST$.next(data);
2789
+ break;
2790
+ case 'DELETE':
2791
+ this.DELETE$.next(data);
2792
+ break;
2793
+ case 'STREAM':
2794
+ this.STREAM.next(data);
2795
+ break;
2796
+ case 'STREAM_AI':
2797
+ this.STREAM_AI.next(data);
2798
+ break;
2799
+ default:
2800
+ break;
2801
+ }
2802
+ })).subscribe();
2803
+ }
2804
+ addHeader() {
2805
+ const header = this.fb.group({
2806
+ key: ['', Validators.required],
2807
+ value: ['']
2808
+ });
2809
+ this.headers.push(header);
2810
+ }
2811
+ removeHeader(index) {
2812
+ this.headers.removeAt(index);
2813
+ }
2814
+ compileRequest() {
2815
+ const requestParams = this.requestForm.value;
2816
+ requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
2817
+ const pathReq = (requestParams.path || "").split("/");
2818
+ if (!this.pollingState.checked)
2819
+ requestParams.polling = 0;
2820
+ if (!this.failedState.checked) {
2821
+ requestParams.retry = { times: 0, delay: 0 };
2822
+ }
2823
+ return ApiRequest.adapt({
2824
+ ...requestParams,
2825
+ // ...{ path: pathReq, server: this.server },
2826
+ ...{ path: pathReq },
2827
+ });
2828
+ }
2829
+ onSetStateOptions() {
2830
+ if (!this.isValid)
2831
+ return;
2832
+ const reqParams = this.compileRequest();
2833
+ const db = DatabaseStorage.adapt(this.database);
2834
+ const type = this.dataType === "ARRAY" ? DataType.ARRAY : DataType.OBJECT;
2835
+ this.stateManagerDemoService.setAPIOptions(reqParams, type, db);
2836
+ this.requestForm.markAsPristine();
2837
+ }
2838
+ onClearRecords() {
2839
+ this.stateManagerDemoService.clearRecords();
2840
+ }
2841
+ onRefreshRecords() {
2842
+ this.stateManagerDemoService.refreshData();
2843
+ }
2844
+ onGetRequest() {
2845
+ this.requestType = 'GET';
2846
+ this.stateManagerDemoService.getClients();
2847
+ }
2848
+ onCreateRequest() {
2849
+ this.requestType = 'POST';
2850
+ this.stateManagerDemoService.createClient(this.sampleClientData);
2851
+ }
2852
+ onUpdateRequest() {
2853
+ this.requestType = 'PUT';
2854
+ this.stateManagerDemoService.updateClient(this.sampleClientData);
2855
+ }
2856
+ onDeleteRequest() {
2857
+ this.requestType = 'DELETE';
2858
+ this.stateManagerDemoService.deleteClient(this.sampleClientData);
2859
+ }
2860
+ onStreamPostRequest() {
2861
+ if (!this.isValid)
2862
+ return;
2863
+ this.requestType = 'STREAM_AI';
2864
+ const reqParams = this.compileRequest();
2865
+ reqParams.server = "http://localhost:11434/api";
2866
+ reqParams.path = ["generate"];
2867
+ reqParams.stream = true;
2868
+ this.stateManagerDemoService.setAPIOptions(reqParams, DataType.ARRAY);
2869
+ const payload = {
2870
+ model: "mistral",
2871
+ prompt: this.questionControl.value,
2872
+ stream: reqParams.stream
2873
+ };
2874
+ this.stateManagerDemoService.streamAIRequest(payload);
2875
+ }
2876
+ onStreamRequest() {
2877
+ if (!this.isValid)
2878
+ return;
2879
+ this.requestType = 'STREAM';
2880
+ const reqParams = this.compileRequest();
2881
+ reqParams.server = "oidc";
2882
+ reqParams.stream = true;
2883
+ this.stateManagerDemoService.setAPIOptions(reqParams, DataType.ARRAY);
2884
+ this.stateManagerDemoService.streamRequest();
2885
+ }
2886
+ errorHandling(err, type) {
2887
+ if (type === 'GET')
2888
+ this.GET_error$.next(err.message);
2889
+ if (type === 'POST')
2890
+ this.POST_error$.next(err.message);
2891
+ if (type === 'PUT')
2892
+ this.PUT_error$.next(err.message);
2893
+ if (type === 'DELETE')
2894
+ this.DELETE_error$.next(err.message);
2895
+ if (type === 'STREAM')
2896
+ this.STREAM_error$.next(err.message);
2897
+ }
2898
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerStateDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2899
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo", viewQueries: [{ propertyName: "failedState", first: true, predicate: ["failedState"], descendants: true, static: true }, { propertyName: "pollingState", first: true, predicate: ["pollingState"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request State Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>State Data Type</mat-label>\n <mat-select formControlName=\"datatype\">\n <mat-option value=\"ARRAY\">Array</mat-option>\n <mat-option value=\"OBJECT\">Object</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"mapper\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n <div *ngIf=\"DBState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem\" formGroupName=\"database\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Table Name</mat-label>\n <input matInput placeholder=\"table\" formControlName=\"table\" value=\"\">\n </mat-form-field>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"1m\">One Minute</mat-option>\n <mat-option value=\"1h\">One Hour</mat-option>\n <mat-option value=\"1d\">One Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </div>\n <div style=\"margin-top: 1rem; display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onSetStateOptions()\" [disabled]=\"!hasChanged\">\n Set API Request Options\n </button>\n </div>\n <div>\n <mat-error *ngIf=\"(error$ | async) as error\">\n {{ error | json }}\n </mat-error>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\" \n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <div *ngIf=\"pollingState.checked\">\n <mat-progress-bar mode=\"determinate\" \n *ngIf=\"!(isPending$ | async) && (this.countdown$ | async) || -1 > 0\" \n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\" *ngIf=\"(GET$ | async) as data\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n <div *ngIf=\"data.length > 1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Records</mat-label>\n <mat-select [formControl]=\"selectedRecord\" [disabled]=\"data === null && data?.length === 0\">\n <mat-option [value]=\"\">None</mat-option>\n <mat-option *ngFor=\"let item of data\" [value]=\"item\">\n {{item.domain}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div *ngIf=\"(dataObservable$ | async) as dataRecord\">\n <div *ngIf=\"(selectedRecord$ | async) as record; else NO_RECORD\">\n {{ record | json }}\n </div>\n <ng-template #NO_RECORD>No Record Selected from State</ng-template>\n \n </div>\n <div style=\"margin-top: 1rem;\">\n <span *ngIf=\"data !== null && data?.length > 0; else NO_DATA\">\n State contains a Total of {{ data.length }} Records\n </span>\n <ng-template #NO_DATA>No Records</ng-template>\n <div style=\"display: flex; gap: .5rem; text-align: end; justify-content: flex-end;\">\n <button class=\"btn\" mat-stroked-button (click)=\"onClearRecords()\">Clear</button>\n <button class=\"btn\" mat-stroked-button (click)=\"onRefreshRecords()\">Refresh</button>\n </div>\n </div>\n </div>\n\n\n\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request ({{ dataType }})</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n <div>{{ (GET$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n <div>{{ (POST$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n <div>{{ (PUT$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n <div>{{ (DELETE$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n \n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n</div>", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i9.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i10$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i12.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: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
2900
+ }
2901
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerStateDemoComponent, decorators: [{
2902
+ type: Component,
2903
+ args: [{ selector: 'app-request-manager-state-demo', template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request State Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>State Data Type</mat-label>\n <mat-select formControlName=\"datatype\">\n <mat-option value=\"ARRAY\">Array</mat-option>\n <mat-option value=\"OBJECT\">Object</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"mapper\">\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n <div *ngIf=\"DBState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem\" formGroupName=\"database\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Table Name</mat-label>\n <input matInput placeholder=\"table\" formControlName=\"table\" value=\"\">\n </mat-form-field>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"1m\">One Minute</mat-option>\n <mat-option value=\"1h\">One Hour</mat-option>\n <mat-option value=\"1d\">One Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </div>\n <div style=\"margin-top: 1rem; display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onSetStateOptions()\" [disabled]=\"!hasChanged\">\n Set API Request Options\n </button>\n </div>\n <div>\n <mat-error *ngIf=\"(error$ | async) as error\">\n {{ error | json }}\n </mat-error>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\" \n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <div *ngIf=\"pollingState.checked\">\n <mat-progress-bar mode=\"determinate\" \n *ngIf=\"!(isPending$ | async) && (this.countdown$ | async) || -1 > 0\" \n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\" *ngIf=\"(GET$ | async) as data\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n <div *ngIf=\"data.length > 1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Records</mat-label>\n <mat-select [formControl]=\"selectedRecord\" [disabled]=\"data === null && data?.length === 0\">\n <mat-option [value]=\"\">None</mat-option>\n <mat-option *ngFor=\"let item of data\" [value]=\"item\">\n {{item.domain}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div *ngIf=\"(dataObservable$ | async) as dataRecord\">\n <div *ngIf=\"(selectedRecord$ | async) as record; else NO_RECORD\">\n {{ record | json }}\n </div>\n <ng-template #NO_RECORD>No Record Selected from State</ng-template>\n \n </div>\n <div style=\"margin-top: 1rem;\">\n <span *ngIf=\"data !== null && data?.length > 0; else NO_DATA\">\n State contains a Total of {{ data.length }} Records\n </span>\n <ng-template #NO_DATA>No Records</ng-template>\n <div style=\"display: flex; gap: .5rem; text-align: end; justify-content: flex-end;\">\n <button class=\"btn\" mat-stroked-button (click)=\"onClearRecords()\">Clear</button>\n <button class=\"btn\" mat-stroked-button (click)=\"onRefreshRecords()\">Refresh</button>\n </div>\n </div>\n </div>\n\n\n\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request ({{ dataType }})</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n <div>{{ (GET$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n <div>{{ (POST$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n <div>{{ (PUT$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n <div>{{ (DELETE$ | async) | json }}</div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n \n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n \n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">STREAMING POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" [disabled]=\"hasChanged\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM_AI$ | async) as data\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n</div>", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}\n"] }]
2904
+ }], ctorParameters: function () { return []; }, propDecorators: { failedState: [{
2905
+ type: ViewChild,
2906
+ args: ["failedState", { static: true }]
2907
+ }], pollingState: [{
2908
+ type: ViewChild,
2909
+ args: ["pollingState", { static: true }]
2910
+ }] } });
2911
+
2912
+ class HttpRequestManagerModule {
2913
+ static forRoot(config = ConfigOptions.adapt()) {
2914
+ return {
2915
+ ngModule: HttpRequestManagerModule,
2916
+ providers: [
2917
+ { provide: CONFIG_SETTINGS_TOKEN, useValue: ConfigOptions.adapt(config) },
2918
+ HTTPManagerService, LocalStorageManagerService //all services that need access to config
2919
+ ],
2920
+ };
2921
+ }
2922
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2923
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, declarations: [HttpRequestServicesDemoComponent,
2924
+ RequestManagerStateDemoComponent,
2925
+ RequestManagerDemoComponent,
2926
+ LocalStorageDemoComponent
2927
+ // DatabaseDataDemoComponent,
2928
+ ], imports: [CommonModule,
2929
+ ToastMessageModule,
2930
+ FormsModule,
2931
+ ReactiveFormsModule,
2932
+ MatButtonModule,
2933
+ MatSelectModule,
2934
+ MatChipsModule,
2935
+ MatMenuModule,
2936
+ MatIconModule,
2937
+ MatTableModule,
2938
+ MatToolbarModule,
2939
+ MatButtonToggleModule,
2940
+ MatAutocompleteModule,
2941
+ MatProgressBarModule,
2942
+ MatSlideToggleModule,
2943
+ MatDividerModule,
2944
+ MatFormFieldModule,
2945
+ MatInputModule,
2946
+ MatSlideToggleModule, i1.TranslateModule, MatSidenavModule,
2947
+ FileDownloaderModule], exports: [HttpRequestServicesDemoComponent] }); }
2948
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, providers: [
2949
+ { provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
2950
+ { provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
2951
+ { provide: HTTP_INTERCEPTORS, useClass: ProxyDebuggerInterceptor, multi: true },
2952
+ { provide: CONFIG_SETTINGS_TOKEN, useValue: ConfigOptions.adapt() },
2953
+ HTTPManagerService, LocalStorageManagerService
2954
+ ], imports: [CommonModule,
2955
+ ToastMessageModule,
2956
+ FormsModule,
2957
+ ReactiveFormsModule,
2958
+ MatButtonModule,
2959
+ MatSelectModule,
2960
+ MatChipsModule,
2961
+ MatMenuModule,
2962
+ MatIconModule,
2963
+ MatTableModule,
2964
+ MatToolbarModule,
2965
+ MatButtonToggleModule,
2966
+ MatAutocompleteModule,
2967
+ MatProgressBarModule,
2968
+ MatSlideToggleModule,
2969
+ MatDividerModule,
2970
+ MatFormFieldModule,
2971
+ MatInputModule,
2972
+ MatSlideToggleModule,
2973
+ TranslateModule.forRoot(),
2974
+ MatSidenavModule,
2975
+ FileDownloaderModule] }); }
2976
+ }
2977
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestManagerModule, decorators: [{
2978
+ type: NgModule,
2979
+ args: [{
2980
+ imports: [
2981
+ CommonModule,
2982
+ ToastMessageModule,
2983
+ FormsModule,
2984
+ ReactiveFormsModule,
2985
+ MatButtonModule,
2986
+ MatSelectModule,
2987
+ MatChipsModule,
2988
+ MatMenuModule,
2989
+ MatIconModule,
2990
+ MatTableModule,
2991
+ MatToolbarModule,
2992
+ MatButtonToggleModule,
2993
+ MatAutocompleteModule,
2994
+ MatProgressBarModule,
2995
+ MatSlideToggleModule,
2996
+ MatDividerModule,
2997
+ MatFormFieldModule,
2998
+ MatInputModule,
2999
+ MatSlideToggleModule,
3000
+ TranslateModule.forRoot(),
3001
+ MatSidenavModule,
3002
+ FileDownloaderModule,
3003
+ ],
3004
+ declarations: [
3005
+ HttpRequestServicesDemoComponent,
3006
+ RequestManagerStateDemoComponent,
3007
+ RequestManagerDemoComponent,
3008
+ LocalStorageDemoComponent
3009
+ // DatabaseDataDemoComponent,
3010
+ ],
3011
+ exports: [
3012
+ HttpRequestServicesDemoComponent,
3013
+ ],
3014
+ providers: [
3015
+ { provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
3016
+ { provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
3017
+ { provide: HTTP_INTERCEPTORS, useClass: ProxyDebuggerInterceptor, multi: true },
3018
+ { provide: CONFIG_SETTINGS_TOKEN, useValue: ConfigOptions.adapt() },
3019
+ HTTPManagerService, LocalStorageManagerService
3020
+ ],
3021
+ }]
3022
+ }] });
3023
+
3024
+ class HttpRequestServicesDemoComponent {
3025
+ constructor(configOptions) {
3026
+ this.configOptions = configOptions;
3027
+ this.requestTypes = [
3028
+ { name: "Http Service", value: 'http_service' },
3029
+ { name: "Http State Service", value: 'http_state_service' },
3030
+ { name: "Database Service", value: 'database_service', divider: true, disabled: true },
3031
+ { name: "Local Storage Service", value: 'local_storage_service' },
3032
+ ];
3033
+ this.selectedService = this.requestTypes[0].value;
3034
+ }
3035
+ ngOnInit() {
3036
+ if (this.configOptions)
3037
+ this.injectionOptions = this.configOptions;
3038
+ }
3039
+ onSelected(type) {
3040
+ this.selectedService = this.requestTypes[type].value;
3041
+ }
3042
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestServicesDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
3043
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HttpRequestServicesDemoComponent, selector: "app-http-request-services-demo", ngImport: i0, template: "<mat-toolbar style=\"display:flex\">\n <div>Global Data</div>\n <div style=\"flex:1\"></div>\n <button mat-stroked-button [matMenuTriggerFor]=\"menu\">Services</button>\n <mat-menu #menu=\"matMenu\">\n <ng-container *ngFor=\"let type of requestTypes; index as i\">\n <div\n *ngIf=\"type?.divider\"\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n </ng-container>\n\n </mat-menu>\n</mat-toolbar>\n\n<span [ngSwitch]=\"selectedService\">\n <p *ngSwitchCase=\"'http_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo></app-request-manager-demo>\n </p>\n <p *ngSwitchCase=\"'http_state_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo></app-request-manager-state-demo>\n </p>\n <p *ngSwitchCase=\"'database_service'\">\n <!-- <app-database-data-demo></app-database-data-demo> -->\n </p>\n <p *ngSwitchCase=\"'local_storage_service'\">\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n <p *ngSwitchDefault>\n Other\n </p>\n</span>\n\n<ng-template #HTTP_OPTIONS>\n <ng-container *ngIf=\"injectionOptions?.httpRequestOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - HTTP Options</h3>\n {{ injectionOptions?.httpRequestOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n <ng-container class=\"box\" *ngIf=\"injectionOptions?.LocalStorageOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - LocalStorage Options</h3>\n {{ injectionOptions?.LocalStorageOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n\n", styles: [".box{padding:1rem;background-color:#f5f5f5;border:thin gray solid;margin-top:1rem}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$2.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i4$1.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo" }, { kind: "component", type: RequestManagerDemoComponent, selector: "app-request-manager-demo" }, { kind: "component", type: LocalStorageDemoComponent, selector: "app-local-storage-demo" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
3044
+ }
3045
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HttpRequestServicesDemoComponent, decorators: [{
3046
+ type: Component,
3047
+ args: [{ selector: 'app-http-request-services-demo', template: "<mat-toolbar style=\"display:flex\">\n <div>Global Data</div>\n <div style=\"flex:1\"></div>\n <button mat-stroked-button [matMenuTriggerFor]=\"menu\">Services</button>\n <mat-menu #menu=\"matMenu\">\n <ng-container *ngFor=\"let type of requestTypes; index as i\">\n <div\n *ngIf=\"type?.divider\"\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n </ng-container>\n\n </mat-menu>\n</mat-toolbar>\n\n<span [ngSwitch]=\"selectedService\">\n <p *ngSwitchCase=\"'http_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo></app-request-manager-demo>\n </p>\n <p *ngSwitchCase=\"'http_state_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo></app-request-manager-state-demo>\n </p>\n <p *ngSwitchCase=\"'database_service'\">\n <!-- <app-database-data-demo></app-database-data-demo> -->\n </p>\n <p *ngSwitchCase=\"'local_storage_service'\">\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n <p *ngSwitchDefault>\n Other\n </p>\n</span>\n\n<ng-template #HTTP_OPTIONS>\n <ng-container *ngIf=\"injectionOptions?.httpRequestOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - HTTP Options</h3>\n {{ injectionOptions?.httpRequestOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n <ng-container class=\"box\" *ngIf=\"injectionOptions?.LocalStorageOptions\">\n <div class=\"box\">\n <h3 style=\"font-weight: bold;\">Injection Token Detected - LocalStorage Options</h3>\n {{ injectionOptions?.LocalStorageOptions| json }}\n </div>\n </ng-container>\n</ng-template>\n\n\n", styles: [".box{padding:1rem;background-color:#f5f5f5;border:thin gray solid;margin-top:1rem}\n"] }]
3048
+ }], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
3049
+ type: Inject,
3050
+ args: [CONFIG_SETTINGS_TOKEN]
3051
+ }] }]; } });
3052
+
1706
3053
  /*
1707
3054
  * Public API Surface of http-request-manager
1708
3055
  */
@@ -1711,5 +3058,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1711
3058
  * Generated bundle index. Do not edit.
1712
3059
  */
1713
3060
 
1714
- export { ApiRequest, AppService, AsymmetricalEncryptionService, DataType, DatabaseStorage, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerStateService, HeadersService, LocalStorageManagerService, PathQueryService, Random, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomSignature, RandomStr, RequestErrorInterceptor, RequestHeadersInterceptor, RequestOptions, RetryOptions, SettingOptions, StorageData, StorageOption, StorageOptionSettings, StorageType, SymmetricalEncryptionService, UUID, UtilsService, WithCredentialsInterceptor, countdown, delayedRetry, requestPolling, requestStreaming };
3061
+ export { ApiRequest, AppService, AsymmetricalEncryptionService, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseStorage, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerStateService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, LocalStorageManagerService, LocalStorageOptions, PathQueryService, Random, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomSignature, RandomStr, RequestErrorInterceptor, RequestHeadersInterceptor, RequestOptions, RetryOptions, SettingOptions, StorageData, StorageOption, StorageType, SymmetricalEncryptionService, UUID, UtilsService, WithCredentialsInterceptor, countdown, delayedRetry, requestPolling, requestStreaming };
1715
3062
  //# sourceMappingURL=http-request-manager.mjs.map