http-request-manager 18.1.1 → 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.
Files changed (24) hide show
  1. package/esm2022/lib/http-request-manager.module.mjs +4 -1
  2. package/esm2022/lib/http-request-services-demo/http-request-services-demo.component.mjs +10 -9
  3. package/esm2022/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.mjs +3 -3
  4. package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.mjs +9 -0
  5. package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.mjs +12 -0
  6. package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.mjs +14 -0
  7. package/esm2022/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.mjs +336 -0
  8. package/esm2022/lib/services/request-manager-services/http-manager-signals.service.mjs +199 -0
  9. package/esm2022/lib/services/request-manager-services/index.mjs +2 -1
  10. package/esm2022/lib/services/request-manager-services/request-signals.service.mjs +170 -0
  11. package/fesm2022/http-request-manager.mjs +1745 -1044
  12. package/fesm2022/http-request-manager.mjs.map +1 -1
  13. package/http-request-manager-18.2.0.tgz +0 -0
  14. package/lib/http-request-manager.module.d.ts +24 -23
  15. package/lib/http-request-services-demo/http-request-services-demo.component.d.ts +8 -0
  16. package/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.d.ts +8 -0
  17. package/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.d.ts +14 -0
  18. package/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.d.ts +14 -0
  19. package/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.d.ts +106 -0
  20. package/lib/services/request-manager-services/http-manager-signals.service.d.ts +38 -0
  21. package/lib/services/request-manager-services/index.d.ts +1 -0
  22. package/lib/services/request-manager-services/request-signals.service.d.ts +26 -0
  23. package/package.json +1 -1
  24. package/http-request-manager-18.1.1.tgz +0 -0
@@ -1197,171 +1197,521 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
1197
1197
  args: [CONFIG_SETTINGS_TOKEN]
1198
1198
  }] }] });
1199
1199
 
1200
- class ApiRequest {
1201
- constructor(server = '', path, headers, adapter, mapper, polling, retry, stream, displayError, saveAs) {
1202
- this.server = server;
1203
- this.path = path;
1204
- this.headers = headers;
1205
- this.adapter = adapter;
1206
- this.mapper = mapper;
1207
- this.polling = polling;
1208
- this.retry = retry;
1209
- this.stream = stream;
1210
- this.displayError = displayError;
1211
- 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());
1212
1208
  }
1213
- static adapt(item) {
1214
- const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
1215
- 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);
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());
1216
1216
  }
1217
- }
1218
-
1219
- class RequestOptions {
1220
- constructor(path = [], headers = {}) {
1221
- this.path = path;
1222
- this.headers = headers;
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());
1223
1224
  }
1224
- static adapt(item) {
1225
- return new RequestOptions(item?.path, item?.headers);
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());
1226
1230
  }
1227
- }
1228
-
1229
- class ObjectMergerService {
1230
- constructor(configOptions) {
1231
- this.configOptions = configOptions;
1232
- this.utils = inject(UtilsService);
1233
- if (!this.configOptions)
1234
- 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());
1235
1236
  }
1236
- mergeOptions(options = ApiRequest.adapt()) {
1237
- const configForRoot = (this.configOptions?.httpRequestOptions) ? this.configOptions.httpRequestOptions : ConfigHTTPOptions.adapt();
1238
- const mergedOptions = ApiRequest.adapt(options);
1239
- mergedOptions.server = (options && options.server === '') ? configForRoot?.server || '' : options.server;
1240
- mergedOptions.path = [...options.path || [], ...configForRoot?.path || []];
1241
- mergedOptions.headers = { ...options.headers || {}, ...configForRoot?.headers || {} };
1242
- mergedOptions.retry = (options && (options?.retry?.times !== 0 || options?.retry?.delay !== 3)) ? options.retry : configForRoot?.retry || { times: 0, delay: 3 };
1243
- mergedOptions.polling = (options && options?.polling !== 0) ? options.polling : configForRoot?.polling || 0;
1244
- mergedOptions.displayError = (options && options?.displayError) ? options.displayError : configForRoot?.displayError || false;
1245
- mergedOptions.stream = (options && options?.stream) ? options.stream : configForRoot?.stream || false;
1246
- return mergedOptions;
1237
+ buildUrlPath(options) {
1238
+ return this.pathQueryService.buildAPIPath(options.server, options.path);
1247
1239
  }
1248
- mergeStorageOptions(options = SettingOptions.adapt()) {
1249
- const configForRoot = (this.configOptions?.LocalStorageOptions) ? this.configOptions.LocalStorageOptions : LocalStorageOptions.adapt();
1250
- const configForRootOptions = configForRoot.options || LocalStorageOptions.adapt().options;
1251
- const mergedOptions = SettingOptions.adapt(options);
1252
- // storage type
1253
- mergedOptions.storage = (options && (typeof options.storage !== 'undefined')) ? options.storage : (configForRootOptions?.storage ?? 0);
1254
- // expires: prefer explicit numeric expires; if not provided, compute from expiresIn string; otherwise use config default
1255
- // if an explicit, non-zero numeric expires is provided, use it
1256
- if (options && (typeof options.expires !== 'undefined') && options.expires !== null && Number(options.expires) > 0) {
1257
- mergedOptions.expires = Number(options.expires);
1258
- }
1259
- else if (options && options.expiresIn) {
1260
- // compute numeric epoch from expiresIn string using UtilsService if available
1261
- try {
1262
- mergedOptions.expires = this.utils ? this.utils.expires(options.expiresIn) : 0;
1240
+ buildHeaders(options) {
1241
+ return this.headersService.generateHeaders(options.headers);
1242
+ }
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
+ }
1263
1270
  }
1264
- catch {
1265
- mergedOptions.expires = 0;
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;
1266
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);
1267
1310
  }
1268
1311
  else {
1269
- mergedOptions.expires = configForRootOptions?.expires ?? 0;
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);
1270
1318
  }
1271
- // keep expiresIn string if explicitly provided, otherwise use config default
1272
- mergedOptions.expiresIn = (options && (typeof options.expiresIn !== 'undefined')) ? options.expiresIn : (configForRootOptions?.expiresIn || '');
1273
- mergedOptions.encrypted = (options && (typeof options.encrypted !== 'undefined')) ? options.encrypted : (configForRootOptions?.encrypted || false);
1274
- return mergedOptions;
1275
1319
  }
1276
- 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 }); }
1277
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectMergerService, providedIn: 'root' }); }
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' }); }
1278
1355
  }
1279
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectMergerService, decorators: [{
1356
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestSignalsService, decorators: [{
1280
1357
  type: Injectable,
1281
1358
  args: [{
1282
1359
  providedIn: 'root'
1283
1360
  }]
1284
- }], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
1285
- type: Inject,
1286
- args: [CONFIG_SETTINGS_TOKEN]
1287
- }, {
1288
- type: Optional
1289
- }] }] });
1361
+ }] });
1290
1362
 
