http-request-manager 0.0.2 → 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.
- package/README.md +53 -13
- package/esm2022/http-request-manager.mjs +5 -0
- package/esm2022/lib/http-request-manager.module.mjs +145 -0
- package/esm2022/lib/http-request-services-demo/http-request-services-demo.component.mjs +41 -0
- package/esm2022/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.mjs +175 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.mjs +80 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.mjs +42 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.mjs +85 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.mjs +11 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.mjs +29 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.mjs +9 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.mjs +12 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.mjs +10 -0
- package/esm2022/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.mjs +276 -0
- package/esm2022/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.mjs +268 -0
- package/esm2022/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.mjs +75 -0
- package/esm2022/lib/index.mjs +4 -0
- package/esm2022/lib/interceptors/credentials.interceptor.mjs +14 -0
- package/esm2022/lib/interceptors/index.mjs +5 -0
- package/esm2022/lib/interceptors/models/error-settings.model.mjs +10 -0
- package/esm2022/lib/interceptors/proxy-debugger.interceptor.mjs +47 -0
- package/esm2022/lib/interceptors/request-error.interceptor.mjs +49 -0
- package/esm2022/lib/interceptors/request-header.interceptor.mjs +41 -0
- package/esm2022/lib/models/config-http-options.model.mjs +18 -0
- package/esm2022/lib/models/config-local-storage-options.model.mjs +12 -0
- package/esm2022/lib/models/config-options.model.mjs +12 -0
- package/esm2022/lib/models/config-token.model.mjs +8 -0
- package/esm2022/lib/models/data-type.enum.mjs +7 -0
- package/esm2022/lib/models/database-storage.model.mjs +10 -0
- package/esm2022/lib/models/index.mjs +7 -0
- package/esm2022/lib/models/retry-options.model.mjs +10 -0
- package/esm2022/lib/services/index.mjs +6 -0
- package/esm2022/lib/services/local-storage-manager-service/index.mjs +3 -0
- package/esm2022/lib/services/local-storage-manager-service/local-storage-manager.service.mjs +300 -0
- package/esm2022/lib/services/local-storage-manager-service/models/global-store-options.model.mjs +13 -0
- package/esm2022/lib/services/local-storage-manager-service/models/index.mjs +6 -0
- package/esm2022/lib/services/local-storage-manager-service/models/setting-options.model.mjs +13 -0
- package/esm2022/lib/services/local-storage-manager-service/models/storage-data.model.mjs +10 -0
- package/esm2022/lib/services/local-storage-manager-service/models/storage-option.model.mjs +12 -0
- package/esm2022/lib/services/local-storage-manager-service/models/storage-type.enum.mjs +7 -0
- package/esm2022/lib/services/request-manager-services/http-manager.service.mjs +208 -0
- package/esm2022/lib/services/request-manager-services/index.mjs +5 -0
- package/esm2022/lib/services/request-manager-services/request.service.mjs +201 -0
- package/esm2022/lib/services/request-manager-services/rxjs-operators/countdown.mjs +9 -0
- package/esm2022/lib/services/request-manager-services/rxjs-operators/delay-retry.mjs +10 -0
- package/esm2022/lib/services/request-manager-services/rxjs-operators/index.mjs +5 -0
- package/esm2022/lib/services/request-manager-services/rxjs-operators/request-polling.mjs +14 -0
- package/esm2022/lib/services/request-manager-services/rxjs-operators/request-streaming.mjs +19 -0
- package/esm2022/lib/services/request-manager-state-service/http-manager-state.store.mjs +266 -0
- package/esm2022/lib/services/request-manager-state-service/index.mjs +3 -0
- package/esm2022/lib/services/request-manager-state-service/models/api-request.model.mjs +20 -0
- package/esm2022/lib/services/request-manager-state-service/models/index.mjs +3 -0
- package/esm2022/lib/services/request-manager-state-service/models/request-options.model.mjs +10 -0
- package/esm2022/lib/services/utils/app.service.mjs +26 -0
- package/esm2022/lib/services/utils/encryption/asymmetrical-encryption.service.mjs +186 -0
- package/esm2022/lib/services/utils/encryption/encryption-test.service.mjs +35 -0
- package/esm2022/lib/services/utils/encryption/index.mjs +4 -0
- package/esm2022/lib/services/utils/encryption/random.mjs +52 -0
- package/esm2022/lib/services/utils/encryption/symmetrical-encryption.service.mjs +77 -0
- package/esm2022/lib/services/utils/headers.service.mjs +21 -0
- package/esm2022/lib/services/utils/index.mjs +6 -0
- package/esm2022/lib/services/utils/object-merger.service.mjs +34 -0
- package/esm2022/lib/services/utils/path-query.service.mjs +54 -0
- package/esm2022/lib/services/utils/utils.service.mjs +155 -0
- package/esm2022/public-api.mjs +7 -0
- package/fesm2022/http-request-manager.mjs +3062 -0
- package/fesm2022/http-request-manager.mjs.map +1 -0
- package/http-request-manager-4.1.2.tgz +0 -0
- package/index.d.ts +5 -0
- package/lib/http-request-manager.module.d.ts +33 -0
- package/lib/http-request-services-demo/http-request-services-demo.component.d.ts +24 -0
- package/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.d.ts +56 -0
- package/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.d.ts +26 -0
- package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.d.ts +13 -0
- package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.d.ts +26 -0
- package/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.d.ts +12 -0
- package/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.d.ts +16 -0
- package/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.d.ts +8 -0
- package/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.d.ts +14 -0
- package/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.d.ts +10 -0
- package/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.d.ts +98 -0
- package/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.d.ts +110 -0
- package/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.d.ts +16 -0
- package/lib/index.d.ts +3 -0
- package/lib/interceptors/credentials.interceptor.d.ts +8 -0
- package/lib/interceptors/index.d.ts +4 -0
- package/lib/interceptors/models/error-settings.model.d.ts +10 -0
- package/lib/interceptors/proxy-debugger.interceptor.d.ts +12 -0
- package/lib/interceptors/request-error.interceptor.d.ts +10 -0
- package/lib/interceptors/request-header.interceptor.d.ts +15 -0
- package/lib/models/config-http-options.model.d.ts +21 -0
- package/lib/models/config-local-storage-options.model.d.ts +13 -0
- package/lib/models/config-options.model.d.ts +12 -0
- package/lib/models/config-token.model.d.ts +8 -0
- package/lib/models/data-type.enum.d.ts +5 -0
- package/lib/models/database-storage.model.d.ts +10 -0
- package/lib/models/index.d.ts +6 -0
- package/lib/models/retry-options.model.d.ts +10 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/local-storage-manager-service/index.d.ts +2 -0
- package/lib/services/local-storage-manager-service/local-storage-manager.service.d.ts +86 -0
- package/lib/services/local-storage-manager-service/models/global-store-options.model.d.ts +15 -0
- package/lib/services/local-storage-manager-service/models/index.d.ts +5 -0
- package/lib/services/local-storage-manager-service/models/setting-options.model.d.ts +15 -0
- package/lib/services/local-storage-manager-service/models/storage-data.model.d.ts +10 -0
- package/lib/services/local-storage-manager-service/models/storage-option.model.d.ts +13 -0
- package/lib/services/local-storage-manager-service/models/storage-type.enum.d.ts +5 -0
- package/lib/services/request-manager-services/http-manager.service.d.ts +40 -0
- package/lib/services/request-manager-services/index.d.ts +3 -0
- package/lib/services/request-manager-services/request.service.d.ts +28 -0
- package/lib/services/request-manager-services/rxjs-operators/countdown.d.ts +2 -0
- package/lib/services/request-manager-services/rxjs-operators/delay-retry.d.ts +2 -0
- package/lib/services/request-manager-services/rxjs-operators/index.d.ts +4 -0
- package/lib/services/request-manager-services/rxjs-operators/request-polling.d.ts +7 -0
- package/lib/services/request-manager-services/rxjs-operators/request-streaming.d.ts +2 -0
- package/lib/services/request-manager-state-service/http-manager-state.store.d.ts +51 -0
- package/lib/services/request-manager-state-service/index.d.ts +2 -0
- package/lib/services/request-manager-state-service/models/api-request.model.d.ts +25 -0
- package/lib/services/request-manager-state-service/models/index.d.ts +2 -0
- package/lib/services/request-manager-state-service/models/request-options.model.d.ts +10 -0
- package/lib/services/utils/app.service.d.ts +8 -0
- package/lib/services/utils/encryption/asymmetrical-encryption.service.d.ts +17 -0
- package/lib/services/utils/encryption/encryption-test.service.d.ts +10 -0
- package/lib/services/utils/encryption/index.d.ts +3 -0
- package/lib/services/utils/encryption/random.d.ts +7 -0
- package/lib/services/utils/encryption/symmetrical-encryption.service.d.ts +14 -0
- package/lib/services/utils/headers.service.d.ts +10 -0
- package/lib/services/utils/index.d.ts +5 -0
- package/lib/services/utils/object-merger.service.d.ts +7 -0
- package/lib/services/utils/path-query.service.d.ts +11 -0
- package/lib/services/utils/utils.service.d.ts +24 -0
- package/package.json +41 -18
- package/public-api.d.ts +3 -0
- package/ng-package.json +0 -7
- package/src/lib/http-request-manager.component.spec.ts +0 -21
- package/src/lib/http-request-manager.component.ts +0 -15
- package/src/lib/http-request-manager.module.ts +0 -16
- package/src/lib/http-request-manager.service.spec.ts +0 -16
- package/src/lib/http-request-manager.service.ts +0 -9
- package/src/public-api.ts +0 -7
- package/tsconfig.lib.json +0 -14
- package/tsconfig.lib.prod.json +0 -10
- package/tsconfig.spec.json +0 -14
|
@@ -0,0 +1,3062 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, Injectable, APP_ID, Inject, InjectionToken, Injector, Optional, EventEmitter, Component, ViewEncapsulation, Input, Output, NgModule, ViewChild } from '@angular/core';
|
|
3
|
+
import { ComponentStore } from '@ngrx/component-store';
|
|
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
|
+
import * as CryptoJS from 'crypto-js';
|
|
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';
|
|
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';
|
|
45
|
+
|
|
46
|
+
var StorageType;
|
|
47
|
+
(function (StorageType) {
|
|
48
|
+
StorageType[StorageType["GLOBAL"] = 0] = "GLOBAL";
|
|
49
|
+
StorageType[StorageType["SESSION"] = 1] = "SESSION";
|
|
50
|
+
StorageType[StorageType["DB"] = 2] = "DB";
|
|
51
|
+
})(StorageType || (StorageType = {}));
|
|
52
|
+
|
|
53
|
+
class SettingOptions {
|
|
54
|
+
constructor(storage, expires, expiresIn, encrypted) {
|
|
55
|
+
this.storage = storage;
|
|
56
|
+
this.expires = expires;
|
|
57
|
+
this.expiresIn = expiresIn;
|
|
58
|
+
this.encrypted = encrypted;
|
|
59
|
+
}
|
|
60
|
+
static adapt(item) {
|
|
61
|
+
return new SettingOptions((item?.storage) ? item.storage : StorageType.GLOBAL, (item?.expires) ? item.expires : 0, (item?.expiresIn) ? item.expiresIn : '', (item?.encrypted) ? item?.encrypted : false);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class StorageOption {
|
|
66
|
+
constructor(id, name = 'untitled', options) {
|
|
67
|
+
this.id = id;
|
|
68
|
+
this.name = name;
|
|
69
|
+
this.options = options;
|
|
70
|
+
}
|
|
71
|
+
static adapt(item) {
|
|
72
|
+
return new StorageOption((item?.id) ? item.id : crypto.randomUUID(), item?.name, (item?.options) ? SettingOptions.adapt(item.options) : SettingOptions.adapt());
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class GlobalStoreOptions {
|
|
77
|
+
constructor(encryption = false, expiresIn, expires, stores = []) {
|
|
78
|
+
this.encryption = encryption;
|
|
79
|
+
this.expiresIn = expiresIn;
|
|
80
|
+
this.expires = expires;
|
|
81
|
+
this.stores = stores;
|
|
82
|
+
}
|
|
83
|
+
static adapt(item) {
|
|
84
|
+
return new GlobalStoreOptions((item?.encryption) ? item.encryption : false, (item?.expiresIn) ? item.expiresIn : '', (item?.expires) ? item.expires : 0, (item?.stores) ? item.stores.map((item) => StorageOption.adapt(item)) : []);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
class StorageData {
|
|
89
|
+
constructor(id, data) {
|
|
90
|
+
this.id = id;
|
|
91
|
+
this.data = data;
|
|
92
|
+
}
|
|
93
|
+
static adapt(item) {
|
|
94
|
+
return new StorageData((item?.id) ? item.id : crypto.randomUUID(), (item?.data) ? item.data : null);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
class UtilsService {
|
|
99
|
+
constructor() {
|
|
100
|
+
this.http = inject(HttpClient);
|
|
101
|
+
this.lc = (str) => str.toLowerCase().replace(/[^\w\s]/g, '').replace(/\s+/g, '_');
|
|
102
|
+
}
|
|
103
|
+
isString(x) {
|
|
104
|
+
return Object.prototype.toString.call(x) === '[object String]';
|
|
105
|
+
}
|
|
106
|
+
isObject(obj) {
|
|
107
|
+
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
108
|
+
}
|
|
109
|
+
JSONToString(value) {
|
|
110
|
+
return (this.isObject(value)) ? JSON.stringify(value) : value;
|
|
111
|
+
}
|
|
112
|
+
stringToJSON(value) {
|
|
113
|
+
return (this.isJSON(value)) ? JSON.parse(value) : value;
|
|
114
|
+
}
|
|
115
|
+
isJSON(str) {
|
|
116
|
+
try {
|
|
117
|
+
JSON.parse(str);
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
getValueByProp(obj, prop) {
|
|
125
|
+
if (typeof obj === 'undefined')
|
|
126
|
+
return false;
|
|
127
|
+
return obj[prop];
|
|
128
|
+
}
|
|
129
|
+
objectsEqual(x, y) {
|
|
130
|
+
const ok = Object.keys, tx = typeof x, ty = typeof y;
|
|
131
|
+
return x && y && tx === 'object' && tx === ty ? (ok(x).length === ok(y).length &&
|
|
132
|
+
ok(x).every((key) => this.objectsEqual(x[key], y[key]))) : (x === y);
|
|
133
|
+
}
|
|
134
|
+
getJSON(file) {
|
|
135
|
+
return this.http.get(`assets/data/${file}`);
|
|
136
|
+
}
|
|
137
|
+
get today() {
|
|
138
|
+
return new Date().getMilliseconds() / 1000;
|
|
139
|
+
}
|
|
140
|
+
base32ToHex(base32) {
|
|
141
|
+
const base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
142
|
+
const charToValue = (char) => base32chars.indexOf(char.toUpperCase());
|
|
143
|
+
let bits = '';
|
|
144
|
+
let hex = '';
|
|
145
|
+
for (let i = 0; i < base32.length; i++) {
|
|
146
|
+
const val = charToValue(base32.charAt(i));
|
|
147
|
+
bits += val.toString(2).padStart(5, '0');
|
|
148
|
+
}
|
|
149
|
+
for (let i = 0; i + 4 <= bits.length; i += 4) {
|
|
150
|
+
const chunk = bits.substr(i, 4);
|
|
151
|
+
hex += parseInt(chunk, 2).toString(16);
|
|
152
|
+
}
|
|
153
|
+
return hex.toUpperCase();
|
|
154
|
+
}
|
|
155
|
+
binaryToHex(binary) {
|
|
156
|
+
let hex = '';
|
|
157
|
+
for (let i = 0; i < binary.length; i += 8) {
|
|
158
|
+
const byte = binary.substr(i, 8);
|
|
159
|
+
const decimal = parseInt(byte, 2);
|
|
160
|
+
hex += decimal.toString(16).padStart(2, '0');
|
|
161
|
+
}
|
|
162
|
+
return hex.padStart(32, '0').substr(0, 32);
|
|
163
|
+
}
|
|
164
|
+
// y = years, m = months, w = weeks, d = days, hr = hours, mn = minutes else seconds
|
|
165
|
+
// returns epoch time corresponding to the expiry type
|
|
166
|
+
expires(str) {
|
|
167
|
+
if (!str)
|
|
168
|
+
return;
|
|
169
|
+
const match = str.match(/[^0-9]+$/);
|
|
170
|
+
const type = (match) ? str.slice(-match[0].length) : 0;
|
|
171
|
+
const now = Math.floor(new Date().getTime() / 1000);
|
|
172
|
+
let value = 0;
|
|
173
|
+
switch (type) {
|
|
174
|
+
case 'y':
|
|
175
|
+
const years = parseInt(str.slice(0, -1));
|
|
176
|
+
value = now + (years * 31556926);
|
|
177
|
+
break;
|
|
178
|
+
case 'm':
|
|
179
|
+
const months = parseInt(str.slice(0, -1));
|
|
180
|
+
value = now + (months * 2629743);
|
|
181
|
+
break;
|
|
182
|
+
case 'w':
|
|
183
|
+
const weeks = parseInt(str.slice(0, -1));
|
|
184
|
+
value = now + (weeks * 604800);
|
|
185
|
+
break;
|
|
186
|
+
case 'd':
|
|
187
|
+
const days = parseInt(str.slice(0, -1));
|
|
188
|
+
value = now + (days * 86400);
|
|
189
|
+
break;
|
|
190
|
+
case 'hr':
|
|
191
|
+
const hrs = parseInt(str.slice(0, -2));
|
|
192
|
+
value = now + (hrs * 3600);
|
|
193
|
+
break;
|
|
194
|
+
case 'mn':
|
|
195
|
+
const min = parseInt(str.slice(0, -2));
|
|
196
|
+
value = now + (min * 60);
|
|
197
|
+
break;
|
|
198
|
+
default: //seconds
|
|
199
|
+
const sec = parseInt(str.slice(0, -1));
|
|
200
|
+
value = now + (sec);
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
hasExpired(expiryDate) {
|
|
206
|
+
if (!expiryDate || expiryDate === 0)
|
|
207
|
+
return false;
|
|
208
|
+
const currentTime = Math.floor(new Date().getTime() / 1000);
|
|
209
|
+
return expiryDate < currentTime;
|
|
210
|
+
}
|
|
211
|
+
hasExpiry(setting) {
|
|
212
|
+
return (setting?.expires) ? true : false;
|
|
213
|
+
}
|
|
214
|
+
expiresIn(expiryDate) {
|
|
215
|
+
if (!expiryDate)
|
|
216
|
+
return;
|
|
217
|
+
const now = Math.floor(new Date().getTime() / 1000);
|
|
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(', ');
|
|
239
|
+
}
|
|
240
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
241
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, providedIn: 'root' }); }
|
|
242
|
+
}
|
|
243
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtilsService, decorators: [{
|
|
244
|
+
type: Injectable,
|
|
245
|
+
args: [{
|
|
246
|
+
providedIn: 'root'
|
|
247
|
+
}]
|
|
248
|
+
}], ctorParameters: function () { return []; } });
|
|
249
|
+
|
|
250
|
+
const Random = () => {
|
|
251
|
+
const typedArray = new Uint8Array(1);
|
|
252
|
+
const randomValue = crypto.getRandomValues(typedArray)[0];
|
|
253
|
+
const randomFloat = randomValue / Math.pow(2, 8);
|
|
254
|
+
return randomFloat;
|
|
255
|
+
};
|
|
256
|
+
const RandomNumber = (min, max) => {
|
|
257
|
+
return Math.floor(Random() * max) + min;
|
|
258
|
+
};
|
|
259
|
+
const RandomNumbers = (min, max, length) => {
|
|
260
|
+
const numbers = [];
|
|
261
|
+
for (let i = 0; i < length; i++)
|
|
262
|
+
numbers.push(Math.floor(Random() * max) + min);
|
|
263
|
+
return numbers;
|
|
264
|
+
};
|
|
265
|
+
const RandomNumbersUnique = (min, max, length) => {
|
|
266
|
+
let count = 0;
|
|
267
|
+
// Adjust the length if it exceeds the number of unique numbers possible in the range
|
|
268
|
+
if (length > (max - min + 1)) {
|
|
269
|
+
console.error('error encountered');
|
|
270
|
+
length = max - min + 1;
|
|
271
|
+
}
|
|
272
|
+
console.log('length', length);
|
|
273
|
+
const numbers = [];
|
|
274
|
+
const maxAttempts = length * 100; // Safeguard to prevent infinite loops
|
|
275
|
+
while (numbers.length < length && count < maxAttempts) {
|
|
276
|
+
const num = Math.floor(Random() * max) + min;
|
|
277
|
+
if (!numbers.includes(num)) {
|
|
278
|
+
numbers.push(num);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (count >= maxAttempts) {
|
|
282
|
+
throw new Error('Maximum attempts exceeded while generating unique numbers');
|
|
283
|
+
}
|
|
284
|
+
return numbers;
|
|
285
|
+
};
|
|
286
|
+
const RandomStr = () => {
|
|
287
|
+
const typedArray = new Uint8Array(8);
|
|
288
|
+
const array = new Uint32Array(1);
|
|
289
|
+
crypto.getRandomValues(array);
|
|
290
|
+
return array[0].toString(36);
|
|
291
|
+
};
|
|
292
|
+
const RandomSignature = () => {
|
|
293
|
+
const typedArray = new Uint8Array(8);
|
|
294
|
+
const array = new Uint32Array(1);
|
|
295
|
+
crypto.getRandomValues(array);
|
|
296
|
+
return array[0];
|
|
297
|
+
};
|
|
298
|
+
const UUID = () => {
|
|
299
|
+
return self.crypto.randomUUID();
|
|
300
|
+
};
|
|
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
|
+
// },
|
|
308
|
+
class AppService {
|
|
309
|
+
constructor(id) {
|
|
310
|
+
this.id = id;
|
|
311
|
+
this.appID = this.id;
|
|
312
|
+
}
|
|
313
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, deps: [{ token: APP_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
314
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, providedIn: 'root' }); }
|
|
315
|
+
}
|
|
316
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppService, decorators: [{
|
|
317
|
+
type: Injectable,
|
|
318
|
+
args: [{
|
|
319
|
+
providedIn: 'root'
|
|
320
|
+
}]
|
|
321
|
+
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
322
|
+
type: Inject,
|
|
323
|
+
args: [APP_ID]
|
|
324
|
+
}] }]; } });
|
|
325
|
+
|
|
326
|
+
class SymmetricalEncryptionService {
|
|
327
|
+
constructor() {
|
|
328
|
+
this.appService = inject(AppService);
|
|
329
|
+
// TODO: The APP ID is not a string, it is a function
|
|
330
|
+
this.appID = (this.appService.appID) ? this.appService.appID : '';
|
|
331
|
+
if (this.appID === '')
|
|
332
|
+
console.warn('No App Key has been define');
|
|
333
|
+
}
|
|
334
|
+
generateCipherKey() {
|
|
335
|
+
return (RandomSignature().toString() + RandomSignature().toString()).substring(0, 8);
|
|
336
|
+
}
|
|
337
|
+
encrypt(str, key = this.appID) {
|
|
338
|
+
if (!str || key === '')
|
|
339
|
+
return '';
|
|
340
|
+
let _key = CryptoJS.enc.Utf8.parse(key);
|
|
341
|
+
let _iv = CryptoJS.enc.Utf8.parse(key);
|
|
342
|
+
try {
|
|
343
|
+
const encrypted = CryptoJS.AES.encrypt(JSON.stringify(str), _key, {
|
|
344
|
+
keySize: 16,
|
|
345
|
+
iv: _iv,
|
|
346
|
+
mode: CryptoJS.mode.ECB,
|
|
347
|
+
padding: CryptoJS.pad.Pkcs7
|
|
348
|
+
});
|
|
349
|
+
return encrypted.toString();
|
|
350
|
+
}
|
|
351
|
+
catch (error) {
|
|
352
|
+
console.log(error);
|
|
353
|
+
}
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
decrypt(str, key = this.appID) {
|
|
357
|
+
if (!str || key === '')
|
|
358
|
+
return;
|
|
359
|
+
let _key = CryptoJS.enc.Utf8.parse(key);
|
|
360
|
+
let _iv = CryptoJS.enc.Utf8.parse(key);
|
|
361
|
+
try {
|
|
362
|
+
return CryptoJS.AES.decrypt(str, _key, {
|
|
363
|
+
keySize: 16,
|
|
364
|
+
iv: _iv,
|
|
365
|
+
mode: CryptoJS.mode.ECB,
|
|
366
|
+
padding: CryptoJS.pad.Pkcs7
|
|
367
|
+
}).toString(CryptoJS.enc.Utf8);
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
console.log(error);
|
|
371
|
+
}
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
createSignature(url, len = 16) {
|
|
375
|
+
const sig = CryptoJS.SHA256(url).toString(CryptoJS.enc.Hex);
|
|
376
|
+
return sig.substring(0, len).toUpperCase();
|
|
377
|
+
}
|
|
378
|
+
normalizeURL(url) {
|
|
379
|
+
const normalizedURL = url.replace(/(https?:\/\/)?(www\.)?/, '').replace(/\/+$/, '');
|
|
380
|
+
return normalizedURL;
|
|
381
|
+
}
|
|
382
|
+
generateSignature(url) {
|
|
383
|
+
const normalizedURL = this.normalizeURL(url);
|
|
384
|
+
const hash = CryptoJS.SHA256(normalizedURL);
|
|
385
|
+
const signature = hash.toString(CryptoJS.enc.Hex);
|
|
386
|
+
return signature;
|
|
387
|
+
}
|
|
388
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
389
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, providedIn: 'root' }); }
|
|
390
|
+
}
|
|
391
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SymmetricalEncryptionService, decorators: [{
|
|
392
|
+
type: Injectable,
|
|
393
|
+
args: [{
|
|
394
|
+
providedIn: 'root'
|
|
395
|
+
}]
|
|
396
|
+
}], ctorParameters: function () { return []; } });
|
|
397
|
+
|
|
398
|
+
class EncryptionTestService {
|
|
399
|
+
constructor() { }
|
|
400
|
+
isBase64(str) {
|
|
401
|
+
const base64Pattern = /^(?:[A-Z0-9+/]{4})*(?:[A-Z0-9+/]{2}==|[A-Z0-9+/]{3}=)?$/i;
|
|
402
|
+
return base64Pattern.test(str);
|
|
403
|
+
}
|
|
404
|
+
isHexadecimal(str) {
|
|
405
|
+
const hexPattern = /^[0-9a-fA-F]+$/;
|
|
406
|
+
return hexPattern.test(str) && (str.length % 2 === 0);
|
|
407
|
+
}
|
|
408
|
+
hasHighEntropy(str) {
|
|
409
|
+
const uniqueChars = new Set(str).size;
|
|
410
|
+
return uniqueChars > str.length * 0.6;
|
|
411
|
+
}
|
|
412
|
+
isEncrypted(str) {
|
|
413
|
+
if (typeof str !== 'string') {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
if (this.isBase64(str) || this.isHexadecimal(str)) {
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
return this.hasHighEntropy(str);
|
|
420
|
+
}
|
|
421
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
422
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, providedIn: 'root' }); }
|
|
423
|
+
}
|
|
424
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EncryptionTestService, decorators: [{
|
|
425
|
+
type: Injectable,
|
|
426
|
+
args: [{
|
|
427
|
+
providedIn: 'root'
|
|
428
|
+
}]
|
|
429
|
+
}], ctorParameters: function () { return []; } });
|
|
430
|
+
|
|
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;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return merged;
|
|
456
|
+
}
|
|
457
|
+
isNonEmptyString(value) {
|
|
458
|
+
return typeof value === 'string' && value.length === 0;
|
|
459
|
+
}
|
|
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;
|
|
481
|
+
}
|
|
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);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
class HeadersService {
|
|
490
|
+
constructor() {
|
|
491
|
+
this.headers = {};
|
|
492
|
+
}
|
|
493
|
+
generateHeaders(headers) {
|
|
494
|
+
const allHeaders = headers ? { ...this.headers, ...headers } : {};
|
|
495
|
+
return { headers: new HttpHeaders(allHeaders) };
|
|
496
|
+
}
|
|
497
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
498
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, providedIn: 'root' }); }
|
|
499
|
+
}
|
|
500
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeadersService, decorators: [{
|
|
501
|
+
type: Injectable,
|
|
502
|
+
args: [{
|
|
503
|
+
providedIn: 'root'
|
|
504
|
+
}]
|
|
505
|
+
}] });
|
|
506
|
+
|
|
507
|
+
class PathQueryService {
|
|
508
|
+
constructor() {
|
|
509
|
+
this.removeEmptyParams = (obj) => Object.fromEntries(Object.entries(obj)
|
|
510
|
+
.map(([key, value]) => [key, value && typeof value === 'object' ? this.removeEmptyParams(value) : value])
|
|
511
|
+
.filter(([_, value]) => value !== undefined && value !== ""));
|
|
512
|
+
}
|
|
513
|
+
buildAPIPath(server, params) {
|
|
514
|
+
server = (Array.isArray(server)) ? server.join('/') : server;
|
|
515
|
+
const pathObjects = (params) ? params.filter((path) => (!this.isObject(path))) : [];
|
|
516
|
+
const queryObjects = (params) ? params.filter((path) => (this.isObject(path))) : [];
|
|
517
|
+
const query = this.removeEmptyParams(queryObjects.reduce((r, c) => {
|
|
518
|
+
Object.entries(c).forEach(([key, value]) => {
|
|
519
|
+
r[key] = Array.isArray(value) ? value.join(',') : value;
|
|
520
|
+
});
|
|
521
|
+
return r;
|
|
522
|
+
}, {}));
|
|
523
|
+
let path = this.buildRestPath(server, pathObjects);
|
|
524
|
+
return (Object.keys(query).length > 0) ? path + '?' + this.buildQueryPath(query) : path;
|
|
525
|
+
}
|
|
526
|
+
buildRestPath(server, params) {
|
|
527
|
+
server = (server) ? server : '';
|
|
528
|
+
server = (server.charAt(0) === '/') ? server.substring(1) : server;
|
|
529
|
+
return this.cleanUrlPath(server + '/' + params.join('/'));
|
|
530
|
+
}
|
|
531
|
+
buildQueryPath(params) {
|
|
532
|
+
const searchParams = new URLSearchParams();
|
|
533
|
+
for (const key in params) {
|
|
534
|
+
if (Array.isArray(params[key])) {
|
|
535
|
+
params[key].forEach((value) => searchParams.append(key, value));
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
searchParams.append(key, params[key]);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return searchParams.toString();
|
|
542
|
+
}
|
|
543
|
+
cleanUrlPath(str) {
|
|
544
|
+
return str.replace(/([^:]\/)\/+/g, "$1").replace(/\/$/, '');
|
|
545
|
+
}
|
|
546
|
+
isObject(val) {
|
|
547
|
+
return (val === null) ? false : ((typeof val === 'function') || (typeof val === 'object'));
|
|
548
|
+
}
|
|
549
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
550
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, providedIn: 'root' }); }
|
|
551
|
+
}
|
|
552
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PathQueryService, decorators: [{
|
|
553
|
+
type: Injectable,
|
|
554
|
+
args: [{
|
|
555
|
+
providedIn: 'root'
|
|
556
|
+
}]
|
|
557
|
+
}] });
|
|
558
|
+
|
|
559
|
+
class AsymmetricalEncryptionService {
|
|
560
|
+
constructor() { }
|
|
561
|
+
generateKeyPair(modulusLength = 2048) {
|
|
562
|
+
// modulusLength - 1024, 2048, 4096
|
|
563
|
+
// hash - SHA-256
|
|
564
|
+
return from(crypto.subtle.generateKey({
|
|
565
|
+
name: "RSA-OAEP",
|
|
566
|
+
modulusLength,
|
|
567
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
568
|
+
hash: { name: "SHA-256" }
|
|
569
|
+
}, true, // Extractable keys
|
|
570
|
+
["encrypt", "decrypt"]));
|
|
571
|
+
}
|
|
572
|
+
encryptData(publicKey, data) {
|
|
573
|
+
const encodedData = new TextEncoder().encode(data);
|
|
574
|
+
return from(crypto.subtle.encrypt({
|
|
575
|
+
name: "RSA-OAEP"
|
|
576
|
+
}, publicKey, encodedData)).pipe(map(enc => this.arrayBufferToBase64(enc)));
|
|
577
|
+
}
|
|
578
|
+
decryptData(privateKey, encryptedData) {
|
|
579
|
+
const encStr = this.base64ToArrayBuffer(encryptedData);
|
|
580
|
+
return from(crypto.subtle.decrypt({
|
|
581
|
+
name: "RSA-OAEP"
|
|
582
|
+
}, privateKey, encStr).then(decryptedData => {
|
|
583
|
+
return new TextDecoder().decode(decryptedData);
|
|
584
|
+
}));
|
|
585
|
+
}
|
|
586
|
+
pemToArrayBuffer(pem) {
|
|
587
|
+
const b64 = pem.replace(/(-----BEGIN (RSA )?(PRIVATE|PUBLIC) KEY-----|-----END (RSA )?(PRIVATE|PUBLIC) KEY-----|\n)/g, '');
|
|
588
|
+
const binaryString = atob(b64);
|
|
589
|
+
const len = binaryString.length;
|
|
590
|
+
const buffer = new ArrayBuffer(len);
|
|
591
|
+
const view = new Uint8Array(buffer);
|
|
592
|
+
for (let i = 0; i < len; i++) {
|
|
593
|
+
view[i] = binaryString.charCodeAt(i);
|
|
594
|
+
}
|
|
595
|
+
return buffer;
|
|
596
|
+
}
|
|
597
|
+
base64ToArrayBuffer(base64) {
|
|
598
|
+
const binaryString = atob(base64);
|
|
599
|
+
const len = binaryString.length;
|
|
600
|
+
const buffer = new ArrayBuffer(len);
|
|
601
|
+
const view = new Uint8Array(buffer);
|
|
602
|
+
for (let i = 0; i < len; i++) {
|
|
603
|
+
view[i] = binaryString.charCodeAt(i);
|
|
604
|
+
}
|
|
605
|
+
return buffer;
|
|
606
|
+
}
|
|
607
|
+
arrayBufferToBase64(buffer) {
|
|
608
|
+
let binary = '';
|
|
609
|
+
const bytes = new Uint8Array(buffer);
|
|
610
|
+
const len = bytes.byteLength;
|
|
611
|
+
for (let i = 0; i < len; i++) {
|
|
612
|
+
binary += String.fromCharCode(bytes[i]);
|
|
613
|
+
}
|
|
614
|
+
return window.btoa(binary);
|
|
615
|
+
}
|
|
616
|
+
base64ToPEM(base64Key, publicKey = true) {
|
|
617
|
+
const keyType = (publicKey) ? 'PUBLIC' : 'PRIVATE';
|
|
618
|
+
const header = `-----BEGIN ${keyType} KEY-----\n`;
|
|
619
|
+
const footer = `\n-----END ${keyType} KEY-----`;
|
|
620
|
+
const keyBody = base64Key.match(/.{1,64}/g)?.join("\n") || "";
|
|
621
|
+
return header + keyBody + footer;
|
|
622
|
+
}
|
|
623
|
+
pemToCryptoKey(pem, algorithm, extractable, keyUsages, format = "pkcs8" //"raw" | "pkcs8" | "spki"
|
|
624
|
+
) {
|
|
625
|
+
const buffer = this.pemToArrayBuffer(pem);
|
|
626
|
+
console.log('buffer found ', buffer);
|
|
627
|
+
return from(crypto.subtle.importKey(format, buffer, algorithm, extractable, keyUsages));
|
|
628
|
+
}
|
|
629
|
+
// TESTING
|
|
630
|
+
testGenerateKeys() {
|
|
631
|
+
const testSequence = new BehaviorSubject("");
|
|
632
|
+
const testSequence$ = testSequence.asObservable();
|
|
633
|
+
testSequence.next("Test Generating Keys");
|
|
634
|
+
// GENERATE KEYS
|
|
635
|
+
this.generateKeyPair().subscribe((data) => {
|
|
636
|
+
console.log("GEN-GENERATED KEYS: ", data);
|
|
637
|
+
crypto.subtle.exportKey('spki', data.publicKey)
|
|
638
|
+
.then(key => {
|
|
639
|
+
const publicKeyBase64 = this.arrayBufferToBase64(key);
|
|
640
|
+
console.log("GEN-EXPORT PUBLIC KEY: ", this.base64ToPEM(publicKeyBase64, true));
|
|
641
|
+
});
|
|
642
|
+
crypto.subtle.exportKey('pkcs8', data.privateKey)
|
|
643
|
+
.then(key => {
|
|
644
|
+
const privateKeyBase64 = this.arrayBufferToBase64(key);
|
|
645
|
+
console.log("GEN-EXPORT PRIVATE KEY: ", this.base64ToPEM(privateKeyBase64, false));
|
|
646
|
+
});
|
|
647
|
+
// TEST WITH GENERATED KEYS
|
|
648
|
+
this.encryptData(data.publicKey, "Sample Data here - Mike Bonifacio")
|
|
649
|
+
.subscribe((enc) => {
|
|
650
|
+
console.log("GEN-ENCRYPT==>: ", enc);
|
|
651
|
+
this.decryptData(data.privateKey, enc).subscribe((dec) => {
|
|
652
|
+
testSequence.next('Test Passed');
|
|
653
|
+
testSequence.complete();
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
return testSequence$;
|
|
658
|
+
}
|
|
659
|
+
testDecryptionWithKeys() {
|
|
660
|
+
const testSequence = new BehaviorSubject("");
|
|
661
|
+
const testSequence$ = testSequence.asObservable();
|
|
662
|
+
testSequence.next("Test Generating Keys");
|
|
663
|
+
const privateKey = `-----BEGIN PRIVATE KEY-----
|
|
664
|
+
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDKVBkCWNb9eHVF
|
|
665
|
+
twAA5mdAyvXFix3WavdrsoYRkvtCl8ogDBQf8f6N0bRkDF1zcVHRrNAEyozXDtuD
|
|
666
|
+
kFgSiivBFREI7fiS3sOvduq6FaGXzX0IY6oaVMu8oOPgDvC0yvoohR+0Qxq2d6lP
|
|
667
|
+
SPyHeKQaxP4KxzCJJzB1XAcbd2eFzUUDv25mNlwdVkmW8FI/sAxnJLgPTW78dzfX
|
|
668
|
+
Ddfk+nxdIqxVKSLATnL0kMN7aGJx24UozioAIpzvvvF5/+7HTd1gi6NeCqrAYr3g
|
|
669
|
+
iP364AE26CFwFvHnafO9uNQhlQ+uiNnOoInXByfFGVP+RidSpfLzaxDjs6RDwpol
|
|
670
|
+
h098btONAgMBAAECggEAAVhHM2OD5IkUtuowwcKNaCTKGmrClRE3gMuzJeBsSJEy
|
|
671
|
+
uAReUFILZylcnhegDytSti2vDA9T7xqtO6CU0p3V8LpU89JMOPRb/deirI4UXSpx
|
|
672
|
+
xbNyjirOO6bnrNlOWfKexdQQsikYPzF2iM1Scpr1u9ZDCHZOl1ZYSrkve5My4coP
|
|
673
|
+
3Gx6tTBqL0jQBfcpf4ES8BH3JSawR/MgqzDS74+bI2VH+kvuPAC1L4fBgaV3VUv0
|
|
674
|
+
nFzim5A3s5VaXPgJbEIghP9BkYGFkeT9ma3nliEZWc96AzsmowFn1ayCvrNVPo9R
|
|
675
|
+
ECD2NnttBiCJZt3H93sR9+OTeA8Bls+aZGlKd5mLAQKBgQDpf8nIYUm/Zmls7/lQ
|
|
676
|
+
QBUSGHEYrbjNsEejQsPgNDtg2EVSxdUkvTn7Wb+HExTk09Z5bNvhaO2532/FH9y8
|
|
677
|
+
ahSXafiMXpfR2olwXdOB9yXXl4F5C0LGnmzGim4OSeWzAX0JCL470KaS0QN3EmoG
|
|
678
|
+
9F0YCfMnZXNTweSSx4xvlO6ggQKBgQDd01uIolm7z1DIWCwNERAXP2GDwcvxyzYK
|
|
679
|
+
YqJfKDeHt2t6yIzZMMotnPDy+OlcdGspIIHkB5a+SZN5Nt7DUKg/MnyOZ3KbVq41
|
|
680
|
+
k7dR4Ka3LRnGkesy7lSr7ef1rfquyR75OXJQcPWvkFcLu0TMiQhvptatZ8VN+F4n
|
|
681
|
+
fDQELRotDQKBgQCgN+AUT7VT0QjcCBnRV/ddUEoiPenFsYSmYMSYzh5ESIHg1wB2
|
|
682
|
+
0iS79Iw4Of6nOTg8X1bM57vfQ5Kk90T2P+/bKYqzfqC8DTErWiYsUpKzyTC9Bt4N
|
|
683
|
+
/Vz0Kr5zrX8ggg/yp/4oevYhXav8AzWfigNq4EDpMnKc8TlPAf+5/L50gQKBgQC2
|
|
684
|
+
mLPhPhr1gUszD3l7bA89w7uGlLFHoQoj9FtKTzWervp3QLzIT+QtNeIVb5XQuDg5
|
|
685
|
+
y3uAdEq+6pvNjMBEMJG+K9Xh9v+dJPYUPjsJ2A4D/MkZ7qWX8B2cxSJK1uLim8W2
|
|
686
|
+
S3ZxBvsGgJ9WldmlMCvUlJZkeWYtr4P5psC+q02/xQKBgQCDII/jcV2+lRM2iNTe
|
|
687
|
+
vBijZSaNMEWOK/Y+/HFK8GYKXnB+xNWhrm8rKgWGzpDJAUPMh9Tt+leW9LKEBuzF
|
|
688
|
+
Y1bGblmGm1zsPWpIx05Fdtv9eOJmFnXbGzIsYyhadZnPcQOWhqxtpVxSuul0Jc7Q
|
|
689
|
+
XNq4qPaPXhbQAshgtyBt75DMkw==
|
|
690
|
+
-----END PRIVATE KEY-----`;
|
|
691
|
+
const pubKey = `-----BEGIN PUBLIC KEY-----
|
|
692
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylQZAljW/Xh1RbcAAOZn
|
|
693
|
+
QMr1xYsd1mr3a7KGEZL7QpfKIAwUH/H+jdG0ZAxdc3FR0azQBMqM1w7bg5BYEoor
|
|
694
|
+
wRURCO34kt7Dr3bquhWhl819CGOqGlTLvKDj4A7wtMr6KIUftEMatnepT0j8h3ik
|
|
695
|
+
GsT+CscwiScwdVwHG3dnhc1FA79uZjZcHVZJlvBSP7AMZyS4D01u/Hc31w3X5Pp8
|
|
696
|
+
XSKsVSkiwE5y9JDDe2hicduFKM4qACKc777xef/ux03dYIujXgqqwGK94Ij9+uAB
|
|
697
|
+
NughcBbx52nzvbjUIZUProjZzqCJ1wcnxRlT/kYnUqXy82sQ47OkQ8KaJYdPfG7T
|
|
698
|
+
jQIDAQAB
|
|
699
|
+
-----END PUBLIC KEY-----`;
|
|
700
|
+
const algorithm = {
|
|
701
|
+
name: "RSA-OAEP",
|
|
702
|
+
modulusLength: 2048,
|
|
703
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
704
|
+
hash: "SHA-256"
|
|
705
|
+
};
|
|
706
|
+
// ENCRYPT
|
|
707
|
+
this.pemToCryptoKey(pubKey, algorithm, true, ["encrypt"], "spki").subscribe((keyPublic) => {
|
|
708
|
+
// console.log("PUBLIC KEY: ", keyPublic)
|
|
709
|
+
this.encryptData(keyPublic, "Sample Data here - Mike Bonifacio")
|
|
710
|
+
.subscribe((str) => {
|
|
711
|
+
console.log("ENCRYPTED STRING: ", str);
|
|
712
|
+
testSequence.next('encrypted string success');
|
|
713
|
+
});
|
|
714
|
+
});
|
|
715
|
+
const enc = "r7UOuEGBZ6jbVTOIBuv9jFOEtRiedmS27hfW40k7XKCTsQ5VhWup0qu2BA2ANZaGKii/uehJ/RSPiyfGbJ6leJrat0mA1hPqH/XodaBzLMDigvdYM1NSXFZMDa40OpLUIXbPlAvybjcGu7Bal+LMA8htHrFu/OmM/fHI66xOzzpuXSYx0OkWjtY81rUQ1FFkvrkx2jGFPZ0p+Nw/v3Q4cJnet6V63vCueFlD749VMcVXo7pvz4AIPpB+IOy3kbxaYTPakLVioJERU6GFMXWkECuRvohhS9CETcORZtRVRkvhcHk3lxgIhfqojUKYgD6K5dDELDPsWIS+iTG1XIQIlg==";
|
|
716
|
+
// DECRYPTION
|
|
717
|
+
this.pemToCryptoKey(privateKey, algorithm, false, ["decrypt"], "pkcs8").subscribe((key) => {
|
|
718
|
+
// console.log("DECRYPT ===", key)
|
|
719
|
+
this.decryptData(key, enc)
|
|
720
|
+
.pipe(catchError(err => {
|
|
721
|
+
console.log("ERROR: ", err);
|
|
722
|
+
return EMPTY;
|
|
723
|
+
})).subscribe((str) => {
|
|
724
|
+
console.log("DECRYPTED STRING: ", str);
|
|
725
|
+
testSequence.next('decrypted string success');
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
return testSequence$;
|
|
729
|
+
}
|
|
730
|
+
;
|
|
731
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
732
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, providedIn: 'root' }); }
|
|
733
|
+
}
|
|
734
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AsymmetricalEncryptionService, decorators: [{
|
|
735
|
+
type: Injectable,
|
|
736
|
+
args: [{
|
|
737
|
+
providedIn: 'root'
|
|
738
|
+
}]
|
|
739
|
+
}], ctorParameters: function () { return []; } });
|
|
740
|
+
|
|
741
|
+
function requestStreaming() {
|
|
742
|
+
return input$ => input$.pipe(filter((event) => event.type === HttpEventType.DownloadProgress || event.type === HttpEventType.Response), map((event) => {
|
|
743
|
+
if (event.type === HttpEventType.DownloadProgress) {
|
|
744
|
+
return event.partialText || '';
|
|
745
|
+
}
|
|
746
|
+
else if (event.type === HttpEventType.Response) {
|
|
747
|
+
return event.body;
|
|
748
|
+
}
|
|
749
|
+
}), map((data) => {
|
|
750
|
+
if (typeof data === 'string') {
|
|
751
|
+
const matches = data.match(/{[^}]+}/g) || [];
|
|
752
|
+
return (matches.length > 0) ? matches.map(match => JSON.parse(match)) : data;
|
|
753
|
+
}
|
|
754
|
+
return data;
|
|
755
|
+
}));
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
class RequestService {
|
|
759
|
+
constructor() {
|
|
760
|
+
this.http = inject(HttpClient);
|
|
761
|
+
this.pathQueryService = inject(PathQueryService);
|
|
762
|
+
this.headersService = inject(HeadersService);
|
|
763
|
+
this.isPending = new BehaviorSubject(false);
|
|
764
|
+
this.isPending$ = this.isPending.asObservable();
|
|
765
|
+
this.progress = new BehaviorSubject(0);
|
|
766
|
+
this.progress$ = this.progress.asObservable();
|
|
767
|
+
}
|
|
768
|
+
getRecordRequest(options) {
|
|
769
|
+
const urlPath = this.buildUrlPath(options);
|
|
770
|
+
const headers = this.buildCombinedHeaders(options);
|
|
771
|
+
this.isPending.next(true);
|
|
772
|
+
return (options.stream)
|
|
773
|
+
? this.http.get(urlPath, headers).pipe(requestStreaming(), this.handleFinalize())
|
|
774
|
+
: this.http.get(urlPath, headers).pipe(this.request(options));
|
|
775
|
+
}
|
|
776
|
+
createRecordRequest(options, data) {
|
|
777
|
+
const urlPath = this.buildUrlPath(options);
|
|
778
|
+
const headers = this.buildCombinedHeaders(options);
|
|
779
|
+
this.isPending.next(true);
|
|
780
|
+
return (options.stream)
|
|
781
|
+
? this.http.post(urlPath, data, headers).pipe(requestStreaming(), this.handleFinalize())
|
|
782
|
+
: this.http.post(urlPath, data, headers).pipe(this.request(options));
|
|
783
|
+
}
|
|
784
|
+
updateRecordRequest(options, data) {
|
|
785
|
+
const urlPath = this.buildUrlPath(options);
|
|
786
|
+
const headers = this.buildHeaders(options);
|
|
787
|
+
this.isPending.next(true);
|
|
788
|
+
return this.http.put(urlPath, data, headers).pipe(this.request(options));
|
|
789
|
+
}
|
|
790
|
+
deleteRecordRequest(options) {
|
|
791
|
+
const urlPath = this.buildUrlPath(options);
|
|
792
|
+
const headers = this.buildHeaders(options);
|
|
793
|
+
this.isPending.next(true);
|
|
794
|
+
return this.http.delete(urlPath, headers).pipe(this.request(options));
|
|
795
|
+
}
|
|
796
|
+
// Helper functions
|
|
797
|
+
buildUrlPath(options) {
|
|
798
|
+
return this.pathQueryService.buildAPIPath(options.server, options.path);
|
|
799
|
+
}
|
|
800
|
+
buildHeaders(options) {
|
|
801
|
+
return this.headersService.generateHeaders(options.headers);
|
|
802
|
+
}
|
|
803
|
+
buildCombinedHeaders(options) {
|
|
804
|
+
const headers = this.combineHeaders(options.headers, options.stream);
|
|
805
|
+
return this.headersService.generateHeaders(headers);
|
|
806
|
+
}
|
|
807
|
+
request(options) {
|
|
808
|
+
return (source$) => {
|
|
809
|
+
return source$.pipe(map(data => {
|
|
810
|
+
if (options?.adapter) {
|
|
811
|
+
return Array.isArray(data)
|
|
812
|
+
? data.map((item) => options.adapter(item))
|
|
813
|
+
: options.adapter(data);
|
|
814
|
+
}
|
|
815
|
+
return data;
|
|
816
|
+
}));
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
downloadFileRequest(options) {
|
|
820
|
+
this.isPending.next(true);
|
|
821
|
+
const urlPath = this.buildUrlPath(options);
|
|
822
|
+
return this.http.get(urlPath, { responseType: 'blob', observe: 'events', reportProgress: true })
|
|
823
|
+
.pipe(map((event) => {
|
|
824
|
+
this.isPending.next(true);
|
|
825
|
+
const info = event;
|
|
826
|
+
switch (event.type) {
|
|
827
|
+
case HttpEventType.DownloadProgress:
|
|
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
|
+
}
|
|
838
|
+
case HttpEventType.Response:
|
|
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
|
+
}
|
|
856
|
+
default:
|
|
857
|
+
this.isPending.next(false);
|
|
858
|
+
return 0;
|
|
859
|
+
}
|
|
860
|
+
}), catchError(err => {
|
|
861
|
+
return throwError(() => err);
|
|
862
|
+
}));
|
|
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
|
+
}
|
|
881
|
+
handleFinalize() {
|
|
882
|
+
return finalize(() => this.isPending.next(false));
|
|
883
|
+
}
|
|
884
|
+
downloadFile(file, fileData) {
|
|
885
|
+
const navigatorAny = window.navigator;
|
|
886
|
+
const extension = file.split('.')[1].toLowerCase();
|
|
887
|
+
var newBlob = new Blob([fileData], { type: this.createFileType(extension) });
|
|
888
|
+
if (navigatorAny.msSaveOrOpenBlob) {
|
|
889
|
+
navigatorAny.msSaveOrOpenBlob(newBlob, file);
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
const link = document.createElement('a');
|
|
893
|
+
const url = window.URL.createObjectURL(newBlob);
|
|
894
|
+
link.href = url;
|
|
895
|
+
link.download = file;
|
|
896
|
+
link.click();
|
|
897
|
+
window.URL.revokeObjectURL(url);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
createFileType(ext) {
|
|
901
|
+
let fileType = "";
|
|
902
|
+
if (ext == 'pdf' || ext == 'csv') {
|
|
903
|
+
fileType = `application/${ext}`;
|
|
904
|
+
}
|
|
905
|
+
else if (ext == 'jpeg' || ext == 'jpg' || ext == 'png') {
|
|
906
|
+
fileType = `image/${ext}`;
|
|
907
|
+
}
|
|
908
|
+
else if (ext == 'txt') {
|
|
909
|
+
fileType = 'text/plain';
|
|
910
|
+
}
|
|
911
|
+
else if (ext == 'ppt' || ext == 'pot' || ext == 'pps' || ext == 'ppa') {
|
|
912
|
+
fileType = 'application/vnd.ms-powerpoint';
|
|
913
|
+
}
|
|
914
|
+
else if (ext == 'pptx') {
|
|
915
|
+
fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
|
916
|
+
}
|
|
917
|
+
else if (ext == 'doc' || ext == 'dot') {
|
|
918
|
+
fileType = 'application/msword';
|
|
919
|
+
}
|
|
920
|
+
else if (ext == 'docx') {
|
|
921
|
+
fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
922
|
+
}
|
|
923
|
+
else if (ext == 'xls' || ext == 'xlt' || ext == 'xla') {
|
|
924
|
+
fileType = 'application/vnd.ms-excel';
|
|
925
|
+
}
|
|
926
|
+
else if (ext == 'xlsx') {
|
|
927
|
+
fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
928
|
+
}
|
|
929
|
+
return fileType;
|
|
930
|
+
}
|
|
931
|
+
combineHeaders(headers, isStreaming) {
|
|
932
|
+
return (isStreaming) ?
|
|
933
|
+
{
|
|
934
|
+
...headers,
|
|
935
|
+
observe: 'events',
|
|
936
|
+
responseType: 'text',
|
|
937
|
+
reportProgress: true,
|
|
938
|
+
Accept: 'text/event-stream'
|
|
939
|
+
}
|
|
940
|
+
: headers;
|
|
941
|
+
}
|
|
942
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
943
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, providedIn: 'root' }); }
|
|
944
|
+
}
|
|
945
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestService, decorators: [{
|
|
946
|
+
type: Injectable,
|
|
947
|
+
args: [{
|
|
948
|
+
providedIn: 'root'
|
|
949
|
+
}]
|
|
950
|
+
}] });
|
|
951
|
+
|
|
952
|
+
function countdown(duration) {
|
|
953
|
+
return defer(() => {
|
|
954
|
+
const currentCount = { current: duration };
|
|
955
|
+
return interval(1000).pipe(map(() => --currentCount.current), takeWhile(count => count >= 0));
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
960
|
+
function delayedRetry(delayMs, maxRetry = DEFAULT_MAX_RETRIES) {
|
|
961
|
+
return (src) => src.pipe(retry({
|
|
962
|
+
count: maxRetry,
|
|
963
|
+
delay: () => timer(delayMs)
|
|
964
|
+
}));
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* @param pollInterval
|
|
969
|
+
* @param stopCondition$
|
|
970
|
+
* @param isPending$
|
|
971
|
+
*/
|
|
972
|
+
function requestPolling(pollInterval, stopCondition$, isPending$) {
|
|
973
|
+
return (source) => {
|
|
974
|
+
return interval(pollInterval * 1000)
|
|
975
|
+
.pipe(startWith(0), tap(() => isPending$.next(true)), mergeMap(() => source), tap(() => isPending$.next(false)), takeUntil(stopCondition$));
|
|
976
|
+
};
|
|
977
|
+
}
|
|
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
|
+
|
|
1044
|
+
class HTTPManagerService extends RequestService {
|
|
1045
|
+
constructor(configOptions) {
|
|
1046
|
+
super();
|
|
1047
|
+
this.configOptions = configOptions;
|
|
1048
|
+
this.toastMessage = inject(ToastMessageService);
|
|
1049
|
+
this.ng_injector = inject(Injector);
|
|
1050
|
+
this.objectMergerService = inject(ObjectMergerService);
|
|
1051
|
+
this.countdown = new BehaviorSubject(0);
|
|
1052
|
+
this.countdown$ = this.countdown.asObservable();
|
|
1053
|
+
this.error = new BehaviorSubject(false);
|
|
1054
|
+
this.error$ = this.error.asObservable();
|
|
1055
|
+
this.data = new BehaviorSubject(null);
|
|
1056
|
+
this.data$ = this.data.asObservable();
|
|
1057
|
+
this.polling$ = new Subject();
|
|
1058
|
+
this.config = ConfigOptions.adapt();
|
|
1059
|
+
this.config = (configOptions) ? ConfigOptions.adapt(configOptions) : ConfigOptions.adapt();
|
|
1060
|
+
}
|
|
1061
|
+
// REQUESTS
|
|
1062
|
+
getRequest(options, params) {
|
|
1063
|
+
this.isPending.next(true);
|
|
1064
|
+
this.data.next(null);
|
|
1065
|
+
options = (options) ? options : ApiRequest.adapt();
|
|
1066
|
+
const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
|
|
1067
|
+
const func = this.getRecordRequest;
|
|
1068
|
+
const requests = this.createRequest(func, updatedOptions);
|
|
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
|
+
}));
|
|
1076
|
+
}
|
|
1077
|
+
postRequest(data, options, params) {
|
|
1078
|
+
this.isPending.next(true);
|
|
1079
|
+
this.data.next(null);
|
|
1080
|
+
options = (options) ? options : ApiRequest.adapt();
|
|
1081
|
+
const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
|
|
1082
|
+
const func = this.createRecordRequest;
|
|
1083
|
+
const requests = this.createRequest(func, updatedOptions, 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
|
+
}));
|
|
1091
|
+
}
|
|
1092
|
+
putRequest(data, options, params) {
|
|
1093
|
+
this.isPending.next(true);
|
|
1094
|
+
this.data.next(null);
|
|
1095
|
+
options = (options) ? options : ApiRequest.adapt();
|
|
1096
|
+
const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
|
|
1097
|
+
const func = this.updateRecordRequest;
|
|
1098
|
+
const requests = this.createRequest(func, updatedOptions, 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
|
+
}));
|
|
1106
|
+
}
|
|
1107
|
+
deleteRequest(options, params) {
|
|
1108
|
+
this.isPending.next(true);
|
|
1109
|
+
this.data.next(null);
|
|
1110
|
+
options = (options) ? options : ApiRequest.adapt();
|
|
1111
|
+
const updatedOptions = this.objectMergerService.mergeOptions(options, this.config.httpRequestOptions);
|
|
1112
|
+
const func = this.deleteRecordRequest;
|
|
1113
|
+
const requests = this.createRequest(func, updatedOptions);
|
|
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
|
+
}));
|
|
1121
|
+
}
|
|
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);
|
|
1126
|
+
const updatedOptions = {
|
|
1127
|
+
...mergedOptions,
|
|
1128
|
+
path: params ? [...options.path, ...params] : options.path,
|
|
1129
|
+
};
|
|
1130
|
+
const func = this.downloadFileRequest;
|
|
1131
|
+
const requests = this.createRequest(func, updatedOptions);
|
|
1132
|
+
return this.createObservable(updatedOptions, requests, func.name)
|
|
1133
|
+
.pipe(catchError((err) => {
|
|
1134
|
+
this.error.next(true);
|
|
1135
|
+
this.isPending.next(false);
|
|
1136
|
+
return this.handleError(err);
|
|
1137
|
+
}));
|
|
1138
|
+
}
|
|
1139
|
+
createObservable(options, request$, funcName) {
|
|
1140
|
+
const polling = options.polling ? (options.polling > 0 ? true : false) : false;
|
|
1141
|
+
const isPolling = polling &&
|
|
1142
|
+
!(funcName === 'deleteRecordRequest' || funcName === 'updateRecordRequest' || funcName === 'createRecordRequest')
|
|
1143
|
+
? true
|
|
1144
|
+
: false;
|
|
1145
|
+
this.polling$.next();
|
|
1146
|
+
const polling$ = (isPolling && options.polling) || 0 >= 3
|
|
1147
|
+
? request$.pipe(requestPolling((options.polling || 0) + 1, this.polling$, this.isPending), tap(() => this.countdown.next(0)), tap(() => {
|
|
1148
|
+
if (!options.polling)
|
|
1149
|
+
return;
|
|
1150
|
+
const count = options.polling ? options.polling : 0;
|
|
1151
|
+
// console.log('COUNT:', count);
|
|
1152
|
+
countdown(count)
|
|
1153
|
+
.pipe(map((x) => {
|
|
1154
|
+
// console.log('XX:', count, x);
|
|
1155
|
+
const pollingInSec = options.polling || 0;
|
|
1156
|
+
const percentageCompleted = ((pollingInSec - x) / pollingInSec) * 100;
|
|
1157
|
+
return Math.round(percentageCompleted);
|
|
1158
|
+
}))
|
|
1159
|
+
.subscribe((countDownValue) => {
|
|
1160
|
+
// console.log(this.countdown.value, countDownValue);
|
|
1161
|
+
this.countdown.next(countDownValue);
|
|
1162
|
+
});
|
|
1163
|
+
}))
|
|
1164
|
+
: request$.pipe(catchError((err) => {
|
|
1165
|
+
if (err instanceof HttpErrorResponse) {
|
|
1166
|
+
this.error.next(true);
|
|
1167
|
+
return this.handleError(err);
|
|
1168
|
+
}
|
|
1169
|
+
return throwError(() => err);
|
|
1170
|
+
}));
|
|
1171
|
+
return polling$.pipe(catchError((err, caught) => {
|
|
1172
|
+
if (err instanceof HttpErrorResponse) {
|
|
1173
|
+
this.error.next(true);
|
|
1174
|
+
if (isPolling)
|
|
1175
|
+
this.stopPolling();
|
|
1176
|
+
return this.handleError(err);
|
|
1177
|
+
}
|
|
1178
|
+
return throwError(() => err);
|
|
1179
|
+
}), options.retry?.times > 0
|
|
1180
|
+
? delayedRetry((options?.retry.delay || 3) * 1000, (options?.retry.times || 0) - 1)
|
|
1181
|
+
: (source) => source);
|
|
1182
|
+
}
|
|
1183
|
+
createRequest(func, options, data) {
|
|
1184
|
+
const dataItem = this.prepareRequestData(options, data, func.name);
|
|
1185
|
+
return func.bind(this)(dataItem.options, dataItem.data);
|
|
1186
|
+
}
|
|
1187
|
+
prepareRequestData(options, data, funcName) {
|
|
1188
|
+
if ((options.mapper && funcName === 'updateRecordRequest') || funcName === 'createRecordRequest') {
|
|
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
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
else {
|
|
1198
|
+
if (options?.adapter) {
|
|
1199
|
+
data = Array.isArray(data)
|
|
1200
|
+
? map((item) => options.adapter(item))
|
|
1201
|
+
: options.adapter(data);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return { options: options, data: data };
|
|
1205
|
+
}
|
|
1206
|
+
// MISC
|
|
1207
|
+
handleError(error) {
|
|
1208
|
+
return throwError(() => error);
|
|
1209
|
+
}
|
|
1210
|
+
handleErrorWithSnackBar(error) {
|
|
1211
|
+
const displayError = ToastDisplay.adapt({
|
|
1212
|
+
message: error.message || `${error.status} - ${error.statusText}`,
|
|
1213
|
+
action: 'OK',
|
|
1214
|
+
color: ToastColors.ERROR,
|
|
1215
|
+
icon: 'error',
|
|
1216
|
+
duration: 5 * 1000, //5 seconds
|
|
1217
|
+
});
|
|
1218
|
+
this.toastMessage.toastMessage(displayError);
|
|
1219
|
+
}
|
|
1220
|
+
stopPolling() {
|
|
1221
|
+
this.isPending.next(false);
|
|
1222
|
+
this.polling$.next();
|
|
1223
|
+
}
|
|
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 }); }
|
|
1225
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, providedIn: 'root' }); }
|
|
1226
|
+
}
|
|
1227
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerService, decorators: [{
|
|
1228
|
+
type: Injectable,
|
|
1229
|
+
args: [{
|
|
1230
|
+
providedIn: 'root',
|
|
1231
|
+
}]
|
|
1232
|
+
}], ctorParameters: function () { return [{ type: ConfigOptions, decorators: [{
|
|
1233
|
+
type: Optional
|
|
1234
|
+
}, {
|
|
1235
|
+
type: Inject,
|
|
1236
|
+
args: [CONFIG_SETTINGS_TOKEN]
|
|
1237
|
+
}] }]; } });
|
|
1238
|
+
|
|
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();
|
|
1261
|
+
}
|
|
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();
|
|
1429
|
+
}
|
|
1430
|
+
resetStore() {
|
|
1431
|
+
const newState = {
|
|
1432
|
+
localStores: [],
|
|
1433
|
+
sessionStores: [],
|
|
1434
|
+
settings: [],
|
|
1435
|
+
};
|
|
1436
|
+
this.updateState(newState);
|
|
1437
|
+
this.persistState(newState);
|
|
1438
|
+
}
|
|
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 || '');
|
|
1448
|
+
}
|
|
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;
|
|
1510
|
+
}
|
|
1511
|
+
ngOnDestroy() {
|
|
1512
|
+
this.persistence$.unsubscribe();
|
|
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' }); }
|
|
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
|
+
}] }]; } });
|
|
1524
|
+
|
|
1525
|
+
class RequestOptions {
|
|
1526
|
+
constructor(path = [], headers = {}) {
|
|
1527
|
+
this.path = path;
|
|
1528
|
+
this.headers = headers;
|
|
1529
|
+
}
|
|
1530
|
+
static adapt(item) {
|
|
1531
|
+
return new RequestOptions(item?.path, item?.headers);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
const API_OPTS = new InjectionToken('API_OPTS');
|
|
1536
|
+
const defaultState = {
|
|
1537
|
+
data: [],
|
|
1538
|
+
dataObject: null,
|
|
1539
|
+
};
|
|
1540
|
+
class HTTPManagerStateService extends ComponentStore {
|
|
1541
|
+
constructor(apiOptions = ApiRequest.adapt(), dataType, database) {
|
|
1542
|
+
super(defaultState);
|
|
1543
|
+
this.apiOptions = apiOptions;
|
|
1544
|
+
this.dataType = dataType;
|
|
1545
|
+
this.database = database;
|
|
1546
|
+
this.httpManagerService = inject(HTTPManagerService);
|
|
1547
|
+
this.error$ = this.httpManagerService.error$;
|
|
1548
|
+
this.isPending$ = this.httpManagerService.isPending$;
|
|
1549
|
+
// PAGINATION
|
|
1550
|
+
this.page = new BehaviorSubject(0);
|
|
1551
|
+
this.page$ = this.page.asObservable();
|
|
1552
|
+
this.totalPages = new BehaviorSubject(0);
|
|
1553
|
+
this.totalPages$ = this.totalPages.asObservable();
|
|
1554
|
+
this.percentage = new BehaviorSubject(0);
|
|
1555
|
+
this.percentage$ = this.percentage.asObservable();
|
|
1556
|
+
// ----------
|
|
1557
|
+
this.hasDatabase = false;
|
|
1558
|
+
this.streamedResponse = [];
|
|
1559
|
+
// --------------------------------------------------------------------------------------------------
|
|
1560
|
+
// SELECTORS
|
|
1561
|
+
this.data$ = this.select(({ data, dataObject }) => {
|
|
1562
|
+
const isArray = (this.dataType === DataType.ARRAY) ? true : false;
|
|
1563
|
+
return (isArray) ? data : dataObject;
|
|
1564
|
+
});
|
|
1565
|
+
this.selectRecord$ = (id) => this.select(this.data$, (data) => {
|
|
1566
|
+
if (this.dataType === DataType.ARRAY && Array.isArray(data)) {
|
|
1567
|
+
return data.find(item => item.id === id);
|
|
1568
|
+
}
|
|
1569
|
+
else {
|
|
1570
|
+
return data.id === id ? data : null;
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
// --------------------------------------------------------------------------------------------------
|
|
1574
|
+
// UPDATERS
|
|
1575
|
+
this.setData$ = this.updater((state, data) => {
|
|
1576
|
+
if (!data)
|
|
1577
|
+
return state;
|
|
1578
|
+
if (this.dataType === DataType.ARRAY) {
|
|
1579
|
+
const dataArray = Array.isArray(data) ? data : [data];
|
|
1580
|
+
const stateDataSample = (state.data.length > 0) ? Object.keys(state.data[0]) : [];
|
|
1581
|
+
const newDataSample = (dataArray.length > 0) ? Object.keys(dataArray[0]) : [];
|
|
1582
|
+
const isSame = (state.data.length === 0) ? false : stateDataSample.every((value, index) => value === newDataSample[index]);
|
|
1583
|
+
const updatedData = (!isSame && dataArray.length !== 0) ? this.updateArrayState([], dataArray) : this.updateArrayState(state.data, dataArray);
|
|
1584
|
+
return { ...state, data: updatedData, dataObject: null };
|
|
1585
|
+
}
|
|
1586
|
+
else {
|
|
1587
|
+
const dataObject = this.isEmpty(data) ? null : data;
|
|
1588
|
+
return { ...state, data: [], dataObject: dataObject };
|
|
1589
|
+
}
|
|
1590
|
+
});
|
|
1591
|
+
this.addData$ = this.updater((state, data) => {
|
|
1592
|
+
if (this.dataType === DataType.ARRAY) {
|
|
1593
|
+
const newState = [...state.data, data];
|
|
1594
|
+
return { ...state, ...{ data: newState } };
|
|
1595
|
+
}
|
|
1596
|
+
else {
|
|
1597
|
+
return { ...state, ...{ dataObject: data } };
|
|
1598
|
+
}
|
|
1599
|
+
});
|
|
1600
|
+
this.deleteData$ = this.updater((state, data) => {
|
|
1601
|
+
if (this.dataType === DataType.ARRAY) {
|
|
1602
|
+
const newState = state.data.filter(item => item.id !== data.id);
|
|
1603
|
+
return { ...state, ...{ data: newState } };
|
|
1604
|
+
}
|
|
1605
|
+
else {
|
|
1606
|
+
return { ...state, ...{ dataObject: null } };
|
|
1607
|
+
}
|
|
1608
|
+
});
|
|
1609
|
+
this.updateData$ = this.updater((state, data) => {
|
|
1610
|
+
if (this.dataType === DataType.ARRAY) {
|
|
1611
|
+
const objIndex = state.data.findIndex(item => item.id === data.id);
|
|
1612
|
+
if (objIndex > -1) {
|
|
1613
|
+
const newState = [...state.data];
|
|
1614
|
+
newState[objIndex] = data;
|
|
1615
|
+
return { ...state, ...{ data: newState } };
|
|
1616
|
+
}
|
|
1617
|
+
return state;
|
|
1618
|
+
}
|
|
1619
|
+
else {
|
|
1620
|
+
return { ...state, ...{ dataObject: data } };
|
|
1621
|
+
}
|
|
1622
|
+
});
|
|
1623
|
+
// --------------------------------------------------------------------------------------------------
|
|
1624
|
+
// EFFECTS
|
|
1625
|
+
this.clearRecords = this.effect(data => data.pipe(tap(() => {
|
|
1626
|
+
if (this.dataType === DataType.ARRAY) {
|
|
1627
|
+
this.setData$([]);
|
|
1628
|
+
}
|
|
1629
|
+
else {
|
|
1630
|
+
this.setData$({});
|
|
1631
|
+
}
|
|
1632
|
+
})));
|
|
1633
|
+
this.refreshData = this.effect(data => data.pipe(tap(() => {
|
|
1634
|
+
// this.apiService.flushDatabase(this.otherOptions.database?.table)
|
|
1635
|
+
this.fetchRecords();
|
|
1636
|
+
})));
|
|
1637
|
+
// --------------------------------------------------------------------------------------------------
|
|
1638
|
+
// CRUD OPERATIONS
|
|
1639
|
+
// FETCH RECORDS
|
|
1640
|
+
this.fetchRecords = (options) => this.effect(() => of(RequestOptions.adapt(options)).pipe(switchMap(() => {
|
|
1641
|
+
this.streamedResponse = [];
|
|
1642
|
+
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
1643
|
+
return this.httpManagerService.getRequest(requestOptions, options?.path)
|
|
1644
|
+
.pipe(tap((data) => {
|
|
1645
|
+
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
1646
|
+
this.setData$(data);
|
|
1647
|
+
}));
|
|
1648
|
+
})));
|
|
1649
|
+
// CREATE RECORD
|
|
1650
|
+
this.createRecord = (data, options) => this.effect(() => of(data).pipe(switchMap((data) => {
|
|
1651
|
+
this.streamedResponse = [];
|
|
1652
|
+
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
1653
|
+
return this.httpManagerService.postRequest(data, requestOptions, options?.path)
|
|
1654
|
+
.pipe(tap((data) => {
|
|
1655
|
+
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
1656
|
+
this.addData$(data);
|
|
1657
|
+
}));
|
|
1658
|
+
})));
|
|
1659
|
+
// UPDATE RECORD
|
|
1660
|
+
this.updateRecord = (data, options) => this.effect(() => of(data).pipe(concatMap((data) => {
|
|
1661
|
+
this.streamedResponse = [];
|
|
1662
|
+
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
1663
|
+
return this.httpManagerService.putRequest(data, requestOptions, options?.path)
|
|
1664
|
+
.pipe(tap((data) => {
|
|
1665
|
+
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
1666
|
+
this.updateData$(data);
|
|
1667
|
+
}));
|
|
1668
|
+
})));
|
|
1669
|
+
// DELETE RECORD
|
|
1670
|
+
this.deleteRecord = (options) => this.effect(() => of(options).pipe(concatMap((data) => {
|
|
1671
|
+
this.streamedResponse = [];
|
|
1672
|
+
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
1673
|
+
return this.httpManagerService.deleteRequest(requestOptions, options?.path)
|
|
1674
|
+
.pipe(tap((data) => {
|
|
1675
|
+
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
1676
|
+
this.deleteData$(data);
|
|
1677
|
+
}));
|
|
1678
|
+
})));
|
|
1679
|
+
// --------------------------------------------------------------------------------------------------
|
|
1680
|
+
// FETCH STREAM
|
|
1681
|
+
this.createStream = (data, options) => this.effect(() => of(data).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((data) => {
|
|
1682
|
+
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
1683
|
+
return this.httpManagerService.postRequest(data, requestOptions, options?.path)
|
|
1684
|
+
.pipe(tap((res) => {
|
|
1685
|
+
if (res.length > 0)
|
|
1686
|
+
this.setData$(res);
|
|
1687
|
+
this.streamedResponse = res;
|
|
1688
|
+
}), scan((acc, res) => {
|
|
1689
|
+
const previous = acc.current;
|
|
1690
|
+
const current = res;
|
|
1691
|
+
return { previous, current };
|
|
1692
|
+
}, { previous: null, current: null }), tap(({ previous, current }) => {
|
|
1693
|
+
if (previous && JSON.stringify(previous) === JSON.stringify(current)) {
|
|
1694
|
+
this.httpManagerService.isPending.next(false);
|
|
1695
|
+
this.setData$([]);
|
|
1696
|
+
}
|
|
1697
|
+
else {
|
|
1698
|
+
this.httpManagerService.isPending.next(true);
|
|
1699
|
+
}
|
|
1700
|
+
}));
|
|
1701
|
+
})));
|
|
1702
|
+
this.fetchStream = (options) => this.effect(() => of(options).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((options) => {
|
|
1703
|
+
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
1704
|
+
return this.httpManagerService.getRequest(requestOptions, options?.path)
|
|
1705
|
+
.pipe(tap((res) => {
|
|
1706
|
+
if (res.length > 0)
|
|
1707
|
+
this.setData$(res);
|
|
1708
|
+
this.streamedResponse = res;
|
|
1709
|
+
}), scan((acc, res) => {
|
|
1710
|
+
const previous = acc.current;
|
|
1711
|
+
const current = res;
|
|
1712
|
+
return { previous, current };
|
|
1713
|
+
}, { previous: null, current: null }), tap(({ previous, current }) => {
|
|
1714
|
+
if (previous && JSON.stringify(previous) === JSON.stringify(current)) {
|
|
1715
|
+
this.httpManagerService.isPending.next(false);
|
|
1716
|
+
this.setData$([]);
|
|
1717
|
+
}
|
|
1718
|
+
else {
|
|
1719
|
+
this.httpManagerService.isPending.next(true);
|
|
1720
|
+
}
|
|
1721
|
+
}));
|
|
1722
|
+
})));
|
|
1723
|
+
this.setApiRequestOptions(apiOptions, dataType, database);
|
|
1724
|
+
}
|
|
1725
|
+
setApiRequestOptions(apiOptions, dataType, database) {
|
|
1726
|
+
this.apiOptions = ApiRequest.adapt(apiOptions);
|
|
1727
|
+
this.dataType = (dataType) ? dataType : DataType.ARRAY;
|
|
1728
|
+
this.hasDatabase = this.database?.table === "" ? false : true;
|
|
1729
|
+
this.database = (this.hasDatabase) ? DatabaseStorage.adapt(database) : undefined;
|
|
1730
|
+
}
|
|
1731
|
+
get ApiRequestOptions() {
|
|
1732
|
+
return this.apiOptions;
|
|
1733
|
+
}
|
|
1734
|
+
initStorage() {
|
|
1735
|
+
// if(this.otherOptions.database) {
|
|
1736
|
+
// console.log('Has Database Option:', this.otherOptions.database.table)
|
|
1737
|
+
// const schema = (this.otherOptions.adapters?.incoming) ? Object.keys(this.otherOptions.adapters.incoming({})).join() : '++id'
|
|
1738
|
+
// this.apiService.initDB(this.otherOptions.database.expiresIn, this.otherOptions.database.table, schema)
|
|
1739
|
+
// }
|
|
1740
|
+
}
|
|
1741
|
+
initializeState(data) {
|
|
1742
|
+
this.setData$(data);
|
|
1743
|
+
}
|
|
1744
|
+
updateArrayState(currentData, newData) {
|
|
1745
|
+
const filterCurrentData = () => {
|
|
1746
|
+
const ids = this.streamedResponse.map((obj) => obj.id);
|
|
1747
|
+
return currentData.filter(obj => (obj.id) ? ids.includes(obj.id) : obj);
|
|
1748
|
+
};
|
|
1749
|
+
const filteredCurrentData = (this.httpManagerService.isPending.value) ? currentData : filterCurrentData();
|
|
1750
|
+
const updatedData = filteredCurrentData.map(item => {
|
|
1751
|
+
const newItem = newData.find(newItem => {
|
|
1752
|
+
const hasId = (newItem?.id && item?.id) ? true : false;
|
|
1753
|
+
return (hasId) ? newItem.id === item.id : JSON.stringify(newItem) === JSON.stringify(item);
|
|
1754
|
+
});
|
|
1755
|
+
return (newItem) ? { ...item, ...newItem } : item;
|
|
1756
|
+
});
|
|
1757
|
+
const addedData = newData.filter(newItem => {
|
|
1758
|
+
return !filteredCurrentData.some(item => {
|
|
1759
|
+
const hasId = (newItem?.id && item?.id) ? true : false;
|
|
1760
|
+
return (hasId) ? item.id === newItem.id : JSON.stringify(newItem) === JSON.stringify(item);
|
|
1761
|
+
});
|
|
1762
|
+
});
|
|
1763
|
+
return [...updatedData, ...addedData];
|
|
1764
|
+
}
|
|
1765
|
+
// --------------------------------------------------------------------------------------------------
|
|
1766
|
+
// MISC
|
|
1767
|
+
isEmpty(obj) {
|
|
1768
|
+
return Object.keys(obj).length === 0;
|
|
1769
|
+
}
|
|
1770
|
+
updateRequestOptions(headers) {
|
|
1771
|
+
const options = ApiRequest.adapt({ ...this.apiOptions });
|
|
1772
|
+
options.headers = (headers)
|
|
1773
|
+
? { ...options.headers, ...headers }
|
|
1774
|
+
: { ...options.headers };
|
|
1775
|
+
return options;
|
|
1776
|
+
}
|
|
1777
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService, deps: [{ token: API_OPTS }, { token: "dataType" }, { token: "database" }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1778
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService }); }
|
|
1779
|
+
}
|
|
1780
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HTTPManagerStateService, decorators: [{
|
|
1781
|
+
type: Injectable
|
|
1782
|
+
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
1783
|
+
type: Inject,
|
|
1784
|
+
args: [API_OPTS]
|
|
1785
|
+
}] }, { type: undefined, decorators: [{
|
|
1786
|
+
type: Inject,
|
|
1787
|
+
args: ["dataType"]
|
|
1788
|
+
}] }, { type: undefined, decorators: [{
|
|
1789
|
+
type: Inject,
|
|
1790
|
+
args: ["database"]
|
|
1791
|
+
}] }]; } });
|
|
1792
|
+
|
|
1793
|
+
// export * from "./database-manager-services/index";
|
|
1794
|
+
|
|
1795
|
+
class ErrorDisplaySettings {
|
|
1796
|
+
constructor(displayTime = 3 * 1000, position = 'top') {
|
|
1797
|
+
this.displayTime = displayTime;
|
|
1798
|
+
this.position = position;
|
|
1799
|
+
}
|
|
1800
|
+
static adapt(item) {
|
|
1801
|
+
return new ErrorDisplaySettings((item?.displayTime) ? item.displayTime * 1000 : 3 * 1000, item?.position);
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
class WithCredentialsInterceptor {
|
|
1806
|
+
intercept(req, next) {
|
|
1807
|
+
req = req.clone({ withCredentials: true });
|
|
1808
|
+
return next.handle(req);
|
|
1809
|
+
}
|
|
1810
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1811
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor }); }
|
|
1812
|
+
}
|
|
1813
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WithCredentialsInterceptor, decorators: [{
|
|
1814
|
+
type: Injectable
|
|
1815
|
+
}] });
|
|
1816
|
+
|
|
1817
|
+
class RequestHeadersInterceptor {
|
|
1818
|
+
get currentDate() {
|
|
1819
|
+
const date = new Date();
|
|
1820
|
+
const year = date.getFullYear();
|
|
1821
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
1822
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
1823
|
+
return `${year}-${month}-${day}`;
|
|
1824
|
+
}
|
|
1825
|
+
constructor(translate) {
|
|
1826
|
+
this.translate = translate;
|
|
1827
|
+
this.subscriptions = new Subscription();
|
|
1828
|
+
this.language = 'en-CA';
|
|
1829
|
+
this.subscriptions.add(this.translate.onLangChange
|
|
1830
|
+
.subscribe((params) => {
|
|
1831
|
+
this.language = `${params.lang}-CA`;
|
|
1832
|
+
}));
|
|
1833
|
+
}
|
|
1834
|
+
intercept(request, next) {
|
|
1835
|
+
request = request.clone({
|
|
1836
|
+
setHeaders: {
|
|
1837
|
+
'Content-Type': 'application/json',
|
|
1838
|
+
'Accept-Language': this.language || 'en-CA',
|
|
1839
|
+
'Current-Date': this.currentDate
|
|
1840
|
+
}
|
|
1841
|
+
});
|
|
1842
|
+
return next.handle(request);
|
|
1843
|
+
}
|
|
1844
|
+
ngOnDestroy() {
|
|
1845
|
+
this.subscriptions.unsubscribe();
|
|
1846
|
+
}
|
|
1847
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1848
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor }); }
|
|
1849
|
+
}
|
|
1850
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestHeadersInterceptor, decorators: [{
|
|
1851
|
+
type: Injectable
|
|
1852
|
+
}], ctorParameters: function () { return [{ type: i1.TranslateService }]; } });
|
|
1853
|
+
|
|
1854
|
+
class RequestErrorInterceptor {
|
|
1855
|
+
constructor() {
|
|
1856
|
+
this.toastMessage = inject(ToastMessageService);
|
|
1857
|
+
}
|
|
1858
|
+
intercept(req, next) {
|
|
1859
|
+
return next.handle(req).pipe(catchError$1((error) => {
|
|
1860
|
+
const displayError = ToastDisplay.adapt({
|
|
1861
|
+
message: 'This is a toast message. This is an Error!!',
|
|
1862
|
+
action: 'OK',
|
|
1863
|
+
color: ToastColors.SUCCESS,
|
|
1864
|
+
icon: 'info',
|
|
1865
|
+
duration: 5 * 1000, //5 seconds
|
|
1866
|
+
});
|
|
1867
|
+
if (error.status >= 400 && error.status < 500) {
|
|
1868
|
+
displayError.color = ToastColors.WARN;
|
|
1869
|
+
displayError.message = error.error || `${error.status}: ${error.statusText}`;
|
|
1870
|
+
console.error('Client Error:', {
|
|
1871
|
+
status: error.status,
|
|
1872
|
+
message: error.message,
|
|
1873
|
+
error: error.error,
|
|
1874
|
+
text: error.statusText,
|
|
1875
|
+
});
|
|
1876
|
+
this.toastMessage.toastMessage(displayError);
|
|
1877
|
+
}
|
|
1878
|
+
else if (error.status >= 500) {
|
|
1879
|
+
displayError.color = ToastColors.ERROR;
|
|
1880
|
+
displayError.message = error.error || `${error.status}: ${error.statusText}`;
|
|
1881
|
+
console.error('Server Error:', {
|
|
1882
|
+
status: error.status,
|
|
1883
|
+
message: error.message,
|
|
1884
|
+
error: error.error,
|
|
1885
|
+
text: error.statusText,
|
|
1886
|
+
});
|
|
1887
|
+
this.toastMessage.toastMessage(displayError);
|
|
1888
|
+
}
|
|
1889
|
+
return throwError(() => error);
|
|
1890
|
+
}));
|
|
1891
|
+
}
|
|
1892
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1893
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor }); }
|
|
1894
|
+
}
|
|
1895
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestErrorInterceptor, decorators: [{
|
|
1896
|
+
type: Injectable
|
|
1897
|
+
}] });
|
|
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 {<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n }\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 {<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n }\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
|
+
|
|
3053
|
+
/*
|
|
3054
|
+
* Public API Surface of http-request-manager
|
|
3055
|
+
*/
|
|
3056
|
+
|
|
3057
|
+
/**
|
|
3058
|
+
* Generated bundle index. Do not edit.
|
|
3059
|
+
*/
|
|
3060
|
+
|
|
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 };
|
|
3062
|
+
//# sourceMappingURL=http-request-manager.mjs.map
|