http-request-manager 18.0.13 → 18.2.0
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/esm2022/lib/http-request-manager.module.mjs +47 -7
- package/esm2022/lib/http-request-services-demo/http-request-services-demo.component.mjs +10 -6
- package/esm2022/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.mjs +184 -0
- package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.mjs +9 -0
- package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.mjs +12 -0
- package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.mjs +14 -0
- package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.mjs +336 -0
- package/esm2022/lib/services/local-storage-manager-service/index.mjs +3 -2
- package/esm2022/lib/services/local-storage-manager-service/local-storage-signals-manager.service.mjs +277 -0
- package/esm2022/lib/services/local-storage-manager-service/models/setting-options.model.mjs +6 -2
- package/esm2022/lib/services/request-manager-services/http-manager-signals.service.mjs +199 -0
- package/esm2022/lib/services/request-manager-services/index.mjs +2 -1
- package/esm2022/lib/services/request-manager-services/request-signals.service.mjs +170 -0
- package/esm2022/lib/services/request-manager-services/rxjs-operators/request-polling.mjs +26 -7
- package/esm2022/lib/services/utils/object-merger.service.mjs +26 -6
- package/fesm2022/http-request-manager.mjs +2053 -842
- package/fesm2022/http-request-manager.mjs.map +1 -1
- package/http-request-manager-18.2.0.tgz +0 -0
- package/lib/http-request-manager.module.d.ts +24 -22
- package/lib/http-request-services-demo/http-request-services-demo.component.d.ts +8 -0
- package/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.d.ts +55 -0
- package/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.d.ts +8 -0
- package/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.d.ts +14 -0
- package/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.d.ts +14 -0
- package/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.d.ts +106 -0
- package/lib/services/local-storage-manager-service/index.d.ts +2 -1
- package/lib/services/local-storage-manager-service/local-storage-signals-manager.service.d.ts +64 -0
- package/lib/services/request-manager-services/http-manager-signals.service.d.ts +38 -0
- package/lib/services/request-manager-services/index.d.ts +1 -0
- package/lib/services/request-manager-services/request-signals.service.d.ts +26 -0
- package/lib/services/request-manager-services/rxjs-operators/request-polling.d.ts +2 -7
- package/lib/services/utils/object-merger.service.d.ts +2 -0
- package/package.json +1 -1
- package/http-request-manager-18.0.13.tgz +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, APP_ID, Inject, InjectionToken, Injector, Optional, EventEmitter, Component, ViewEncapsulation, Input, Output, ViewChild, NgModule } from '@angular/core';
|
|
2
|
+
import { inject, Injectable, APP_ID, Inject, InjectionToken, Injector, Optional, signal, computed, effect, EventEmitter, Component, ViewEncapsulation, Input, Output, ViewChild, NgModule } from '@angular/core';
|
|
3
3
|
import { ComponentStore } from '@ngrx/component-store';
|
|
4
4
|
import { map, catchError, filter, delay, finalize, takeWhile, retry, startWith, tap, mergeMap, takeUntil, withLatestFrom, switchMap, concatMap, scan, distinctUntilChanged } from 'rxjs/operators';
|
|
5
5
|
import { HttpClient, HttpHeaders, HttpEventType, HttpHeaderResponse, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
@@ -59,7 +59,11 @@ class SettingOptions {
|
|
|
59
59
|
this.encrypted = encrypted;
|
|
60
60
|
}
|
|
61
61
|
static adapt(item) {
|
|
62
|
-
|
|
62
|
+
const storage = (typeof item?.storage !== 'undefined' && item?.storage !== null) ? Number(item.storage) : StorageType.GLOBAL;
|
|
63
|
+
const expires = (typeof item?.expires !== 'undefined' && item?.expires !== null) ? Number(item.expires) : 0;
|
|
64
|
+
const expiresIn = (typeof item?.expiresIn !== 'undefined' && item?.expiresIn !== null) ? item.expiresIn : '';
|
|
65
|
+
const encrypted = (typeof item?.encrypted !== 'undefined' && item?.encrypted !== null) ? Boolean(item.encrypted) : false;
|
|
66
|
+
return new SettingOptions(storage, expires, expiresIn, encrypted);
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
|
|
@@ -902,15 +906,34 @@ function delayedRetry(delayMs, maxRetry = DEFAULT_MAX_RETRIES) {
|
|
|
902
906
|
}));
|
|
903
907
|
}
|
|
904
908
|
|
|
905
|
-
/**
|
|
906
|
-
* @param pollInterval
|
|
907
|
-
* @param stopCondition$
|
|
908
|
-
* @param isPending$
|
|
909
|
-
*/
|
|
910
909
|
function requestPolling(pollInterval, stopCondition$, isPending$) {
|
|
911
910
|
return (source) => {
|
|
912
911
|
return interval(pollInterval * 1000)
|
|
913
|
-
.pipe(startWith(0), tap(() =>
|
|
912
|
+
.pipe(startWith(0), tap(() => {
|
|
913
|
+
try {
|
|
914
|
+
if (isPending$ && typeof isPending$.next === 'function') {
|
|
915
|
+
isPending$.next(true);
|
|
916
|
+
}
|
|
917
|
+
else if (isPending$ && typeof isPending$.set === 'function') {
|
|
918
|
+
isPending$.set(true);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
catch (e) {
|
|
922
|
+
// no-op if setting fails
|
|
923
|
+
}
|
|
924
|
+
}), mergeMap(() => source), tap(() => {
|
|
925
|
+
try {
|
|
926
|
+
if (isPending$ && typeof isPending$.next === 'function') {
|
|
927
|
+
isPending$.next(false);
|
|
928
|
+
}
|
|
929
|
+
else if (isPending$ && typeof isPending$.set === 'function') {
|
|
930
|
+
isPending$.set(false);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
catch (e) {
|
|
934
|
+
// no-op if setting fails
|
|
935
|
+
}
|
|
936
|
+
}), takeUntil(stopCondition$));
|
|
914
937
|
};
|
|
915
938
|
}
|
|
916
939
|
|
|
@@ -1174,151 +1197,520 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
1174
1197
|
args: [CONFIG_SETTINGS_TOKEN]
|
|
1175
1198
|
}] }] });
|
|
1176
1199
|
|
|
1177
|
-
class
|
|
1178
|
-
constructor(
|
|
1179
|
-
this.
|
|
1180
|
-
this.
|
|
1181
|
-
this.
|
|
1182
|
-
this.
|
|
1183
|
-
this.
|
|
1184
|
-
this.
|
|
1185
|
-
this.retry = retry;
|
|
1186
|
-
this.stream = stream;
|
|
1187
|
-
this.displayError = displayError;
|
|
1188
|
-
this.saveAs = saveAs;
|
|
1200
|
+
class RequestSignalsService {
|
|
1201
|
+
constructor() {
|
|
1202
|
+
this.http = inject(HttpClient);
|
|
1203
|
+
this.pathQueryService = inject(PathQueryService);
|
|
1204
|
+
this.headersService = inject(HeadersService);
|
|
1205
|
+
this.isPending = signal(false);
|
|
1206
|
+
this.progress = signal(0);
|
|
1207
|
+
this.isIdle = computed(() => !this.isPending());
|
|
1189
1208
|
}
|
|
1190
|
-
|
|
1191
|
-
const
|
|
1192
|
-
|
|
1209
|
+
getRecordRequest(options) {
|
|
1210
|
+
const urlPath = this.buildUrlPath(options);
|
|
1211
|
+
const headers = this.buildCombinedHeaders(options);
|
|
1212
|
+
this.isPending.set(true);
|
|
1213
|
+
return (options.stream)
|
|
1214
|
+
? this.http.get(urlPath, headers).pipe(requestStreaming(), this.handleFinalize())
|
|
1215
|
+
: this.http.get(urlPath, headers).pipe(this.request(options), this.handleFinalize());
|
|
1193
1216
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1217
|
+
createRecordRequest(options, data) {
|
|
1218
|
+
const urlPath = this.buildUrlPath(options);
|
|
1219
|
+
const headers = this.buildCombinedHeaders(options);
|
|
1220
|
+
this.isPending.set(true);
|
|
1221
|
+
return (options.stream)
|
|
1222
|
+
? this.http.post(urlPath, data, headers).pipe(requestStreaming(), this.handleFinalize())
|
|
1223
|
+
: this.http.post(urlPath, data, headers).pipe(this.request(options), this.handleFinalize());
|
|
1200
1224
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1225
|
+
updateRecordRequest(options, data) {
|
|
1226
|
+
const urlPath = this.buildUrlPath(options);
|
|
1227
|
+
const headers = this.buildHeaders(options);
|
|
1228
|
+
this.isPending.set(true);
|
|
1229
|
+
return this.http.put(urlPath, data, headers).pipe(this.request(options), this.handleFinalize());
|
|
1203
1230
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
this.
|
|
1209
|
-
if (!this.configOptions)
|
|
1210
|
-
this.configOptions = ConfigOptions.adapt();
|
|
1231
|
+
deleteRecordRequest(options) {
|
|
1232
|
+
const urlPath = this.buildUrlPath(options);
|
|
1233
|
+
const headers = this.buildHeaders(options);
|
|
1234
|
+
this.isPending.set(true);
|
|
1235
|
+
return this.http.delete(urlPath, headers).pipe(this.request(options), this.handleFinalize());
|
|
1211
1236
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
const mergedOptions = ApiRequest.adapt(options);
|
|
1215
|
-
mergedOptions.server = (options && options.server === '') ? configForRoot?.server || '' : options.server;
|
|
1216
|
-
mergedOptions.path = [...options.path || [], ...configForRoot?.path || []];
|
|
1217
|
-
mergedOptions.headers = { ...options.headers || {}, ...configForRoot?.headers || {} };
|
|
1218
|
-
mergedOptions.retry = (options && (options?.retry?.times !== 0 || options?.retry?.delay !== 3)) ? options.retry : configForRoot?.retry || { times: 0, delay: 3 };
|
|
1219
|
-
mergedOptions.polling = (options && options?.polling !== 0) ? options.polling : configForRoot?.polling || 0;
|
|
1220
|
-
mergedOptions.displayError = (options && options?.displayError) ? options.displayError : configForRoot?.displayError || false;
|
|
1221
|
-
mergedOptions.stream = (options && options?.stream) ? options.stream : configForRoot?.stream || false;
|
|
1222
|
-
return mergedOptions;
|
|
1237
|
+
buildUrlPath(options) {
|
|
1238
|
+
return this.pathQueryService.buildAPIPath(options.server, options.path);
|
|
1223
1239
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
const configForRootOptions = configForRoot.options || LocalStorageOptions.adapt().options;
|
|
1227
|
-
const mergedOptions = SettingOptions.adapt(options);
|
|
1228
|
-
mergedOptions.storage = (options && options.storage === 0) ? configForRootOptions?.storage || 0 : options.storage;
|
|
1229
|
-
mergedOptions.expires = (options && options.expires === 0) ? configForRootOptions?.expires || 0 : options.expires;
|
|
1230
|
-
mergedOptions.expiresIn = (options && options.expiresIn === '') ? configForRootOptions?.expiresIn || '' : options.expiresIn;
|
|
1231
|
-
mergedOptions.encrypted = (options && !options.encrypted) ? configForRootOptions?.encrypted || false : options.encrypted;
|
|
1232
|
-
return mergedOptions;
|
|
1240
|
+
buildHeaders(options) {
|
|
1241
|
+
return this.headersService.generateHeaders(options.headers);
|
|
1233
1242
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1243
|
+
buildCombinedHeaders(options) {
|
|
1244
|
+
const headers = this.headersService.generateHeaders(options.headers);
|
|
1245
|
+
return this.combineHeaders(headers, options.stream || false);
|
|
1246
|
+
}
|
|
1247
|
+
request(options) {
|
|
1248
|
+
return (source$) => {
|
|
1249
|
+
return source$.pipe(map(data => {
|
|
1250
|
+
if (options?.adapter) {
|
|
1251
|
+
return Array.isArray(data)
|
|
1252
|
+
? data.map((item) => options.adapter(item))
|
|
1253
|
+
: options.adapter(data);
|
|
1254
|
+
}
|
|
1255
|
+
return data;
|
|
1256
|
+
}));
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
downloadFileRequest(options) {
|
|
1260
|
+
this.isPending.set(true);
|
|
1261
|
+
const urlPath = this.buildUrlPath(options);
|
|
1262
|
+
return this.http.get(urlPath, { responseType: 'blob', observe: 'events', reportProgress: true })
|
|
1263
|
+
.pipe(map((event) => {
|
|
1264
|
+
this.isPending.set(true);
|
|
1265
|
+
if (event instanceof HttpHeaderResponse) {
|
|
1266
|
+
if (event.status !== 200) {
|
|
1267
|
+
this.isPending.set(false);
|
|
1268
|
+
throw new Error('Download failed');
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
switch (event.type) {
|
|
1272
|
+
case HttpEventType.DownloadProgress:
|
|
1273
|
+
const status = (event.total) ? Math.round(event.loaded / (event.total || 1) * 100) : 100;
|
|
1274
|
+
this.progress.set(status);
|
|
1275
|
+
return status;
|
|
1276
|
+
case HttpEventType.Response:
|
|
1277
|
+
try {
|
|
1278
|
+
const fileNamePath = (options?.saveAs) ? options.saveAs : (options.path) ? options.path[options.path.length - 1] : [];
|
|
1279
|
+
const header_content = event.headers.get('Content-Disposition') || '';
|
|
1280
|
+
const file = (header_content) ? header_content.split('=')[1].substring(0, header_content.split('=')[1].length) : '';
|
|
1281
|
+
const fileName = (fileNamePath !== '') ? fileNamePath : file;
|
|
1282
|
+
if (fileName === '') {
|
|
1283
|
+
this.isPending.set(false);
|
|
1284
|
+
throw new Error('Save File: (file name and extension) not found in Headers or Path');
|
|
1285
|
+
}
|
|
1286
|
+
this.downloadFile(fileName, event.body);
|
|
1287
|
+
this.isPending.set(false);
|
|
1288
|
+
return 100;
|
|
1289
|
+
}
|
|
1290
|
+
catch (error) {
|
|
1291
|
+
throw new Error('Download failed');
|
|
1292
|
+
}
|
|
1293
|
+
default:
|
|
1294
|
+
this.isPending.set(false);
|
|
1295
|
+
return 0;
|
|
1296
|
+
}
|
|
1297
|
+
}), catchError(err => {
|
|
1298
|
+
return throwError(() => err);
|
|
1299
|
+
}));
|
|
1300
|
+
}
|
|
1301
|
+
handleFinalize() {
|
|
1302
|
+
return finalize(() => this.isPending.set(false));
|
|
1303
|
+
}
|
|
1304
|
+
downloadFile(file, fileData) {
|
|
1305
|
+
const navigatorAny = window.navigator;
|
|
1306
|
+
const extension = file.split('.')[1]?.toLowerCase();
|
|
1307
|
+
const newBlob = new Blob([fileData], { type: this.createFileType(extension) });
|
|
1308
|
+
if (navigatorAny.msSaveOrOpenBlob) {
|
|
1309
|
+
navigatorAny.msSaveOrOpenBlob(newBlob, file);
|
|
1310
|
+
}
|
|
1311
|
+
else {
|
|
1312
|
+
const link = document.createElement('a');
|
|
1313
|
+
const url = window.URL.createObjectURL(newBlob);
|
|
1314
|
+
link.href = url;
|
|
1315
|
+
link.download = file;
|
|
1316
|
+
link.click();
|
|
1317
|
+
window.URL.revokeObjectURL(url);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
createFileType(ext) {
|
|
1321
|
+
let fileType = "";
|
|
1322
|
+
if (ext === 'pdf' || ext === 'csv')
|
|
1323
|
+
fileType = `application/${ext}`;
|
|
1324
|
+
else if (ext === 'jpeg' || ext === 'jpg' || ext === 'png')
|
|
1325
|
+
fileType = `image/${ext}`;
|
|
1326
|
+
else if (ext === 'txt')
|
|
1327
|
+
fileType = 'text/plain';
|
|
1328
|
+
else if (ext === 'ppt' || ext === 'pot' || ext === 'pps' || ext === 'ppa')
|
|
1329
|
+
fileType = 'application/vnd.ms-powerpoint';
|
|
1330
|
+
else if (ext === 'pptx')
|
|
1331
|
+
fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
|
1332
|
+
else if (ext === 'doc' || ext === 'dot')
|
|
1333
|
+
fileType = 'application/msword';
|
|
1334
|
+
else if (ext === 'docx')
|
|
1335
|
+
fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
1336
|
+
else if (ext === 'xls' || ext === 'xlt' || ext === 'xla')
|
|
1337
|
+
fileType = 'application/vnd.ms-excel';
|
|
1338
|
+
else if (ext === 'xlsx')
|
|
1339
|
+
fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
1340
|
+
return fileType;
|
|
1341
|
+
}
|
|
1342
|
+
combineHeaders(headers, isStreaming) {
|
|
1343
|
+
return (isStreaming)
|
|
1344
|
+
? {
|
|
1345
|
+
...headers,
|
|
1346
|
+
observe: 'events',
|
|
1347
|
+
responseType: 'text',
|
|
1348
|
+
reportProgress: true,
|
|
1349
|
+
Accept: 'text/event-stream'
|
|
1350
|
+
}
|
|
1351
|
+
: headers;
|
|
1352
|
+
}
|
|
1353
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestSignalsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1354
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestSignalsService, providedIn: 'root' }); }
|
|
1236
1355
|
}
|
|
1237
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
1356
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestSignalsService, decorators: [{
|
|
1238
1357
|
type: Injectable,
|
|
1239
1358
|
args: [{
|
|
1240
1359
|
providedIn: 'root'
|
|
1241
1360
|
}]
|
|
1242
|
-
}]
|
|
1243
|
-
type: Inject,
|
|
1244
|
-
args: [CONFIG_SETTINGS_TOKEN]
|
|
1245
|
-
}, {
|
|
1246
|
-
type: Optional
|
|
1247
|
-
}] }] });
|
|
1361
|
+
}] });
|
|
1248
1362
|
|
|
1249
|
-
|
|
1250
|
-
localStores: [],
|
|
1251
|
-
sessionStores: [],
|
|
1252
|
-
settings: [],
|
|
1253
|
-
};
|
|
1254
|
-
class LocalStorageManagerService extends ComponentStore {
|
|
1255
|
-
startTimer() {
|
|
1256
|
-
const timer$ = interval(1000 * 3).pipe(withLatestFrom(this.data$), map(([_, state]) => state), tap((state) => {
|
|
1257
|
-
const expired = this.expired(state) ? this.expired(state) : [];
|
|
1258
|
-
if (expired.length > 0) {
|
|
1259
|
-
const ids = expired.map((item) => item.id);
|
|
1260
|
-
const updatedState = {
|
|
1261
|
-
...state,
|
|
1262
|
-
localStores: state.localStores.filter((item) => !ids.includes(item.id)),
|
|
1263
|
-
sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
|
|
1264
|
-
settings: state.settings.filter((item) => !ids.includes(item.id)),
|
|
1265
|
-
};
|
|
1266
|
-
this.persistState(updatedState);
|
|
1267
|
-
this.updateState(updatedState);
|
|
1268
|
-
}
|
|
1269
|
-
}));
|
|
1270
|
-
timer$.subscribe();
|
|
1271
|
-
}
|
|
1363
|
+
class HTTPManagerSignalsService extends RequestSignalsService {
|
|
1272
1364
|
constructor(configOptions) {
|
|
1273
|
-
super(
|
|
1365
|
+
super();
|
|
1274
1366
|
this.configOptions = configOptions;
|
|
1275
|
-
this.
|
|
1276
|
-
this.
|
|
1277
|
-
this.defaultOptions = SettingOptions.adapt();
|
|
1278
|
-
this.stateRetrieved = false;
|
|
1279
|
-
this.encrypted = false;
|
|
1280
|
-
this.app = inject(AppService);
|
|
1281
|
-
this.utils = inject(UtilsService);
|
|
1367
|
+
this.toastMessage = inject(ToastMessageDisplayService);
|
|
1368
|
+
this.ng_injector = inject(Injector);
|
|
1282
1369
|
this.objectMergerService = inject(ObjectMergerService);
|
|
1283
|
-
|
|
1284
|
-
this.
|
|
1285
|
-
|
|
1286
|
-
this.data
|
|
1287
|
-
this.
|
|
1288
|
-
this.
|
|
1289
|
-
this.
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
.
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
this.
|
|
1370
|
+
// ✅ Replaced BehaviorSubjects with Angular signals
|
|
1371
|
+
this.countdown = signal(0);
|
|
1372
|
+
this.error = signal(false);
|
|
1373
|
+
this.data = signal(null);
|
|
1374
|
+
this.polling$ = new Subject();
|
|
1375
|
+
this.config = ApiRequest.adapt();
|
|
1376
|
+
this.config = configOptions
|
|
1377
|
+
? ApiRequest.adapt(configOptions.httpRequestOptions)
|
|
1378
|
+
: this.config;
|
|
1379
|
+
}
|
|
1380
|
+
// REQUESTS
|
|
1381
|
+
getRequest(options, params) {
|
|
1382
|
+
this.isPending.set(true);
|
|
1383
|
+
this.data.set(null);
|
|
1384
|
+
const updatedOptions = this.defineReqOptions(options, params);
|
|
1385
|
+
const func = this.getRecordRequest;
|
|
1386
|
+
const requests = this.createRequest(func, updatedOptions);
|
|
1387
|
+
return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.set(data)), finalize(() => this.isPending.set(false)), catchError((err) => {
|
|
1388
|
+
if (updatedOptions.displayError)
|
|
1389
|
+
this.handleErrorWithSnackBar(err);
|
|
1390
|
+
this.isPending.set(false);
|
|
1391
|
+
return this.handleError(err);
|
|
1392
|
+
}));
|
|
1393
|
+
}
|
|
1394
|
+
postRequest(data, options, params) {
|
|
1395
|
+
this.isPending.set(true);
|
|
1396
|
+
this.data.set(null);
|
|
1397
|
+
const updatedOptions = this.defineReqOptions(options, params);
|
|
1398
|
+
const func = this.createRecordRequest;
|
|
1399
|
+
const requests = this.createRequest(func, updatedOptions, data);
|
|
1400
|
+
return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.set(data)), finalize(() => this.isPending.set(false)), catchError((err) => {
|
|
1401
|
+
if (updatedOptions.displayError)
|
|
1402
|
+
this.handleErrorWithSnackBar(err);
|
|
1403
|
+
this.isPending.set(false);
|
|
1404
|
+
return this.handleError(err);
|
|
1405
|
+
}));
|
|
1406
|
+
}
|
|
1407
|
+
putRequest(data, options, params) {
|
|
1408
|
+
this.isPending.set(true);
|
|
1409
|
+
this.data.set(null);
|
|
1410
|
+
const updatedOptions = this.defineReqOptions(options, params);
|
|
1411
|
+
const func = this.updateRecordRequest;
|
|
1412
|
+
const requests = this.createRequest(func, updatedOptions, data);
|
|
1413
|
+
return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.set(data)), finalize(() => this.isPending.set(false)), catchError((err) => {
|
|
1414
|
+
if (updatedOptions.displayError)
|
|
1415
|
+
this.handleErrorWithSnackBar(err);
|
|
1416
|
+
this.isPending.set(false);
|
|
1417
|
+
return this.handleError(err);
|
|
1418
|
+
}));
|
|
1419
|
+
}
|
|
1420
|
+
deleteRequest(options, params) {
|
|
1421
|
+
this.isPending.set(true);
|
|
1422
|
+
this.data.set(null);
|
|
1423
|
+
const updatedOptions = this.defineReqOptions(options, params);
|
|
1424
|
+
const func = this.deleteRecordRequest;
|
|
1425
|
+
const requests = this.createRequest(func, updatedOptions);
|
|
1426
|
+
return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => this.data.set(data)), finalize(() => this.isPending.set(false)), catchError((err) => {
|
|
1427
|
+
if (updatedOptions.displayError)
|
|
1428
|
+
this.handleErrorWithSnackBar(err);
|
|
1429
|
+
this.isPending.set(false);
|
|
1430
|
+
return this.handleError(err);
|
|
1431
|
+
}));
|
|
1432
|
+
}
|
|
1433
|
+
downloadRequest(options, params, saveAs) {
|
|
1434
|
+
this.isPending.set(true);
|
|
1435
|
+
const updatedOptions = this.defineReqOptions(options, params);
|
|
1436
|
+
const func = this.downloadFileRequest;
|
|
1437
|
+
const requests = this.createRequest(func, updatedOptions);
|
|
1438
|
+
return this.createObservable(updatedOptions, requests, func.name).pipe(catchError((err) => {
|
|
1439
|
+
this.error.set(true);
|
|
1440
|
+
this.isPending.set(false);
|
|
1441
|
+
return this.handleError(err);
|
|
1442
|
+
}));
|
|
1443
|
+
}
|
|
1444
|
+
// --- private helpers ---
|
|
1445
|
+
createObservable(options, request$, funcName) {
|
|
1446
|
+
const polling = options.polling ? (options.polling > 0 ? true : false) : false;
|
|
1447
|
+
const isPolling = polling &&
|
|
1448
|
+
!(funcName === 'deleteRecordRequest' ||
|
|
1449
|
+
funcName === 'updateRecordRequest' ||
|
|
1450
|
+
funcName === 'createRecordRequest');
|
|
1451
|
+
this.polling$.next();
|
|
1452
|
+
const polling$ = (isPolling && options.polling) || 0 >= 3
|
|
1453
|
+
? request$.pipe(requestPolling((options.polling || 0) + 1, this.polling$, this.isPending), tap(() => this.countdown.set(0)), tap(() => {
|
|
1454
|
+
if (!options.polling)
|
|
1455
|
+
return;
|
|
1456
|
+
const count = options.polling ? options.polling : 0;
|
|
1457
|
+
countdown(count)
|
|
1458
|
+
.pipe(map((x) => {
|
|
1459
|
+
const pollingInSec = options.polling || 0;
|
|
1460
|
+
const percentageCompleted = ((pollingInSec - x) / pollingInSec) * 100;
|
|
1461
|
+
return Math.round(percentageCompleted);
|
|
1462
|
+
}))
|
|
1463
|
+
.subscribe((countDownValue) => {
|
|
1464
|
+
this.countdown.set(countDownValue);
|
|
1465
|
+
});
|
|
1466
|
+
}))
|
|
1467
|
+
: request$.pipe(catchError((err) => {
|
|
1468
|
+
if (err instanceof HttpErrorResponse) {
|
|
1469
|
+
this.error.set(true);
|
|
1470
|
+
return this.handleError(err);
|
|
1471
|
+
}
|
|
1472
|
+
return throwError(() => err);
|
|
1473
|
+
}));
|
|
1474
|
+
return polling$.pipe(catchError((err, caught) => {
|
|
1475
|
+
if (err instanceof HttpErrorResponse) {
|
|
1476
|
+
this.error.set(true);
|
|
1477
|
+
if (isPolling)
|
|
1478
|
+
this.stopPolling();
|
|
1479
|
+
return this.handleError(err);
|
|
1480
|
+
}
|
|
1481
|
+
return throwError(() => err);
|
|
1482
|
+
}), options?.retry && options.retry.times > 0
|
|
1483
|
+
? delayedRetry((options.retry.delay || 3) * 1000, (options.retry.times || 0) - 1)
|
|
1484
|
+
: (source) => source);
|
|
1485
|
+
}
|
|
1486
|
+
createRequest(func, options, data) {
|
|
1487
|
+
const dataItem = this.prepareRequestData(options, data, func.name);
|
|
1488
|
+
return func.bind(this)(dataItem.options, dataItem.data);
|
|
1489
|
+
}
|
|
1490
|
+
prepareRequestData(options, data, funcName) {
|
|
1491
|
+
if ((options.mapper && funcName === 'updateRecordRequest') || funcName === 'createRecordRequest') {
|
|
1492
|
+
if (options?.mapper) {
|
|
1493
|
+
data = options.mapper
|
|
1494
|
+
? Array.isArray(data)
|
|
1495
|
+
? map((item) => options.mapper(item))
|
|
1496
|
+
: options.mapper(data)
|
|
1497
|
+
: data;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
else {
|
|
1501
|
+
if (options?.adapter) {
|
|
1502
|
+
data = Array.isArray(data)
|
|
1503
|
+
? map((item) => options.adapter(item))
|
|
1504
|
+
: options.adapter(data);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
return { options: options, data: data };
|
|
1508
|
+
}
|
|
1509
|
+
handleError(error) {
|
|
1510
|
+
this.error.set(error.message || `${error.status} - ${error.statusText}`);
|
|
1511
|
+
return throwError(() => error);
|
|
1512
|
+
}
|
|
1513
|
+
handleErrorWithSnackBar(error) {
|
|
1514
|
+
const displayError = ToastDisplay.adapt({
|
|
1515
|
+
message: error.message || `${error.status} - ${error.statusText}`,
|
|
1516
|
+
action: 'OK',
|
|
1517
|
+
color: ToastColors.ERROR,
|
|
1518
|
+
icon: 'error',
|
|
1519
|
+
duration: 5 * 1000,
|
|
1520
|
+
});
|
|
1521
|
+
this.toastMessage.toastMessage(displayError);
|
|
1522
|
+
}
|
|
1523
|
+
stopPolling() {
|
|
1524
|
+
this.isPending.set(false);
|
|
1525
|
+
this.polling$.next();
|
|
1526
|
+
}
|
|
1527
|
+
defineReqOptions(options, params) {
|
|
1528
|
+
const req = ApiRequest.adapt(options);
|
|
1529
|
+
if (req?.path)
|
|
1530
|
+
req.path = params ? [...req.path, ...params] : req.path;
|
|
1531
|
+
const optionsReq = req ? req : ApiRequest.adapt();
|
|
1532
|
+
const updatedOptions = this.objectMergerService.mergeOptions(optionsReq);
|
|
1533
|
+
return updatedOptions;
|
|
1534
|
+
}
|
|
1535
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerSignalsService, deps: [{ token: CONFIG_SETTINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1536
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerSignalsService, providedIn: 'root' }); }
|
|
1537
|
+
}
|
|
1538
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerSignalsService, decorators: [{
|
|
1539
|
+
type: Injectable,
|
|
1540
|
+
args: [{
|
|
1541
|
+
providedIn: 'root',
|
|
1542
|
+
}]
|
|
1543
|
+
}], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
|
|
1544
|
+
type: Optional
|
|
1545
|
+
}, {
|
|
1546
|
+
type: Inject,
|
|
1547
|
+
args: [CONFIG_SETTINGS_TOKEN]
|
|
1548
|
+
}] }] });
|
|
1549
|
+
|
|
1550
|
+
class ApiRequest {
|
|
1551
|
+
constructor(server = '', path, headers, adapter, mapper, polling, retry, stream, displayError, saveAs) {
|
|
1552
|
+
this.server = server;
|
|
1553
|
+
this.path = path;
|
|
1554
|
+
this.headers = headers;
|
|
1555
|
+
this.adapter = adapter;
|
|
1556
|
+
this.mapper = mapper;
|
|
1557
|
+
this.polling = polling;
|
|
1558
|
+
this.retry = retry;
|
|
1559
|
+
this.stream = stream;
|
|
1560
|
+
this.displayError = displayError;
|
|
1561
|
+
this.saveAs = saveAs;
|
|
1562
|
+
}
|
|
1563
|
+
static adapt(item) {
|
|
1564
|
+
const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
|
|
1565
|
+
return new ApiRequest(server, (item?.path) ? item.path : [], (item?.headers) ? item.headers : {}, item?.adapter, item?.mapper, item?.polling ? Math.floor(item.polling) : 0, item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt(), (item?.stream) ? item.stream : false, (item?.displayError) ? item.displayError : false, item?.saveAs);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
class RequestOptions {
|
|
1570
|
+
constructor(path = [], headers = {}) {
|
|
1571
|
+
this.path = path;
|
|
1572
|
+
this.headers = headers;
|
|
1573
|
+
}
|
|
1574
|
+
static adapt(item) {
|
|
1575
|
+
return new RequestOptions(item?.path, item?.headers);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
class ObjectMergerService {
|
|
1580
|
+
constructor(configOptions) {
|
|
1581
|
+
this.configOptions = configOptions;
|
|
1582
|
+
this.utils = inject(UtilsService);
|
|
1583
|
+
if (!this.configOptions)
|
|
1584
|
+
this.configOptions = ConfigOptions.adapt();
|
|
1585
|
+
}
|
|
1586
|
+
mergeOptions(options = ApiRequest.adapt()) {
|
|
1587
|
+
const configForRoot = (this.configOptions?.httpRequestOptions) ? this.configOptions.httpRequestOptions : ConfigHTTPOptions.adapt();
|
|
1588
|
+
const mergedOptions = ApiRequest.adapt(options);
|
|
1589
|
+
mergedOptions.server = (options && options.server === '') ? configForRoot?.server || '' : options.server;
|
|
1590
|
+
mergedOptions.path = [...options.path || [], ...configForRoot?.path || []];
|
|
1591
|
+
mergedOptions.headers = { ...options.headers || {}, ...configForRoot?.headers || {} };
|
|
1592
|
+
mergedOptions.retry = (options && (options?.retry?.times !== 0 || options?.retry?.delay !== 3)) ? options.retry : configForRoot?.retry || { times: 0, delay: 3 };
|
|
1593
|
+
mergedOptions.polling = (options && options?.polling !== 0) ? options.polling : configForRoot?.polling || 0;
|
|
1594
|
+
mergedOptions.displayError = (options && options?.displayError) ? options.displayError : configForRoot?.displayError || false;
|
|
1595
|
+
mergedOptions.stream = (options && options?.stream) ? options.stream : configForRoot?.stream || false;
|
|
1596
|
+
return mergedOptions;
|
|
1597
|
+
}
|
|
1598
|
+
mergeStorageOptions(options = SettingOptions.adapt()) {
|
|
1599
|
+
const configForRoot = (this.configOptions?.LocalStorageOptions) ? this.configOptions.LocalStorageOptions : LocalStorageOptions.adapt();
|
|
1600
|
+
const configForRootOptions = configForRoot.options || LocalStorageOptions.adapt().options;
|
|
1601
|
+
const mergedOptions = SettingOptions.adapt(options);
|
|
1602
|
+
// storage type
|
|
1603
|
+
mergedOptions.storage = (options && (typeof options.storage !== 'undefined')) ? options.storage : (configForRootOptions?.storage ?? 0);
|
|
1604
|
+
// expires: prefer explicit numeric expires; if not provided, compute from expiresIn string; otherwise use config default
|
|
1605
|
+
// if an explicit, non-zero numeric expires is provided, use it
|
|
1606
|
+
if (options && (typeof options.expires !== 'undefined') && options.expires !== null && Number(options.expires) > 0) {
|
|
1607
|
+
mergedOptions.expires = Number(options.expires);
|
|
1608
|
+
}
|
|
1609
|
+
else if (options && options.expiresIn) {
|
|
1610
|
+
// compute numeric epoch from expiresIn string using UtilsService if available
|
|
1611
|
+
try {
|
|
1612
|
+
mergedOptions.expires = this.utils ? this.utils.expires(options.expiresIn) : 0;
|
|
1613
|
+
}
|
|
1614
|
+
catch {
|
|
1615
|
+
mergedOptions.expires = 0;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
else {
|
|
1619
|
+
mergedOptions.expires = configForRootOptions?.expires ?? 0;
|
|
1620
|
+
}
|
|
1621
|
+
// keep expiresIn string if explicitly provided, otherwise use config default
|
|
1622
|
+
mergedOptions.expiresIn = (options && (typeof options.expiresIn !== 'undefined')) ? options.expiresIn : (configForRootOptions?.expiresIn || '');
|
|
1623
|
+
mergedOptions.encrypted = (options && (typeof options.encrypted !== 'undefined')) ? options.encrypted : (configForRootOptions?.encrypted || false);
|
|
1624
|
+
return mergedOptions;
|
|
1625
|
+
}
|
|
1626
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectMergerService, deps: [{ token: CONFIG_SETTINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1627
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectMergerService, providedIn: 'root' }); }
|
|
1628
|
+
}
|
|
1629
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectMergerService, decorators: [{
|
|
1630
|
+
type: Injectable,
|
|
1631
|
+
args: [{
|
|
1632
|
+
providedIn: 'root'
|
|
1633
|
+
}]
|
|
1634
|
+
}], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
|
|
1635
|
+
type: Inject,
|
|
1636
|
+
args: [CONFIG_SETTINGS_TOKEN]
|
|
1637
|
+
}, {
|
|
1638
|
+
type: Optional
|
|
1639
|
+
}] }] });
|
|
1640
|
+
|
|
1641
|
+
const storage = {
|
|
1642
|
+
localStores: [],
|
|
1643
|
+
sessionStores: [],
|
|
1644
|
+
settings: [],
|
|
1645
|
+
};
|
|
1646
|
+
class LocalStorageManagerService extends ComponentStore {
|
|
1647
|
+
startTimer() {
|
|
1648
|
+
const timer$ = interval(1000 * 3).pipe(withLatestFrom(this.data$), map(([_, state]) => state), tap((state) => {
|
|
1649
|
+
const expired = this.expired(state) ? this.expired(state) : [];
|
|
1650
|
+
if (expired.length > 0) {
|
|
1651
|
+
const ids = expired.map((item) => item.id);
|
|
1652
|
+
const updatedState = {
|
|
1653
|
+
...state,
|
|
1654
|
+
localStores: state.localStores.filter((item) => !ids.includes(item.id)),
|
|
1655
|
+
sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
|
|
1656
|
+
settings: state.settings.filter((item) => !ids.includes(item.id)),
|
|
1657
|
+
};
|
|
1658
|
+
this.persistState(updatedState);
|
|
1659
|
+
this.updateState(updatedState);
|
|
1660
|
+
}
|
|
1661
|
+
}));
|
|
1662
|
+
timer$.subscribe();
|
|
1663
|
+
}
|
|
1664
|
+
constructor(configOptions) {
|
|
1665
|
+
super(storage);
|
|
1666
|
+
this.configOptions = configOptions;
|
|
1667
|
+
this.storageName = 'storage';
|
|
1668
|
+
this.storageSettingsName = 'global-storage';
|
|
1669
|
+
this.defaultOptions = SettingOptions.adapt();
|
|
1670
|
+
this.stateRetrieved = false;
|
|
1671
|
+
this.encrypted = false;
|
|
1672
|
+
this.app = inject(AppService);
|
|
1673
|
+
this.utils = inject(UtilsService);
|
|
1674
|
+
this.objectMergerService = inject(ObjectMergerService);
|
|
1675
|
+
this.encryption = inject(SymmetricalEncryptionService);
|
|
1676
|
+
this.encryptionTest = inject(EncryptionTestService);
|
|
1677
|
+
// SELECTORS
|
|
1678
|
+
this.data$ = this.select((state) => state);
|
|
1679
|
+
this.stores$ = this.select((state) => state.settings);
|
|
1680
|
+
this.storeExists$ = (store) => this.select(this.data$, (data) => data.settings.find(item => item.name === store) ? true : false);
|
|
1681
|
+
this.store$ = (store) => this.select(this.data$, (data) => {
|
|
1682
|
+
const foundStore = data.settings.find(item => item.name === store);
|
|
1683
|
+
if (foundStore) {
|
|
1684
|
+
const options = SettingOptions.adapt(foundStore.options);
|
|
1685
|
+
const found = foundStore.options?.storage === StorageType.GLOBAL
|
|
1686
|
+
? data.localStores.find(item => item.id === foundStore.id)
|
|
1687
|
+
: data.sessionStores.find(item => item.id === foundStore.id);
|
|
1688
|
+
if (!found) {
|
|
1689
|
+
this.deleteStore({ name: store });
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
if (!this.app?.appID) {
|
|
1693
|
+
console.warn('No App ID found - AppId not Provided');
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
const storageData = (options.encrypted) ? this.encryption.decrypt(found.data, this.app.appID) : found.data;
|
|
1697
|
+
return (this.isString(storageData)) ? JSON.parse(storageData) : storageData;
|
|
1698
|
+
}
|
|
1699
|
+
else {
|
|
1700
|
+
return null;
|
|
1701
|
+
}
|
|
1702
|
+
});
|
|
1703
|
+
this.settings$ = this.select(state => (state) ? state.settings : storage.settings);
|
|
1704
|
+
this.setting$ = (store) => this.select(this.data$, (state) => {
|
|
1705
|
+
const foundSetting = state.settings.find(item => item.name === store);
|
|
1706
|
+
return (foundSetting) ? foundSetting : null;
|
|
1707
|
+
});
|
|
1708
|
+
this.persistence$ = this.data$
|
|
1709
|
+
.subscribe(data => {
|
|
1710
|
+
if (this.stateRetrieved)
|
|
1711
|
+
this.persistState(data);
|
|
1712
|
+
});
|
|
1713
|
+
this.updateState = this.updater((state, updatedState) => ({
|
|
1322
1714
|
...updatedState,
|
|
1323
1715
|
}));
|
|
1324
1716
|
this.setStore = this.updater((state, store) => {
|
|
@@ -1457,54 +1849,308 @@ class LocalStorageManagerService extends ComponentStore {
|
|
|
1457
1849
|
localStorage.setItem(this.storageSettingsName, settingsStr || '');
|
|
1458
1850
|
}
|
|
1459
1851
|
expired(state) {
|
|
1460
|
-
if (!state)
|
|
1461
|
-
return [];
|
|
1462
|
-
return state.settings?.filter(item => (item.options?.expires || 0) > 0 && this.utils.hasExpired(item.options?.expires || 0));
|
|
1852
|
+
if (!state)
|
|
1853
|
+
return [];
|
|
1854
|
+
return state.settings?.filter(item => (item.options?.expires || 0) > 0 && this.utils.hasExpired(item.options?.expires || 0));
|
|
1855
|
+
}
|
|
1856
|
+
retrieveState() {
|
|
1857
|
+
const str = localStorage.getItem(this.storageSettingsName);
|
|
1858
|
+
const localStr = localStorage.getItem(this.storageName);
|
|
1859
|
+
const sessionStr = sessionStorage.getItem(this.storageName);
|
|
1860
|
+
const localData = (localStr) ? JSON.parse(localStr) : null;
|
|
1861
|
+
const sessionData = (sessionStr) ? JSON.parse(sessionStr) : null;
|
|
1862
|
+
const decryptedStr = str ? this.encryption.decrypt(str, this.app.appID) : null;
|
|
1863
|
+
const settings = (decryptedStr && decryptedStr !== null) ? JSON.parse(decryptedStr) : [];
|
|
1864
|
+
settings.forEach(store => {
|
|
1865
|
+
const expired = (store.options?.expires || 0) > 0 && this.utils.hasExpired(store.options?.expires || 0);
|
|
1866
|
+
if (!expired) {
|
|
1867
|
+
const hasStorage = this.hasGlobalStorage(store.options?.storage, store.id || '');
|
|
1868
|
+
if (!hasStorage) {
|
|
1869
|
+
this.createStore({ id: store.id, name: store.name, data: [], options: SettingOptions.adapt(store.options) });
|
|
1870
|
+
}
|
|
1871
|
+
else {
|
|
1872
|
+
const storeData = (store.options?.storage === StorageType.GLOBAL) ? localData.find(item => item.id === store.id) : sessionData.find(item => item.id === store.id);
|
|
1873
|
+
this.setStore({ id: store.id || '', name: store.name, data: storeData?.data, options: SettingOptions.adapt(store.options) });
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
});
|
|
1877
|
+
this.stateRetrieved = true;
|
|
1878
|
+
}
|
|
1879
|
+
isString(obj) {
|
|
1880
|
+
return (Object.prototype.toString.call(obj) === '[object String]');
|
|
1881
|
+
}
|
|
1882
|
+
fixAndParseJSON(jsonString) {
|
|
1883
|
+
const fixedString = jsonString
|
|
1884
|
+
.replace(/'/g, '"')
|
|
1885
|
+
.replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
|
|
1886
|
+
.replace(/,\s*(\}|\])/g, '$1');
|
|
1887
|
+
try {
|
|
1888
|
+
return JSON.parse(fixedString);
|
|
1889
|
+
}
|
|
1890
|
+
catch (error) {
|
|
1891
|
+
throw new Error('Failed to parse JSON: ' + error.message);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
validStoreName(str) {
|
|
1895
|
+
return str
|
|
1896
|
+
.toLowerCase() // Convert to lowercase
|
|
1897
|
+
.replace(/\s+/g, '_') // Replace spaces with underscores
|
|
1898
|
+
.replace(/[^ -~]/g, ''); // Remove non-ASCII characters
|
|
1899
|
+
}
|
|
1900
|
+
hasGlobalStorage(type = StorageType.GLOBAL, id) {
|
|
1901
|
+
const strData = [];
|
|
1902
|
+
if (type === StorageType.GLOBAL) {
|
|
1903
|
+
const str = localStorage.getItem(this.storageName);
|
|
1904
|
+
strData.push(...(str ? JSON.parse(str) : []));
|
|
1905
|
+
}
|
|
1906
|
+
else {
|
|
1907
|
+
const str = sessionStorage.getItem(this.storageName);
|
|
1908
|
+
strData.push(...(str ? JSON.parse(str) : []));
|
|
1909
|
+
}
|
|
1910
|
+
const found = strData.find(store => store.id === id);
|
|
1911
|
+
return (found) ? true : false;
|
|
1912
|
+
}
|
|
1913
|
+
ngOnDestroy() {
|
|
1914
|
+
this.persistence$.unsubscribe();
|
|
1915
|
+
}
|
|
1916
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageManagerService, deps: [{ token: CONFIG_SETTINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1917
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageManagerService, providedIn: 'root' }); }
|
|
1918
|
+
}
|
|
1919
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageManagerService, decorators: [{
|
|
1920
|
+
type: Injectable,
|
|
1921
|
+
args: [{ providedIn: 'root' }]
|
|
1922
|
+
}], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
|
|
1923
|
+
type: Optional
|
|
1924
|
+
}, {
|
|
1925
|
+
type: Inject,
|
|
1926
|
+
args: [CONFIG_SETTINGS_TOKEN]
|
|
1927
|
+
}] }] });
|
|
1928
|
+
|
|
1929
|
+
const initialState = {
|
|
1930
|
+
localStores: [],
|
|
1931
|
+
sessionStores: [],
|
|
1932
|
+
settings: [],
|
|
1933
|
+
};
|
|
1934
|
+
class LocalStorageSignalsManagerService {
|
|
1935
|
+
constructor(configOptions) {
|
|
1936
|
+
this.configOptions = configOptions;
|
|
1937
|
+
this.state = signal(initialState);
|
|
1938
|
+
this.storageName = 'storage';
|
|
1939
|
+
this.storageSettingsName = 'global-storage';
|
|
1940
|
+
this.defaultOptions = SettingOptions.adapt();
|
|
1941
|
+
this.stateRetrieved = false;
|
|
1942
|
+
this.encrypted = false;
|
|
1943
|
+
this.app = inject(AppService);
|
|
1944
|
+
this.utils = inject(UtilsService);
|
|
1945
|
+
this.objectMergerService = inject(ObjectMergerService);
|
|
1946
|
+
this.encryption = inject(SymmetricalEncryptionService);
|
|
1947
|
+
this.encryptionTest = inject(EncryptionTestService);
|
|
1948
|
+
// --- SELECTORS ---
|
|
1949
|
+
this.stores = computed(() => this.state().settings);
|
|
1950
|
+
this.storeExists = (store) => computed(() => !!this.state().settings.find(item => item.name === store));
|
|
1951
|
+
this.store = (store) => computed(() => {
|
|
1952
|
+
const data = this.state();
|
|
1953
|
+
const foundStore = data.settings.find(item => item.name === store);
|
|
1954
|
+
if (!foundStore)
|
|
1955
|
+
return null;
|
|
1956
|
+
const options = SettingOptions.adapt(foundStore.options);
|
|
1957
|
+
const found = options.storage === StorageType.GLOBAL
|
|
1958
|
+
? data.localStores.find(item => item.id === foundStore.id)
|
|
1959
|
+
: data.sessionStores.find(item => item.id === foundStore.id);
|
|
1960
|
+
if (!found) {
|
|
1961
|
+
this.deleteStore({ name: store });
|
|
1962
|
+
return null;
|
|
1963
|
+
}
|
|
1964
|
+
if (!this.app?.appID) {
|
|
1965
|
+
console.warn('No App ID found - AppId not Provided');
|
|
1966
|
+
return null;
|
|
1967
|
+
}
|
|
1968
|
+
const storageData = options.encrypted
|
|
1969
|
+
? this.encryption.decrypt(found.data, this.app.appID)
|
|
1970
|
+
: found.data;
|
|
1971
|
+
return this.isString(storageData) ? JSON.parse(storageData) : storageData;
|
|
1972
|
+
});
|
|
1973
|
+
this.settings = computed(() => this.state().settings);
|
|
1974
|
+
this.setting = (store) => computed(() => this.state().settings.find(item => item.name === store) ?? null);
|
|
1975
|
+
this.storageName = configOptions?.LocalStorageOptions?.storageName || this.storageName;
|
|
1976
|
+
this.storageSettingsName = configOptions?.LocalStorageOptions?.storageSettingsName || this.storageSettingsName;
|
|
1977
|
+
this.defaultOptions = configOptions?.LocalStorageOptions?.options || this.defaultOptions;
|
|
1978
|
+
this.retrieveState();
|
|
1979
|
+
// Auto-persist when state changes
|
|
1980
|
+
effect(() => {
|
|
1981
|
+
if (this.stateRetrieved) {
|
|
1982
|
+
this.persistState(this.state());
|
|
1983
|
+
}
|
|
1984
|
+
});
|
|
1985
|
+
// Expiration timer every 3s
|
|
1986
|
+
setInterval(() => {
|
|
1987
|
+
const state = this.state();
|
|
1988
|
+
const expired = this.expired(state);
|
|
1989
|
+
if (expired.length > 0) {
|
|
1990
|
+
const ids = expired.map(i => i.id);
|
|
1991
|
+
const updated = {
|
|
1992
|
+
...state,
|
|
1993
|
+
localStores: state.localStores.filter(i => !ids.includes(i.id)),
|
|
1994
|
+
sessionStores: state.sessionStores.filter(i => !ids.includes(i.id)),
|
|
1995
|
+
settings: state.settings.filter(i => !ids.includes(i.id)),
|
|
1996
|
+
};
|
|
1997
|
+
this.state.set(updated);
|
|
1998
|
+
this.persistState(updated);
|
|
1999
|
+
}
|
|
2000
|
+
}, 3000);
|
|
2001
|
+
}
|
|
2002
|
+
// --- STATE MUTATORS ---
|
|
2003
|
+
setStore(store) {
|
|
2004
|
+
this.state.update(state => {
|
|
2005
|
+
const settings = StorageOption.adapt(store);
|
|
2006
|
+
settings.options = this.objectMergerService.mergeStorageOptions(settings.options);
|
|
2007
|
+
store.name = this.validStoreName(store.name);
|
|
2008
|
+
const str = this.encryptionTest.isEncrypted(store.data) ? store.data : JSON.stringify(store.data);
|
|
2009
|
+
const dataStr = this.isObjectOrArray(str) && store.options.encrypted
|
|
2010
|
+
? this.encryption.encrypt(str, this.app.appID)
|
|
2011
|
+
: store.data;
|
|
2012
|
+
const localData = dataStr && settings.options?.storage === StorageType.GLOBAL
|
|
2013
|
+
? [{ data: dataStr, id: settings.id }]
|
|
2014
|
+
: [];
|
|
2015
|
+
const sessionData = dataStr && settings.options?.storage === StorageType.SESSION
|
|
2016
|
+
? [{ data: dataStr, id: settings.id }]
|
|
2017
|
+
: [];
|
|
2018
|
+
return {
|
|
2019
|
+
...state,
|
|
2020
|
+
localStores: [...state.localStores, ...localData],
|
|
2021
|
+
sessionStores: [...state.sessionStores, ...sessionData],
|
|
2022
|
+
settings: [...state.settings, settings],
|
|
2023
|
+
};
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
createStore(store) {
|
|
2027
|
+
this.state.update(state => {
|
|
2028
|
+
const settings = StorageOption.adapt(store);
|
|
2029
|
+
settings.options = this.objectMergerService.mergeStorageOptions(settings.options);
|
|
2030
|
+
if (state.settings.some(item => item.name === store.name)) {
|
|
2031
|
+
return state;
|
|
2032
|
+
}
|
|
2033
|
+
if (!this.isObjectOrArray(store.data)) {
|
|
2034
|
+
console.warn('Data must be an Object or Array');
|
|
2035
|
+
return state;
|
|
2036
|
+
}
|
|
2037
|
+
const dataStr = store.options.encrypted ? this.encryption.encrypt(store.data, this.app.appID) : store.data;
|
|
2038
|
+
const localData = settings.options?.storage === StorageType.GLOBAL ? [{ data: dataStr, id: settings.id }] : [];
|
|
2039
|
+
const sessionData = settings.options?.storage === StorageType.SESSION ? [{ data: dataStr, id: settings.id }] : [];
|
|
2040
|
+
return {
|
|
2041
|
+
...state,
|
|
2042
|
+
localStores: [...state.localStores, ...localData],
|
|
2043
|
+
sessionStores: [...state.sessionStores, ...sessionData],
|
|
2044
|
+
settings: [...state.settings, settings],
|
|
2045
|
+
};
|
|
2046
|
+
});
|
|
2047
|
+
}
|
|
2048
|
+
updateStore(store) {
|
|
2049
|
+
this.state.update(state => {
|
|
2050
|
+
const settings = state.settings.find(item => item.name === store.name);
|
|
2051
|
+
if (!settings)
|
|
2052
|
+
return state;
|
|
2053
|
+
const dataStr = settings.options?.encrypted
|
|
2054
|
+
? this.encryption.encrypt(store.data, this.app.appID)
|
|
2055
|
+
: store.data;
|
|
2056
|
+
const localData = settings.options?.storage === StorageType.GLOBAL ? [{ data: dataStr, id: settings.id }] : [];
|
|
2057
|
+
const sessionData = settings.options?.storage === StorageType.SESSION ? [{ data: dataStr, id: settings.id }] : [];
|
|
2058
|
+
return {
|
|
2059
|
+
...state,
|
|
2060
|
+
localStores: [...state.localStores.filter(i => i.id !== settings.id), ...localData],
|
|
2061
|
+
sessionStores: [...state.sessionStores.filter(i => i.id !== settings.id), ...sessionData],
|
|
2062
|
+
};
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
deleteStore(store) {
|
|
2066
|
+
this.state.update(state => {
|
|
2067
|
+
const id = state.settings.find(item => item.name === store.name)?.id;
|
|
2068
|
+
if (!id)
|
|
2069
|
+
return state;
|
|
2070
|
+
return {
|
|
2071
|
+
...state,
|
|
2072
|
+
localStores: state.localStores.filter(i => i.id !== id),
|
|
2073
|
+
sessionStores: state.sessionStores.filter(i => i.id !== id),
|
|
2074
|
+
settings: state.settings.filter(i => i.id !== id),
|
|
2075
|
+
};
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
resetStore() {
|
|
2079
|
+
const cleared = { localStores: [], sessionStores: [], settings: [] };
|
|
2080
|
+
this.state.set(cleared);
|
|
2081
|
+
this.persistState(cleared);
|
|
2082
|
+
}
|
|
2083
|
+
// --- HELPERS ---
|
|
2084
|
+
persistState(state) {
|
|
2085
|
+
localStorage.setItem(this.storageName, JSON.stringify(state.localStores));
|
|
2086
|
+
sessionStorage.setItem(this.storageName, JSON.stringify(state.sessionStores));
|
|
2087
|
+
const settingsStr = this.encryption.encrypt(state.settings, this.app.appID);
|
|
2088
|
+
localStorage.setItem(this.storageSettingsName, settingsStr || '');
|
|
2089
|
+
}
|
|
2090
|
+
expired(state) {
|
|
2091
|
+
return state.settings.filter(s => (s.options?.expires || 0) > 0 && this.utils.hasExpired(s.options?.expires));
|
|
1463
2092
|
}
|
|
1464
2093
|
retrieveState() {
|
|
1465
2094
|
const str = localStorage.getItem(this.storageSettingsName);
|
|
1466
2095
|
const localStr = localStorage.getItem(this.storageName);
|
|
1467
2096
|
const sessionStr = sessionStorage.getItem(this.storageName);
|
|
1468
|
-
const localData =
|
|
1469
|
-
const sessionData =
|
|
2097
|
+
const localData = localStr ? JSON.parse(localStr) : [];
|
|
2098
|
+
const sessionData = sessionStr ? JSON.parse(sessionStr) : [];
|
|
1470
2099
|
const decryptedStr = str ? this.encryption.decrypt(str, this.app.appID) : null;
|
|
1471
|
-
const settings =
|
|
2100
|
+
const settings = decryptedStr ? JSON.parse(decryptedStr) : [];
|
|
1472
2101
|
settings.forEach(store => {
|
|
1473
|
-
|
|
2102
|
+
// normalize options so we compare numbers and compute expires correctly
|
|
2103
|
+
const options = SettingOptions.adapt(store.options);
|
|
2104
|
+
// if persisted data included expiresIn but not numeric expires, compute it now
|
|
2105
|
+
if ((!options.expires || options.expires === 0) && options.expiresIn) {
|
|
2106
|
+
try {
|
|
2107
|
+
const computed = this.utils.expires(options.expiresIn);
|
|
2108
|
+
options.expires = computed || 0;
|
|
2109
|
+
}
|
|
2110
|
+
catch {
|
|
2111
|
+
options.expires = 0;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
const expired = (options.expires || 0) > 0 && this.utils.hasExpired(options.expires || 0);
|
|
1474
2115
|
if (!expired) {
|
|
1475
|
-
const hasStorage = this.hasGlobalStorage(
|
|
2116
|
+
const hasStorage = this.hasGlobalStorage(options.storage, store.id || '');
|
|
1476
2117
|
if (!hasStorage) {
|
|
1477
|
-
this.createStore({ id: store.id, name: store.name, data: [], options
|
|
2118
|
+
this.createStore({ id: store.id, name: store.name, data: [], options });
|
|
1478
2119
|
}
|
|
1479
2120
|
else {
|
|
1480
|
-
const storeData = (
|
|
1481
|
-
|
|
2121
|
+
const storeData = (options.storage === StorageType.GLOBAL)
|
|
2122
|
+
? localData.find(item => item.id === store.id)
|
|
2123
|
+
: sessionData.find(item => item.id === store.id);
|
|
2124
|
+
this.setStore({ id: store.id || '', name: store.name, data: storeData?.data, options });
|
|
1482
2125
|
}
|
|
1483
2126
|
}
|
|
1484
2127
|
});
|
|
1485
2128
|
this.stateRetrieved = true;
|
|
1486
|
-
|
|
1487
|
-
isString(obj) {
|
|
1488
|
-
return (Object.prototype.toString.call(obj) === '[object String]');
|
|
1489
|
-
}
|
|
1490
|
-
fixAndParseJSON(jsonString) {
|
|
1491
|
-
const fixedString = jsonString
|
|
1492
|
-
.replace(/'/g, '"')
|
|
1493
|
-
.replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
|
|
1494
|
-
.replace(/,\s*(\}|\])/g, '$1');
|
|
2129
|
+
// Ensure all stored settings have numeric expires computed and persisted
|
|
1495
2130
|
try {
|
|
1496
|
-
|
|
2131
|
+
const current = this.state();
|
|
2132
|
+
let changed = false;
|
|
2133
|
+
const normalizedSettings = current.settings.map(s => {
|
|
2134
|
+
const opts = SettingOptions.adapt(s.options);
|
|
2135
|
+
if ((!opts.expires || opts.expires === 0) && opts.expiresIn) {
|
|
2136
|
+
const computed = this.utils.expires(opts.expiresIn) || 0;
|
|
2137
|
+
if (computed && computed !== opts.expires) {
|
|
2138
|
+
opts.expires = computed;
|
|
2139
|
+
changed = true;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return { ...s, options: opts };
|
|
2143
|
+
});
|
|
2144
|
+
if (changed) {
|
|
2145
|
+
const updated = { ...current, settings: normalizedSettings };
|
|
2146
|
+
this.state.set(updated);
|
|
2147
|
+
this.persistState(updated);
|
|
2148
|
+
}
|
|
1497
2149
|
}
|
|
1498
|
-
catch (
|
|
1499
|
-
|
|
2150
|
+
catch (e) {
|
|
2151
|
+
// swallow normalization errors to avoid breaking init
|
|
1500
2152
|
}
|
|
1501
2153
|
}
|
|
1502
|
-
validStoreName(str) {
|
|
1503
|
-
return str
|
|
1504
|
-
.toLowerCase() // Convert to lowercase
|
|
1505
|
-
.replace(/\s+/g, '_') // Replace spaces with underscores
|
|
1506
|
-
.replace(/[^ -~]/g, ''); // Remove non-ASCII characters
|
|
1507
|
-
}
|
|
1508
2154
|
hasGlobalStorage(type = StorageType.GLOBAL, id) {
|
|
1509
2155
|
const strData = [];
|
|
1510
2156
|
if (type === StorageType.GLOBAL) {
|
|
@@ -1516,15 +2162,27 @@ class LocalStorageManagerService extends ComponentStore {
|
|
|
1516
2162
|
strData.push(...(str ? JSON.parse(str) : []));
|
|
1517
2163
|
}
|
|
1518
2164
|
const found = strData.find(store => store.id === id);
|
|
1519
|
-
return
|
|
2165
|
+
return !!found;
|
|
1520
2166
|
}
|
|
1521
|
-
|
|
1522
|
-
|
|
2167
|
+
isObjectOrArray(obj) {
|
|
2168
|
+
try {
|
|
2169
|
+
const parsed = typeof obj === 'object' ? obj : JSON.parse(obj);
|
|
2170
|
+
return typeof parsed === 'object' && parsed !== null;
|
|
2171
|
+
}
|
|
2172
|
+
catch {
|
|
2173
|
+
return false;
|
|
2174
|
+
}
|
|
1523
2175
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
2176
|
+
isString(obj) {
|
|
2177
|
+
return Object.prototype.toString.call(obj) === '[object String]';
|
|
2178
|
+
}
|
|
2179
|
+
validStoreName(str) {
|
|
2180
|
+
return str.toLowerCase().replace(/\s+/g, '_').replace(/[^ -~]/g, '');
|
|
2181
|
+
}
|
|
2182
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageSignalsManagerService, deps: [{ token: CONFIG_SETTINGS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2183
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageSignalsManagerService, providedIn: 'root' }); }
|
|
1526
2184
|
}
|
|
1527
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
2185
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageSignalsManagerService, decorators: [{
|
|
1528
2186
|
type: Injectable,
|
|
1529
2187
|
args: [{ providedIn: 'root' }]
|
|
1530
2188
|
}], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
|
|
@@ -1858,247 +2516,627 @@ class RequestErrorInterceptor {
|
|
|
1858
2516
|
constructor() {
|
|
1859
2517
|
this.toastMessage = inject(ToastMessageDisplayService);
|
|
1860
2518
|
}
|
|
1861
|
-
intercept(req, next) {
|
|
1862
|
-
return next.handle(req).pipe(catchError$1((error) => {
|
|
1863
|
-
const displayError = ToastDisplay.adapt({
|
|
1864
|
-
message: 'This is a toast message. This is an Error!!',
|
|
1865
|
-
action: 'OK',
|
|
1866
|
-
color: ToastColors.SUCCESS,
|
|
1867
|
-
icon: 'info',
|
|
1868
|
-
duration: 5 * 1000, //5 seconds
|
|
1869
|
-
});
|
|
1870
|
-
if (error.status >= 400 && error.status < 500) {
|
|
1871
|
-
displayError.color = ToastColors.WARN;
|
|
1872
|
-
displayError.message = error.error || `${error.status}: ${error.statusText}`;
|
|
1873
|
-
console.error('Client Error:', {
|
|
1874
|
-
status: error.status,
|
|
1875
|
-
message: error.message,
|
|
1876
|
-
error: error.error,
|
|
1877
|
-
text: error.statusText,
|
|
1878
|
-
});
|
|
1879
|
-
this.toastMessage.toastMessage(displayError);
|
|
1880
|
-
}
|
|
1881
|
-
else if (error.status >= 500) {
|
|
1882
|
-
displayError.color = ToastColors.ERROR;
|
|
1883
|
-
displayError.message = error.error || `${error.status}: ${error.statusText}`;
|
|
1884
|
-
console.error('Server Error:', {
|
|
1885
|
-
status: error.status,
|
|
1886
|
-
message: error.message,
|
|
1887
|
-
error: error.error,
|
|
1888
|
-
text: error.statusText,
|
|
1889
|
-
});
|
|
1890
|
-
this.toastMessage.toastMessage(displayError);
|
|
1891
|
-
}
|
|
1892
|
-
return throwError(() => error);
|
|
1893
|
-
}));
|
|
2519
|
+
intercept(req, next) {
|
|
2520
|
+
return next.handle(req).pipe(catchError$1((error) => {
|
|
2521
|
+
const displayError = ToastDisplay.adapt({
|
|
2522
|
+
message: 'This is a toast message. This is an Error!!',
|
|
2523
|
+
action: 'OK',
|
|
2524
|
+
color: ToastColors.SUCCESS,
|
|
2525
|
+
icon: 'info',
|
|
2526
|
+
duration: 5 * 1000, //5 seconds
|
|
2527
|
+
});
|
|
2528
|
+
if (error.status >= 400 && error.status < 500) {
|
|
2529
|
+
displayError.color = ToastColors.WARN;
|
|
2530
|
+
displayError.message = error.error || `${error.status}: ${error.statusText}`;
|
|
2531
|
+
console.error('Client Error:', {
|
|
2532
|
+
status: error.status,
|
|
2533
|
+
message: error.message,
|
|
2534
|
+
error: error.error,
|
|
2535
|
+
text: error.statusText,
|
|
2536
|
+
});
|
|
2537
|
+
this.toastMessage.toastMessage(displayError);
|
|
2538
|
+
}
|
|
2539
|
+
else if (error.status >= 500) {
|
|
2540
|
+
displayError.color = ToastColors.ERROR;
|
|
2541
|
+
displayError.message = error.error || `${error.status}: ${error.statusText}`;
|
|
2542
|
+
console.error('Server Error:', {
|
|
2543
|
+
status: error.status,
|
|
2544
|
+
message: error.message,
|
|
2545
|
+
error: error.error,
|
|
2546
|
+
text: error.statusText,
|
|
2547
|
+
});
|
|
2548
|
+
this.toastMessage.toastMessage(displayError);
|
|
2549
|
+
}
|
|
2550
|
+
return throwError(() => error);
|
|
2551
|
+
}));
|
|
2552
|
+
}
|
|
2553
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestErrorInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2554
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestErrorInterceptor }); }
|
|
2555
|
+
}
|
|
2556
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestErrorInterceptor, decorators: [{
|
|
2557
|
+
type: Injectable
|
|
2558
|
+
}] });
|
|
2559
|
+
|
|
2560
|
+
let ClientInfo$1 = class ClientInfo {
|
|
2561
|
+
constructor(domain = '', service = '', id = 0, name = '') {
|
|
2562
|
+
this.domain = domain;
|
|
2563
|
+
this.service = service;
|
|
2564
|
+
this.id = id;
|
|
2565
|
+
this.name = name;
|
|
2566
|
+
}
|
|
2567
|
+
static adapt(item) {
|
|
2568
|
+
return new ClientInfo(item?.domain, item?.service, item?.id, (item?.first_name || item?.last_name) ? `${item?.first_name} ${item?.last_name}` : '');
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
|
|
2572
|
+
let ClientInfoMapper$1 = class ClientInfoMapper {
|
|
2573
|
+
constructor(id = 0, first_name = '', last_name = '', email = '') {
|
|
2574
|
+
this.id = id;
|
|
2575
|
+
this.first_name = first_name;
|
|
2576
|
+
this.last_name = last_name;
|
|
2577
|
+
this.email = email;
|
|
2578
|
+
}
|
|
2579
|
+
static adapt(item) {
|
|
2580
|
+
const first_name = (item?.name) ? item.name.split(' ')[0] : '';
|
|
2581
|
+
const last_name = (item?.name) ? item.name.split(' ')[1] : '';
|
|
2582
|
+
return new ClientInfoMapper(item?.id, first_name, last_name, item?.email);
|
|
2583
|
+
}
|
|
2584
|
+
};
|
|
2585
|
+
|
|
2586
|
+
let AIPrompt$1 = class AIPrompt {
|
|
2587
|
+
constructor(response = '') {
|
|
2588
|
+
this.response = response;
|
|
2589
|
+
}
|
|
2590
|
+
static adapt(item) {
|
|
2591
|
+
return new AIPrompt(item?.response);
|
|
2592
|
+
}
|
|
2593
|
+
};
|
|
2594
|
+
|
|
2595
|
+
class DownloadLabels {
|
|
2596
|
+
constructor(error = '', action = '', icon = 'error') {
|
|
2597
|
+
this.error = error;
|
|
2598
|
+
this.action = action;
|
|
2599
|
+
this.icon = icon;
|
|
2600
|
+
}
|
|
2601
|
+
static adapt(item) {
|
|
2602
|
+
return new DownloadLabels(item?.error, item?.action, item?.icon);
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
class DownloadFileComponent {
|
|
2607
|
+
constructor() {
|
|
2608
|
+
this.subscriptions = new Subscription();
|
|
2609
|
+
this.displayError = 3; // seconds
|
|
2610
|
+
this.diameter = 32;
|
|
2611
|
+
this.mode = 'determinate';
|
|
2612
|
+
this.isPending = false;
|
|
2613
|
+
this.active = false;
|
|
2614
|
+
this.disabled = false;
|
|
2615
|
+
this.error = new EventEmitter();
|
|
2616
|
+
this._progress = 0;
|
|
2617
|
+
this._hasError = false;
|
|
2618
|
+
this.errorTimerActive = false;
|
|
2619
|
+
}
|
|
2620
|
+
set progress(value) {
|
|
2621
|
+
this._progress = value ?? 0;
|
|
2622
|
+
}
|
|
2623
|
+
get progress() {
|
|
2624
|
+
return this._progress;
|
|
2625
|
+
}
|
|
2626
|
+
set hasError(value) {
|
|
2627
|
+
this._hasError = !!value;
|
|
2628
|
+
if (this._hasError && !this.errorTimerActive) {
|
|
2629
|
+
this.errorTimerActive = true;
|
|
2630
|
+
this.active = false;
|
|
2631
|
+
this.error.emit();
|
|
2632
|
+
this.subscriptions.add(timer(this.displayError * 1000)
|
|
2633
|
+
.subscribe((err) => {
|
|
2634
|
+
this._hasError = false;
|
|
2635
|
+
this.errorTimerActive = false;
|
|
2636
|
+
}));
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
get hasError() {
|
|
2640
|
+
return this._hasError;
|
|
2641
|
+
}
|
|
2642
|
+
ngOnInit() { }
|
|
2643
|
+
onAction() {
|
|
2644
|
+
this.isPending = false;
|
|
2645
|
+
if (this.event)
|
|
2646
|
+
this.event();
|
|
2647
|
+
}
|
|
2648
|
+
ngOnDestroy() {
|
|
2649
|
+
this.subscriptions.unsubscribe();
|
|
2650
|
+
}
|
|
2651
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DownloadFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2652
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", 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: i8.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]", exportAs: ["matButton"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
2653
|
+
}
|
|
2654
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DownloadFileComponent, decorators: [{
|
|
2655
|
+
type: Component,
|
|
2656
|
+
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"] }]
|
|
2657
|
+
}], propDecorators: { event: [{
|
|
2658
|
+
type: Input
|
|
2659
|
+
}], displayError: [{
|
|
2660
|
+
type: Input
|
|
2661
|
+
}], diameter: [{
|
|
2662
|
+
type: Input
|
|
2663
|
+
}], mode: [{
|
|
2664
|
+
type: Input
|
|
2665
|
+
}], isPending: [{
|
|
2666
|
+
type: Input
|
|
2667
|
+
}], active: [{
|
|
2668
|
+
type: Input
|
|
2669
|
+
}], disabled: [{
|
|
2670
|
+
type: Input
|
|
2671
|
+
}], error: [{
|
|
2672
|
+
type: Output
|
|
2673
|
+
}], progress: [{
|
|
2674
|
+
type: Input
|
|
2675
|
+
}], hasError: [{
|
|
2676
|
+
type: Input
|
|
2677
|
+
}] } });
|
|
2678
|
+
|
|
2679
|
+
class FileDownloaderComponent extends HTTPManagerService {
|
|
2680
|
+
set labels(value) {
|
|
2681
|
+
this._labels = (value) ? DownloadLabels.adapt(value) : DownloadLabels.adapt();
|
|
2682
|
+
}
|
|
2683
|
+
get labels() {
|
|
2684
|
+
return this._labels;
|
|
2685
|
+
}
|
|
2686
|
+
constructor() {
|
|
2687
|
+
super();
|
|
2688
|
+
this.delayError = 3;
|
|
2689
|
+
this.apiRequest = ApiRequest.adapt();
|
|
2690
|
+
this.displayErrorMessage = false;
|
|
2691
|
+
this._labels = DownloadLabels.adapt();
|
|
2692
|
+
this.active = false;
|
|
2693
|
+
this.subscription = new Subscription();
|
|
2694
|
+
this.completed = new EventEmitter();
|
|
2695
|
+
this.failed = new EventEmitter();
|
|
2696
|
+
this.disabled = false;
|
|
2697
|
+
}
|
|
2698
|
+
ngOnInit() {
|
|
2699
|
+
}
|
|
2700
|
+
onDownloadStreaming() {
|
|
2701
|
+
if (this.active)
|
|
2702
|
+
return;
|
|
2703
|
+
this.active = true;
|
|
2704
|
+
return this.downloadRequest(this.apiRequest, [])
|
|
2705
|
+
.pipe(distinctUntilChanged(), catchError((err) => {
|
|
2706
|
+
this.onError(err.message);
|
|
2707
|
+
this.active = false;
|
|
2708
|
+
this.failed.emit(err);
|
|
2709
|
+
return throwError(() => err);
|
|
2710
|
+
}), finalize(() => {
|
|
2711
|
+
if (!this.active)
|
|
2712
|
+
return;
|
|
2713
|
+
this.active = false;
|
|
2714
|
+
this.completed.emit();
|
|
2715
|
+
}))
|
|
2716
|
+
.subscribe();
|
|
2717
|
+
}
|
|
2718
|
+
onError(message) {
|
|
2719
|
+
if (!message || !this.displayErrorMessage)
|
|
2720
|
+
return;
|
|
2721
|
+
const display = ToastDisplay.adapt({
|
|
2722
|
+
message,
|
|
2723
|
+
action: 'Ok',
|
|
2724
|
+
color: ToastColors.ERROR,
|
|
2725
|
+
icon: 'error',
|
|
2726
|
+
});
|
|
2727
|
+
this.active = false;
|
|
2728
|
+
this.toastMessage.toastMessage(display);
|
|
2729
|
+
}
|
|
2730
|
+
OnDestroy() {
|
|
2731
|
+
this.subscription.unsubscribe();
|
|
1894
2732
|
}
|
|
1895
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
1896
|
-
static { this.ɵ
|
|
2733
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileDownloaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2734
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FileDownloaderComponent, selector: "app-file-downloader", inputs: { delayError: "delayError", apiRequest: "apiRequest", displayErrorMessage: "displayErrorMessage", saveFileAs: "saveFileAs", 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 }); }
|
|
1897
2735
|
}
|
|
1898
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
1899
|
-
type:
|
|
1900
|
-
|
|
2736
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileDownloaderComponent, decorators: [{
|
|
2737
|
+
type: Component,
|
|
2738
|
+
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"] }]
|
|
2739
|
+
}], ctorParameters: () => [], propDecorators: { delayError: [{
|
|
2740
|
+
type: Input
|
|
2741
|
+
}], apiRequest: [{
|
|
2742
|
+
type: Input
|
|
2743
|
+
}], displayErrorMessage: [{
|
|
2744
|
+
type: Input
|
|
2745
|
+
}], saveFileAs: [{
|
|
2746
|
+
type: Input
|
|
2747
|
+
}], labels: [{
|
|
2748
|
+
type: Input
|
|
2749
|
+
}], completed: [{
|
|
2750
|
+
type: Output
|
|
2751
|
+
}], failed: [{
|
|
2752
|
+
type: Output
|
|
2753
|
+
}], disabled: [{
|
|
2754
|
+
type: Input
|
|
2755
|
+
}] } });
|
|
1901
2756
|
|
|
1902
|
-
class
|
|
1903
|
-
|
|
1904
|
-
this.
|
|
1905
|
-
this.service = service;
|
|
1906
|
-
this.id = id;
|
|
1907
|
-
this.name = name;
|
|
2757
|
+
class RequestManagerDemoComponent {
|
|
2758
|
+
get retry() {
|
|
2759
|
+
return this.requestForm.get('retry')?.value;
|
|
1908
2760
|
}
|
|
1909
|
-
|
|
1910
|
-
return
|
|
2761
|
+
get headers() {
|
|
2762
|
+
return this.requestForm.get('headers');
|
|
1911
2763
|
}
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
constructor(id = 0, first_name = '', last_name = '', email = '') {
|
|
1916
|
-
this.id = id;
|
|
1917
|
-
this.first_name = first_name;
|
|
1918
|
-
this.last_name = last_name;
|
|
1919
|
-
this.email = email;
|
|
2764
|
+
get isValid() {
|
|
2765
|
+
this.requestForm.markAllAsTouched();
|
|
2766
|
+
return this.requestForm.valid;
|
|
1920
2767
|
}
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2768
|
+
constructor() {
|
|
2769
|
+
this.displayedColumns = ['id', 'name', 'lastName', 'age'];
|
|
2770
|
+
this.fb = inject(FormBuilder);
|
|
2771
|
+
this.toastMessage = inject(ToastMessageDisplayService);
|
|
2772
|
+
this.httpManagerService = inject(HTTPManagerService);
|
|
2773
|
+
this.isPending$ = this.httpManagerService.isPending$;
|
|
2774
|
+
this.countdown$ = this.httpManagerService.countdown$;
|
|
2775
|
+
this.GET_error$ = new BehaviorSubject('');
|
|
2776
|
+
this.POST_error$ = new BehaviorSubject('');
|
|
2777
|
+
this.PUT_error$ = new BehaviorSubject('');
|
|
2778
|
+
this.DELETE_error$ = new BehaviorSubject('');
|
|
2779
|
+
this.STREAM_error$ = new BehaviorSubject('');
|
|
2780
|
+
this.STREAM_AI_error$ = new BehaviorSubject('');
|
|
2781
|
+
this.requestParams = {
|
|
2782
|
+
GET: ApiRequest.adapt(),
|
|
2783
|
+
POST: ApiRequest.adapt(),
|
|
2784
|
+
PUT: ApiRequest.adapt(),
|
|
2785
|
+
DELETE: ApiRequest.adapt(),
|
|
2786
|
+
STREAM: ApiRequest.adapt(),
|
|
2787
|
+
};
|
|
2788
|
+
this.questionControl = this.fb.control("", [Validators.required]);
|
|
2789
|
+
this.downloadRequest = ApiRequest.adapt({
|
|
2790
|
+
server: 'assets/images',
|
|
2791
|
+
path: ['me.jpg'],
|
|
2792
|
+
// saveAs: 'john.jpg' // Optional
|
|
2793
|
+
});
|
|
2794
|
+
// downloadRequest = ApiRequest.adapt({
|
|
2795
|
+
// server: 'oidc/ai/file'
|
|
2796
|
+
// })
|
|
2797
|
+
this.sampleClientData = {
|
|
2798
|
+
id: 0,
|
|
2799
|
+
name: "Old School Dates",
|
|
2800
|
+
domain: "osd.com",
|
|
2801
|
+
service: "osd",
|
|
2802
|
+
spiffe: "osd.com/osd",
|
|
2803
|
+
secret: "SMOPECXP-OS4P-USOG-X2II-3XMD1FQDR3IJX",
|
|
2804
|
+
created: 1693003138,
|
|
2805
|
+
modified: 1693003138,
|
|
2806
|
+
icon: "",
|
|
2807
|
+
imageFile: "",
|
|
2808
|
+
email: "wavecoders@gmail.com"
|
|
2809
|
+
};
|
|
2810
|
+
this.requestForm = this.fb.group({
|
|
2811
|
+
path: this.fb.control("ai/"),
|
|
2812
|
+
headers: this.fb.array([]),
|
|
2813
|
+
adapter: [null],
|
|
2814
|
+
mapper: [null],
|
|
2815
|
+
retry: this.fb.group({
|
|
2816
|
+
times: [3],
|
|
2817
|
+
delay: [3],
|
|
2818
|
+
}),
|
|
2819
|
+
polling: [3],
|
|
2820
|
+
});
|
|
2821
|
+
this.AIType = 0;
|
|
2822
|
+
this.sampleAdaptors = [
|
|
2823
|
+
{ label: "ClientInfo Basic", value: ClientInfo$1.adapt },
|
|
2824
|
+
{ label: "AI Prompt", value: AIPrompt$1.adapt },
|
|
2825
|
+
];
|
|
2826
|
+
this.sampleMappers = [
|
|
2827
|
+
{ label: "Mapper Basic", value: ClientInfoMapper$1.adapt },
|
|
2828
|
+
{ label: "AI Prompt", value: AIPrompt$1.adapt },
|
|
2829
|
+
];
|
|
2830
|
+
this.hasId = (arr) => {
|
|
2831
|
+
if (arr.length === 0)
|
|
2832
|
+
return false;
|
|
2833
|
+
return !isNaN(arr[arr.length - 1]);
|
|
2834
|
+
};
|
|
2835
|
+
this.props = (adapter) => {
|
|
2836
|
+
return (adapter) ? adapter() : null;
|
|
2837
|
+
};
|
|
2838
|
+
// server = `http://sample-endpoint/as/authorization.oauth2`
|
|
2839
|
+
this.arrayObjectsToObjects = (arr) => {
|
|
2840
|
+
return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
|
|
2841
|
+
};
|
|
1925
2842
|
}
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
2843
|
+
ngOnInit() {
|
|
2844
|
+
// const reqGet2 = ApiRequest.adapt({
|
|
2845
|
+
// server,
|
|
2846
|
+
// path: ['clients'],
|
|
2847
|
+
// headers: { authentication: "Bearer <KEY>" },
|
|
2848
|
+
// adapter: ClientInfo,
|
|
2849
|
+
// dataType: DataType.OBJECT,
|
|
2850
|
+
// // concurrent: false,
|
|
2851
|
+
// // polling: 3, //seconds
|
|
2852
|
+
// })
|
|
2853
|
+
// const req2 = [1024,1025,1026].map(item => {
|
|
2854
|
+
// return this.httpManagerService.getRequest<ClientInfo[]>(reqGet2, [item])
|
|
2855
|
+
// .pipe(
|
|
2856
|
+
// catchError(error => {
|
|
2857
|
+
// return throwError(() => new Error(error.error.message))
|
|
2858
|
+
// })
|
|
2859
|
+
// )
|
|
2860
|
+
// })
|
|
2861
|
+
// forkJoin(req2)
|
|
2862
|
+
// .subscribe(res => console.log(res))
|
|
1931
2863
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
2864
|
+
addHeader() {
|
|
2865
|
+
const header = this.fb.group({
|
|
2866
|
+
key: ['', Validators.required],
|
|
2867
|
+
value: ['']
|
|
2868
|
+
});
|
|
2869
|
+
this.headers.push(header);
|
|
1934
2870
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
class DownloadLabels {
|
|
1938
|
-
constructor(error = '', action = '', icon = 'error') {
|
|
1939
|
-
this.error = error;
|
|
1940
|
-
this.action = action;
|
|
1941
|
-
this.icon = icon;
|
|
2871
|
+
removeHeader(index) {
|
|
2872
|
+
this.headers.removeAt(index);
|
|
1942
2873
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
2874
|
+
compileRequest() {
|
|
2875
|
+
const requestParams = this.requestForm.value;
|
|
2876
|
+
requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
|
|
2877
|
+
const pathReq = (requestParams.path === "") ? [] : (requestParams.path || "").split("/");
|
|
2878
|
+
if (!this.pollingState.checked)
|
|
2879
|
+
requestParams.polling = 0;
|
|
2880
|
+
if (!this.failedState.checked) {
|
|
2881
|
+
requestParams.retry = { times: 0, delay: 0 };
|
|
2882
|
+
}
|
|
2883
|
+
const apiOptions = ApiRequest.adapt(requestParams);
|
|
2884
|
+
apiOptions.path = [];
|
|
2885
|
+
return { apiOptions: apiOptions, path: pathReq };
|
|
1945
2886
|
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
this.
|
|
1951
|
-
this.
|
|
1952
|
-
this.
|
|
1953
|
-
this.
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
2887
|
+
onGetRequest() {
|
|
2888
|
+
if (!this.isValid)
|
|
2889
|
+
return;
|
|
2890
|
+
const reqParams = this.compileRequest();
|
|
2891
|
+
this.requestParams.GET = reqParams.apiOptions;
|
|
2892
|
+
this.GET$ = EMPTY; //Cancels Previous
|
|
2893
|
+
this.GET_error$.next('');
|
|
2894
|
+
this.GET$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
2895
|
+
.pipe(
|
|
2896
|
+
// tap((data) => console.log("API GET response", data)),
|
|
2897
|
+
catchError(error => {
|
|
2898
|
+
return throwError(() => this.errorHandling(error, 'GET'));
|
|
2899
|
+
}));
|
|
2900
|
+
}
|
|
2901
|
+
onCreateRequest() {
|
|
2902
|
+
if (!this.isValid)
|
|
2903
|
+
return;
|
|
2904
|
+
const reqParams = this.compileRequest();
|
|
2905
|
+
this.requestParams.POST = reqParams.apiOptions;
|
|
2906
|
+
this.POST$ = EMPTY; //Cancels Previous
|
|
2907
|
+
this.POST_error$.next('');
|
|
2908
|
+
console.log("POST", this.sampleClientData);
|
|
2909
|
+
console.log("POST", reqParams.apiOptions);
|
|
2910
|
+
console.log("POST", reqParams.path);
|
|
2911
|
+
this.POST$ = this.httpManagerService.postRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
|
|
2912
|
+
.pipe(
|
|
2913
|
+
// tap((data) => console.log("API POST response", data)),
|
|
2914
|
+
catchError(error => {
|
|
2915
|
+
return throwError(() => this.errorHandling(error, 'POST'));
|
|
2916
|
+
}));
|
|
1961
2917
|
}
|
|
1962
|
-
|
|
1963
|
-
this.
|
|
2918
|
+
onUpdateRequest() {
|
|
2919
|
+
if (!this.isValid)
|
|
2920
|
+
return;
|
|
2921
|
+
const reqParams = this.compileRequest();
|
|
2922
|
+
if (!this.hasId(reqParams.path)) {
|
|
2923
|
+
console.log("Missing ID");
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2926
|
+
this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
|
|
2927
|
+
this.requestParams.PUT = reqParams.apiOptions;
|
|
2928
|
+
this.PUT$ = EMPTY; //Cancels Previous
|
|
2929
|
+
this.PUT_error$.next('');
|
|
2930
|
+
this.PUT$ = this.httpManagerService.putRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
|
|
2931
|
+
.pipe(
|
|
2932
|
+
// tap((data) => console.log("API PUT response", data)),
|
|
2933
|
+
catchError(error => {
|
|
2934
|
+
return throwError(() => this.errorHandling(error, 'PUT'));
|
|
2935
|
+
}));
|
|
1964
2936
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
2937
|
+
onDeleteRequest() {
|
|
2938
|
+
if (!this.isValid)
|
|
2939
|
+
return;
|
|
2940
|
+
const reqParams = this.compileRequest();
|
|
2941
|
+
this.requestParams.DELETE = reqParams.apiOptions;
|
|
2942
|
+
if (!this.hasId(reqParams.path)) {
|
|
2943
|
+
console.log("Missing ID");
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
|
|
2947
|
+
this.requestParams.DELETE = reqParams.apiOptions;
|
|
2948
|
+
this.DELETE$ = EMPTY; //Cancels Previous
|
|
2949
|
+
this.DELETE_error$.next('');
|
|
2950
|
+
this.DELETE$ = this.httpManagerService.deleteRequest(reqParams.apiOptions, reqParams.path)
|
|
2951
|
+
.pipe(
|
|
2952
|
+
// tap((data) => console.log("API DELETE response", data)),
|
|
2953
|
+
catchError(error => {
|
|
2954
|
+
return throwError(() => this.errorHandling(error, 'DELETE'));
|
|
2955
|
+
}));
|
|
1967
2956
|
}
|
|
1968
|
-
|
|
1969
|
-
this.
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
}
|
|
2957
|
+
onStreamPostRequest() {
|
|
2958
|
+
if (!this.isValid)
|
|
2959
|
+
return;
|
|
2960
|
+
const reqParams = this.compileRequest();
|
|
2961
|
+
let payload = {};
|
|
2962
|
+
let apiPath = reqParams.path;
|
|
2963
|
+
let apiOptions = reqParams.apiOptions;
|
|
2964
|
+
let responseMapper = (items) => items.response;
|
|
2965
|
+
if (this.AIType === 0) {
|
|
2966
|
+
// API request
|
|
2967
|
+
payload = { prompt: this.questionControl.value };
|
|
2968
|
+
}
|
|
2969
|
+
else {
|
|
2970
|
+
// Local Ollama request
|
|
2971
|
+
apiOptions.server = "api";
|
|
2972
|
+
apiPath = ["generate"];
|
|
2973
|
+
apiOptions.stream = true;
|
|
2974
|
+
payload = {
|
|
2975
|
+
model: "phi3:latest",
|
|
2976
|
+
prompt: this.questionControl.value,
|
|
2977
|
+
stream: true,
|
|
2978
|
+
};
|
|
2979
|
+
responseMapper = (items) => items.map((word) => word.response).flat().join('');
|
|
1979
2980
|
}
|
|
2981
|
+
this.requestParams.STREAM = apiOptions;
|
|
2982
|
+
this.STREAM_AI$ = EMPTY;
|
|
2983
|
+
this.STREAM_AI_error$.next('');
|
|
2984
|
+
this.STREAM_AI$ = this.httpManagerService.postRequest(payload, apiOptions, apiPath).pipe(map(responseMapper), tap(() => this.questionControl.reset()), catchError(error => throwError(() => this.errorHandling(error, 'STREAM'))));
|
|
1980
2985
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
2986
|
+
onStreamRequest() {
|
|
2987
|
+
if (!this.isValid)
|
|
2988
|
+
return;
|
|
2989
|
+
const reqParams = this.compileRequest();
|
|
2990
|
+
reqParams.apiOptions.stream = true;
|
|
2991
|
+
this.requestParams.GET = reqParams.apiOptions;
|
|
2992
|
+
this.STREAM$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
2993
|
+
.pipe(
|
|
2994
|
+
// tap((data) => console.log("API STREAM response", data)),
|
|
2995
|
+
catchError(error => {
|
|
2996
|
+
return throwError(() => this.errorHandling(error, 'STREAM'));
|
|
2997
|
+
}));
|
|
1983
2998
|
}
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2999
|
+
onDownloadCompleted() {
|
|
3000
|
+
const message = "Download Completed";
|
|
3001
|
+
const display = ToastDisplay.adapt({
|
|
3002
|
+
message,
|
|
3003
|
+
action: 'Ok',
|
|
3004
|
+
color: ToastColors.SUCCESS,
|
|
3005
|
+
icon: 'sentiment_satisfied_alt',
|
|
3006
|
+
});
|
|
3007
|
+
this.toastMessage.toastMessage(display);
|
|
1989
3008
|
}
|
|
1990
|
-
|
|
1991
|
-
|
|
3009
|
+
onDownloadFailed(err) {
|
|
3010
|
+
const message = "Download Failed";
|
|
3011
|
+
const display = ToastDisplay.adapt({
|
|
3012
|
+
message,
|
|
3013
|
+
action: 'Ok',
|
|
3014
|
+
color: ToastColors.ERROR,
|
|
3015
|
+
icon: 'warning',
|
|
3016
|
+
});
|
|
3017
|
+
this.toastMessage.toastMessage(display);
|
|
1992
3018
|
}
|
|
1993
|
-
|
|
1994
|
-
|
|
3019
|
+
errorHandling(err, type) {
|
|
3020
|
+
if (type === 'GET')
|
|
3021
|
+
this.GET_error$.next(err.message);
|
|
3022
|
+
if (type === 'POST')
|
|
3023
|
+
this.POST_error$.next(err.message);
|
|
3024
|
+
if (type === 'PUT')
|
|
3025
|
+
this.PUT_error$.next(err.message);
|
|
3026
|
+
if (type === 'DELETE')
|
|
3027
|
+
this.DELETE_error$.next(err.message);
|
|
3028
|
+
if (type === 'STREAM')
|
|
3029
|
+
this.STREAM_error$.next(err.message);
|
|
3030
|
+
}
|
|
3031
|
+
onSelectAIType(type) {
|
|
3032
|
+
this.AIType = type;
|
|
3033
|
+
}
|
|
3034
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3035
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", 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\" #adapterSelect>\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\" #mapperSelect>\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 style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\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 <h3>Include Record ID in the RestPath</h3>\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 <h3>Include Record ID in the RestPath</h3>\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; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\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 *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"(STREAM_AI$ | async) as data\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\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}.box{padding:10px;border:1px solid #ccc}\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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i10.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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", "saveFileAs", "labels", "disabled"], outputs: ["completed", "failed"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
|
|
1995
3036
|
}
|
|
1996
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
3037
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerDemoComponent, decorators: [{
|
|
1997
3038
|
type: Component,
|
|
1998
|
-
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"] }]
|
|
1999
|
-
}], propDecorators: {
|
|
2000
|
-
type:
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
}], mode: [{
|
|
2006
|
-
type: Input
|
|
2007
|
-
}], isPending: [{
|
|
2008
|
-
type: Input
|
|
2009
|
-
}], active: [{
|
|
2010
|
-
type: Input
|
|
2011
|
-
}], disabled: [{
|
|
2012
|
-
type: Input
|
|
2013
|
-
}], error: [{
|
|
2014
|
-
type: Output
|
|
2015
|
-
}], progress: [{
|
|
2016
|
-
type: Input
|
|
2017
|
-
}], hasError: [{
|
|
2018
|
-
type: Input
|
|
3039
|
+
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\" #adapterSelect>\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\" #mapperSelect>\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 style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\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 <h3>Include Record ID in the RestPath</h3>\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 <h3>Include Record ID in the RestPath</h3>\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; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\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 *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"(STREAM_AI$ | async) as data\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\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}.box{padding:10px;border:1px solid #ccc}\n"] }]
|
|
3040
|
+
}], ctorParameters: () => [], propDecorators: { failedState: [{
|
|
3041
|
+
type: ViewChild,
|
|
3042
|
+
args: ["failedState", { static: true }]
|
|
3043
|
+
}], pollingState: [{
|
|
3044
|
+
type: ViewChild,
|
|
3045
|
+
args: ["pollingState", { static: true }]
|
|
2019
3046
|
}] } });
|
|
2020
3047
|
|
|
2021
|
-
class
|
|
2022
|
-
|
|
2023
|
-
|
|
3048
|
+
class StateManagerDemoService extends HTTPManagerStateService {
|
|
3049
|
+
constructor() {
|
|
3050
|
+
super(ApiRequest.adapt({
|
|
3051
|
+
server: "",
|
|
3052
|
+
path: [],
|
|
3053
|
+
headers: {},
|
|
3054
|
+
adapter: ClientInfo$1.adapt,
|
|
3055
|
+
mapper: ClientInfoMapper$1.adapt,
|
|
3056
|
+
stream: false,
|
|
3057
|
+
}), DataType.ARRAY, DatabaseStorage.adapt());
|
|
2024
3058
|
}
|
|
2025
|
-
|
|
2026
|
-
|
|
3059
|
+
setAPIOptions(apiOptions, dataType, database) {
|
|
3060
|
+
this.setApiRequestOptions(apiOptions, dataType, database);
|
|
2027
3061
|
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
this.
|
|
2034
|
-
this.active = false;
|
|
2035
|
-
this.subscription = new Subscription();
|
|
2036
|
-
this.completed = new EventEmitter();
|
|
2037
|
-
this.failed = new EventEmitter();
|
|
2038
|
-
this.disabled = false;
|
|
3062
|
+
getClients() {
|
|
3063
|
+
// const headers = {
|
|
3064
|
+
// auth: "sample-auth-token"
|
|
3065
|
+
// }
|
|
3066
|
+
// const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
|
|
3067
|
+
this.fetchRecords();
|
|
2039
3068
|
}
|
|
2040
|
-
|
|
3069
|
+
createClient(data) {
|
|
3070
|
+
// const headers = {
|
|
3071
|
+
// auth: "sample-auth-token"
|
|
3072
|
+
// }
|
|
3073
|
+
// const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
|
|
3074
|
+
this.createRecord(data);
|
|
2041
3075
|
}
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
this.active = false;
|
|
2050
|
-
this.failed.emit(err);
|
|
2051
|
-
return throwError(() => err);
|
|
2052
|
-
}), finalize(() => {
|
|
2053
|
-
if (!this.active)
|
|
2054
|
-
return;
|
|
2055
|
-
this.active = false;
|
|
2056
|
-
this.completed.emit();
|
|
2057
|
-
}))
|
|
2058
|
-
.subscribe();
|
|
3076
|
+
updateClient(data) {
|
|
3077
|
+
// const headers = {
|
|
3078
|
+
// auth: "sample-auth-token"
|
|
3079
|
+
// }
|
|
3080
|
+
data.id = 1031;
|
|
3081
|
+
const sampleOptions = RequestOptions.adapt({ path: [data.id] });
|
|
3082
|
+
this.updateRecord(data, sampleOptions);
|
|
2059
3083
|
}
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
icon: 'error',
|
|
2068
|
-
});
|
|
2069
|
-
this.active = false;
|
|
2070
|
-
this.toastMessage.toastMessage(display);
|
|
3084
|
+
deleteClient(data) {
|
|
3085
|
+
// const headers = {
|
|
3086
|
+
// auth: "sample-auth-token"
|
|
3087
|
+
// }
|
|
3088
|
+
data.id = 1031;
|
|
3089
|
+
const sampleOptions = RequestOptions.adapt({ path: [data.id] });
|
|
3090
|
+
this.deleteRecord(sampleOptions);
|
|
2071
3091
|
}
|
|
2072
|
-
|
|
2073
|
-
|
|
3092
|
+
streamRequest() {
|
|
3093
|
+
const headers = {
|
|
3094
|
+
auth: "sample-auth-token"
|
|
3095
|
+
};
|
|
3096
|
+
// const sampleOptions = RequestOptions.adapt({ path: [1], headers })
|
|
3097
|
+
this.fetchStream();
|
|
2074
3098
|
}
|
|
2075
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
2076
|
-
static { this.ɵ
|
|
3099
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3100
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, providedIn: 'root' }); }
|
|
2077
3101
|
}
|
|
2078
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
2079
|
-
type:
|
|
2080
|
-
args: [{
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
type: Input
|
|
2085
|
-
}], displayErrorMessage: [{
|
|
2086
|
-
type: Input
|
|
2087
|
-
}], saveFileAs: [{
|
|
2088
|
-
type: Input
|
|
2089
|
-
}], labels: [{
|
|
2090
|
-
type: Input
|
|
2091
|
-
}], completed: [{
|
|
2092
|
-
type: Output
|
|
2093
|
-
}], failed: [{
|
|
2094
|
-
type: Output
|
|
2095
|
-
}], disabled: [{
|
|
2096
|
-
type: Input
|
|
2097
|
-
}] } });
|
|
3102
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, decorators: [{
|
|
3103
|
+
type: Injectable,
|
|
3104
|
+
args: [{
|
|
3105
|
+
providedIn: 'root'
|
|
3106
|
+
}]
|
|
3107
|
+
}], ctorParameters: () => [] });
|
|
2098
3108
|
|
|
2099
|
-
class
|
|
3109
|
+
class RequestManagerStateDemoComponent {
|
|
3110
|
+
get dataObservable$() {
|
|
3111
|
+
switch (this.requestType) {
|
|
3112
|
+
case 'GET':
|
|
3113
|
+
return this.GET$;
|
|
3114
|
+
case 'PUT':
|
|
3115
|
+
return this.PUT$;
|
|
3116
|
+
case 'POST':
|
|
3117
|
+
return this.POST$;
|
|
3118
|
+
case 'DELETE':
|
|
3119
|
+
return this.DELETE$;
|
|
3120
|
+
case 'STREAM':
|
|
3121
|
+
return this.STREAM;
|
|
3122
|
+
case 'STREAM_AI':
|
|
3123
|
+
return this.STREAM_AI;
|
|
3124
|
+
default:
|
|
3125
|
+
return this.GET$;
|
|
3126
|
+
break;
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
get hasChanged() {
|
|
3130
|
+
return this.requestForm.dirty || this.requestForm.untouched;
|
|
3131
|
+
}
|
|
3132
|
+
get dataType() {
|
|
3133
|
+
return this.requestForm.get("datatype")?.value;
|
|
3134
|
+
}
|
|
3135
|
+
get database() {
|
|
3136
|
+
return this.requestForm.get("database")?.value;
|
|
3137
|
+
}
|
|
2100
3138
|
get retry() {
|
|
2101
|
-
return this.requestForm.get(
|
|
3139
|
+
return this.requestForm.get("retry")?.value;
|
|
2102
3140
|
}
|
|
2103
3141
|
get headers() {
|
|
2104
3142
|
return this.requestForm.get('headers');
|
|
@@ -2108,11 +3146,12 @@ class RequestManagerDemoComponent {
|
|
|
2108
3146
|
return this.requestForm.valid;
|
|
2109
3147
|
}
|
|
2110
3148
|
constructor() {
|
|
3149
|
+
this.stateManagerDemoService = inject(StateManagerDemoService);
|
|
2111
3150
|
this.displayedColumns = ['id', 'name', 'lastName', 'age'];
|
|
2112
3151
|
this.fb = inject(FormBuilder);
|
|
2113
|
-
this.toastMessage = inject(ToastMessageDisplayService);
|
|
2114
3152
|
this.httpManagerService = inject(HTTPManagerService);
|
|
2115
|
-
this.isPending$ = this.
|
|
3153
|
+
this.isPending$ = this.stateManagerDemoService.isPending$;
|
|
3154
|
+
this.error$ = this.stateManagerDemoService.error$;
|
|
2116
3155
|
this.countdown$ = this.httpManagerService.countdown$;
|
|
2117
3156
|
this.GET_error$ = new BehaviorSubject('');
|
|
2118
3157
|
this.POST_error$ = new BehaviorSubject('');
|
|
@@ -2120,22 +3159,19 @@ class RequestManagerDemoComponent {
|
|
|
2120
3159
|
this.DELETE_error$ = new BehaviorSubject('');
|
|
2121
3160
|
this.STREAM_error$ = new BehaviorSubject('');
|
|
2122
3161
|
this.STREAM_AI_error$ = new BehaviorSubject('');
|
|
2123
|
-
this.
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
3162
|
+
this.GET$ = new BehaviorSubject(null);
|
|
3163
|
+
this.POST$ = new BehaviorSubject(null);
|
|
3164
|
+
this.PUT$ = new BehaviorSubject(null);
|
|
3165
|
+
this.DELETE$ = new BehaviorSubject(null);
|
|
3166
|
+
this.STREAM = new BehaviorSubject(null);
|
|
3167
|
+
this.STREAM$ = this.STREAM.asObservable();
|
|
3168
|
+
this.STREAM_AI = new BehaviorSubject([]);
|
|
3169
|
+
this.STREAM_AI$ = this.STREAM_AI.asObservable()
|
|
3170
|
+
.pipe(map$1((items) => (items) ? items.map((item) => item.response) : []), map$1((items) => items.join('\n').trim()));
|
|
2130
3171
|
this.questionControl = this.fb.control("", [Validators.required]);
|
|
2131
|
-
this.
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
// saveAs: 'john.jpg' // Optional
|
|
2135
|
-
});
|
|
2136
|
-
// downloadRequest = ApiRequest.adapt({
|
|
2137
|
-
// server: 'oidc/ai/file'
|
|
2138
|
-
// })
|
|
3172
|
+
this.requestType = '';
|
|
3173
|
+
this.prompts = [];
|
|
3174
|
+
this.AIType = 0;
|
|
2139
3175
|
this.sampleClientData = {
|
|
2140
3176
|
id: 0,
|
|
2141
3177
|
name: "Old School Dates",
|
|
@@ -2147,9 +3183,10 @@ class RequestManagerDemoComponent {
|
|
|
2147
3183
|
modified: 1693003138,
|
|
2148
3184
|
icon: "",
|
|
2149
3185
|
imageFile: "",
|
|
2150
|
-
email: "wavecoders@gmail.com"
|
|
2151
3186
|
};
|
|
3187
|
+
this.selectedRecord = this.fb.control(null);
|
|
2152
3188
|
this.requestForm = this.fb.group({
|
|
3189
|
+
datatype: this.fb.control('ARRAY'),
|
|
2153
3190
|
path: this.fb.control("ai/"),
|
|
2154
3191
|
headers: this.fb.array([]),
|
|
2155
3192
|
adapter: [null],
|
|
@@ -2159,49 +3196,64 @@ class RequestManagerDemoComponent {
|
|
|
2159
3196
|
delay: [3],
|
|
2160
3197
|
}),
|
|
2161
3198
|
polling: [3],
|
|
3199
|
+
database: this.fb.group({
|
|
3200
|
+
table: [''],
|
|
3201
|
+
expiresIn: ['1m'],
|
|
3202
|
+
})
|
|
2162
3203
|
});
|
|
2163
|
-
this.AIType = 0;
|
|
2164
3204
|
this.sampleAdaptors = [
|
|
2165
|
-
{ label: "ClientInfo Basic", value: ClientInfo.adapt },
|
|
2166
|
-
{ label: "AI Prompt", value: AIPrompt.adapt },
|
|
3205
|
+
{ label: "ClientInfo Basic", value: ClientInfo$1.adapt },
|
|
3206
|
+
{ label: "AI Prompt", value: AIPrompt$1.adapt },
|
|
2167
3207
|
];
|
|
2168
3208
|
this.sampleMappers = [
|
|
2169
|
-
{ label: "Mapper Basic", value: ClientInfoMapper.adapt },
|
|
2170
|
-
{ label: "AI Prompt", value: AIPrompt.adapt },
|
|
3209
|
+
{ label: "Mapper Basic", value: ClientInfoMapper$1.adapt },
|
|
3210
|
+
{ label: "AI Prompt", value: AIPrompt$1.adapt },
|
|
2171
3211
|
];
|
|
2172
|
-
this.hasId = (arr) => {
|
|
2173
|
-
if (arr.length === 0)
|
|
2174
|
-
return false;
|
|
2175
|
-
return !isNaN(arr[arr.length - 1]);
|
|
2176
|
-
};
|
|
2177
|
-
this.props = (adapter) => {
|
|
2178
|
-
return (adapter) ? adapter() : null;
|
|
2179
|
-
};
|
|
2180
3212
|
// server = `http://sample-endpoint/as/authorization.oauth2`
|
|
2181
3213
|
this.arrayObjectsToObjects = (arr) => {
|
|
2182
3214
|
return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
|
|
2183
3215
|
};
|
|
3216
|
+
this.props = (adapter) => {
|
|
3217
|
+
return (adapter) ? adapter() : null;
|
|
3218
|
+
};
|
|
2184
3219
|
}
|
|
2185
3220
|
ngOnInit() {
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
3221
|
+
this.stateManagerDemoService.data$.pipe(tap$1((data) => console.log("API STREAM_AI response", data)));
|
|
3222
|
+
this.error$.pipe(tap$1((data) => {
|
|
3223
|
+
debugger;
|
|
3224
|
+
console.log("API STREAM response", data);
|
|
3225
|
+
}), catchError$1(error => {
|
|
3226
|
+
return throwError(() => this.errorHandling(error, 'STREAM'));
|
|
3227
|
+
}));
|
|
3228
|
+
this.selectedRecord.valueChanges
|
|
3229
|
+
.subscribe((data) => {
|
|
3230
|
+
this.selectedRecord$ = (data) ? this.stateManagerDemoService.selectRecord$(data.id) : EMPTY;
|
|
3231
|
+
});
|
|
3232
|
+
this.stateManagerDemoService.data$
|
|
3233
|
+
.pipe(tap$1((data) => {
|
|
3234
|
+
switch (this.requestType) {
|
|
3235
|
+
case 'GET':
|
|
3236
|
+
this.GET$.next(data);
|
|
3237
|
+
break;
|
|
3238
|
+
case 'PUT':
|
|
3239
|
+
this.PUT$.next(data);
|
|
3240
|
+
break;
|
|
3241
|
+
case 'POST':
|
|
3242
|
+
this.POST$.next(data);
|
|
3243
|
+
break;
|
|
3244
|
+
case 'DELETE':
|
|
3245
|
+
this.DELETE$.next(data);
|
|
3246
|
+
break;
|
|
3247
|
+
case 'STREAM':
|
|
3248
|
+
this.STREAM.next(data);
|
|
3249
|
+
break;
|
|
3250
|
+
case 'STREAM_AI':
|
|
3251
|
+
this.STREAM_AI.next(data);
|
|
3252
|
+
break;
|
|
3253
|
+
default:
|
|
3254
|
+
break;
|
|
3255
|
+
}
|
|
3256
|
+
})).subscribe();
|
|
2205
3257
|
}
|
|
2206
3258
|
addHeader() {
|
|
2207
3259
|
const header = this.fb.group({
|
|
@@ -2210,155 +3262,64 @@ class RequestManagerDemoComponent {
|
|
|
2210
3262
|
});
|
|
2211
3263
|
this.headers.push(header);
|
|
2212
3264
|
}
|
|
2213
|
-
removeHeader(index) {
|
|
2214
|
-
this.headers.removeAt(index);
|
|
2215
|
-
}
|
|
2216
|
-
compileRequest() {
|
|
2217
|
-
const requestParams = this.requestForm.value;
|
|
2218
|
-
requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
|
|
2219
|
-
const pathReq = (requestParams.path === "") ? [] : (requestParams.path || "").split("/");
|
|
2220
|
-
if (!this.pollingState.checked)
|
|
2221
|
-
requestParams.polling = 0;
|
|
2222
|
-
if (!this.failedState.checked) {
|
|
2223
|
-
requestParams.retry = { times: 0, delay: 0 };
|
|
2224
|
-
}
|
|
2225
|
-
const apiOptions = ApiRequest.adapt(requestParams);
|
|
2226
|
-
apiOptions.path = [];
|
|
2227
|
-
return { apiOptions: apiOptions, path: pathReq };
|
|
2228
|
-
}
|
|
2229
|
-
onGetRequest() {
|
|
2230
|
-
if (!this.isValid)
|
|
2231
|
-
return;
|
|
2232
|
-
const reqParams = this.compileRequest();
|
|
2233
|
-
this.requestParams.GET = reqParams.apiOptions;
|
|
2234
|
-
this.GET$ = EMPTY; //Cancels Previous
|
|
2235
|
-
this.GET_error$.next('');
|
|
2236
|
-
this.GET$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
2237
|
-
.pipe(
|
|
2238
|
-
// tap((data) => console.log("API GET response", data)),
|
|
2239
|
-
catchError(error => {
|
|
2240
|
-
return throwError(() => this.errorHandling(error, 'GET'));
|
|
2241
|
-
}));
|
|
2242
|
-
}
|
|
2243
|
-
onCreateRequest() {
|
|
2244
|
-
if (!this.isValid)
|
|
2245
|
-
return;
|
|
2246
|
-
const reqParams = this.compileRequest();
|
|
2247
|
-
this.requestParams.POST = reqParams.apiOptions;
|
|
2248
|
-
this.POST$ = EMPTY; //Cancels Previous
|
|
2249
|
-
this.POST_error$.next('');
|
|
2250
|
-
console.log("POST", this.sampleClientData);
|
|
2251
|
-
console.log("POST", reqParams.apiOptions);
|
|
2252
|
-
console.log("POST", reqParams.path);
|
|
2253
|
-
this.POST$ = this.httpManagerService.postRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
|
|
2254
|
-
.pipe(
|
|
2255
|
-
// tap((data) => console.log("API POST response", data)),
|
|
2256
|
-
catchError(error => {
|
|
2257
|
-
return throwError(() => this.errorHandling(error, 'POST'));
|
|
2258
|
-
}));
|
|
2259
|
-
}
|
|
2260
|
-
onUpdateRequest() {
|
|
2261
|
-
if (!this.isValid)
|
|
2262
|
-
return;
|
|
2263
|
-
const reqParams = this.compileRequest();
|
|
2264
|
-
if (!this.hasId(reqParams.path)) {
|
|
2265
|
-
console.log("Missing ID");
|
|
2266
|
-
return;
|
|
2267
|
-
}
|
|
2268
|
-
this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
|
|
2269
|
-
this.requestParams.PUT = reqParams.apiOptions;
|
|
2270
|
-
this.PUT$ = EMPTY; //Cancels Previous
|
|
2271
|
-
this.PUT_error$.next('');
|
|
2272
|
-
this.PUT$ = this.httpManagerService.putRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
|
|
2273
|
-
.pipe(
|
|
2274
|
-
// tap((data) => console.log("API PUT response", data)),
|
|
2275
|
-
catchError(error => {
|
|
2276
|
-
return throwError(() => this.errorHandling(error, 'PUT'));
|
|
2277
|
-
}));
|
|
2278
|
-
}
|
|
2279
|
-
onDeleteRequest() {
|
|
2280
|
-
if (!this.isValid)
|
|
2281
|
-
return;
|
|
2282
|
-
const reqParams = this.compileRequest();
|
|
2283
|
-
this.requestParams.DELETE = reqParams.apiOptions;
|
|
2284
|
-
if (!this.hasId(reqParams.path)) {
|
|
2285
|
-
console.log("Missing ID");
|
|
2286
|
-
return;
|
|
3265
|
+
removeHeader(index) {
|
|
3266
|
+
this.headers.removeAt(index);
|
|
3267
|
+
}
|
|
3268
|
+
compileRequest() {
|
|
3269
|
+
const requestParams = this.requestForm.value;
|
|
3270
|
+
requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
|
|
3271
|
+
const pathReq = (requestParams.path === "") ? [] : (requestParams.path || "").split("/");
|
|
3272
|
+
if (!this.pollingState.checked)
|
|
3273
|
+
requestParams.polling = 0;
|
|
3274
|
+
if (!this.failedState.checked) {
|
|
3275
|
+
requestParams.retry = { times: 0, delay: 0 };
|
|
2287
3276
|
}
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
this.DELETE$ = this.httpManagerService.deleteRequest(reqParams.apiOptions, reqParams.path)
|
|
2293
|
-
.pipe(
|
|
2294
|
-
// tap((data) => console.log("API DELETE response", data)),
|
|
2295
|
-
catchError(error => {
|
|
2296
|
-
return throwError(() => this.errorHandling(error, 'DELETE'));
|
|
2297
|
-
}));
|
|
3277
|
+
const currentOptions = ApiRequest.adapt(requestParams);
|
|
3278
|
+
currentOptions.path = [];
|
|
3279
|
+
const apiOptions = ApiRequest.adapt({ ...currentOptions, path: pathReq });
|
|
3280
|
+
return { apiOptions: apiOptions, path: pathReq };
|
|
2298
3281
|
}
|
|
2299
|
-
|
|
3282
|
+
onSetStateOptions() {
|
|
2300
3283
|
if (!this.isValid)
|
|
2301
3284
|
return;
|
|
2302
3285
|
const reqParams = this.compileRequest();
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
this.
|
|
2324
|
-
this.
|
|
2325
|
-
|
|
2326
|
-
|
|
3286
|
+
const db = DatabaseStorage.adapt(this.database);
|
|
3287
|
+
const type = this.dataType === "ARRAY" ? DataType.ARRAY : DataType.OBJECT;
|
|
3288
|
+
this.stateManagerDemoService.setAPIOptions(reqParams.apiOptions, type, db);
|
|
3289
|
+
this.requestForm.markAsPristine();
|
|
3290
|
+
}
|
|
3291
|
+
onClearRecords() {
|
|
3292
|
+
this.stateManagerDemoService.clearRecords();
|
|
3293
|
+
}
|
|
3294
|
+
onRefreshRecords() {
|
|
3295
|
+
this.stateManagerDemoService.refreshData();
|
|
3296
|
+
}
|
|
3297
|
+
onGetRequest() {
|
|
3298
|
+
this.requestType = 'GET';
|
|
3299
|
+
this.stateManagerDemoService.getClients();
|
|
3300
|
+
}
|
|
3301
|
+
onCreateRequest() {
|
|
3302
|
+
this.requestType = 'POST';
|
|
3303
|
+
this.stateManagerDemoService.createClient(this.sampleClientData);
|
|
3304
|
+
}
|
|
3305
|
+
onUpdateRequest() {
|
|
3306
|
+
this.requestType = 'PUT';
|
|
3307
|
+
this.stateManagerDemoService.updateClient(this.sampleClientData);
|
|
3308
|
+
}
|
|
3309
|
+
onDeleteRequest() {
|
|
3310
|
+
this.requestType = 'DELETE';
|
|
3311
|
+
this.stateManagerDemoService.deleteClient(this.sampleClientData);
|
|
2327
3312
|
}
|
|
2328
3313
|
onStreamRequest() {
|
|
2329
3314
|
if (!this.isValid)
|
|
2330
3315
|
return;
|
|
2331
3316
|
const reqParams = this.compileRequest();
|
|
2332
3317
|
reqParams.apiOptions.stream = true;
|
|
2333
|
-
this.
|
|
2334
|
-
this.
|
|
2335
|
-
.pipe(
|
|
2336
|
-
// tap((data) => console.log("API STREAM response", data)),
|
|
2337
|
-
catchError(error => {
|
|
2338
|
-
return throwError(() => this.errorHandling(error, 'STREAM'));
|
|
2339
|
-
}));
|
|
2340
|
-
}
|
|
2341
|
-
onDownloadCompleted() {
|
|
2342
|
-
const message = "Download Completed";
|
|
2343
|
-
const display = ToastDisplay.adapt({
|
|
2344
|
-
message,
|
|
2345
|
-
action: 'Ok',
|
|
2346
|
-
color: ToastColors.SUCCESS,
|
|
2347
|
-
icon: 'sentiment_satisfied_alt',
|
|
2348
|
-
});
|
|
2349
|
-
this.toastMessage.toastMessage(display);
|
|
2350
|
-
}
|
|
2351
|
-
onDownloadFailed(err) {
|
|
2352
|
-
const message = "Download Failed";
|
|
2353
|
-
const display = ToastDisplay.adapt({
|
|
2354
|
-
message,
|
|
2355
|
-
action: 'Ok',
|
|
2356
|
-
color: ToastColors.ERROR,
|
|
2357
|
-
icon: 'warning',
|
|
2358
|
-
});
|
|
2359
|
-
this.toastMessage.toastMessage(display);
|
|
3318
|
+
this.requestType = 'STREAM';
|
|
3319
|
+
this.stateManagerDemoService.streamRequest();
|
|
2360
3320
|
}
|
|
2361
3321
|
errorHandling(err, type) {
|
|
3322
|
+
console.log(err, type);
|
|
2362
3323
|
if (type === 'GET')
|
|
2363
3324
|
this.GET_error$.next(err.message);
|
|
2364
3325
|
if (type === 'POST')
|
|
@@ -2369,16 +3330,21 @@ class RequestManagerDemoComponent {
|
|
|
2369
3330
|
this.DELETE_error$.next(err.message);
|
|
2370
3331
|
if (type === 'STREAM')
|
|
2371
3332
|
this.STREAM_error$.next(err.message);
|
|
3333
|
+
if (type === 'STREAM_AI')
|
|
3334
|
+
this.STREAM_AI_error$.next(err.message);
|
|
2372
3335
|
}
|
|
2373
3336
|
onSelectAIType(type) {
|
|
2374
3337
|
this.AIType = type;
|
|
2375
3338
|
}
|
|
2376
|
-
|
|
2377
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", 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\" #adapterSelect>\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\" #mapperSelect>\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 style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\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 <h3>Include Record ID in the RestPath</h3>\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 <h3>Include Record ID in the RestPath</h3>\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; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\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 *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"(STREAM_AI$ | async) as data\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\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}.box{padding:10px;border:1px solid #ccc}\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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i10.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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", "saveFileAs", "labels", "disabled"], outputs: ["completed", "failed"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
|
|
3339
|
+
onClearHistory() {
|
|
3340
|
+
this.prompts = [];
|
|
3341
|
+
}
|
|
3342
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerStateDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3343
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", 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\" #adapterSelect>\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\" #mapperSelect>\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\n <div style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\n </div>\n\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 }}\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.name || (item.first_name) | titlecase}}\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()\" [disabled]=\"hasChanged\">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 *ngIf=\"(GET$ | async) as getData\">{{ getData | 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 *ngIf=\"(POST$ | async) as postData\">{{ postData | 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 *ngIf=\"(PUT$ | async) as putData\">{{ putData | 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 *ngIf=\"(DELETE$ | async) as deleteData\">{{ deleteData | 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()\" class=\"btn\" [disabled]=\"hasChanged\">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>\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}.box{padding:10px;border:1px solid #ccc}\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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i10.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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" }, { kind: "pipe", type: i1$1.TitleCasePipe, name: "titlecase" }] }); }
|
|
2378
3344
|
}
|
|
2379
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
3345
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerStateDemoComponent, decorators: [{
|
|
2380
3346
|
type: Component,
|
|
2381
|
-
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\" #adapterSelect>\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\" #mapperSelect>\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 style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\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 <h3>Include Record ID in the RestPath</h3>\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 <h3>Include Record ID in the RestPath</h3>\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; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\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 *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"(STREAM_AI$ | async) as data\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\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}.box{padding:10px;border:1px solid #ccc}\n"] }]
|
|
3347
|
+
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\" #adapterSelect>\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\" #mapperSelect>\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\n <div style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\n </div>\n\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 }}\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.name || (item.first_name) | titlecase}}\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()\" [disabled]=\"hasChanged\">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 *ngIf=\"(GET$ | async) as getData\">{{ getData | 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 *ngIf=\"(POST$ | async) as postData\">{{ postData | 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 *ngIf=\"(PUT$ | async) as putData\">{{ putData | 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 *ngIf=\"(DELETE$ | async) as deleteData\">{{ deleteData | 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()\" class=\"btn\" [disabled]=\"hasChanged\">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>\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}.box{padding:10px;border:1px solid #ccc}\n"] }]
|
|
2382
3348
|
}], ctorParameters: () => [], propDecorators: { failedState: [{
|
|
2383
3349
|
type: ViewChild,
|
|
2384
3350
|
args: ["failedState", { static: true }]
|
|
@@ -2387,98 +3353,240 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
2387
3353
|
args: ["pollingState", { static: true }]
|
|
2388
3354
|
}] } });
|
|
2389
3355
|
|
|
2390
|
-
class
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
3356
|
+
class LocalStorageDemoComponent {
|
|
3357
|
+
get type() {
|
|
3358
|
+
return (this.typeControl.value) ? +this.typeControl.value : 0;
|
|
3359
|
+
}
|
|
3360
|
+
get isValid() {
|
|
3361
|
+
return this.newStoreForm.valid;
|
|
3362
|
+
}
|
|
3363
|
+
get isValidData() {
|
|
3364
|
+
return this.storageForm.valid;
|
|
3365
|
+
}
|
|
3366
|
+
constructor(configOptions) {
|
|
3367
|
+
this.configOptions = configOptions;
|
|
3368
|
+
this.fb = inject(FormBuilder);
|
|
3369
|
+
this.utils = inject(UtilsService);
|
|
3370
|
+
this.type$ = new BehaviorSubject(StorageType.GLOBAL);
|
|
3371
|
+
this.typeControl = this.fb.control(StorageType.GLOBAL.toString());
|
|
3372
|
+
this.localStorageManagerService = inject(LocalStorageManagerService);
|
|
3373
|
+
this.settings$ = this.localStorageManagerService.settings$;
|
|
3374
|
+
this.setting$ = (store) => this.localStorageManagerService.setting$(store);
|
|
3375
|
+
this.storageForm = this.fb.group({
|
|
3376
|
+
store: this.fb.control(null),
|
|
3377
|
+
type: 'local',
|
|
3378
|
+
settingType: 'local',
|
|
3379
|
+
encrypted: false,
|
|
3380
|
+
data: this.fb.control('', Validators.required),
|
|
3381
|
+
});
|
|
3382
|
+
this.newStoreForm = this.fb.group({
|
|
3383
|
+
name: this.fb.control(null, Validators.required),
|
|
3384
|
+
storage: 'local',
|
|
3385
|
+
encrypted: false,
|
|
3386
|
+
data: this.fb.control('', Validators.required),
|
|
3387
|
+
expiresIn: this.fb.control('0')
|
|
3388
|
+
});
|
|
3389
|
+
this.storeData$ = this.storageForm.get('store')?.valueChanges
|
|
3390
|
+
.pipe(switchMap((data) => {
|
|
3391
|
+
return data
|
|
3392
|
+
? this.localStorageManagerService.store$(data.name)
|
|
3393
|
+
: of('');
|
|
3394
|
+
}), tap(data => {
|
|
3395
|
+
this.storageForm.get('data')?.patchValue(data, { emitEvent: false });
|
|
3396
|
+
}));
|
|
3397
|
+
this.expiresIn = (epoch) => this.utils.expiresIn(epoch);
|
|
3398
|
+
this.isValidJSON = (str) => {
|
|
3399
|
+
try {
|
|
3400
|
+
JSON.parse(str);
|
|
3401
|
+
return true;
|
|
3402
|
+
}
|
|
3403
|
+
catch (e) {
|
|
3404
|
+
return false;
|
|
3405
|
+
}
|
|
3406
|
+
};
|
|
3407
|
+
this.displayedColumns = ['name', 'id', 'encrypted', 'expires', "option"];
|
|
3408
|
+
this.filterData = (values) => {
|
|
3409
|
+
if (!values)
|
|
3410
|
+
return [];
|
|
3411
|
+
return values.filter((item) => item.options.storage === +this.type);
|
|
3412
|
+
};
|
|
3413
|
+
this.create = false;
|
|
3414
|
+
}
|
|
3415
|
+
ngOnInit() {
|
|
3416
|
+
this.storeProps = this.configOptions?.LocalStorageOptions;
|
|
3417
|
+
this.options = this.storeProps?.options;
|
|
3418
|
+
if (this.options?.storage) {
|
|
3419
|
+
this.typeControl.patchValue(this.options.storage.toString());
|
|
3420
|
+
this.typeControl.disable();
|
|
3421
|
+
}
|
|
3422
|
+
else {
|
|
3423
|
+
this.typeControl.enable();
|
|
3424
|
+
}
|
|
3425
|
+
if (this.options?.expiresIn) {
|
|
3426
|
+
this.newStoreForm.get('expiresIn')?.patchValue(this.options.expiresIn);
|
|
3427
|
+
this.newStoreForm.get('expiresIn')?.disable();
|
|
3428
|
+
}
|
|
3429
|
+
else {
|
|
3430
|
+
this.newStoreForm.get('expiresIn')?.enable();
|
|
3431
|
+
}
|
|
3432
|
+
if (this.options?.encrypted) {
|
|
3433
|
+
this.newStoreForm.get('encrypted')?.patchValue(this.options.encrypted);
|
|
3434
|
+
this.newStoreForm.get('encrypted')?.disable();
|
|
3435
|
+
}
|
|
3436
|
+
else {
|
|
3437
|
+
this.newStoreForm.get('encrypted')?.enable();
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
onCreateStore() {
|
|
3441
|
+
if (!this.isValid)
|
|
3442
|
+
return;
|
|
3443
|
+
const store = this.newStoreForm.value;
|
|
3444
|
+
if (!store.name || store.name === '')
|
|
3445
|
+
return;
|
|
3446
|
+
const options = { storage: this.type, encrypted: store.encrypted, expiresIn: store.expiresIn };
|
|
3447
|
+
this.localStorageManagerService.createStore({
|
|
3448
|
+
name: store.name,
|
|
3449
|
+
data: store.data,
|
|
3450
|
+
options: SettingOptions.adapt(options)
|
|
3451
|
+
});
|
|
3452
|
+
this.newStoreForm.reset();
|
|
3453
|
+
this.create = false;
|
|
3454
|
+
}
|
|
3455
|
+
onUpdateStore(store) {
|
|
3456
|
+
if (!this.storageForm.valid)
|
|
3457
|
+
return;
|
|
3458
|
+
const storeData = this.storageForm.value;
|
|
3459
|
+
const data = JSON.parse(storeData.data || '');
|
|
3460
|
+
const type = (storeData.type === 'local') ? StorageType.GLOBAL : StorageType.SESSION;
|
|
3461
|
+
this.localStorageManagerService.updateStore({
|
|
3462
|
+
name: store.name,
|
|
3463
|
+
data
|
|
3464
|
+
});
|
|
3465
|
+
}
|
|
3466
|
+
onSelectedRow(store) {
|
|
3467
|
+
this.store = store;
|
|
3468
|
+
this.data$ = this.localStorageManagerService.store$(store.name).pipe(map(item => JSON.stringify(item)));
|
|
3469
|
+
this.create = false;
|
|
3470
|
+
}
|
|
3471
|
+
onCreate() {
|
|
3472
|
+
this.onCancel();
|
|
3473
|
+
this.create = true;
|
|
3474
|
+
}
|
|
3475
|
+
onDelete(store) {
|
|
3476
|
+
this.localStorageManagerService.deleteStore({
|
|
3477
|
+
name: store.name,
|
|
3478
|
+
});
|
|
3479
|
+
this.onCancel();
|
|
3480
|
+
}
|
|
3481
|
+
onCancel() {
|
|
3482
|
+
this.data$ = EMPTY;
|
|
3483
|
+
this.store = null;
|
|
3484
|
+
this.create = false;
|
|
2400
3485
|
}
|
|
2401
|
-
|
|
2402
|
-
this.
|
|
3486
|
+
onUpdate(store, data) {
|
|
3487
|
+
this.localStorageManagerService.updateStore({
|
|
3488
|
+
name: store.name,
|
|
3489
|
+
data: JSON.parse(data)
|
|
3490
|
+
});
|
|
3491
|
+
this.onCancel();
|
|
2403
3492
|
}
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
// auth: "sample-auth-token"
|
|
2407
|
-
// }
|
|
2408
|
-
// const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
|
|
2409
|
-
this.fetchRecords();
|
|
3493
|
+
onReset() {
|
|
3494
|
+
this.localStorageManagerService.resetStore();
|
|
2410
3495
|
}
|
|
2411
|
-
|
|
2412
|
-
// const headers = {
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
3496
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3497
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", 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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i10$1.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i10$1.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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 }); }
|
|
3498
|
+
}
|
|
3499
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageDemoComponent, decorators: [{
|
|
3500
|
+
type: Component,
|
|
3501
|
+
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"] }]
|
|
3502
|
+
}], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
|
|
3503
|
+
type: Inject,
|
|
3504
|
+
args: [CONFIG_SETTINGS_TOKEN]
|
|
3505
|
+
}] }] });
|
|
3506
|
+
|
|
3507
|
+
const PROXY_CONFIG = new InjectionToken('PROXY_CONFIG');
|
|
3508
|
+
class ProxyDebuggerInterceptor {
|
|
3509
|
+
constructor(proxyConfig) {
|
|
3510
|
+
this.proxyConfig = proxyConfig;
|
|
2417
3511
|
}
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
3512
|
+
intercept(req, next) {
|
|
3513
|
+
if (!this.proxyConfig) {
|
|
3514
|
+
return next.handle(req);
|
|
3515
|
+
}
|
|
3516
|
+
const headers = req.headers.keys().reduce((acc, key) => {
|
|
3517
|
+
acc[key] = req.headers.get(key) || '';
|
|
3518
|
+
return acc;
|
|
3519
|
+
}, {});
|
|
3520
|
+
for (const proxyPath in this.proxyConfig) {
|
|
3521
|
+
if (this.proxyConfig.hasOwnProperty(proxyPath)) {
|
|
3522
|
+
const proxyDetails = this.proxyConfig[proxyPath];
|
|
3523
|
+
const regex = new RegExp('^' + proxyPath.replace('/', '').replace('*', '(.*)'));
|
|
3524
|
+
if (regex.test(req.url)) {
|
|
3525
|
+
const target = proxyDetails.target;
|
|
3526
|
+
const endpoint = req.url.replace(regex, '$1');
|
|
3527
|
+
const actualPath = target + '/' + endpoint;
|
|
3528
|
+
console.log('Request Proxied:', {
|
|
3529
|
+
requestUrl: req.url,
|
|
3530
|
+
requestPayload: req.body,
|
|
3531
|
+
headers: headers,
|
|
3532
|
+
proxyPath: proxyPath,
|
|
3533
|
+
actualPath: actualPath,
|
|
3534
|
+
});
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
return next.handle(req);
|
|
2425
3539
|
}
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
3540
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor, deps: [{ token: PROXY_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3541
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor }); }
|
|
3542
|
+
}
|
|
3543
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor, decorators: [{
|
|
3544
|
+
type: Injectable
|
|
3545
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
3546
|
+
type: Optional
|
|
3547
|
+
}, {
|
|
3548
|
+
type: Inject,
|
|
3549
|
+
args: [PROXY_CONFIG]
|
|
3550
|
+
}] }] });
|
|
3551
|
+
|
|
3552
|
+
class ClientInfo {
|
|
3553
|
+
constructor(domain = '', service = '', id = 0, name = '') {
|
|
3554
|
+
this.domain = domain;
|
|
3555
|
+
this.service = service;
|
|
3556
|
+
this.id = id;
|
|
3557
|
+
this.name = name;
|
|
2433
3558
|
}
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
auth: "sample-auth-token"
|
|
2437
|
-
};
|
|
2438
|
-
// const sampleOptions = RequestOptions.adapt({ path: [1], headers })
|
|
2439
|
-
this.fetchStream();
|
|
3559
|
+
static adapt(item) {
|
|
3560
|
+
return new ClientInfo(item?.domain, item?.service, item?.id, (item?.first_name || item?.last_name) ? `${item?.first_name} ${item?.last_name}` : '');
|
|
2440
3561
|
}
|
|
2441
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2442
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, providedIn: 'root' }); }
|
|
2443
3562
|
}
|
|
2444
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, decorators: [{
|
|
2445
|
-
type: Injectable,
|
|
2446
|
-
args: [{
|
|
2447
|
-
providedIn: 'root'
|
|
2448
|
-
}]
|
|
2449
|
-
}], ctorParameters: () => [] });
|
|
2450
3563
|
|
|
2451
|
-
class
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
return this.PUT$;
|
|
2458
|
-
case 'POST':
|
|
2459
|
-
return this.POST$;
|
|
2460
|
-
case 'DELETE':
|
|
2461
|
-
return this.DELETE$;
|
|
2462
|
-
case 'STREAM':
|
|
2463
|
-
return this.STREAM;
|
|
2464
|
-
case 'STREAM_AI':
|
|
2465
|
-
return this.STREAM_AI;
|
|
2466
|
-
default:
|
|
2467
|
-
return this.GET$;
|
|
2468
|
-
break;
|
|
2469
|
-
}
|
|
3564
|
+
class ClientInfoMapper {
|
|
3565
|
+
constructor(id = 0, first_name = '', last_name = '', email = '') {
|
|
3566
|
+
this.id = id;
|
|
3567
|
+
this.first_name = first_name;
|
|
3568
|
+
this.last_name = last_name;
|
|
3569
|
+
this.email = email;
|
|
2470
3570
|
}
|
|
2471
|
-
|
|
2472
|
-
|
|
3571
|
+
static adapt(item) {
|
|
3572
|
+
const first_name = (item?.name) ? item.name.split(' ')[0] : '';
|
|
3573
|
+
const last_name = (item?.name) ? item.name.split(' ')[1] : '';
|
|
3574
|
+
return new ClientInfoMapper(item?.id, first_name, last_name, item?.email);
|
|
2473
3575
|
}
|
|
2474
|
-
|
|
2475
|
-
|
|
3576
|
+
}
|
|
3577
|
+
|
|
3578
|
+
class AIPrompt {
|
|
3579
|
+
constructor(response = '') {
|
|
3580
|
+
this.response = response;
|
|
2476
3581
|
}
|
|
2477
|
-
|
|
2478
|
-
return
|
|
3582
|
+
static adapt(item) {
|
|
3583
|
+
return new AIPrompt(item?.response);
|
|
2479
3584
|
}
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
class RequestSignalsManagerDemoComponent {
|
|
2480
3588
|
get retry() {
|
|
2481
|
-
return this.requestForm.get(
|
|
3589
|
+
return this.requestForm.get('retry')?.value;
|
|
2482
3590
|
}
|
|
2483
3591
|
get headers() {
|
|
2484
3592
|
return this.requestForm.get('headers');
|
|
@@ -2488,32 +3596,42 @@ class RequestManagerStateDemoComponent {
|
|
|
2488
3596
|
return this.requestForm.valid;
|
|
2489
3597
|
}
|
|
2490
3598
|
constructor() {
|
|
2491
|
-
this.stateManagerDemoService = inject(StateManagerDemoService);
|
|
2492
3599
|
this.displayedColumns = ['id', 'name', 'lastName', 'age'];
|
|
2493
3600
|
this.fb = inject(FormBuilder);
|
|
2494
|
-
this.
|
|
2495
|
-
this.
|
|
2496
|
-
|
|
2497
|
-
this.
|
|
2498
|
-
this.
|
|
2499
|
-
|
|
2500
|
-
this.
|
|
2501
|
-
this.
|
|
2502
|
-
this.
|
|
2503
|
-
this.
|
|
2504
|
-
this.
|
|
2505
|
-
this.
|
|
2506
|
-
this.
|
|
2507
|
-
this.
|
|
2508
|
-
this.
|
|
2509
|
-
this.
|
|
2510
|
-
this.
|
|
2511
|
-
this.
|
|
2512
|
-
|
|
3601
|
+
this.toastMessage = inject(ToastMessageDisplayService);
|
|
3602
|
+
this.httpManagerSignalsService = inject(HTTPManagerSignalsService);
|
|
3603
|
+
// Using signals service: signals are callable in templates (e.g. isPending())
|
|
3604
|
+
this.isPending = this.httpManagerSignalsService.isPending;
|
|
3605
|
+
this.countdown = this.httpManagerSignalsService.countdown;
|
|
3606
|
+
// per-operation plain results and error messages (no rxjs in component)
|
|
3607
|
+
this.GET_result = null;
|
|
3608
|
+
this.POST_result = null;
|
|
3609
|
+
this.PUT_result = null;
|
|
3610
|
+
this.DELETE_result = null;
|
|
3611
|
+
this.STREAM_result = null;
|
|
3612
|
+
this.STREAM_AI_result = null;
|
|
3613
|
+
this.GET_error = '';
|
|
3614
|
+
this.POST_error = '';
|
|
3615
|
+
this.PUT_error = '';
|
|
3616
|
+
this.DELETE_error = '';
|
|
3617
|
+
this.STREAM_error = '';
|
|
3618
|
+
this.STREAM_AI_error = '';
|
|
3619
|
+
this.requestParams = {
|
|
3620
|
+
GET: ApiRequest.adapt(),
|
|
3621
|
+
POST: ApiRequest.adapt(),
|
|
3622
|
+
PUT: ApiRequest.adapt(),
|
|
3623
|
+
DELETE: ApiRequest.adapt(),
|
|
3624
|
+
STREAM: ApiRequest.adapt(),
|
|
3625
|
+
};
|
|
2513
3626
|
this.questionControl = this.fb.control("", [Validators.required]);
|
|
2514
|
-
this.
|
|
2515
|
-
|
|
2516
|
-
|
|
3627
|
+
this.downloadRequest = ApiRequest.adapt({
|
|
3628
|
+
server: 'assets/images',
|
|
3629
|
+
path: ['me.jpg'],
|
|
3630
|
+
// saveAs: 'john.jpg' // Optional
|
|
3631
|
+
});
|
|
3632
|
+
// downloadRequest = ApiRequest.adapt({
|
|
3633
|
+
// server: 'oidc/ai/file'
|
|
3634
|
+
// })
|
|
2517
3635
|
this.sampleClientData = {
|
|
2518
3636
|
id: 0,
|
|
2519
3637
|
name: "Old School Dates",
|
|
@@ -2525,10 +3643,9 @@ class RequestManagerStateDemoComponent {
|
|
|
2525
3643
|
modified: 1693003138,
|
|
2526
3644
|
icon: "",
|
|
2527
3645
|
imageFile: "",
|
|
3646
|
+
email: "wavecoders@gmail.com"
|
|
2528
3647
|
};
|
|
2529
|
-
this.selectedRecord = this.fb.control(null);
|
|
2530
3648
|
this.requestForm = this.fb.group({
|
|
2531
|
-
datatype: this.fb.control('ARRAY'),
|
|
2532
3649
|
path: this.fb.control("ai/"),
|
|
2533
3650
|
headers: this.fb.array([]),
|
|
2534
3651
|
adapter: [null],
|
|
@@ -2538,64 +3655,49 @@ class RequestManagerStateDemoComponent {
|
|
|
2538
3655
|
delay: [3],
|
|
2539
3656
|
}),
|
|
2540
3657
|
polling: [3],
|
|
2541
|
-
database: this.fb.group({
|
|
2542
|
-
table: [''],
|
|
2543
|
-
expiresIn: ['1m'],
|
|
2544
|
-
})
|
|
2545
3658
|
});
|
|
3659
|
+
this.AIType = 0;
|
|
2546
3660
|
this.sampleAdaptors = [
|
|
2547
3661
|
{ label: "ClientInfo Basic", value: ClientInfo.adapt },
|
|
2548
3662
|
{ label: "AI Prompt", value: AIPrompt.adapt },
|
|
2549
|
-
];
|
|
2550
|
-
this.sampleMappers = [
|
|
2551
|
-
{ label: "Mapper Basic", value: ClientInfoMapper.adapt },
|
|
2552
|
-
{ label: "AI Prompt", value: AIPrompt.adapt },
|
|
2553
|
-
];
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
this.
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
this.DELETE$.next(data);
|
|
2588
|
-
break;
|
|
2589
|
-
case 'STREAM':
|
|
2590
|
-
this.STREAM.next(data);
|
|
2591
|
-
break;
|
|
2592
|
-
case 'STREAM_AI':
|
|
2593
|
-
this.STREAM_AI.next(data);
|
|
2594
|
-
break;
|
|
2595
|
-
default:
|
|
2596
|
-
break;
|
|
2597
|
-
}
|
|
2598
|
-
})).subscribe();
|
|
3663
|
+
];
|
|
3664
|
+
this.sampleMappers = [
|
|
3665
|
+
{ label: "Mapper Basic", value: ClientInfoMapper.adapt },
|
|
3666
|
+
{ label: "AI Prompt", value: AIPrompt.adapt },
|
|
3667
|
+
];
|
|
3668
|
+
this.hasId = (arr) => {
|
|
3669
|
+
if (arr.length === 0)
|
|
3670
|
+
return false;
|
|
3671
|
+
return !isNaN(arr[arr.length - 1]);
|
|
3672
|
+
};
|
|
3673
|
+
this.props = (adapter) => {
|
|
3674
|
+
return (adapter) ? adapter() : null;
|
|
3675
|
+
};
|
|
3676
|
+
// server = `http://sample-endpoint/as/authorization.oauth2`
|
|
3677
|
+
this.arrayObjectsToObjects = (arr) => {
|
|
3678
|
+
return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
|
|
3679
|
+
};
|
|
3680
|
+
}
|
|
3681
|
+
ngOnInit() {
|
|
3682
|
+
// const reqGet2 = ApiRequest.adapt({
|
|
3683
|
+
// server,
|
|
3684
|
+
// path: ['clients'],
|
|
3685
|
+
// headers: { authentication: "Bearer <KEY>" },
|
|
3686
|
+
// adapter: ClientInfo,
|
|
3687
|
+
// dataType: DataType.OBJECT,
|
|
3688
|
+
// // concurrent: false,
|
|
3689
|
+
// // polling: 3, //seconds
|
|
3690
|
+
// })
|
|
3691
|
+
// const req2 = [1024,1025,1026].map(item => {
|
|
3692
|
+
// return this.httpManagerService.getRequest<ClientInfo[]>(reqGet2, [item])
|
|
3693
|
+
// .pipe(
|
|
3694
|
+
// catchError(error => {
|
|
3695
|
+
// return throwError(() => new Error(error.error.message))
|
|
3696
|
+
// })
|
|
3697
|
+
// )
|
|
3698
|
+
// })
|
|
3699
|
+
// forkJoin(req2)
|
|
3700
|
+
// .subscribe(res => console.log(res))
|
|
2599
3701
|
}
|
|
2600
3702
|
addHeader() {
|
|
2601
3703
|
const header = this.fb.group({
|
|
@@ -2616,77 +3718,178 @@ class RequestManagerStateDemoComponent {
|
|
|
2616
3718
|
if (!this.failedState.checked) {
|
|
2617
3719
|
requestParams.retry = { times: 0, delay: 0 };
|
|
2618
3720
|
}
|
|
2619
|
-
const
|
|
2620
|
-
|
|
2621
|
-
const apiOptions = ApiRequest.adapt({ ...currentOptions, path: pathReq });
|
|
3721
|
+
const apiOptions = ApiRequest.adapt(requestParams);
|
|
3722
|
+
apiOptions.path = [];
|
|
2622
3723
|
return { apiOptions: apiOptions, path: pathReq };
|
|
2623
3724
|
}
|
|
2624
|
-
|
|
3725
|
+
onGetRequest() {
|
|
2625
3726
|
if (!this.isValid)
|
|
2626
3727
|
return;
|
|
2627
3728
|
const reqParams = this.compileRequest();
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
this.
|
|
2631
|
-
this.
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
this.stateManagerDemoService.refreshData();
|
|
2638
|
-
}
|
|
2639
|
-
onGetRequest() {
|
|
2640
|
-
this.requestType = 'GET';
|
|
2641
|
-
this.stateManagerDemoService.getClients();
|
|
3729
|
+
this.requestParams.GET = reqParams.apiOptions;
|
|
3730
|
+
// reset local state
|
|
3731
|
+
this.GET_result = null;
|
|
3732
|
+
this.GET_error = '';
|
|
3733
|
+
this.httpManagerSignalsService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
3734
|
+
.subscribe({
|
|
3735
|
+
next: (res) => this.GET_result = res,
|
|
3736
|
+
error: (err) => this.errorHandling(err, 'GET')
|
|
3737
|
+
});
|
|
2642
3738
|
}
|
|
2643
3739
|
onCreateRequest() {
|
|
2644
|
-
this.
|
|
2645
|
-
|
|
3740
|
+
if (!this.isValid)
|
|
3741
|
+
return;
|
|
3742
|
+
const reqParams = this.compileRequest();
|
|
3743
|
+
this.requestParams.POST = reqParams.apiOptions;
|
|
3744
|
+
// reset local state
|
|
3745
|
+
this.POST_result = null;
|
|
3746
|
+
this.POST_error = '';
|
|
3747
|
+
this.httpManagerSignalsService.postRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
|
|
3748
|
+
.subscribe({
|
|
3749
|
+
next: (res) => this.POST_result = res,
|
|
3750
|
+
error: (err) => this.errorHandling(err, 'POST')
|
|
3751
|
+
});
|
|
2646
3752
|
}
|
|
2647
3753
|
onUpdateRequest() {
|
|
2648
|
-
this.
|
|
2649
|
-
|
|
3754
|
+
if (!this.isValid)
|
|
3755
|
+
return;
|
|
3756
|
+
const reqParams = this.compileRequest();
|
|
3757
|
+
if (!this.hasId(reqParams.path)) {
|
|
3758
|
+
console.log("Missing ID");
|
|
3759
|
+
return;
|
|
3760
|
+
}
|
|
3761
|
+
this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
|
|
3762
|
+
this.requestParams.PUT = reqParams.apiOptions;
|
|
3763
|
+
// reset local state
|
|
3764
|
+
this.PUT_result = null;
|
|
3765
|
+
this.PUT_error = '';
|
|
3766
|
+
this.httpManagerSignalsService.putRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
|
|
3767
|
+
.subscribe({
|
|
3768
|
+
next: (res) => this.PUT_result = res,
|
|
3769
|
+
error: (err) => this.errorHandling(err, 'PUT')
|
|
3770
|
+
});
|
|
2650
3771
|
}
|
|
2651
3772
|
onDeleteRequest() {
|
|
2652
|
-
this.
|
|
2653
|
-
|
|
3773
|
+
if (!this.isValid)
|
|
3774
|
+
return;
|
|
3775
|
+
const reqParams = this.compileRequest();
|
|
3776
|
+
this.requestParams.DELETE = reqParams.apiOptions;
|
|
3777
|
+
if (!this.hasId(reqParams.path)) {
|
|
3778
|
+
console.log("Missing ID");
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3781
|
+
this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
|
|
3782
|
+
this.requestParams.DELETE = reqParams.apiOptions;
|
|
3783
|
+
// reset local state
|
|
3784
|
+
this.DELETE_result = null;
|
|
3785
|
+
this.DELETE_error = '';
|
|
3786
|
+
this.httpManagerSignalsService.deleteRequest(reqParams.apiOptions, reqParams.path)
|
|
3787
|
+
.subscribe({
|
|
3788
|
+
next: (res) => this.DELETE_result = res,
|
|
3789
|
+
error: (err) => this.errorHandling(err, 'DELETE')
|
|
3790
|
+
});
|
|
3791
|
+
}
|
|
3792
|
+
onStreamPostRequest() {
|
|
3793
|
+
if (!this.isValid)
|
|
3794
|
+
return;
|
|
3795
|
+
const reqParams = this.compileRequest();
|
|
3796
|
+
let payload = {};
|
|
3797
|
+
let apiPath = reqParams.path;
|
|
3798
|
+
let apiOptions = reqParams.apiOptions;
|
|
3799
|
+
let responseMapper = (items) => items.response;
|
|
3800
|
+
if (this.AIType === 0) {
|
|
3801
|
+
// API request
|
|
3802
|
+
payload = { prompt: this.questionControl.value };
|
|
3803
|
+
}
|
|
3804
|
+
else {
|
|
3805
|
+
// Local Ollama request
|
|
3806
|
+
apiOptions.server = "api";
|
|
3807
|
+
apiPath = ["generate"];
|
|
3808
|
+
apiOptions.stream = true;
|
|
3809
|
+
payload = {
|
|
3810
|
+
model: "phi3:latest",
|
|
3811
|
+
prompt: this.questionControl.value,
|
|
3812
|
+
stream: true,
|
|
3813
|
+
};
|
|
3814
|
+
responseMapper = (items) => items.map((word) => word.response).flat().join('');
|
|
3815
|
+
}
|
|
3816
|
+
this.requestParams.STREAM = apiOptions;
|
|
3817
|
+
this.STREAM_AI_result = null;
|
|
3818
|
+
this.STREAM_AI_error = '';
|
|
3819
|
+
this.httpManagerSignalsService.postRequest(payload, apiOptions, apiPath)
|
|
3820
|
+
.subscribe({
|
|
3821
|
+
next: (res) => {
|
|
3822
|
+
try {
|
|
3823
|
+
this.STREAM_AI_result = responseMapper(res);
|
|
3824
|
+
}
|
|
3825
|
+
catch (e) {
|
|
3826
|
+
this.STREAM_AI_result = res;
|
|
3827
|
+
}
|
|
3828
|
+
this.questionControl.reset();
|
|
3829
|
+
},
|
|
3830
|
+
error: (err) => this.errorHandling(err, 'STREAM')
|
|
3831
|
+
});
|
|
2654
3832
|
}
|
|
2655
3833
|
onStreamRequest() {
|
|
2656
3834
|
if (!this.isValid)
|
|
2657
3835
|
return;
|
|
2658
3836
|
const reqParams = this.compileRequest();
|
|
2659
3837
|
reqParams.apiOptions.stream = true;
|
|
2660
|
-
this.
|
|
2661
|
-
this.
|
|
3838
|
+
this.requestParams.GET = reqParams.apiOptions;
|
|
3839
|
+
this.STREAM_result = null;
|
|
3840
|
+
this.STREAM_error = '';
|
|
3841
|
+
this.httpManagerSignalsService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
3842
|
+
.subscribe({
|
|
3843
|
+
next: (res) => this.STREAM_result = res,
|
|
3844
|
+
error: (err) => this.errorHandling(err, 'STREAM')
|
|
3845
|
+
});
|
|
3846
|
+
}
|
|
3847
|
+
onDownloadCompleted() {
|
|
3848
|
+
const message = "Download Completed";
|
|
3849
|
+
const display = ToastDisplay.adapt({
|
|
3850
|
+
message,
|
|
3851
|
+
action: 'Ok',
|
|
3852
|
+
color: ToastColors.SUCCESS,
|
|
3853
|
+
icon: 'sentiment_satisfied_alt',
|
|
3854
|
+
});
|
|
3855
|
+
this.toastMessage.toastMessage(display);
|
|
3856
|
+
}
|
|
3857
|
+
onDownloadFailed(err) {
|
|
3858
|
+
const message = "Download Failed";
|
|
3859
|
+
const display = ToastDisplay.adapt({
|
|
3860
|
+
message,
|
|
3861
|
+
action: 'Ok',
|
|
3862
|
+
color: ToastColors.ERROR,
|
|
3863
|
+
icon: 'warning',
|
|
3864
|
+
});
|
|
3865
|
+
this.toastMessage.toastMessage(display);
|
|
2662
3866
|
}
|
|
2663
3867
|
errorHandling(err, type) {
|
|
2664
|
-
|
|
3868
|
+
const message = err?.message || String(err);
|
|
3869
|
+
// set local error state
|
|
2665
3870
|
if (type === 'GET')
|
|
2666
|
-
this.GET_error
|
|
3871
|
+
this.GET_error = message;
|
|
2667
3872
|
if (type === 'POST')
|
|
2668
|
-
this.POST_error
|
|
3873
|
+
this.POST_error = message;
|
|
2669
3874
|
if (type === 'PUT')
|
|
2670
|
-
this.PUT_error
|
|
3875
|
+
this.PUT_error = message;
|
|
2671
3876
|
if (type === 'DELETE')
|
|
2672
|
-
this.DELETE_error
|
|
3877
|
+
this.DELETE_error = message;
|
|
2673
3878
|
if (type === 'STREAM')
|
|
2674
|
-
this.STREAM_error
|
|
2675
|
-
|
|
2676
|
-
|
|
3879
|
+
this.STREAM_error = message;
|
|
3880
|
+
// also set the shared service error signal
|
|
3881
|
+
this.httpManagerSignalsService.error.set(message);
|
|
3882
|
+
return err;
|
|
2677
3883
|
}
|
|
2678
3884
|
onSelectAIType(type) {
|
|
2679
3885
|
this.AIType = type;
|
|
2680
3886
|
}
|
|
2681
|
-
|
|
2682
|
-
this.prompts = [];
|
|
2683
|
-
}
|
|
2684
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerStateDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2685
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", 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\" #adapterSelect>\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\" #mapperSelect>\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\n <div style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\n </div>\n\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 }}\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.name || (item.first_name) | titlecase}}\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()\" [disabled]=\"hasChanged\">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 *ngIf=\"(GET$ | async) as getData\">{{ getData | 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 *ngIf=\"(POST$ | async) as postData\">{{ postData | 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 *ngIf=\"(PUT$ | async) as putData\">{{ putData | 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 *ngIf=\"(DELETE$ | async) as deleteData\">{{ deleteData | 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()\" class=\"btn\" [disabled]=\"hasChanged\">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>\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}.box{padding:10px;border:1px solid #ccc}\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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i10.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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" }, { kind: "pipe", type: i1$1.TitleCasePipe, name: "titlecase" }] }); }
|
|
3887
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestSignalsManagerDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3888
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: RequestSignalsManagerDemoComponent, selector: "app-request-signals-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 <span>HTTP Request Signals Manager</span>\n <span style=\"margin-left: .5rem;\">\n <mat-icon color=\"accent\">fiber_new</mat-icon>\n </span>\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\" #adapterSelect>\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\" #mapperSelect>\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 style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\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()\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !isPending()\"\n [value]=\"countdown()\"\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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ GET_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"GET_result\">\n {{ GET_result | 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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ POST_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"POST_result\">\n {{ POST_result | 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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ PUT_error }}</mat-error>\n </div>\n\n <h3>Include Record ID in the RestPath</h3>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"PUT_result\">\n {{ PUT_result | 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 <h3>Include Record ID in the RestPath</h3>\n\n <div *ngIf=\"DELETE_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ DELETE_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"DELETE_result\">\n {{ DELETE_result | 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_result 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; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ STREAM_AI_error }}</mat-error>\n </div>\n\n <div *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"STREAM_AI_result\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{STREAM_AI_result}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\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}.box{padding:10px;border:1px solid #ccc}\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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i10.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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", "saveFileAs", "labels", "disabled"], outputs: ["completed", "failed"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
|
|
2686
3889
|
}
|
|
2687
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
3890
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestSignalsManagerDemoComponent, decorators: [{
|
|
2688
3891
|
type: Component,
|
|
2689
|
-
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\" #adapterSelect>\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\" #mapperSelect>\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\n <div style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\n </div>\n\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 }}\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.name || (item.first_name) | titlecase}}\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()\" [disabled]=\"hasChanged\">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 *ngIf=\"(GET$ | async) as getData\">{{ getData | 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 *ngIf=\"(POST$ | async) as postData\">{{ postData | 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 *ngIf=\"(PUT$ | async) as putData\">{{ putData | 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 *ngIf=\"(DELETE$ | async) as deleteData\">{{ deleteData | 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()\" class=\"btn\" [disabled]=\"hasChanged\">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>\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}.box{padding:10px;border:1px solid #ccc}\n"] }]
|
|
3892
|
+
args: [{ selector: 'app-request-signals-manager-demo', template: "<div style=\"margin: 2rem;\">\n\n <h2>\n <span>HTTP Request Signals Manager</span>\n <span style=\"margin-left: .5rem;\">\n <mat-icon color=\"accent\">fiber_new</mat-icon>\n </span>\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\" #adapterSelect>\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\" #mapperSelect>\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 style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\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()\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !isPending()\"\n [value]=\"countdown()\"\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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ GET_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"GET_result\">\n {{ GET_result | 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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ POST_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"POST_result\">\n {{ POST_result | 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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ PUT_error }}</mat-error>\n </div>\n\n <h3>Include Record ID in the RestPath</h3>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"PUT_result\">\n {{ PUT_result | 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 <h3>Include Record ID in the RestPath</h3>\n\n <div *ngIf=\"DELETE_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ DELETE_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"DELETE_result\">\n {{ DELETE_result | 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_result 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; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\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\" style=\"margin-top: .5rem;\">\n <mat-error>{{ STREAM_AI_error }}</mat-error>\n </div>\n\n <div *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"STREAM_AI_result\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{STREAM_AI_result}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\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}.box{padding:10px;border:1px solid #ccc}\n"] }]
|
|
2690
3893
|
}], ctorParameters: () => [], propDecorators: { failedState: [{
|
|
2691
3894
|
type: ViewChild,
|
|
2692
3895
|
args: ["failedState", { static: true }]
|
|
@@ -2695,7 +3898,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
2695
3898
|
args: ["pollingState", { static: true }]
|
|
2696
3899
|
}] } });
|
|
2697
3900
|
|
|
2698
|
-
class
|
|
3901
|
+
class LocalStorageSignalsDemoComponent {
|
|
3902
|
+
// store type is driven by the form control
|
|
2699
3903
|
get type() {
|
|
2700
3904
|
return (this.typeControl.value) ? +this.typeControl.value : 0;
|
|
2701
3905
|
}
|
|
@@ -2705,15 +3909,33 @@ class LocalStorageDemoComponent {
|
|
|
2705
3909
|
get isValidData() {
|
|
2706
3910
|
return this.storageForm.valid;
|
|
2707
3911
|
}
|
|
3912
|
+
settingFor(name) {
|
|
3913
|
+
const c = this.localStorageManagerService.setting(name);
|
|
3914
|
+
return c ? c() : null;
|
|
3915
|
+
}
|
|
2708
3916
|
constructor(configOptions) {
|
|
2709
3917
|
this.configOptions = configOptions;
|
|
2710
3918
|
this.fb = inject(FormBuilder);
|
|
2711
3919
|
this.utils = inject(UtilsService);
|
|
2712
|
-
this.type$ = new BehaviorSubject(StorageType.GLOBAL);
|
|
2713
3920
|
this.typeControl = this.fb.control(StorageType.GLOBAL.toString());
|
|
2714
|
-
this.localStorageManagerService = inject(
|
|
2715
|
-
|
|
2716
|
-
this.
|
|
3921
|
+
this.localStorageManagerService = inject(LocalStorageSignalsManagerService);
|
|
3922
|
+
// Use signals directly and computed values for template binding
|
|
3923
|
+
this.settings = computed(() => this.localStorageManagerService.settings());
|
|
3924
|
+
// selected store (signal) and its JSON data for template
|
|
3925
|
+
this.storeSelected = signal(null);
|
|
3926
|
+
this.selectedStoreData = computed(() => {
|
|
3927
|
+
const s = this.storeSelected();
|
|
3928
|
+
if (!s)
|
|
3929
|
+
return '';
|
|
3930
|
+
const computed = this.localStorageManagerService.store(s.name);
|
|
3931
|
+
return computed ? JSON.stringify(computed()) : '';
|
|
3932
|
+
});
|
|
3933
|
+
// filtered settings by selected type
|
|
3934
|
+
this.selectedType = signal(StorageType.GLOBAL);
|
|
3935
|
+
this.filteredSettings = computed(() => {
|
|
3936
|
+
const values = this.settings() || [];
|
|
3937
|
+
return values.filter((item) => item.options.storage === +this.selectedType());
|
|
3938
|
+
});
|
|
2717
3939
|
this.storageForm = this.fb.group({
|
|
2718
3940
|
store: this.fb.control(null),
|
|
2719
3941
|
type: 'local',
|
|
@@ -2728,14 +3950,7 @@ class LocalStorageDemoComponent {
|
|
|
2728
3950
|
data: this.fb.control('', Validators.required),
|
|
2729
3951
|
expiresIn: this.fb.control('0')
|
|
2730
3952
|
});
|
|
2731
|
-
|
|
2732
|
-
.pipe(switchMap((data) => {
|
|
2733
|
-
return data
|
|
2734
|
-
? this.localStorageManagerService.store$(data.name)
|
|
2735
|
-
: of('');
|
|
2736
|
-
}), tap(data => {
|
|
2737
|
-
this.storageForm.get('data')?.patchValue(data, { emitEvent: false });
|
|
2738
|
-
}));
|
|
3953
|
+
// no RxJS Observables here; template uses signals/computed directly
|
|
2739
3954
|
this.expiresIn = (epoch) => this.utils.expiresIn(epoch);
|
|
2740
3955
|
this.isValidJSON = (str) => {
|
|
2741
3956
|
try {
|
|
@@ -2750,7 +3965,7 @@ class LocalStorageDemoComponent {
|
|
|
2750
3965
|
this.filterData = (values) => {
|
|
2751
3966
|
if (!values)
|
|
2752
3967
|
return [];
|
|
2753
|
-
return values.filter((item) => item.options.storage === +this.type);
|
|
3968
|
+
return values.filter((item) => item.options && item.options.storage === +this.type);
|
|
2754
3969
|
};
|
|
2755
3970
|
this.create = false;
|
|
2756
3971
|
}
|
|
@@ -2778,6 +3993,7 @@ class LocalStorageDemoComponent {
|
|
|
2778
3993
|
else {
|
|
2779
3994
|
this.newStoreForm.get('encrypted')?.enable();
|
|
2780
3995
|
}
|
|
3996
|
+
// nothing to synchronize - templates read computed signals directly
|
|
2781
3997
|
}
|
|
2782
3998
|
onCreateStore() {
|
|
2783
3999
|
if (!this.isValid)
|
|
@@ -2807,7 +4023,7 @@ class LocalStorageDemoComponent {
|
|
|
2807
4023
|
}
|
|
2808
4024
|
onSelectedRow(store) {
|
|
2809
4025
|
this.store = store;
|
|
2810
|
-
this.
|
|
4026
|
+
this.storeSelected.set(store);
|
|
2811
4027
|
this.create = false;
|
|
2812
4028
|
}
|
|
2813
4029
|
onCreate() {
|
|
@@ -2821,7 +4037,7 @@ class LocalStorageDemoComponent {
|
|
|
2821
4037
|
this.onCancel();
|
|
2822
4038
|
}
|
|
2823
4039
|
onCancel() {
|
|
2824
|
-
this.
|
|
4040
|
+
this.storeSelected.set(null);
|
|
2825
4041
|
this.store = null;
|
|
2826
4042
|
this.create = false;
|
|
2827
4043
|
}
|
|
@@ -2835,70 +4051,27 @@ class LocalStorageDemoComponent {
|
|
|
2835
4051
|
onReset() {
|
|
2836
4052
|
this.localStorageManagerService.resetStore();
|
|
2837
4053
|
}
|
|
2838
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
2839
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", 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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i10$1.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i10$1.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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 }); }
|
|
4054
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageSignalsDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4055
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: LocalStorageSignalsDemoComponent, selector: "app-local-storage-signals-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;\">\n <span>Local Storage Manager</span>\n <span style=\"margin-left: .5rem;\">\n <mat-icon color=\"accent\">fiber_new</mat-icon>\n </span>\n </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() | json }}\n <div *ngIf=\"filterData(settings()) 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=\"storeSelected() as selectedStore\" 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;\">{{ selectedStore.name | uppercase }}</span></h3>\n <h3>SETTINGS: {{ localStorageManagerService.setting(selectedStore.name) ? (localStorageManagerService.setting(selectedStore.name)() | 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]=\"selectedStoreData()\"></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(selectedStore, 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] ", exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button]", 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: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i10$1.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i10$1.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.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.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
2840
4056
|
}
|
|
2841
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type:
|
|
4057
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageSignalsDemoComponent, decorators: [{
|
|
2842
4058
|
type: Component,
|
|
2843
|
-
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
|
|
4059
|
+
args: [{ selector: 'app-local-storage-signals-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;\">\n <span>Local Storage Manager</span>\n <span style=\"margin-left: .5rem;\">\n <mat-icon color=\"accent\">fiber_new</mat-icon>\n </span>\n </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() | json }}\n <div *ngIf=\"filterData(settings()) 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=\"storeSelected() as selectedStore\" 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;\">{{ selectedStore.name | uppercase }}</span></h3>\n <h3>SETTINGS: {{ localStorageManagerService.setting(selectedStore.name) ? (localStorageManagerService.setting(selectedStore.name)() | 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]=\"selectedStoreData()\"></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(selectedStore, 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"] }]
|
|
2844
4060
|
}], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
|
|
2845
4061
|
type: Inject,
|
|
2846
4062
|
args: [CONFIG_SETTINGS_TOKEN]
|
|
2847
4063
|
}] }] });
|
|
2848
4064
|
|
|
2849
|
-
const PROXY_CONFIG = new InjectionToken('PROXY_CONFIG');
|
|
2850
|
-
class ProxyDebuggerInterceptor {
|
|
2851
|
-
constructor(proxyConfig) {
|
|
2852
|
-
this.proxyConfig = proxyConfig;
|
|
2853
|
-
}
|
|
2854
|
-
intercept(req, next) {
|
|
2855
|
-
if (!this.proxyConfig) {
|
|
2856
|
-
return next.handle(req);
|
|
2857
|
-
}
|
|
2858
|
-
const headers = req.headers.keys().reduce((acc, key) => {
|
|
2859
|
-
acc[key] = req.headers.get(key) || '';
|
|
2860
|
-
return acc;
|
|
2861
|
-
}, {});
|
|
2862
|
-
for (const proxyPath in this.proxyConfig) {
|
|
2863
|
-
if (this.proxyConfig.hasOwnProperty(proxyPath)) {
|
|
2864
|
-
const proxyDetails = this.proxyConfig[proxyPath];
|
|
2865
|
-
const regex = new RegExp('^' + proxyPath.replace('/', '').replace('*', '(.*)'));
|
|
2866
|
-
if (regex.test(req.url)) {
|
|
2867
|
-
const target = proxyDetails.target;
|
|
2868
|
-
const endpoint = req.url.replace(regex, '$1');
|
|
2869
|
-
const actualPath = target + '/' + endpoint;
|
|
2870
|
-
console.log('Request Proxied:', {
|
|
2871
|
-
requestUrl: req.url,
|
|
2872
|
-
requestPayload: req.body,
|
|
2873
|
-
headers: headers,
|
|
2874
|
-
proxyPath: proxyPath,
|
|
2875
|
-
actualPath: actualPath,
|
|
2876
|
-
});
|
|
2877
|
-
}
|
|
2878
|
-
}
|
|
2879
|
-
}
|
|
2880
|
-
return next.handle(req);
|
|
2881
|
-
}
|
|
2882
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor, deps: [{ token: PROXY_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2883
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor }); }
|
|
2884
|
-
}
|
|
2885
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor, decorators: [{
|
|
2886
|
-
type: Injectable
|
|
2887
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
2888
|
-
type: Optional
|
|
2889
|
-
}, {
|
|
2890
|
-
type: Inject,
|
|
2891
|
-
args: [PROXY_CONFIG]
|
|
2892
|
-
}] }] });
|
|
2893
|
-
|
|
2894
4065
|
class HttpRequestServicesDemoComponent {
|
|
2895
4066
|
constructor(configOptions) {
|
|
2896
4067
|
this.configOptions = configOptions;
|
|
2897
4068
|
this.requestTypes = [
|
|
2898
4069
|
{ name: "Http Service", value: 'http_service' },
|
|
4070
|
+
{ name: "Http Signals Service", value: 'http_signals_service', new: true },
|
|
2899
4071
|
{ name: "Http State Service", value: 'http_state_service' },
|
|
2900
4072
|
{ name: "Database Service", value: 'database_service', divider: true, disabled: true },
|
|
2901
4073
|
{ name: "Local Storage Service", value: 'local_storage_service' },
|
|
4074
|
+
{ name: "Local Signals Storage Service", value: 'local_storage_signals_service', new: true },
|
|
2902
4075
|
];
|
|
2903
4076
|
this.selectedService = this.requestTypes[0].value;
|
|
2904
4077
|
}
|
|
@@ -2910,11 +4083,11 @@ class HttpRequestServicesDemoComponent {
|
|
|
2910
4083
|
this.selectedService = this.requestTypes[type].value;
|
|
2911
4084
|
}
|
|
2912
4085
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HttpRequestServicesDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2913
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: HttpRequestServicesDemoComponent, selector: "app-http-request-services-demo", ngImport: i0, template: "<mat-toolbar style=\"display:flex\">\n <div>Http Request Manager Services</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] ", exportAs: ["matButton"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: i5$1.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { 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" }] }); }
|
|
4086
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: HttpRequestServicesDemoComponent, selector: "app-http-request-services-demo", ngImport: i0, template: "<mat-toolbar style=\"display:flex\">\n <div>Http Request Manager Services</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_signals_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-signals-manager-demo></app-request-signals-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 *ngSwitchCase=\"'local_storage_signals_service'\">\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-signals-demo></app-local-storage-signals-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] ", exportAs: ["matButton"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: i5$1.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo" }, { kind: "component", type: RequestManagerDemoComponent, selector: "app-request-manager-demo" }, { kind: "component", type: RequestSignalsManagerDemoComponent, selector: "app-request-signals-manager-demo" }, { kind: "component", type: LocalStorageDemoComponent, selector: "app-local-storage-demo" }, { kind: "component", type: LocalStorageSignalsDemoComponent, selector: "app-local-storage-signals-demo" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
|
|
2914
4087
|
}
|
|
2915
4088
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HttpRequestServicesDemoComponent, decorators: [{
|
|
2916
4089
|
type: Component,
|
|
2917
|
-
args: [{ selector: 'app-http-request-services-demo', template: "<mat-toolbar style=\"display:flex\">\n <div>Http Request Manager Services</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"] }]
|
|
4090
|
+
args: [{ selector: 'app-http-request-services-demo', template: "<mat-toolbar style=\"display:flex\">\n <div>Http Request Manager Services</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_signals_service'\">\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-signals-manager-demo></app-request-signals-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 *ngSwitchCase=\"'local_storage_signals_service'\">\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-signals-demo></app-local-storage-signals-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"] }]
|
|
2918
4091
|
}], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
|
|
2919
4092
|
type: Inject,
|
|
2920
4093
|
args: [CONFIG_SETTINGS_TOKEN]
|
|
@@ -2993,9 +4166,9 @@ class HttpRequestManagerModule {
|
|
|
2993
4166
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: HttpRequestManagerModule, declarations: [HttpRequestServicesDemoComponent,
|
|
2994
4167
|
RequestManagerStateDemoComponent,
|
|
2995
4168
|
RequestManagerDemoComponent,
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
4169
|
+
RequestSignalsManagerDemoComponent,
|
|
4170
|
+
LocalStorageDemoComponent,
|
|
4171
|
+
LocalStorageSignalsDemoComponent], imports: [CommonModule,
|
|
2999
4172
|
ToastMessageDisplayModule,
|
|
3000
4173
|
FormsModule,
|
|
3001
4174
|
ReactiveFormsModule,
|
|
@@ -3014,7 +4187,19 @@ class HttpRequestManagerModule {
|
|
|
3014
4187
|
MatInputModule,
|
|
3015
4188
|
MatToolbarModule,
|
|
3016
4189
|
MatSlideToggleModule, i1.TranslateModule, MatSidenavModule,
|
|
3017
|
-
FileDownloaderModule], exports: [HttpRequestServicesDemoComponent
|
|
4190
|
+
FileDownloaderModule], exports: [HttpRequestServicesDemoComponent,
|
|
4191
|
+
// Re-export commonly used modules so demo component templates have access to
|
|
4192
|
+
// Angular common pipes and Material components when the library is imported.
|
|
4193
|
+
CommonModule,
|
|
4194
|
+
MatButtonToggleModule,
|
|
4195
|
+
MatFormFieldModule,
|
|
4196
|
+
MatSelectModule,
|
|
4197
|
+
MatInputModule,
|
|
4198
|
+
MatIconModule,
|
|
4199
|
+
MatTableModule,
|
|
4200
|
+
MatSlideToggleModule,
|
|
4201
|
+
MatProgressBarModule,
|
|
4202
|
+
MatDividerModule] }); }
|
|
3018
4203
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HttpRequestManagerModule, providers: [
|
|
3019
4204
|
{ provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
|
|
3020
4205
|
{ provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
|
|
@@ -3042,7 +4227,19 @@ class HttpRequestManagerModule {
|
|
|
3042
4227
|
MatSlideToggleModule,
|
|
3043
4228
|
TranslateModule.forRoot(),
|
|
3044
4229
|
MatSidenavModule,
|
|
3045
|
-
FileDownloaderModule
|
|
4230
|
+
FileDownloaderModule,
|
|
4231
|
+
// Re-export commonly used modules so demo component templates have access to
|
|
4232
|
+
// Angular common pipes and Material components when the library is imported.
|
|
4233
|
+
CommonModule,
|
|
4234
|
+
MatButtonToggleModule,
|
|
4235
|
+
MatFormFieldModule,
|
|
4236
|
+
MatSelectModule,
|
|
4237
|
+
MatInputModule,
|
|
4238
|
+
MatIconModule,
|
|
4239
|
+
MatTableModule,
|
|
4240
|
+
MatSlideToggleModule,
|
|
4241
|
+
MatProgressBarModule,
|
|
4242
|
+
MatDividerModule] }); }
|
|
3046
4243
|
}
|
|
3047
4244
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HttpRequestManagerModule, decorators: [{
|
|
3048
4245
|
type: NgModule,
|
|
@@ -3075,11 +4272,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
3075
4272
|
HttpRequestServicesDemoComponent,
|
|
3076
4273
|
RequestManagerStateDemoComponent,
|
|
3077
4274
|
RequestManagerDemoComponent,
|
|
3078
|
-
|
|
4275
|
+
RequestSignalsManagerDemoComponent,
|
|
4276
|
+
LocalStorageDemoComponent,
|
|
4277
|
+
LocalStorageSignalsDemoComponent,
|
|
3079
4278
|
// DatabaseDataDemoComponent,
|
|
3080
4279
|
],
|
|
3081
4280
|
exports: [
|
|
3082
4281
|
HttpRequestServicesDemoComponent,
|
|
4282
|
+
// Re-export commonly used modules so demo component templates have access to
|
|
4283
|
+
// Angular common pipes and Material components when the library is imported.
|
|
4284
|
+
CommonModule,
|
|
4285
|
+
MatButtonToggleModule,
|
|
4286
|
+
MatFormFieldModule,
|
|
4287
|
+
MatSelectModule,
|
|
4288
|
+
MatInputModule,
|
|
4289
|
+
MatIconModule,
|
|
4290
|
+
MatTableModule,
|
|
4291
|
+
MatSlideToggleModule,
|
|
4292
|
+
MatProgressBarModule,
|
|
4293
|
+
MatDividerModule,
|
|
3083
4294
|
],
|
|
3084
4295
|
providers: [
|
|
3085
4296
|
{ provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
|
|
@@ -3440,5 +4651,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
3440
4651
|
* Generated bundle index. Do not edit.
|
|
3441
4652
|
*/
|
|
3442
4653
|
|
|
3443
|
-
export { ApiRequest, AppService, AsymmetricalEncryptionService, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseDataDemoComponent, DatabaseStorage, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerStateService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, LocalStorageDemoComponent, LocalStorageManagerService, LocalStorageOptions, PathQueryService, Random, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomSignature, RandomStr, RequestErrorInterceptor, RequestHeadersInterceptor, RequestManagerDemoComponent, RequestManagerStateDemoComponent, RequestOptions, RetryOptions, SettingOptions, StorageData, StorageOption, StorageType, SymmetricalEncryptionService, UUID, UtilsService, WithCredentialsInterceptor, countdown, delayedRetry, requestPolling, requestStreaming };
|
|
4654
|
+
export { ApiRequest, AppService, AsymmetricalEncryptionService, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseDataDemoComponent, DatabaseStorage, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerSignalsService, HTTPManagerStateService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, LocalStorageDemoComponent, LocalStorageManagerService, LocalStorageOptions, LocalStorageSignalsManagerService, PathQueryService, Random, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomSignature, RandomStr, RequestErrorInterceptor, RequestHeadersInterceptor, RequestManagerDemoComponent, RequestManagerStateDemoComponent, RequestOptions, RetryOptions, SettingOptions, StorageData, StorageOption, StorageType, SymmetricalEncryptionService, UUID, UtilsService, WithCredentialsInterceptor, countdown, delayedRetry, requestPolling, requestStreaming };
|
|
3444
4655
|
//# sourceMappingURL=http-request-manager.mjs.map
|