1291
- const storage = {
1292
- localStores: [],
1293
- sessionStores: [],
1294
- settings: [],
1295
- };
1296
- class LocalStorageManagerService extends ComponentStore {
1297
- startTimer() {
1298
- const timer$ = interval(1000 * 3).pipe(withLatestFrom(this.data$), map(([_, state]) => state), tap((state) => {
1299
- const expired = this.expired(state) ? this.expired(state) : [];
1300
- if (expired.length > 0) {
1301
- const ids = expired.map((item) => item.id);
1302
- const updatedState = {
1303
- ...state,
1304
- localStores: state.localStores.filter((item) => !ids.includes(item.id)),
1305
- sessionStores: state.sessionStores.filter((item) => !ids.includes(item.id)),
1306
- settings: state.settings.filter((item) => !ids.includes(item.id)),
1307
- };
1308
- this.persistState(updatedState);
1309
- this.updateState(updatedState);
1310
- }
1311
- }));
1312
- timer$.subscribe();
1313
- }
1363
+ class HTTPManagerSignalsService extends RequestSignalsService {
1314
1364
  constructor(configOptions) {
1315
- super(storage);
1365
+ super();
1316
1366
  this.configOptions = configOptions;
1317
- this.storageName = 'storage';
1318
- this.storageSettingsName = 'global-storage';
1319
- this.defaultOptions = SettingOptions.adapt();
1320
- this.stateRetrieved = false;
1321
- this.encrypted = false;
1322
- this.app = inject(AppService);
1323
- this.utils = inject(UtilsService);
1367
+ this.toastMessage = inject(ToastMessageDisplayService);
1368
+ this.ng_injector = inject(Injector);
1324
1369
  this.objectMergerService = inject(ObjectMergerService);
1325
- this.encryption = inject(SymmetricalEncryptionService);
1326
- this.encryptionTest = inject(EncryptionTestService);
1327
- // SELECTORS
1328
- this.data$ = this.select((state) => state);
1329
- this.stores$ = this.select((state) => state.settings);
1330
- this.storeExists$ = (store) => this.select(this.data$, (data) => data.settings.find(item => item.name === store) ? true : false);
1331
- this.store$ = (store) => this.select(this.data$, (data) => {
1332
- const foundStore = data.settings.find(item => item.name === store);
1333
- if (foundStore) {
1334
- const options = SettingOptions.adapt(foundStore.options);
1335
- const found = foundStore.options?.storage === StorageType.GLOBAL
1336
- ? data.localStores.find(item => item.id === foundStore.id)
1337
- : data.sessionStores.find(item => item.id === foundStore.id);
1338
- if (!found) {
1339
- this.deleteStore({ name: store });
1340
- return;
1341
- }
1342
- if (!this.app?.appID) {
1343
- console.warn('No App ID found - AppId not Provided');
1344
- return;
1345
- }
1346
- const storageData = (options.encrypted) ? this.encryption.decrypt(found.data, this.app.appID) : found.data;
1347
- return (this.isString(storageData)) ? JSON.parse(storageData) : storageData;
1348
- }
1349
- else {
1350
- return null;
1351
- }
1352
- });
1353
- this.settings$ = this.select(state => (state) ? state.settings : storage.settings);
1354
- this.setting$ = (store) => this.select(this.data$, (state) => {
1355
- const foundSetting = state.settings.find(item => item.name === store);
1356
- return (foundSetting) ? foundSetting : null;
1357
- });
1358
- this.persistence$ = this.data$
1359
- .subscribe(data => {
1360
- if (this.stateRetrieved)
1361
- this.persistState(data);
1362
- });
1363
- this.updateState = this.updater((state, updatedState) => ({
1364
- ...updatedState,
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) => ({
1714
+ ...updatedState,
1365
1715
  }));
1366
1716
  this.setStore = this.updater((state, store) => {
1367
1717
  const settings = StorageOption.adapt(store);
@@ -2033,380 +2383,760 @@ class HTTPManagerStateService extends ComponentStore {
2033
2383
  })));
2034
2384
  this.setApiRequestOptions(apiOptions, dataType, database);
2035
2385
  }
2036
- setApiRequestOptions(apiOptions, dataType, database) {
2037
- this.apiOptions = ApiRequest.adapt(apiOptions);
2038
- this.dataType = (dataType) ? dataType : DataType.ARRAY;
2039
- this.hasDatabase = this.database?.table === "" ? false : true;
2040
- this.database = (this.hasDatabase) ? DatabaseStorage.adapt(database) : undefined;
2386
+ setApiRequestOptions(apiOptions, dataType, database) {
2387
+ this.apiOptions = ApiRequest.adapt(apiOptions);
2388
+ this.dataType = (dataType) ? dataType : DataType.ARRAY;
2389
+ this.hasDatabase = this.database?.table === "" ? false : true;
2390
+ this.database = (this.hasDatabase) ? DatabaseStorage.adapt(database) : undefined;
2391
+ }
2392
+ get ApiRequestOptions() {
2393
+ return this.apiOptions;
2394
+ }
2395
+ initStorage() {
2396
+ // if(this.otherOptions.database) {
2397
+ // console.log('Has Database Option:', this.otherOptions.database.table)
2398
+ // const schema = (this.otherOptions.adapters?.incoming) ? Object.keys(this.otherOptions.adapters.incoming({})).join() : '++id'
2399
+ // this.apiService.initDB(this.otherOptions.database.expiresIn, this.otherOptions.database.table, schema)
2400
+ // }
2401
+ }
2402
+ initializeState(data) {
2403
+ this.setData$(data);
2404
+ }
2405
+ updateArrayState(currentData, newData) {
2406
+ const filterCurrentData = () => {
2407
+ const ids = this.streamedResponse.map((obj) => obj.id);
2408
+ return currentData.filter(obj => (obj.id) ? ids.includes(obj.id) : obj);
2409
+ };
2410
+ const filteredCurrentData = (this.httpManagerService.isPending.value) ? currentData : filterCurrentData();
2411
+ const updatedData = filteredCurrentData.map(item => {
2412
+ const newItem = newData.find(newItem => {
2413
+ const hasId = (newItem?.id && item?.id) ? true : false;
2414
+ return (hasId) ? newItem.id === item.id : JSON.stringify(newItem) === JSON.stringify(item);
2415
+ });
2416
+ return (newItem) ? { ...item, ...newItem } : item;
2417
+ });
2418
+ const addedData = newData.filter(newItem => {
2419
+ return !filteredCurrentData.some(item => {
2420
+ const hasId = (newItem?.id && item?.id) ? true : false;
2421
+ return (hasId) ? item.id === newItem.id : JSON.stringify(newItem) === JSON.stringify(item);
2422
+ });
2423
+ });
2424
+ return [...updatedData, ...addedData];
2425
+ }
2426
+ // --------------------------------------------------------------------------------------------------
2427
+ // MISC
2428
+ isEmpty(obj) {
2429
+ return Object.keys(obj).length === 0;
2430
+ }
2431
+ updateRequestOptions(headers) {
2432
+ const options = ApiRequest.adapt({ ...this.apiOptions });
2433
+ options.headers = (headers)
2434
+ ? { ...options.headers, ...headers }
2435
+ : { ...options.headers };
2436
+ return options;
2437
+ }
2438
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerStateService, deps: [{ token: API_OPTS }, { token: "dataType" }, { token: "database" }], target: i0.ɵɵFactoryTarget.Injectable }); }
2439
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerStateService }); }
2440
+ }
2441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerStateService, decorators: [{
2442
+ type: Injectable
2443
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
2444
+ type: Inject,
2445
+ args: [API_OPTS]
2446
+ }] }, { type: undefined, decorators: [{
2447
+ type: Inject,
2448
+ args: ["dataType"]
2449
+ }] }, { type: undefined, decorators: [{
2450
+ type: Inject,
2451
+ args: ["database"]
2452
+ }] }] });
2453
+
2454
+ // export * from "./database-manager-services/index";
2455
+
2456
+ class ErrorDisplaySettings {
2457
+ constructor(displayTime = 3 * 1000, position = 'top') {
2458
+ this.displayTime = displayTime;
2459
+ this.position = position;
2460
+ }
2461
+ static adapt(item) {
2462
+ return new ErrorDisplaySettings((item?.displayTime) ? item.displayTime * 1000 : 3 * 1000, item?.position);
2463
+ }
2464
+ }
2465
+
2466
+ class WithCredentialsInterceptor {
2467
+ intercept(req, next) {
2468
+ req = req.clone({ withCredentials: true });
2469
+ return next.handle(req);
2470
+ }
2471
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WithCredentialsInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2472
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WithCredentialsInterceptor }); }
2473
+ }
2474
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WithCredentialsInterceptor, decorators: [{
2475
+ type: Injectable
2476
+ }] });
2477
+
2478
+ class RequestHeadersInterceptor {
2479
+ get currentDate() {
2480
+ const date = new Date();
2481
+ const year = date.getFullYear();
2482
+ const month = String(date.getMonth() + 1).padStart(2, '0');
2483
+ const day = String(date.getDate()).padStart(2, '0');
2484
+ return `${year}-${month}-${day}`;
2485
+ }
2486
+ constructor(translate) {
2487
+ this.translate = translate;
2488
+ this.subscriptions = new Subscription();
2489
+ this.language = 'en-CA';
2490
+ this.subscriptions.add(this.translate.onLangChange
2491
+ .subscribe((params) => {
2492
+ this.language = `${params.lang}-CA`;
2493
+ }));
2494
+ }
2495
+ intercept(request, next) {
2496
+ request = request.clone({
2497
+ setHeaders: {
2498
+ 'Content-Type': 'application/json',
2499
+ 'Accept-Language': this.language || 'en-CA',
2500
+ 'Current-Date': this.currentDate
2501
+ }
2502
+ });
2503
+ return next.handle(request);
2504
+ }
2505
+ ngOnDestroy() {
2506
+ this.subscriptions.unsubscribe();
2507
+ }
2508
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestHeadersInterceptor, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2509
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestHeadersInterceptor }); }
2510
+ }
2511
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestHeadersInterceptor, decorators: [{
2512
+ type: Injectable
2513
+ }], ctorParameters: () => [{ type: i1.TranslateService }] });
2514
+
2515
+ class RequestErrorInterceptor {
2516
+ constructor() {
2517
+ this.toastMessage = inject(ToastMessageDisplayService);
2518
+ }
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();
2041
2647
  }
2042
- get ApiRequestOptions() {
2043
- return this.apiOptions;
2648
+ ngOnDestroy() {
2649
+ this.subscriptions.unsubscribe();
2044
2650
  }
2045
- initStorage() {
2046
- // if(this.otherOptions.database) {
2047
- // console.log('Has Database Option:', this.otherOptions.database.table)
2048
- // const schema = (this.otherOptions.adapters?.incoming) ? Object.keys(this.otherOptions.adapters.incoming({})).join() : '++id'
2049
- // this.apiService.initDB(this.otherOptions.database.expiresIn, this.otherOptions.database.table, schema)
2050
- // }
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();
2051
2682
  }
2052
- initializeState(data) {
2053
- this.setData$(data);
2683
+ get labels() {
2684
+ return this._labels;
2054
2685
  }
2055
- updateArrayState(currentData, newData) {
2056
- const filterCurrentData = () => {
2057
- const ids = this.streamedResponse.map((obj) => obj.id);
2058
- return currentData.filter(obj => (obj.id) ? ids.includes(obj.id) : obj);
2059
- };
2060
- const filteredCurrentData = (this.httpManagerService.isPending.value) ? currentData : filterCurrentData();
2061
- const updatedData = filteredCurrentData.map(item => {
2062
- const newItem = newData.find(newItem => {
2063
- const hasId = (newItem?.id && item?.id) ? true : false;
2064
- return (hasId) ? newItem.id === item.id : JSON.stringify(newItem) === JSON.stringify(item);
2065
- });
2066
- return (newItem) ? { ...item, ...newItem } : item;
2067
- });
2068
- const addedData = newData.filter(newItem => {
2069
- return !filteredCurrentData.some(item => {
2070
- const hasId = (newItem?.id && item?.id) ? true : false;
2071
- return (hasId) ? item.id === newItem.id : JSON.stringify(newItem) === JSON.stringify(item);
2072
- });
2073
- });
2074
- return [...updatedData, ...addedData];
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;
2075
2697
  }
2076
- // --------------------------------------------------------------------------------------------------
2077
- // MISC
2078
- isEmpty(obj) {
2079
- return Object.keys(obj).length === 0;
2698
+ ngOnInit() {
2080
2699
  }
2081
- updateRequestOptions(headers) {
2082
- const options = ApiRequest.adapt({ ...this.apiOptions });
2083
- options.headers = (headers)
2084
- ? { ...options.headers, ...headers }
2085
- : { ...options.headers };
2086
- return options;
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();
2087
2717
  }
2088
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerStateService, deps: [{ token: API_OPTS }, { token: "dataType" }, { token: "database" }], target: i0.ɵɵFactoryTarget.Injectable }); }
2089
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerStateService }); }
2090
- }
2091
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HTTPManagerStateService, decorators: [{
2092
- type: Injectable
2093
- }], ctorParameters: () => [{ type: undefined, decorators: [{
2094
- type: Inject,
2095
- args: [API_OPTS]
2096
- }] }, { type: undefined, decorators: [{
2097
- type: Inject,
2098
- args: ["dataType"]
2099
- }] }, { type: undefined, decorators: [{
2100
- type: Inject,
2101
- args: ["database"]
2102
- }] }] });
2103
-
2104
- // export * from "./database-manager-services/index";
2105
-
2106
- class ErrorDisplaySettings {
2107
- constructor(displayTime = 3 * 1000, position = 'top') {
2108
- this.displayTime = displayTime;
2109
- this.position = position;
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);
2110
2729
  }
2111
- static adapt(item) {
2112
- return new ErrorDisplaySettings((item?.displayTime) ? item.displayTime * 1000 : 3 * 1000, item?.position);
2730
+ OnDestroy() {
2731
+ this.subscription.unsubscribe();
2113
2732
  }
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 }); }
2114
2735
  }
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
+ }] } });
2115
2756
 
2116
- class WithCredentialsInterceptor {
2117
- intercept(req, next) {
2118
- req = req.clone({ withCredentials: true });
2119
- return next.handle(req);
2757
+ class RequestManagerDemoComponent {
2758
+ get retry() {
2759
+ return this.requestForm.get('retry')?.value;
2120
2760
  }
2121
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WithCredentialsInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2122
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WithCredentialsInterceptor }); }
2123
- }
2124
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WithCredentialsInterceptor, decorators: [{
2125
- type: Injectable
2126
- }] });
2127
-
2128
- class RequestHeadersInterceptor {
2129
- get currentDate() {
2130
- const date = new Date();
2131
- const year = date.getFullYear();
2132
- const month = String(date.getMonth() + 1).padStart(2, '0');
2133
- const day = String(date.getDate()).padStart(2, '0');
2134
- return `${year}-${month}-${day}`;
2761
+ get headers() {
2762
+ return this.requestForm.get('headers');
2763
+ }
2764
+ get isValid() {
2765
+ this.requestForm.markAllAsTouched();
2766
+ return this.requestForm.valid;
2767
+ }
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
+ };
2135
2842
  }
2136
- constructor(translate) {
2137
- this.translate = translate;
2138
- this.subscriptions = new Subscription();
2139
- this.language = 'en-CA';
2140
- this.subscriptions.add(this.translate.onLangChange
2141
- .subscribe((params) => {
2142
- this.language = `${params.lang}-CA`;
2143
- }));
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))
2144
2863
  }
2145
- intercept(request, next) {
2146
- request = request.clone({
2147
- setHeaders: {
2148
- 'Content-Type': 'application/json',
2149
- 'Accept-Language': this.language || 'en-CA',
2150
- 'Current-Date': this.currentDate
2151
- }
2864
+ addHeader() {
2865
+ const header = this.fb.group({
2866
+ key: ['', Validators.required],
2867
+ value: ['']
2152
2868
  });
2153
- return next.handle(request);
2869
+ this.headers.push(header);
2154
2870
  }
2155
- ngOnDestroy() {
2156
- this.subscriptions.unsubscribe();
2871
+ removeHeader(index) {
2872
+ this.headers.removeAt(index);
2157
2873
  }
2158
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestHeadersInterceptor, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2159
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestHeadersInterceptor }); }
2160
- }
2161
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestHeadersInterceptor, decorators: [{
2162
- type: Injectable
2163
- }], ctorParameters: () => [{ type: i1.TranslateService }] });
2164
-
2165
- class RequestErrorInterceptor {
2166
- constructor() {
2167
- this.toastMessage = inject(ToastMessageDisplayService);
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 };
2168
2886
  }
2169
- intercept(req, next) {
2170
- return next.handle(req).pipe(catchError$1((error) => {
2171
- const displayError = ToastDisplay.adapt({
2172
- message: 'This is a toast message. This is an Error!!',
2173
- action: 'OK',
2174
- color: ToastColors.SUCCESS,
2175
- icon: 'info',
2176
- duration: 5 * 1000, //5 seconds
2177
- });
2178
- if (error.status >= 400 && error.status < 500) {
2179
- displayError.color = ToastColors.WARN;
2180
- displayError.message = error.error || `${error.status}: ${error.statusText}`;
2181
- console.error('Client Error:', {
2182
- status: error.status,
2183
- message: error.message,
2184
- error: error.error,
2185
- text: error.statusText,
2186
- });
2187
- this.toastMessage.toastMessage(displayError);
2188
- }
2189
- else if (error.status >= 500) {
2190
- displayError.color = ToastColors.ERROR;
2191
- displayError.message = error.error || `${error.status}: ${error.statusText}`;
2192
- console.error('Server Error:', {
2193
- status: error.status,
2194
- message: error.message,
2195
- error: error.error,
2196
- text: error.statusText,
2197
- });
2198
- this.toastMessage.toastMessage(displayError);
2199
- }
2200
- return throwError(() => error);
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'));
2201
2899
  }));
2202
2900
  }
2203
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestErrorInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2204
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestErrorInterceptor }); }
2205
- }
2206
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestErrorInterceptor, decorators: [{
2207
- type: Injectable
2208
- }] });
2209
-
2210
- class ClientInfo {
2211
- constructor(domain = '', service = '', id = 0, name = '') {
2212
- this.domain = domain;
2213
- this.service = service;
2214
- this.id = id;
2215
- this.name = name;
2216
- }
2217
- static adapt(item) {
2218
- return new ClientInfo(item?.domain, item?.service, item?.id, (item?.first_name || item?.last_name) ? `${item?.first_name} ${item?.last_name}` : '');
2219
- }
2220
- }
2221
-
2222
- class ClientInfoMapper {
2223
- constructor(id = 0, first_name = '', last_name = '', email = '') {
2224
- this.id = id;
2225
- this.first_name = first_name;
2226
- this.last_name = last_name;
2227
- this.email = email;
2228
- }
2229
- static adapt(item) {
2230
- const first_name = (item?.name) ? item.name.split(' ')[0] : '';
2231
- const last_name = (item?.name) ? item.name.split(' ')[1] : '';
2232
- return new ClientInfoMapper(item?.id, first_name, last_name, item?.email);
2233
- }
2234
- }
2235
-
2236
- class AIPrompt {
2237
- constructor(response = '') {
2238
- this.response = response;
2239
- }
2240
- static adapt(item) {
2241
- return new AIPrompt(item?.response);
2242
- }
2243
- }
2244
-
2245
- class DownloadLabels {
2246
- constructor(error = '', action = '', icon = 'error') {
2247
- this.error = error;
2248
- this.action = action;
2249
- this.icon = icon;
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
+ }));
2250
2917
  }
2251
- static adapt(item) {
2252
- return new DownloadLabels(item?.error, item?.action, item?.icon);
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
+ }));
2253
2936
  }
2254
- }
2255
-
2256
- class DownloadFileComponent {
2257
- constructor() {
2258
- this.subscriptions = new Subscription();
2259
- this.displayError = 3; // seconds
2260
- this.diameter = 32;
2261
- this.mode = 'determinate';
2262
- this.isPending = false;
2263
- this.active = false;
2264
- this.disabled = false;
2265
- this.error = new EventEmitter();
2266
- this._progress = 0;
2267
- this._hasError = false;
2268
- this.errorTimerActive = false;
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
+ }));
2269
2956
  }
2270
- set progress(value) {
2271
- this._progress = value ?? 0;
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('');
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'))));
2272
2985
  }
2273
- get progress() {
2274
- return this._progress;
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
+ }));
2275
2998
  }
2276
- set hasError(value) {
2277
- this._hasError = !!value;
2278
- if (this._hasError && !this.errorTimerActive) {
2279
- this.errorTimerActive = true;
2280
- this.active = false;
2281
- this.error.emit();
2282
- this.subscriptions.add(timer(this.displayError * 1000)
2283
- .subscribe((err) => {
2284
- this._hasError = false;
2285
- this.errorTimerActive = false;
2286
- }));
2287
- }
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);
2288
3008
  }
2289
- get hasError() {
2290
- return this._hasError;
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);
2291
3018
  }
2292
- ngOnInit() { }
2293
- onAction() {
2294
- this.isPending = false;
2295
- if (this.event)
2296
- this.event();
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);
2297
3030
  }
2298
- ngOnDestroy() {
2299
- this.subscriptions.unsubscribe();
3031
+ onSelectAIType(type) {
3032
+ this.AIType = type;
2300
3033
  }
2301
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DownloadFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2302
- 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 }); }
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" }] }); }
2303
3036
  }
2304
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DownloadFileComponent, decorators: [{
3037
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerDemoComponent, decorators: [{
2305
3038
  type: Component,
2306
- 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"] }]
2307
- }], propDecorators: { event: [{
2308
- type: Input
2309
- }], displayError: [{
2310
- type: Input
2311
- }], diameter: [{
2312
- type: Input
2313
- }], mode: [{
2314
- type: Input
2315
- }], isPending: [{
2316
- type: Input
2317
- }], active: [{
2318
- type: Input
2319
- }], disabled: [{
2320
- type: Input
2321
- }], error: [{
2322
- type: Output
2323
- }], progress: [{
2324
- type: Input
2325
- }], hasError: [{
2326
- 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 }]
2327
3046
  }] } });
2328
3047
 
2329
- class FileDownloaderComponent extends HTTPManagerService {
2330
- set labels(value) {
2331
- this._labels = (value) ? DownloadLabels.adapt(value) : DownloadLabels.adapt();
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());
2332
3058
  }
2333
- get labels() {
2334
- return this._labels;
3059
+ setAPIOptions(apiOptions, dataType, database) {
3060
+ this.setApiRequestOptions(apiOptions, dataType, database);
2335
3061
  }
2336
- constructor() {
2337
- super();
2338
- this.delayError = 3;
2339
- this.apiRequest = ApiRequest.adapt();
2340
- this.displayErrorMessage = false;
2341
- this._labels = DownloadLabels.adapt();
2342
- this.active = false;
2343
- this.subscription = new Subscription();
2344
- this.completed = new EventEmitter();
2345
- this.failed = new EventEmitter();
2346
- 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();
2347
3068
  }
2348
- ngOnInit() {
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);
2349
3075
  }
2350
- onDownloadStreaming() {
2351
- if (this.active)
2352
- return;
2353
- this.active = true;
2354
- return this.downloadRequest(this.apiRequest, [])
2355
- .pipe(distinctUntilChanged(), catchError((err) => {
2356
- this.onError(err.message);
2357
- this.active = false;
2358
- this.failed.emit(err);
2359
- return throwError(() => err);
2360
- }), finalize(() => {
2361
- if (!this.active)
2362
- return;
2363
- this.active = false;
2364
- this.completed.emit();
2365
- }))
2366
- .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);
2367
3083
  }
2368
- onError(message) {
2369
- if (!message || !this.displayErrorMessage)
2370
- return;
2371
- const display = ToastDisplay.adapt({
2372
- message,
2373
- action: 'Ok',
2374
- color: ToastColors.ERROR,
2375
- icon: 'error',
2376
- });
2377
- this.active = false;
2378
- 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);
2379
3091
  }
2380
- OnDestroy() {
2381
- this.subscription.unsubscribe();
3092
+ streamRequest() {
3093
+ const headers = {
3094
+ auth: "sample-auth-token"
3095
+ };
3096
+ // const sampleOptions = RequestOptions.adapt({ path: [1], headers })
3097
+ this.fetchStream();
2382
3098
  }
2383
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileDownloaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2384
- 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 }); }
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' }); }
2385
3101
  }
2386
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileDownloaderComponent, decorators: [{
2387
- type: Component,
2388
- 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"] }]
2389
- }], ctorParameters: () => [], propDecorators: { delayError: [{
2390
- type: Input
2391
- }], apiRequest: [{
2392
- type: Input
2393
- }], displayErrorMessage: [{
2394
- type: Input
2395
- }], saveFileAs: [{
2396
- type: Input
2397
- }], labels: [{
2398
- type: Input
2399
- }], completed: [{
2400
- type: Output
2401
- }], failed: [{
2402
- type: Output
2403
- }], disabled: [{
2404
- type: Input
2405
- }] } });
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: () => [] });
2406
3108
 
2407
- class RequestManagerDemoComponent {
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
+ }
2408
3138
  get retry() {
2409
- return this.requestForm.get('retry')?.value;
3139
+ return this.requestForm.get("retry")?.value;
2410
3140
  }
2411
3141
  get headers() {
2412
3142
  return this.requestForm.get('headers');
@@ -2416,11 +3146,12 @@ class RequestManagerDemoComponent {
2416
3146
  return this.requestForm.valid;
2417
3147
  }
2418
3148
  constructor() {
3149
+ this.stateManagerDemoService = inject(StateManagerDemoService);
2419
3150
  this.displayedColumns = ['id', 'name', 'lastName', 'age'];
2420
3151
  this.fb = inject(FormBuilder);
2421
- this.toastMessage = inject(ToastMessageDisplayService);
2422
3152
  this.httpManagerService = inject(HTTPManagerService);
2423
- this.isPending$ = this.httpManagerService.isPending$;
3153
+ this.isPending$ = this.stateManagerDemoService.isPending$;
3154
+ this.error$ = this.stateManagerDemoService.error$;
2424
3155
  this.countdown$ = this.httpManagerService.countdown$;
2425
3156
  this.GET_error$ = new BehaviorSubject('');
2426
3157
  this.POST_error$ = new BehaviorSubject('');
@@ -2428,22 +3159,19 @@ class RequestManagerDemoComponent {
2428
3159
  this.DELETE_error$ = new BehaviorSubject('');
2429
3160
  this.STREAM_error$ = new BehaviorSubject('');
2430
3161
  this.STREAM_AI_error$ = new BehaviorSubject('');
2431
- this.requestParams = {
2432
- GET: ApiRequest.adapt(),
2433
- POST: ApiRequest.adapt(),
2434
- PUT: ApiRequest.adapt(),
2435
- DELETE: ApiRequest.adapt(),
2436
- STREAM: ApiRequest.adapt(),
2437
- };
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()));
2438
3171
  this.questionControl = this.fb.control("", [Validators.required]);
2439
- this.downloadRequest = ApiRequest.adapt({
2440
- server: 'assets/images',
2441
- path: ['me.jpg'],
2442
- // saveAs: 'john.jpg' // Optional
2443
- });
2444
- // downloadRequest = ApiRequest.adapt({
2445
- // server: 'oidc/ai/file'
2446
- // })
3172
+ this.requestType = '';
3173
+ this.prompts = [];
3174
+ this.AIType = 0;
2447
3175
  this.sampleClientData = {
2448
3176
  id: 0,
2449
3177
  name: "Old School Dates",
@@ -2455,9 +3183,10 @@ class RequestManagerDemoComponent {
2455
3183
  modified: 1693003138,
2456
3184
  icon: "",
2457
3185
  imageFile: "",
2458
- email: "wavecoders@gmail.com"
2459
3186
  };
3187
+ this.selectedRecord = this.fb.control(null);
2460
3188
  this.requestForm = this.fb.group({
3189
+ datatype: this.fb.control('ARRAY'),
2461
3190
  path: this.fb.control("ai/"),
2462
3191
  headers: this.fb.array([]),
2463
3192
  adapter: [null],
@@ -2467,49 +3196,64 @@ class RequestManagerDemoComponent {
2467
3196
  delay: [3],
2468
3197
  }),
2469
3198
  polling: [3],
3199
+ database: this.fb.group({
3200
+ table: [''],
3201
+ expiresIn: ['1m'],
3202
+ })
2470
3203
  });
2471
- this.AIType = 0;
2472
3204
  this.sampleAdaptors = [
2473
- { label: "ClientInfo Basic", value: ClientInfo.adapt },
2474
- { label: "AI Prompt", value: AIPrompt.adapt },
3205
+ { label: "ClientInfo Basic", value: ClientInfo$1.adapt },
3206
+ { label: "AI Prompt", value: AIPrompt$1.adapt },
2475
3207
  ];
2476
3208
  this.sampleMappers = [
2477
- { label: "Mapper Basic", value: ClientInfoMapper.adapt },
2478
- { label: "AI Prompt", value: AIPrompt.adapt },
3209
+ { label: "Mapper Basic", value: ClientInfoMapper$1.adapt },
3210
+ { label: "AI Prompt", value: AIPrompt$1.adapt },
2479
3211
  ];
2480
- this.hasId = (arr) => {
2481
- if (arr.length === 0)
2482
- return false;
2483
- return !isNaN(arr[arr.length - 1]);
2484
- };
2485
- this.props = (adapter) => {
2486
- return (adapter) ? adapter() : null;
2487
- };
2488
3212
  // server = `http://sample-endpoint/as/authorization.oauth2`
2489
3213
  this.arrayObjectsToObjects = (arr) => {
2490
3214
  return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
2491
3215
  };
3216
+ this.props = (adapter) => {
3217
+ return (adapter) ? adapter() : null;
3218
+ };
2492
3219
  }
2493
3220
  ngOnInit() {
2494
- // const reqGet2 = ApiRequest.adapt({
2495
- // server,
2496
- // path: ['clients'],
2497
- // headers: { authentication: "Bearer <KEY>" },
2498
- // adapter: ClientInfo,
2499
- // dataType: DataType.OBJECT,
2500
- // // concurrent: false,
2501
- // // polling: 3, //seconds
2502
- // })
2503
- // const req2 = [1024,1025,1026].map(item => {
2504
- // return this.httpManagerService.getRequest<ClientInfo[]>(reqGet2, [item])
2505
- // .pipe(
2506
- // catchError(error => {
2507
- // return throwError(() => new Error(error.error.message))
2508
- // })
2509
- // )
2510
- // })
2511
- // forkJoin(req2)
2512
- // .subscribe(res => console.log(res))
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();
2513
3257
  }
2514
3258
  addHeader() {
2515
3259
  const header = this.fb.group({
@@ -2530,143 +3274,52 @@ class RequestManagerDemoComponent {
2530
3274
  if (!this.failedState.checked) {
2531
3275
  requestParams.retry = { times: 0, delay: 0 };
2532
3276
  }
2533
- const apiOptions = ApiRequest.adapt(requestParams);
2534
- apiOptions.path = [];
3277
+ const currentOptions = ApiRequest.adapt(requestParams);
3278
+ currentOptions.path = [];
3279
+ const apiOptions = ApiRequest.adapt({ ...currentOptions, path: pathReq });
2535
3280
  return { apiOptions: apiOptions, path: pathReq };
2536
3281
  }
2537
- onGetRequest() {
2538
- if (!this.isValid)
2539
- return;
2540
- const reqParams = this.compileRequest();
2541
- this.requestParams.GET = reqParams.apiOptions;
2542
- this.GET$ = EMPTY; //Cancels Previous
2543
- this.GET_error$.next('');
2544
- this.GET$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
2545
- .pipe(
2546
- // tap((data) => console.log("API GET response", data)),
2547
- catchError(error => {
2548
- return throwError(() => this.errorHandling(error, 'GET'));
2549
- }));
2550
- }
2551
- onCreateRequest() {
2552
- if (!this.isValid)
2553
- return;
2554
- const reqParams = this.compileRequest();
2555
- this.requestParams.POST = reqParams.apiOptions;
2556
- this.POST$ = EMPTY; //Cancels Previous
2557
- this.POST_error$.next('');
2558
- console.log("POST", this.sampleClientData);
2559
- console.log("POST", reqParams.apiOptions);
2560
- console.log("POST", reqParams.path);
2561
- this.POST$ = this.httpManagerService.postRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
2562
- .pipe(
2563
- // tap((data) => console.log("API POST response", data)),
2564
- catchError(error => {
2565
- return throwError(() => this.errorHandling(error, 'POST'));
2566
- }));
2567
- }
2568
- onUpdateRequest() {
3282
+ onSetStateOptions() {
2569
3283
  if (!this.isValid)
2570
3284
  return;
2571
3285
  const reqParams = this.compileRequest();
2572
- if (!this.hasId(reqParams.path)) {
2573
- console.log("Missing ID");
2574
- return;
2575
- }
2576
- this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
2577
- this.requestParams.PUT = reqParams.apiOptions;
2578
- this.PUT$ = EMPTY; //Cancels Previous
2579
- this.PUT_error$.next('');
2580
- this.PUT$ = this.httpManagerService.putRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
2581
- .pipe(
2582
- // tap((data) => console.log("API PUT response", data)),
2583
- catchError(error => {
2584
- return throwError(() => this.errorHandling(error, 'PUT'));
2585
- }));
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();
2586
3290
  }
2587
- onDeleteRequest() {
2588
- if (!this.isValid)
2589
- return;
2590
- const reqParams = this.compileRequest();
2591
- this.requestParams.DELETE = reqParams.apiOptions;
2592
- if (!this.hasId(reqParams.path)) {
2593
- console.log("Missing ID");
2594
- return;
2595
- }
2596
- this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
2597
- this.requestParams.DELETE = reqParams.apiOptions;
2598
- this.DELETE$ = EMPTY; //Cancels Previous
2599
- this.DELETE_error$.next('');
2600
- this.DELETE$ = this.httpManagerService.deleteRequest(reqParams.apiOptions, reqParams.path)
2601
- .pipe(
2602
- // tap((data) => console.log("API DELETE response", data)),
2603
- catchError(error => {
2604
- return throwError(() => this.errorHandling(error, 'DELETE'));
2605
- }));
3291
+ onClearRecords() {
3292
+ this.stateManagerDemoService.clearRecords();
2606
3293
  }
2607
- onStreamPostRequest() {
2608
- if (!this.isValid)
2609
- return;
2610
- const reqParams = this.compileRequest();
2611
- let payload = {};
2612
- let apiPath = reqParams.path;
2613
- let apiOptions = reqParams.apiOptions;
2614
- let responseMapper = (items) => items.response;
2615
- if (this.AIType === 0) {
2616
- // API request
2617
- payload = { prompt: this.questionControl.value };
2618
- }
2619
- else {
2620
- // Local Ollama request
2621
- apiOptions.server = "api";
2622
- apiPath = ["generate"];
2623
- apiOptions.stream = true;
2624
- payload = {
2625
- model: "phi3:latest",
2626
- prompt: this.questionControl.value,
2627
- stream: true,
2628
- };
2629
- responseMapper = (items) => items.map((word) => word.response).flat().join('');
2630
- }
2631
- this.requestParams.STREAM = apiOptions;
2632
- this.STREAM_AI$ = EMPTY;
2633
- this.STREAM_AI_error$.next('');
2634
- this.STREAM_AI$ = this.httpManagerService.postRequest(payload, apiOptions, apiPath).pipe(map(responseMapper), tap(() => this.questionControl.reset()), catchError(error => throwError(() => this.errorHandling(error, 'STREAM'))));
3294
+ onRefreshRecords() {
3295
+ this.stateManagerDemoService.refreshData();
2635
3296
  }
2636
- onStreamRequest() {
2637
- if (!this.isValid)
2638
- return;
2639
- const reqParams = this.compileRequest();
2640
- reqParams.apiOptions.stream = true;
2641
- this.requestParams.GET = reqParams.apiOptions;
2642
- this.STREAM$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
2643
- .pipe(
2644
- // tap((data) => console.log("API STREAM response", data)),
2645
- catchError(error => {
2646
- return throwError(() => this.errorHandling(error, 'STREAM'));
2647
- }));
3297
+ onGetRequest() {
3298
+ this.requestType = 'GET';
3299
+ this.stateManagerDemoService.getClients();
2648
3300
  }
2649
- onDownloadCompleted() {
2650
- const message = "Download Completed";
2651
- const display = ToastDisplay.adapt({
2652
- message,
2653
- action: 'Ok',
2654
- color: ToastColors.SUCCESS,
2655
- icon: 'sentiment_satisfied_alt',
2656
- });
2657
- this.toastMessage.toastMessage(display);
3301
+ onCreateRequest() {
3302
+ this.requestType = 'POST';
3303
+ this.stateManagerDemoService.createClient(this.sampleClientData);
2658
3304
  }
2659
- onDownloadFailed(err) {
2660
- const message = "Download Failed";
2661
- const display = ToastDisplay.adapt({
2662
- message,
2663
- action: 'Ok',
2664
- color: ToastColors.ERROR,
2665
- icon: 'warning',
2666
- });
2667
- this.toastMessage.toastMessage(display);
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);
3312
+ }
3313
+ onStreamRequest() {
3314
+ if (!this.isValid)
3315
+ return;
3316
+ const reqParams = this.compileRequest();
3317
+ reqParams.apiOptions.stream = true;
3318
+ this.requestType = 'STREAM';
3319
+ this.stateManagerDemoService.streamRequest();
2668
3320
  }
2669
3321
  errorHandling(err, type) {
3322
+ console.log(err, type);
2670
3323
  if (type === 'GET')
2671
3324
  this.GET_error$.next(err.message);
2672
3325
  if (type === 'POST')
@@ -2677,16 +3330,21 @@ class RequestManagerDemoComponent {
2677
3330
  this.DELETE_error$.next(err.message);
2678
3331
  if (type === 'STREAM')
2679
3332
  this.STREAM_error$.next(err.message);
3333
+ if (type === 'STREAM_AI')
3334
+ this.STREAM_AI_error$.next(err.message);
2680
3335
  }
2681
3336
  onSelectAIType(type) {
2682
3337
  this.AIType = type;
2683
3338
  }
2684
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2685
- 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" }] }); }
2686
3344
  }
2687
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerDemoComponent, decorators: [{
3345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerStateDemoComponent, decorators: [{
2688
3346
  type: Component,
2689
- 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"] }]
2690
3348
  }], ctorParameters: () => [], propDecorators: { failedState: [{
2691
3349
  type: ViewChild,
2692
3350
  args: ["failedState", { static: true }]
@@ -2695,98 +3353,240 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
2695
3353
  args: ["pollingState", { static: true }]
2696
3354
  }] } });
2697
3355
 
2698
- class StateManagerDemoService extends HTTPManagerStateService {
2699
- constructor() {
2700
- super(ApiRequest.adapt({
2701
- server: "",
2702
- path: [],
2703
- headers: {},
2704
- adapter: ClientInfo.adapt,
2705
- mapper: ClientInfoMapper.adapt,
2706
- stream: false,
2707
- }), DataType.ARRAY, DatabaseStorage.adapt());
3356
+ class LocalStorageDemoComponent {
3357
+ get type() {
3358
+ return (this.typeControl.value) ? +this.typeControl.value : 0;
2708
3359
  }
2709
- setAPIOptions(apiOptions, dataType, database) {
2710
- this.setApiRequestOptions(apiOptions, dataType, database);
3360
+ get isValid() {
3361
+ return this.newStoreForm.valid;
2711
3362
  }
2712
- getClients() {
2713
- // const headers = {
2714
- // auth: "sample-auth-token"
2715
- // }
2716
- // const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
2717
- this.fetchRecords();
3363
+ get isValidData() {
3364
+ return this.storageForm.valid;
2718
3365
  }
2719
- createClient(data) {
2720
- // const headers = {
2721
- // auth: "sample-auth-token"
2722
- // }
2723
- // const sampleOptions = RequestOptions.adapt({ path: ["id", 12], headers, sample: true })
2724
- this.createRecord(data);
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;
2725
3414
  }
2726
- updateClient(data) {
2727
- // const headers = {
2728
- // auth: "sample-auth-token"
2729
- // }
2730
- data.id = 1031;
2731
- const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2732
- this.updateRecord(data, sampleOptions);
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
+ }
2733
3439
  }
2734
- deleteClient(data) {
2735
- // const headers = {
2736
- // auth: "sample-auth-token"
2737
- // }
2738
- data.id = 1031;
2739
- const sampleOptions = RequestOptions.adapt({ path: [data.id] });
2740
- this.deleteRecord(sampleOptions);
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;
3485
+ }
3486
+ onUpdate(store, data) {
3487
+ this.localStorageManagerService.updateStore({
3488
+ name: store.name,
3489
+ data: JSON.parse(data)
3490
+ });
3491
+ this.onCancel();
3492
+ }
3493
+ onReset() {
3494
+ this.localStorageManagerService.resetStore();
3495
+ }
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 &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", 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 &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"] }]
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;
3511
+ }
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);
3539
+ }
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;
2741
3558
  }
2742
- streamRequest() {
2743
- const headers = {
2744
- auth: "sample-auth-token"
2745
- };
2746
- // const sampleOptions = RequestOptions.adapt({ path: [1], headers })
2747
- 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}` : '');
2748
3561
  }
2749
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2750
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, providedIn: 'root' }); }
2751
3562
  }
2752
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StateManagerDemoService, decorators: [{
2753
- type: Injectable,
2754
- args: [{
2755
- providedIn: 'root'
2756
- }]
2757
- }], ctorParameters: () => [] });
2758
3563
 
2759
- class RequestManagerStateDemoComponent {
2760
- get dataObservable$() {
2761
- switch (this.requestType) {
2762
- case 'GET':
2763
- return this.GET$;
2764
- case 'PUT':
2765
- return this.PUT$;
2766
- case 'POST':
2767
- return this.POST$;
2768
- case 'DELETE':
2769
- return this.DELETE$;
2770
- case 'STREAM':
2771
- return this.STREAM;
2772
- case 'STREAM_AI':
2773
- return this.STREAM_AI;
2774
- default:
2775
- return this.GET$;
2776
- break;
2777
- }
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;
2778
3570
  }
2779
- get hasChanged() {
2780
- return this.requestForm.dirty || this.requestForm.untouched;
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);
2781
3575
  }
2782
- get dataType() {
2783
- return this.requestForm.get("datatype")?.value;
3576
+ }
3577
+
3578
+ class AIPrompt {
3579
+ constructor(response = '') {
3580
+ this.response = response;
2784
3581
  }
2785
- get database() {
2786
- return this.requestForm.get("database")?.value;
3582
+ static adapt(item) {
3583
+ return new AIPrompt(item?.response);
2787
3584
  }
3585
+ }
3586
+
3587
+ class RequestSignalsManagerDemoComponent {
2788
3588
  get retry() {
2789
- return this.requestForm.get("retry")?.value;
3589
+ return this.requestForm.get('retry')?.value;
2790
3590
  }
2791
3591
  get headers() {
2792
3592
  return this.requestForm.get('headers');
@@ -2796,32 +3596,42 @@ class RequestManagerStateDemoComponent {
2796
3596
  return this.requestForm.valid;
2797
3597
  }
2798
3598
  constructor() {
2799
- this.stateManagerDemoService = inject(StateManagerDemoService);
2800
3599
  this.displayedColumns = ['id', 'name', 'lastName', 'age'];
2801
3600
  this.fb = inject(FormBuilder);
2802
- this.httpManagerService = inject(HTTPManagerService);
2803
- this.isPending$ = this.stateManagerDemoService.isPending$;
2804
- this.error$ = this.stateManagerDemoService.error$;
2805
- this.countdown$ = this.httpManagerService.countdown$;
2806
- this.GET_error$ = new BehaviorSubject('');
2807
- this.POST_error$ = new BehaviorSubject('');
2808
- this.PUT_error$ = new BehaviorSubject('');
2809
- this.DELETE_error$ = new BehaviorSubject('');
2810
- this.STREAM_error$ = new BehaviorSubject('');
2811
- this.STREAM_AI_error$ = new BehaviorSubject('');
2812
- this.GET$ = new BehaviorSubject(null);
2813
- this.POST$ = new BehaviorSubject(null);
2814
- this.PUT$ = new BehaviorSubject(null);
2815
- this.DELETE$ = new BehaviorSubject(null);
2816
- this.STREAM = new BehaviorSubject(null);
2817
- this.STREAM$ = this.STREAM.asObservable();
2818
- this.STREAM_AI = new BehaviorSubject([]);
2819
- this.STREAM_AI$ = this.STREAM_AI.asObservable()
2820
- .pipe(map$1((items) => (items) ? items.map((item) => item.response) : []), map$1((items) => items.join('\n').trim()));
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
+ };
2821
3626
  this.questionControl = this.fb.control("", [Validators.required]);
2822
- this.requestType = '';
2823
- this.prompts = [];
2824
- this.AIType = 0;
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
+ // })
2825
3635
  this.sampleClientData = {
2826
3636
  id: 0,
2827
3637
  name: "Old School Dates",
@@ -2833,10 +3643,9 @@ class RequestManagerStateDemoComponent {
2833
3643
  modified: 1693003138,
2834
3644
  icon: "",
2835
3645
  imageFile: "",
3646
+ email: "wavecoders@gmail.com"
2836
3647
  };
2837
- this.selectedRecord = this.fb.control(null);
2838
3648
  this.requestForm = this.fb.group({
2839
- datatype: this.fb.control('ARRAY'),
2840
3649
  path: this.fb.control("ai/"),
2841
3650
  headers: this.fb.array([]),
2842
3651
  adapter: [null],
@@ -2846,11 +3655,8 @@ class RequestManagerStateDemoComponent {
2846
3655
  delay: [3],
2847
3656
  }),
2848
3657
  polling: [3],
2849
- database: this.fb.group({
2850
- table: [''],
2851
- expiresIn: ['1m'],
2852
- })
2853
3658
  });
3659
+ this.AIType = 0;
2854
3660
  this.sampleAdaptors = [
2855
3661
  { label: "ClientInfo Basic", value: ClientInfo.adapt },
2856
3662
  { label: "AI Prompt", value: AIPrompt.adapt },
@@ -2859,51 +3665,39 @@ class RequestManagerStateDemoComponent {
2859
3665
  { label: "Mapper Basic", value: ClientInfoMapper.adapt },
2860
3666
  { label: "AI Prompt", value: AIPrompt.adapt },
2861
3667
  ];
2862
- // server = `http://sample-endpoint/as/authorization.oauth2`
2863
- this.arrayObjectsToObjects = (arr) => {
2864
- return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
3668
+ this.hasId = (arr) => {
3669
+ if (arr.length === 0)
3670
+ return false;
3671
+ return !isNaN(arr[arr.length - 1]);
2865
3672
  };
2866
3673
  this.props = (adapter) => {
2867
3674
  return (adapter) ? adapter() : null;
2868
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
+ };
2869
3680
  }
2870
3681
  ngOnInit() {
2871
- this.stateManagerDemoService.data$.pipe(tap$1((data) => console.log("API STREAM_AI response", data)));
2872
- this.error$.pipe(tap$1((data) => {
2873
- debugger;
2874
- console.log("API STREAM response", data);
2875
- }), catchError$1(error => {
2876
- return throwError(() => this.errorHandling(error, 'STREAM'));
2877
- }));
2878
- this.selectedRecord.valueChanges
2879
- .subscribe((data) => {
2880
- this.selectedRecord$ = (data) ? this.stateManagerDemoService.selectRecord$(data.id) : EMPTY;
2881
- });
2882
- this.stateManagerDemoService.data$
2883
- .pipe(tap$1((data) => {
2884
- switch (this.requestType) {
2885
- case 'GET':
2886
- this.GET$.next(data);
2887
- break;
2888
- case 'PUT':
2889
- this.PUT$.next(data);
2890
- break;
2891
- case 'POST':
2892
- this.POST$.next(data);
2893
- break;
2894
- case 'DELETE':
2895
- this.DELETE$.next(data);
2896
- break;
2897
- case 'STREAM':
2898
- this.STREAM.next(data);
2899
- break;
2900
- case 'STREAM_AI':
2901
- this.STREAM_AI.next(data);
2902
- break;
2903
- default:
2904
- break;
2905
- }
2906
- })).subscribe();
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))
2907
3701
  }
2908
3702
  addHeader() {
2909
3703
  const header = this.fb.group({
@@ -2924,77 +3718,178 @@ class RequestManagerStateDemoComponent {
2924
3718
  if (!this.failedState.checked) {
2925
3719
  requestParams.retry = { times: 0, delay: 0 };
2926
3720
  }
2927
- const currentOptions = ApiRequest.adapt(requestParams);
2928
- currentOptions.path = [];
2929
- const apiOptions = ApiRequest.adapt({ ...currentOptions, path: pathReq });
3721
+ const apiOptions = ApiRequest.adapt(requestParams);
3722
+ apiOptions.path = [];
2930
3723
  return { apiOptions: apiOptions, path: pathReq };
2931
3724
  }
2932
- onSetStateOptions() {
3725
+ onGetRequest() {
2933
3726
  if (!this.isValid)
2934
3727
  return;
2935
3728
  const reqParams = this.compileRequest();
2936
- const db = DatabaseStorage.adapt(this.database);
2937
- const type = this.dataType === "ARRAY" ? DataType.ARRAY : DataType.OBJECT;
2938
- this.stateManagerDemoService.setAPIOptions(reqParams.apiOptions, type, db);
2939
- this.requestForm.markAsPristine();
2940
- }
2941
- onClearRecords() {
2942
- this.stateManagerDemoService.clearRecords();
2943
- }
2944
- onRefreshRecords() {
2945
- this.stateManagerDemoService.refreshData();
2946
- }
2947
- onGetRequest() {
2948
- this.requestType = 'GET';
2949
- 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
+ });
2950
3738
  }
2951
3739
  onCreateRequest() {
2952
- this.requestType = 'POST';
2953
- this.stateManagerDemoService.createClient(this.sampleClientData);
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
+ });
2954
3752
  }
2955
3753
  onUpdateRequest() {
2956
- this.requestType = 'PUT';
2957
- this.stateManagerDemoService.updateClient(this.sampleClientData);
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
+ });
2958
3771
  }
2959
3772
  onDeleteRequest() {
2960
- this.requestType = 'DELETE';
2961
- this.stateManagerDemoService.deleteClient(this.sampleClientData);
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
+ });
2962
3832
  }
2963
3833
  onStreamRequest() {
2964
3834
  if (!this.isValid)
2965
3835
  return;
2966
3836
  const reqParams = this.compileRequest();
2967
3837
  reqParams.apiOptions.stream = true;
2968
- this.requestType = 'STREAM';
2969
- this.stateManagerDemoService.streamRequest();
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);
2970
3866
  }
2971
3867
  errorHandling(err, type) {
2972
- console.log(err, type);
3868
+ const message = err?.message || String(err);
3869
+ // set local error state
2973
3870
  if (type === 'GET')
2974
- this.GET_error$.next(err.message);
3871
+ this.GET_error = message;
2975
3872
  if (type === 'POST')
2976
- this.POST_error$.next(err.message);
3873
+ this.POST_error = message;
2977
3874
  if (type === 'PUT')
2978
- this.PUT_error$.next(err.message);
3875
+ this.PUT_error = message;
2979
3876
  if (type === 'DELETE')
2980
- this.DELETE_error$.next(err.message);
3877
+ this.DELETE_error = message;
2981
3878
  if (type === 'STREAM')
2982
- this.STREAM_error$.next(err.message);
2983
- if (type === 'STREAM_AI')
2984
- this.STREAM_AI_error$.next(err.message);
3879
+ this.STREAM_error = message;
3880
+ // also set the shared service error signal
3881
+ this.httpManagerSignalsService.error.set(message);
3882
+ return err;
2985
3883
  }
2986
3884
  onSelectAIType(type) {
2987
3885
  this.AIType = type;
2988
3886
  }
2989
- onClearHistory() {
2990
- this.prompts = [];
2991
- }
2992
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerStateDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2993
- 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" }] }); }
2994
3889
  }
2995
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestManagerStateDemoComponent, decorators: [{
3890
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RequestSignalsManagerDemoComponent, decorators: [{
2996
3891
  type: Component,
2997
- 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"] }]
2998
3893
  }], ctorParameters: () => [], propDecorators: { failedState: [{
2999
3894
  type: ViewChild,
3000
3895
  args: ["failedState", { static: true }]
@@ -3003,202 +3898,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3003
3898
  args: ["pollingState", { static: true }]
3004
3899
  }] } });
3005
3900
 
3006
- class LocalStorageDemoComponent {
3007
- get type() {
3008
- return (this.typeControl.value) ? +this.typeControl.value : 0;
3009
- }
3010
- get isValid() {
3011
- return this.newStoreForm.valid;
3012
- }
3013
- get isValidData() {
3014
- return this.storageForm.valid;
3015
- }
3016
- constructor(configOptions) {
3017
- this.configOptions = configOptions;
3018
- this.fb = inject(FormBuilder);
3019
- this.utils = inject(UtilsService);
3020
- this.type$ = new BehaviorSubject(StorageType.GLOBAL);
3021
- this.typeControl = this.fb.control(StorageType.GLOBAL.toString());
3022
- this.localStorageManagerService = inject(LocalStorageManagerService);
3023
- this.settings$ = this.localStorageManagerService.settings$;
3024
- this.setting$ = (store) => this.localStorageManagerService.setting$(store);
3025
- this.storageForm = this.fb.group({
3026
- store: this.fb.control(null),
3027
- type: 'local',
3028
- settingType: 'local',
3029
- encrypted: false,
3030
- data: this.fb.control('', Validators.required),
3031
- });
3032
- this.newStoreForm = this.fb.group({
3033
- name: this.fb.control(null, Validators.required),
3034
- storage: 'local',
3035
- encrypted: false,
3036
- data: this.fb.control('', Validators.required),
3037
- expiresIn: this.fb.control('0')
3038
- });
3039
- this.storeData$ = this.storageForm.get('store')?.valueChanges
3040
- .pipe(switchMap((data) => {
3041
- return data
3042
- ? this.localStorageManagerService.store$(data.name)
3043
- : of('');
3044
- }), tap(data => {
3045
- this.storageForm.get('data')?.patchValue(data, { emitEvent: false });
3046
- }));
3047
- this.expiresIn = (epoch) => this.utils.expiresIn(epoch);
3048
- this.isValidJSON = (str) => {
3049
- try {
3050
- JSON.parse(str);
3051
- return true;
3052
- }
3053
- catch (e) {
3054
- return false;
3055
- }
3056
- };
3057
- this.displayedColumns = ['name', 'id', 'encrypted', 'expires', "option"];
3058
- this.filterData = (values) => {
3059
- if (!values)
3060
- return [];
3061
- return values.filter((item) => item.options.storage === +this.type);
3062
- };
3063
- this.create = false;
3064
- }
3065
- ngOnInit() {
3066
- this.storeProps = this.configOptions?.LocalStorageOptions;
3067
- this.options = this.storeProps?.options;
3068
- if (this.options?.storage) {
3069
- this.typeControl.patchValue(this.options.storage.toString());
3070
- this.typeControl.disable();
3071
- }
3072
- else {
3073
- this.typeControl.enable();
3074
- }
3075
- if (this.options?.expiresIn) {
3076
- this.newStoreForm.get('expiresIn')?.patchValue(this.options.expiresIn);
3077
- this.newStoreForm.get('expiresIn')?.disable();
3078
- }
3079
- else {
3080
- this.newStoreForm.get('expiresIn')?.enable();
3081
- }
3082
- if (this.options?.encrypted) {
3083
- this.newStoreForm.get('encrypted')?.patchValue(this.options.encrypted);
3084
- this.newStoreForm.get('encrypted')?.disable();
3085
- }
3086
- else {
3087
- this.newStoreForm.get('encrypted')?.enable();
3088
- }
3089
- }
3090
- onCreateStore() {
3091
- if (!this.isValid)
3092
- return;
3093
- const store = this.newStoreForm.value;
3094
- if (!store.name || store.name === '')
3095
- return;
3096
- const options = { storage: this.type, encrypted: store.encrypted, expiresIn: store.expiresIn };
3097
- this.localStorageManagerService.createStore({
3098
- name: store.name,
3099
- data: store.data,
3100
- options: SettingOptions.adapt(options)
3101
- });
3102
- this.newStoreForm.reset();
3103
- this.create = false;
3104
- }
3105
- onUpdateStore(store) {
3106
- if (!this.storageForm.valid)
3107
- return;
3108
- const storeData = this.storageForm.value;
3109
- const data = JSON.parse(storeData.data || '');
3110
- const type = (storeData.type === 'local') ? StorageType.GLOBAL : StorageType.SESSION;
3111
- this.localStorageManagerService.updateStore({
3112
- name: store.name,
3113
- data
3114
- });
3115
- }
3116
- onSelectedRow(store) {
3117
- this.store = store;
3118
- this.data$ = this.localStorageManagerService.store$(store.name).pipe(map(item => JSON.stringify(item)));
3119
- this.create = false;
3120
- }
3121
- onCreate() {
3122
- this.onCancel();
3123
- this.create = true;
3124
- }
3125
- onDelete(store) {
3126
- this.localStorageManagerService.deleteStore({
3127
- name: store.name,
3128
- });
3129
- this.onCancel();
3130
- }
3131
- onCancel() {
3132
- this.data$ = EMPTY;
3133
- this.store = null;
3134
- this.create = false;
3135
- }
3136
- onUpdate(store, data) {
3137
- this.localStorageManagerService.updateStore({
3138
- name: store.name,
3139
- data: JSON.parse(data)
3140
- });
3141
- this.onCancel();
3142
- }
3143
- onReset() {
3144
- this.localStorageManagerService.resetStore();
3145
- }
3146
- 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 }); }
3147
- 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 &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", 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 }); }
3148
- }
3149
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageDemoComponent, decorators: [{
3150
- type: Component,
3151
- args: [{ selector: 'app-local-storage-demo', encapsulation: ViewEncapsulation.None, template: "<div style=\"margin: 2rem;\">\n\n <div style=\"display: flex; gap: 1rem\">\n <h2 style=\"padding-top: .5rem; display: flex;\">\n <div style=\"padding-top: .5rem;\">Local Storage Manager</div>\n <div>\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>info</mat-icon>\n </button>\n </div>\n </h2>\n <span style=\"flex:1\"></span>\n <div style=\"padding-top: .25rem;\">\n <mat-button-toggle-group name=\"storage\" [formControl]=\"typeControl\" (change)=\"onCancel()\">\n <mat-button-toggle value=\"0\">Local Storage</mat-button-toggle>\n <mat-button-toggle value=\"1\">Session Storage</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"margin-top: .25rem;\">\n <button mat-icon-button (click)=\"onCreate()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"storeProps?.storageName || storeProps?.storageSettingsName\">\n <div style=\"display: flex; gap: .5rem; flex-direction: column; border: gray solid thin; background-color: whitesmoke; padding: 1rem;\"\n >\n <div style=\"display: flex;\">\n <div *ngIf=\"storeProps?.storageSettingsName\" style=\"flex:1\">\n Database: <b>{{ storeProps?.storageSettingsName }}</b>\n </div>\n <div *ngIf=\"storeProps?.storageName\" style=\"flex:1\">\n Data: <b>{{ storeProps?.storageName }}</b>\n </div>\n </div>\n </div>\n </ng-container>\n\n <div style=\"margin-top: 2rem;\" [formGroup]=\"newStoreForm\" *ngIf=\"create; else LIST\">\n\n <h2>Create Store</h2>\n\n <div style=\"display: flex; gap: 1rem;\">\n <div style=\"flex:1\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Store Name</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"name\">\n </mat-form-field>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>Expires In...</mat-label>\n <mat-select formControlName=\"expiresIn\">\n <mat-option value=\"0\">None</mat-option>\n <mat-option value=\"30s\">30 Seconds</mat-option>\n <mat-option value=\"1mn\">1 Minute</mat-option>\n <mat-option value=\"1hr\">1 Hour</mat-option>\n <mat-option value=\"1d\">1 Day</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"margin-top: 1rem;\">\n <mat-slide-toggle formControlName=\"encrypted\">Encrypted</mat-slide-toggle>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" formControlName=\"data\" #json></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCreateStore()\" [disabled]=\"!(isValid && isValidJSON(json.value))\">\n Save Store\n </button>\n </div>\n\n </div>\n\n <ng-template #LIST>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n{{ settings$ | async | json }}\n <div *ngIf=\"filterData(settings$ | async) as data\">\n <ng-container *ngIf=\"data.length > 0; else NO_DATA\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> Store </th>\n <td mat-cell *matCellDef=\"let element\" style=\"font-weight: bold; text-transform: uppercase;\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"encrypted\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Encrypted </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.encrypted; else NO\">YES</ng-container>\n <ng-template #NO><span style=\"color:gray\">NO</span></ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"expires\">\n <th mat-header-cell *matHeaderCellDef style=\"text-align: center;\"> Expires </th>\n <td mat-cell *matCellDef=\"let element\" style=\"text-align: center;\">\n <ng-container *ngIf=\"element.options.expires !== 0; else NO_DATA\">\n {{expiresIn(element.options.expires)}}\n </ng-container>\n <ng-template #NO_DATA>\n \u221E\n </ng-template>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"option\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let element\" style=\"padding-right: 0;\">\n <div style=\"display: flex;justify-content: flex-end;\">\n <button mat-icon-button color=\"warn\" (click)=\"onDelete(element); $event.stopPropagation()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"onSelectedRow(row)\"></tr>\n </table>\n </ng-container>\n\n <ng-template #NO_DATA>\n <h3 style=\"margin-top: 1rem;\">No Data</h3>\n </ng-template>\n\n <div *ngIf=\"(data$ | async) as data\" style=\"margin-top: 2rem;\">\n <div style=\"margin-bottom: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <h3>STORE: <span style=\"font-weight: bold;\">{{ store.name | uppercase }}</span></h3>\n <h3>SETTINGS: {{ setting$(store.name) | async | json }}</h3>\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex: 1;\">\n <mat-label>Data (Must be an Object or Array of any)</mat-label>\n <textarea matInput placeholder=\"[]\" #json [value]=\"data\"></textarea>\n </mat-form-field>\n </div>\n <mat-error *ngIf=\"!isValidJSON(json.value)\">Not Valid Data</mat-error>\n\n <div style=\"display: flex; gap: .5rem;\">\n <span style=\"flex:1\"></span>\n <button mat-stroked-button (click)=\"onCancel()\">Cancel</button>\n <button mat-stroked-button (click)=\"onUpdate(store, json.value)\" [disabled]=\"!(isValidJSON(json.value))\">Update</button>\n </div>\n </div>\n </div>\n\n </ng-template>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <button mat-stroked-button (click)=\"onReset()\">Delete All Stores</button>\n </div>\n\n</div>\n\n\n<mat-menu #menu=\"matMenu\">\n <div style=\"padding: 1rem;\">\n <p>Please note that the LocalStorage (encryption) and management of data is dependant on initializing the APP_ID</p>\n <p>Must provide a value for <b>APP_ID</b> in AppModule->Providers</p>\n <mat-divider></mat-divider>\n <div style=\"font-size: smaller; margin-top: .5rem;\">\n <p>Example: UUID (self.crypto.randomUUID() to generate)</p>\n <div style=\"background-color: whitesmoke; padding: 1rem;\">\n &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"] }]
3152
- }], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
3153
- type: Inject,
3154
- args: [CONFIG_SETTINGS_TOKEN]
3155
- }] }] });
3156
-
3157
- const PROXY_CONFIG = new InjectionToken('PROXY_CONFIG');
3158
- class ProxyDebuggerInterceptor {
3159
- constructor(proxyConfig) {
3160
- this.proxyConfig = proxyConfig;
3161
- }
3162
- intercept(req, next) {
3163
- if (!this.proxyConfig) {
3164
- return next.handle(req);
3165
- }
3166
- const headers = req.headers.keys().reduce((acc, key) => {
3167
- acc[key] = req.headers.get(key) || '';
3168
- return acc;
3169
- }, {});
3170
- for (const proxyPath in this.proxyConfig) {
3171
- if (this.proxyConfig.hasOwnProperty(proxyPath)) {
3172
- const proxyDetails = this.proxyConfig[proxyPath];
3173
- const regex = new RegExp('^' + proxyPath.replace('/', '').replace('*', '(.*)'));
3174
- if (regex.test(req.url)) {
3175
- const target = proxyDetails.target;
3176
- const endpoint = req.url.replace(regex, '$1');
3177
- const actualPath = target + '/' + endpoint;
3178
- console.log('Request Proxied:', {
3179
- requestUrl: req.url,
3180
- requestPayload: req.body,
3181
- headers: headers,
3182
- proxyPath: proxyPath,
3183
- actualPath: actualPath,
3184
- });
3185
- }
3186
- }
3187
- }
3188
- return next.handle(req);
3189
- }
3190
- 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 }); }
3191
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor }); }
3192
- }
3193
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ProxyDebuggerInterceptor, decorators: [{
3194
- type: Injectable
3195
- }], ctorParameters: () => [{ type: undefined, decorators: [{
3196
- type: Optional
3197
- }, {
3198
- type: Inject,
3199
- args: [PROXY_CONFIG]
3200
- }] }] });
3201
-
3202
3901
  class LocalStorageSignalsDemoComponent {
3203
3902
  // store type is driven by the form control
3204
3903
  get type() {
@@ -3353,11 +4052,11 @@ class LocalStorageSignalsDemoComponent {
3353
4052
  this.localStorageManagerService.resetStore();
3354
4053
  }
3355
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 }); }
3356
- 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;\">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() | 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 &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", 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 }); }
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 &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", 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 }); }
3357
4056
  }
3358
4057
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorageSignalsDemoComponent, decorators: [{
3359
4058
  type: Component,
3360
- 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;\">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() | 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 &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"] }]
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 &#123;<br>\n provide: APP_ID,<br>\n useValue: \"056991ac-3537-43ab-b5b9-83edf6554eff\",<br>\n &#125;\n </div>\n </div>\n </div>\n</mat-menu>\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.demo-row-is-clicked{font-weight:700}.mat-mdc-menu-panel.mat-mdc-menu-panel{max-width:280px!important}\n"] }]
3361
4060
  }], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
3362
4061
  type: Inject,
3363
4062
  args: [CONFIG_SETTINGS_TOKEN]
@@ -3368,11 +4067,11 @@ class HttpRequestServicesDemoComponent {
3368
4067
  this.configOptions = configOptions;
3369
4068
  this.requestTypes = [
3370
4069
  { name: "Http Service", value: 'http_service' },
3371
- { name: "Http Signals Service", value: 'http-signals_service' },
4070
+ { name: "Http Signals Service", value: 'http_signals_service', new: true },
3372
4071
  { name: "Http State Service", value: 'http_state_service' },
3373
4072
  { name: "Database Service", value: 'database_service', divider: true, disabled: true },
3374
4073
  { name: "Local Storage Service", value: 'local_storage_service' },
3375
- { name: "Local Signals Storage Service", value: 'local_storage_signals_service' },
4074
+ { name: "Local Signals Storage Service", value: 'local_storage_signals_service', new: true },
3376
4075
  ];
3377
4076
  this.selectedService = this.requestTypes[0].value;
3378
4077
  }
@@ -3384,11 +4083,11 @@ class HttpRequestServicesDemoComponent {
3384
4083
  this.selectedService = this.requestTypes[type].value;
3385
4084
  }
3386
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 }); }
3387
- 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: LocalStorageDemoComponent, selector: "app-local-storage-demo" }, { kind: "component", type: LocalStorageSignalsDemoComponent, selector: "app-local-storage-signals-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" }] }); }
3388
4087
  }
3389
4088
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HttpRequestServicesDemoComponent, decorators: [{
3390
4089
  type: Component,
3391
- 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"] }]
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"] }]
3392
4091
  }], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
3393
4092
  type: Inject,
3394
4093
  args: [CONFIG_SETTINGS_TOKEN]
@@ -3467,6 +4166,7 @@ class HttpRequestManagerModule {
3467
4166
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: HttpRequestManagerModule, declarations: [HttpRequestServicesDemoComponent,
3468
4167
  RequestManagerStateDemoComponent,
3469
4168
  RequestManagerDemoComponent,
4169
+ RequestSignalsManagerDemoComponent,
3470
4170
  LocalStorageDemoComponent,
3471
4171
  LocalStorageSignalsDemoComponent], imports: [CommonModule,
3472
4172
  ToastMessageDisplayModule,
@@ -3572,6 +4272,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3572
4272
  HttpRequestServicesDemoComponent,
3573
4273
  RequestManagerStateDemoComponent,
3574
4274
  RequestManagerDemoComponent,
4275
+ RequestSignalsManagerDemoComponent,
3575
4276
  LocalStorageDemoComponent,
3576
4277
  LocalStorageSignalsDemoComponent,
3577
4278
  // DatabaseDataDemoComponent,
@@ -3950,5 +4651,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3950
4651
  * Generated bundle index. Do not edit.
3951
4652
  */
3952
4653
 
3953
- export { ApiRequest, AppService, AsymmetricalEncryptionService, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseDataDemoComponent, DatabaseStorage, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, 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 };
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 };
3954
4655
  //# sourceMappingURL=http-request-manager.mjs.map