http-request-manager 18.12.4 → 18.12.9
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, Injectable, APP_ID, Inject, InjectionToken, isDevMode, signal, effect, computed, Injector, Optional, EventEmitter, Input, Output, ViewEncapsulation, Component, NgModule, ViewChild } from '@angular/core';
|
|
3
3
|
import { ComponentStore } from '@ngrx/component-store';
|
|
4
|
-
import { map, catchError, filter, tap,
|
|
4
|
+
import { map, catchError, filter, finalize, tap, scan, takeWhile, retry, startWith, mergeMap, takeUntil, concatMap, toArray, withLatestFrom, switchMap, take, distinctUntilChanged } from 'rxjs/operators';
|
|
5
5
|
import { HttpClient, HttpHeaders, HttpEventType, HttpHeaderResponse, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
6
6
|
import * as CryptoJS from 'crypto-js';
|
|
7
7
|
import { from, BehaviorSubject, EMPTY, throwError, defer, interval, timer, Subject, of, Observable, merge, Subscription, take as take$1, catchError as catchError$1, map as map$1, tap as tap$1, switchMap as switchMap$1, startWith as startWith$1, distinctUntilChanged as distinctUntilChanged$1, combineLatest, filter as filter$1, takeUntil as takeUntil$1, ReplaySubject } from 'rxjs';
|
|
@@ -884,6 +884,7 @@ class StreamingProcessor {
|
|
|
884
884
|
this.contentType = '';
|
|
885
885
|
this.maxBufferSize = 10 * 1024 * 1024; // 10MB limit
|
|
886
886
|
this.lastParsedLength = 0; // Track parsed position to avoid duplicates
|
|
887
|
+
this.lastParsedLineEnd = 0; // Track end of last-parsed complete line for NDJSON incremental parsing
|
|
887
888
|
this.streamConfig = config || { streamType: StreamType.AI_STREAMING };
|
|
888
889
|
}
|
|
889
890
|
/**
|
|
@@ -906,18 +907,26 @@ class StreamingProcessor {
|
|
|
906
907
|
return null;
|
|
907
908
|
case HttpEventType.DownloadProgress:
|
|
908
909
|
if (event.partialText) {
|
|
909
|
-
|
|
910
|
+
// partialText is cumulative, so replace the buffer instead of appending
|
|
911
|
+
this.buffer = event.partialText;
|
|
910
912
|
const parsedData = this.parseBuffer();
|
|
911
|
-
//
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const
|
|
915
|
-
|
|
913
|
+
// For NDJSON incremental parsing, parsedData already contains only new items.
|
|
914
|
+
// For other formats, parsedData is cumulative so slice from lastParsedLength.
|
|
915
|
+
const isIncremental = this.streamConfig.streamType === StreamType.NDJSON;
|
|
916
|
+
const newItems = isIncremental ? parsedData : parsedData.slice(this.lastParsedLength);
|
|
917
|
+
// received = cumulative total for progress display
|
|
918
|
+
const received = isIncremental
|
|
919
|
+
? this.lastParsedLength + parsedData.length
|
|
920
|
+
: parsedData.length;
|
|
921
|
+
this.lastParsedLength = received;
|
|
922
|
+
// Return null when no new items — prevents empty array emissions
|
|
923
|
+
if (newItems.length === 0) {
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
916
926
|
const total = this.totalFromHeader;
|
|
917
927
|
const percent = total
|
|
918
928
|
? Math.min(100, Math.round((received / total) * 100))
|
|
919
929
|
: 0;
|
|
920
|
-
// console.log('[STREAM] progress:', percent, 'received:', received, 'total:', total, 'bufferLen:', this.buffer.length, 'parsedCount:', parsedData.length);
|
|
921
930
|
const progress = {
|
|
922
931
|
received,
|
|
923
932
|
total,
|
|
@@ -925,19 +934,24 @@ class StreamingProcessor {
|
|
|
925
934
|
stage: 'streaming'
|
|
926
935
|
};
|
|
927
936
|
return {
|
|
928
|
-
data: newItems
|
|
937
|
+
data: newItems,
|
|
929
938
|
progress
|
|
930
939
|
};
|
|
931
940
|
}
|
|
932
941
|
return null;
|
|
933
942
|
case HttpEventType.Response:
|
|
934
943
|
if (event.body) {
|
|
935
|
-
|
|
944
|
+
// event.body is the complete response, replace the buffer
|
|
945
|
+
this.buffer = event.body;
|
|
936
946
|
const parsedData = this.parseBuffer();
|
|
937
|
-
//
|
|
938
|
-
|
|
939
|
-
this.
|
|
940
|
-
const
|
|
947
|
+
// For NDJSON incremental parsing, parsedData already contains only new items.
|
|
948
|
+
// For other formats, parsedData is cumulative so slice from lastParsedLength.
|
|
949
|
+
const isIncremental = this.streamConfig.streamType === StreamType.NDJSON;
|
|
950
|
+
const remaining = isIncremental ? parsedData : parsedData.slice(this.lastParsedLength);
|
|
951
|
+
const received = isIncremental
|
|
952
|
+
? this.lastParsedLength + parsedData.length
|
|
953
|
+
: parsedData.length;
|
|
954
|
+
this.lastParsedLength = received;
|
|
941
955
|
const total = this.totalFromHeader;
|
|
942
956
|
const percent = total
|
|
943
957
|
? Math.min(100, Math.round((received / total) * 100))
|
|
@@ -966,23 +980,40 @@ class StreamingProcessor {
|
|
|
966
980
|
// Implement sliding window if buffer gets too large
|
|
967
981
|
if (this.buffer.length > this.maxBufferSize) {
|
|
968
982
|
this.buffer = this.buffer.slice(-this.maxBufferSize / 2);
|
|
983
|
+
this.lastParsedLineEnd = 0;
|
|
984
|
+
this.lastParsedLength = 0;
|
|
969
985
|
}
|
|
970
986
|
}
|
|
971
987
|
/**
|
|
972
|
-
* Parse current buffer content
|
|
988
|
+
* Parse current buffer content.
|
|
989
|
+
*
|
|
990
|
+
* Per-record parsing failures are already handled by the inner parsers
|
|
991
|
+
* (`safeJsonParse`, `parseNdjson`, `parseEventStream`, `extractJsonObjects`),
|
|
992
|
+
* which skip malformed records and return what was successfully parsed.
|
|
993
|
+
* No outer try/catch — wrapping these calls in `catch { return []; }`
|
|
994
|
+
* would discard every successfully-parsed record in the buffer whenever a
|
|
995
|
+
* single unexpected error bubbles up, instead of omitting the bad record.
|
|
973
996
|
*/
|
|
974
997
|
parseBuffer() {
|
|
975
998
|
if (!this.buffer.trim()) {
|
|
976
999
|
return [];
|
|
977
1000
|
}
|
|
978
|
-
|
|
979
|
-
|
|
1001
|
+
if (this.streamConfig.streamType === StreamType.NDJSON) {
|
|
1002
|
+
// For NDJSON, only parse complete lines since the last parse.
|
|
1003
|
+
// Find the last newline in the buffer — everything after it is an incomplete line.
|
|
1004
|
+
const lastNewlineIndex = this.buffer.lastIndexOf('\n');
|
|
1005
|
+
if (lastNewlineIndex === -1) {
|
|
1006
|
+
// No complete lines yet
|
|
1007
|
+
return [];
|
|
1008
|
+
}
|
|
1009
|
+
// Parse only the content from lastParsedLineEnd up to (and including) the last newline
|
|
1010
|
+
const bufferToParse = this.buffer.substring(this.lastParsedLineEnd, lastNewlineIndex + 1);
|
|
1011
|
+
this.lastParsedLineEnd = lastNewlineIndex + 1;
|
|
1012
|
+
const result = parseStreamData(bufferToParse, this.contentType, this.streamConfig);
|
|
980
1013
|
return result;
|
|
981
1014
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
return [];
|
|
985
|
-
}
|
|
1015
|
+
const result = parseStreamData(this.buffer, this.contentType, this.streamConfig);
|
|
1016
|
+
return result;
|
|
986
1017
|
}
|
|
987
1018
|
/**
|
|
988
1019
|
* Reset processor state
|
|
@@ -991,6 +1022,7 @@ class StreamingProcessor {
|
|
|
991
1022
|
this.buffer = '';
|
|
992
1023
|
this.contentType = '';
|
|
993
1024
|
this.lastParsedLength = 0;
|
|
1025
|
+
this.lastParsedLineEnd = 0;
|
|
994
1026
|
this.totalFromHeader = undefined;
|
|
995
1027
|
}
|
|
996
1028
|
/**
|
|
@@ -2891,7 +2923,9 @@ class RequestService extends WebsocketService {
|
|
|
2891
2923
|
observe: 'events',
|
|
2892
2924
|
responseType: 'text',
|
|
2893
2925
|
reportProgress: true
|
|
2894
|
-
}).pipe(
|
|
2926
|
+
}).pipe(
|
|
2927
|
+
// tap(data => console.log('STREAM DATA', data)),
|
|
2928
|
+
requestStreaming({
|
|
2895
2929
|
streamType: options.streamType || StreamType.AI_STREAMING,
|
|
2896
2930
|
totalHeader: options.totalHeader
|
|
2897
2931
|
}), this.requestStreaming(options), finalize(() => {
|
|
@@ -2981,19 +3015,19 @@ class RequestService extends WebsocketService {
|
|
|
2981
3015
|
requestStreaming(options) {
|
|
2982
3016
|
return (source$) => {
|
|
2983
3017
|
return source$.pipe(tap(output => {
|
|
2984
|
-
// Update progress from stream output
|
|
2985
3018
|
this.progress.next(output.progress.percent);
|
|
2986
3019
|
this.streamProgress.next(output.progress);
|
|
2987
|
-
}),
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
return data;
|
|
2991
|
-
}
|
|
3020
|
+
}), scan((acc, output) => {
|
|
3021
|
+
// Accumulate data from each emission
|
|
3022
|
+
const newData = output.data;
|
|
2992
3023
|
if (options?.adapter) {
|
|
2993
|
-
|
|
3024
|
+
const adaptedData = newData.map((item) => options.adapter(item));
|
|
3025
|
+
return [...acc, ...adaptedData];
|
|
2994
3026
|
}
|
|
2995
|
-
|
|
2996
|
-
|
|
3027
|
+
else {
|
|
3028
|
+
return [...acc, ...newData];
|
|
3029
|
+
}
|
|
3030
|
+
}, []));
|
|
2997
3031
|
};
|
|
2998
3032
|
}
|
|
2999
3033
|
downloadFileRequest(options) {
|
|
@@ -4170,7 +4204,7 @@ class HTTPManagerService extends RequestService {
|
|
|
4170
4204
|
}
|
|
4171
4205
|
handleSequentialError(request, error, index, options) {
|
|
4172
4206
|
if (options.logErrors !== false) {
|
|
4173
|
-
console.error(`Batch request ${index} failed:`, error);
|
|
4207
|
+
// console.error(`Batch request ${index} failed:`, error);
|
|
4174
4208
|
}
|
|
4175
4209
|
if (options.stopOnError) {
|
|
4176
4210
|
return throwError(() => error);
|
|
@@ -4182,7 +4216,7 @@ class HTTPManagerService extends RequestService {
|
|
|
4182
4216
|
}
|
|
4183
4217
|
handleParallelError(request, error, index, options) {
|
|
4184
4218
|
if (options.logErrors !== false) {
|
|
4185
|
-
console.error(`Batch request ${index} failed:`, error);
|
|
4219
|
+
// console.error(`Batch request ${index} failed:`, error);
|
|
4186
4220
|
}
|
|
4187
4221
|
if (options.ignoreErrors) {
|
|
4188
4222
|
return of(undefined);
|
|
@@ -4277,17 +4311,17 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4277
4311
|
* - Streams are protected - non-stream requests wait for active streams
|
|
4278
4312
|
*/
|
|
4279
4313
|
queueRequest(request$, method, isStream = false) {
|
|
4280
|
-
console.log(`[Queue] ${method} queued (isStream=${isStream})`, {
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
});
|
|
4314
|
+
// console.log(`[Queue] ${method} queued (isStream=${isStream})`, {
|
|
4315
|
+
// activeMethod: this.activeMethod,
|
|
4316
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4317
|
+
// queueLength: this.requestQueue.length
|
|
4318
|
+
// });
|
|
4285
4319
|
return new Observable((observer) => {
|
|
4286
|
-
console.log(`[Queue] ${method} observer created, checking conditions...`, {
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
});
|
|
4320
|
+
// console.log(`[Queue] ${method} observer created, checking conditions...`, {
|
|
4321
|
+
// activeMethod: this.activeMethod,
|
|
4322
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4323
|
+
// isStream
|
|
4324
|
+
// });
|
|
4291
4325
|
const queuedRequest = {
|
|
4292
4326
|
observable: request$,
|
|
4293
4327
|
resolve: (value) => observer.next(value),
|
|
@@ -4297,7 +4331,7 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4297
4331
|
};
|
|
4298
4332
|
// If a stream is currently active, non-stream requests must wait
|
|
4299
4333
|
if (this.activeStreamMethod && !isStream) {
|
|
4300
|
-
console.log(`[Queue] ${method} queued (1), waiting for stream ${this.activeStreamMethod}`);
|
|
4334
|
+
// console.log(`[Queue] ${method} queued (1), waiting for stream ${this.activeStreamMethod}`);
|
|
4301
4335
|
this.requestQueue.push(queuedRequest);
|
|
4302
4336
|
return () => {
|
|
4303
4337
|
const idx = this.requestQueue.findIndex(q => q === queuedRequest);
|
|
@@ -4307,7 +4341,7 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4307
4341
|
}
|
|
4308
4342
|
// If a request is already running, queue this one (FIFO)
|
|
4309
4343
|
if (this.activeMethod) {
|
|
4310
|
-
console.log(`[Queue] ${method} queued (2), waiting for ${this.activeMethod}`);
|
|
4344
|
+
// console.log(`[Queue] ${method} queued (2), waiting for ${this.activeMethod}`);
|
|
4311
4345
|
this.requestQueue.push(queuedRequest);
|
|
4312
4346
|
return () => {
|
|
4313
4347
|
const idx = this.requestQueue.findIndex(q => q === queuedRequest);
|
|
@@ -4316,7 +4350,7 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4316
4350
|
};
|
|
4317
4351
|
}
|
|
4318
4352
|
// No active request - start immediately
|
|
4319
|
-
console.log(`[Queue] ${method} starting immediately`);
|
|
4353
|
+
// console.log(`[Queue] ${method} starting immediately`);
|
|
4320
4354
|
this.startRequest(queuedRequest, observer);
|
|
4321
4355
|
return () => {
|
|
4322
4356
|
const idx = this.requestQueue.findIndex(q => q === queuedRequest);
|
|
@@ -4334,23 +4368,23 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4334
4368
|
this.activeStreamMethod = queuedRequest.method;
|
|
4335
4369
|
}
|
|
4336
4370
|
this._activeRequestCount.update(c => c + 1);
|
|
4337
|
-
console.log(`[Queue] Starting ${queuedRequest.method}${queuedRequest.isStream ? ' (STREAM)' : ''}`, {
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
});
|
|
4371
|
+
// console.log(`[Queue] Starting ${queuedRequest.method}${queuedRequest.isStream ? ' (STREAM)' : ''}`, {
|
|
4372
|
+
// activeMethod: this.activeMethod,
|
|
4373
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4374
|
+
// queueLength: this.requestQueue.length
|
|
4375
|
+
// });
|
|
4342
4376
|
const sub = queuedRequest.observable.subscribe({
|
|
4343
4377
|
next: (value) => {
|
|
4344
|
-
console.log(`[Queue] ${queuedRequest.method} received value, isStream=${queuedRequest.isStream}`);
|
|
4378
|
+
// console.log(`[Queue] ${queuedRequest.method} received value, isStream=${queuedRequest.isStream}`);
|
|
4345
4379
|
observer.next(value);
|
|
4346
4380
|
},
|
|
4347
4381
|
error: (error) => {
|
|
4348
|
-
console.log(`[Queue] ${queuedRequest.method} error:`, error);
|
|
4382
|
+
// console.log(`[Queue] ${queuedRequest.method} error:`, error);
|
|
4349
4383
|
observer.error(error);
|
|
4350
4384
|
this.cleanupAndProcessNext(queuedRequest.method, !!queuedRequest.isStream);
|
|
4351
4385
|
},
|
|
4352
4386
|
complete: () => {
|
|
4353
|
-
console.log(`[Queue] ${queuedRequest.method} complete, isStream=${queuedRequest.isStream}`);
|
|
4387
|
+
// console.log(`[Queue] ${queuedRequest.method} complete, isStream=${queuedRequest.isStream}`);
|
|
4354
4388
|
observer.complete();
|
|
4355
4389
|
this.cleanupAndProcessNext(queuedRequest.method, !!queuedRequest.isStream);
|
|
4356
4390
|
}
|
|
@@ -4361,35 +4395,29 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4361
4395
|
* Clean up completed request and process next in queue
|
|
4362
4396
|
*/
|
|
4363
4397
|
cleanupAndProcessNext(method, wasStream) {
|
|
4364
|
-
console.log(`[Queue] cleanupAndProcessNext called: method=${method}, wasStream=${wasStream}`, {
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
});
|
|
4398
|
+
// console.log(`[Queue] cleanupAndProcessNext called: method=${method}, wasStream=${wasStream}`, {
|
|
4399
|
+
// activeMethod: this.activeMethod,
|
|
4400
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4401
|
+
// queueLength: this.requestQueue.length
|
|
4402
|
+
// });
|
|
4369
4403
|
this.activeRequests.delete(method);
|
|
4370
4404
|
this.activeMethod = null;
|
|
4371
4405
|
if (wasStream) {
|
|
4372
4406
|
this.activeStreamMethod = null;
|
|
4373
4407
|
}
|
|
4374
|
-
this._activeRequestCount.update(c =>
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
});
|
|
4381
|
-
console.log(`[Queue] After cleanup:`, {
|
|
4382
|
-
activeMethod: this.activeMethod,
|
|
4383
|
-
activeStreamMethod: this.activeStreamMethod,
|
|
4384
|
-
queueLength: this.requestQueue.length
|
|
4385
|
-
});
|
|
4408
|
+
this._activeRequestCount.update(c => Math.max(0, c - 1));
|
|
4409
|
+
// console.log(`[Queue] After cleanup:`, {
|
|
4410
|
+
// activeMethod: this.activeMethod,
|
|
4411
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4412
|
+
// queueLength: this.requestQueue.length
|
|
4413
|
+
// });
|
|
4386
4414
|
// Process next request in queue
|
|
4387
4415
|
if (this.requestQueue.length > 0) {
|
|
4388
4416
|
const next = this.requestQueue.shift();
|
|
4389
|
-
console.log(`[Queue] Processing next from queue: ${next.method}`, {
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
});
|
|
4417
|
+
// console.log(`[Queue] Processing next from queue: ${next.method}`, {
|
|
4418
|
+
// isStream: next.isStream,
|
|
4419
|
+
// queueLength: this.requestQueue.length
|
|
4420
|
+
// });
|
|
4393
4421
|
this.startRequest(next, {
|
|
4394
4422
|
next: (value) => next.resolve(value),
|
|
4395
4423
|
error: (error) => next.reject(error),
|
|
@@ -6344,9 +6372,9 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
6344
6372
|
this.utils = inject(UtilsService);
|
|
6345
6373
|
this.logger = inject(LoggerService);
|
|
6346
6374
|
this.error$ = this.httpManagerService.error$;
|
|
6347
|
-
this.isPending$ = this.httpManagerService.isPending
|
|
6348
|
-
this.progress$ = this.httpManagerService.progress
|
|
6349
|
-
this.streamProgress$ = this.httpManagerService.streamProgress
|
|
6375
|
+
this.isPending$ = this.httpManagerService.isPending$;
|
|
6376
|
+
this.progress$ = this.httpManagerService.progress$;
|
|
6377
|
+
this.streamProgress$ = this.httpManagerService.streamProgress$;
|
|
6350
6378
|
this.operationSuccess = new BehaviorSubject(null);
|
|
6351
6379
|
this.operationSuccess$ = this.operationSuccess.asObservable();
|
|
6352
6380
|
// PAGINATION
|
|
@@ -6673,10 +6701,10 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
6673
6701
|
return state;
|
|
6674
6702
|
if (this.dataType === DataType.ARRAY) {
|
|
6675
6703
|
const dataArray = Array.isArray(data) ? data : [data];
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
const updatedData =
|
|
6704
|
+
// Non-streaming path: merge incoming records with existing state.
|
|
6705
|
+
// Streaming responses go through `setStreamData$` instead, which always
|
|
6706
|
+
// replaces with the fully-accumulated array from the streaming operator.
|
|
6707
|
+
const updatedData = this.updateArrayState(state.data, dataArray);
|
|
6680
6708
|
return { ...state, data: updatedData, dataObject: null };
|
|
6681
6709
|
}
|
|
6682
6710
|
else {
|
|
@@ -6684,6 +6712,18 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
6684
6712
|
return { ...state, data: [], dataObject: dataObject };
|
|
6685
6713
|
}
|
|
6686
6714
|
});
|
|
6715
|
+
/**
|
|
6716
|
+
* Streaming-only updater: replaces `data` with the incoming array.
|
|
6717
|
+
*
|
|
6718
|
+
* The streaming operator (`requestStreaming`) accumulates records via `scan`,
|
|
6719
|
+
* so each emission is the full accumulated dataset. Replace, don't merge.
|
|
6720
|
+
*/
|
|
6721
|
+
this.setStreamData$ = this.updater((state, data) => {
|
|
6722
|
+
if (!data)
|
|
6723
|
+
return state;
|
|
6724
|
+
const dataArray = Array.isArray(data) ? data : [data];
|
|
6725
|
+
return { ...state, data: dataArray, dataObject: null };
|
|
6726
|
+
});
|
|
6687
6727
|
this.addData$ = this.updater((state, data) => {
|
|
6688
6728
|
if (this.dataType === DataType.ARRAY) {
|
|
6689
6729
|
const exists = state.data.some(item => item.id === data.id);
|
|
@@ -6928,32 +6968,27 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
6928
6968
|
}
|
|
6929
6969
|
}));
|
|
6930
6970
|
})));
|
|
6931
|
-
this.fetchStream =
|
|
6932
|
-
|
|
6933
|
-
|
|
6971
|
+
this.fetchStream = this.effect((options$) => options$.pipe(tap((options) => {
|
|
6972
|
+
if (this.activeStream$.value) {
|
|
6973
|
+
console.warn('[fetchStream] Stream already active, skipping');
|
|
6974
|
+
return;
|
|
6975
|
+
}
|
|
6934
6976
|
this.httpManagerService.isPending.next(true);
|
|
6935
6977
|
this.activeStream$.next(true); // Mark stream as active
|
|
6978
|
+
// Reset streamed-response tracker so a new stream starts clean
|
|
6979
|
+
this.streamedResponse = [];
|
|
6936
6980
|
}), concatMap((options) => {
|
|
6937
6981
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
6938
6982
|
requestOptions.stream = true;
|
|
6939
|
-
console.log('[DEBUG] Making streaming request:', requestOptions);
|
|
6940
6983
|
return this.httpManagerService.getRequest(requestOptions, options?.path)
|
|
6941
6984
|
.pipe(tap((res) => {
|
|
6942
|
-
//
|
|
6943
|
-
// Always
|
|
6944
|
-
if (res && res.length > 0) {
|
|
6945
|
-
|
|
6946
|
-
this.setData$(res);
|
|
6985
|
+
// Streaming operator emits the fully-accumulated array on every chunk.
|
|
6986
|
+
// Always replace state — don't merge — to keep table in sync as records append.
|
|
6987
|
+
if (res && Array.isArray(res) && res.length > 0) {
|
|
6988
|
+
this.setStreamData$(res);
|
|
6947
6989
|
this.streamedResponse = res;
|
|
6948
6990
|
}
|
|
6949
|
-
|
|
6950
|
-
// console.log('[DEBUG] No streaming data or empty array:', res)
|
|
6951
|
-
}
|
|
6952
|
-
}), map((res) => {
|
|
6953
|
-
// console.log('[DEBUG] Returning data to subscribers:', res)
|
|
6954
|
-
return res; // Return the data so subscribers can receive it
|
|
6955
|
-
}), catchError((error) => {
|
|
6956
|
-
// console.error('[DEBUG] Streaming error:', error)
|
|
6991
|
+
}), map((res) => res), catchError((error) => {
|
|
6957
6992
|
this.httpManagerService.isPending.next(false);
|
|
6958
6993
|
return of([]);
|
|
6959
6994
|
}), finalize(() => this.activeStream$.next(false)) // Mark stream as complete
|
|
@@ -8467,7 +8502,7 @@ class RequestManagerBasicDemoComponent {
|
|
|
8467
8502
|
// Update displayed columns when data changes
|
|
8468
8503
|
updateDisplayedColumns(data) {
|
|
8469
8504
|
this.displayedColumns = this.getColumnsFromData(data);
|
|
8470
|
-
console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
8505
|
+
// console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
8471
8506
|
}
|
|
8472
8507
|
// Helper to check if value is an object
|
|
8473
8508
|
isObject(value) {
|
|
@@ -8727,7 +8762,7 @@ class RequestManagerBasicDemoComponent {
|
|
|
8727
8762
|
this.requestParams.GET = reqParams.apiOptions;
|
|
8728
8763
|
this.STREAM$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
8729
8764
|
.pipe(tap((data) => {
|
|
8730
|
-
console.log("API STREAM response", data)
|
|
8765
|
+
// console.log("API STREAM response", data)
|
|
8731
8766
|
if (data && data.length > 0) {
|
|
8732
8767
|
this.updateDisplayedColumns(data);
|
|
8733
8768
|
}
|
|
@@ -8860,7 +8895,7 @@ class StateManagerDemoService extends HTTPManagerStateService {
|
|
|
8860
8895
|
auth: "sample-auth-token"
|
|
8861
8896
|
};
|
|
8862
8897
|
console.log('[DEMO SERVICE] Calling fetchStream with headers:', headers);
|
|
8863
|
-
this.fetchStream();
|
|
8898
|
+
this.fetchStream({ headers });
|
|
8864
8899
|
}
|
|
8865
8900
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StateManagerDemoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
8866
8901
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StateManagerDemoService }); }
|
|
@@ -8894,7 +8929,7 @@ class RequestManagerStateDemoComponent {
|
|
|
8894
8929
|
// Update displayed columns when data changes
|
|
8895
8930
|
updateDisplayedColumns(data) {
|
|
8896
8931
|
this.displayedColumns = this.getColumnsFromData(data);
|
|
8897
|
-
console.log('[STATE DEMO] Updated columns:', this.displayedColumns)
|
|
8932
|
+
// console.log('[STATE DEMO] Updated columns:', this.displayedColumns)
|
|
8898
8933
|
}
|
|
8899
8934
|
// Helper to check if value is an object
|
|
8900
8935
|
isObject(value) {
|
|
@@ -8974,7 +9009,7 @@ class RequestManagerStateDemoComponent {
|
|
|
8974
9009
|
this.POST$ = new BehaviorSubject(null);
|
|
8975
9010
|
this.PUT$ = new BehaviorSubject(null);
|
|
8976
9011
|
this.DELETE$ = new BehaviorSubject(null);
|
|
8977
|
-
this.STREAM = new BehaviorSubject(
|
|
9012
|
+
this.STREAM = new BehaviorSubject([]);
|
|
8978
9013
|
this.STREAM$ = this.STREAM.asObservable();
|
|
8979
9014
|
this.STREAM_AI = new BehaviorSubject([]);
|
|
8980
9015
|
this.STREAM_AI$ = this.STREAM_AI.asObservable()
|
|
@@ -9032,7 +9067,7 @@ class RequestManagerStateDemoComponent {
|
|
|
9032
9067
|
this.stateManagerDemoService.data$.pipe(tap$1((data) => console.log("API STREAM_AI response", data)));
|
|
9033
9068
|
this.error$.pipe(tap$1((data) => {
|
|
9034
9069
|
debugger;
|
|
9035
|
-
console.log("API STREAM response", data)
|
|
9070
|
+
// console.log("API STREAM response", data)
|
|
9036
9071
|
}), catchError$1(error => {
|
|
9037
9072
|
return throwError(() => this.errorHandling(error, 'STREAM'));
|
|
9038
9073
|
}));
|
|
@@ -9042,26 +9077,26 @@ class RequestManagerStateDemoComponent {
|
|
|
9042
9077
|
});
|
|
9043
9078
|
this.stateManagerDemoService.data$
|
|
9044
9079
|
.pipe(tap$1((data) => {
|
|
9045
|
-
console.log('[COMPONENT] State data received:', data)
|
|
9080
|
+
// console.log('[COMPONENT] State data received:', data)
|
|
9046
9081
|
switch (this.requestType) {
|
|
9047
9082
|
case 'GET':
|
|
9048
|
-
console.log('[COMPONENT] Updating GET$ with data:', data)
|
|
9083
|
+
// console.log('[COMPONENT] Updating GET$ with data:', data)
|
|
9049
9084
|
this.GET$.next(data);
|
|
9050
9085
|
break;
|
|
9051
9086
|
case 'PUT':
|
|
9052
|
-
console.log('[COMPONENT] Updating PUT$ with data:', data)
|
|
9087
|
+
// console.log('[COMPONENT] Updating PUT$ with data:', data)
|
|
9053
9088
|
this.PUT$.next(data);
|
|
9054
9089
|
break;
|
|
9055
9090
|
case 'POST':
|
|
9056
|
-
console.log('[COMPONENT] Updating POST$ with data:', data)
|
|
9091
|
+
// console.log('[COMPONENT] Updating POST$ with data:', data)
|
|
9057
9092
|
this.POST$.next(data);
|
|
9058
9093
|
break;
|
|
9059
9094
|
case 'DELETE':
|
|
9060
|
-
console.log('[COMPONENT] Updating DELETE$ with data:', data)
|
|
9095
|
+
// console.log('[COMPONENT] Updating DELETE$ with data:', data)
|
|
9061
9096
|
this.DELETE$.next(data);
|
|
9062
9097
|
break;
|
|
9063
9098
|
case 'STREAM':
|
|
9064
|
-
console.log('[COMPONENT] Updating STREAM$ with data:', data)
|
|
9099
|
+
// console.log('[COMPONENT] Updating STREAM$ with data:', data)
|
|
9065
9100
|
this.STREAM.next(data);
|
|
9066
9101
|
// Update table columns dynamically based on streaming data
|
|
9067
9102
|
if (data && Array.isArray(data) && data.length > 0) {
|
|
@@ -9069,11 +9104,11 @@ class RequestManagerStateDemoComponent {
|
|
|
9069
9104
|
}
|
|
9070
9105
|
break;
|
|
9071
9106
|
case 'STREAM_AI':
|
|
9072
|
-
console.log('[COMPONENT] Updating STREAM_AI$ with data:', data)
|
|
9107
|
+
// console.log('[COMPONENT] Updating STREAM_AI$ with data:', data)
|
|
9073
9108
|
this.STREAM_AI.next(data);
|
|
9074
9109
|
break;
|
|
9075
9110
|
default:
|
|
9076
|
-
console.log('[COMPONENT] No requestType set, ignoring data')
|
|
9111
|
+
// console.log('[COMPONENT] No requestType set, ignoring data')
|
|
9077
9112
|
break;
|
|
9078
9113
|
}
|
|
9079
9114
|
})).subscribe();
|
|
@@ -9137,18 +9172,18 @@ class RequestManagerStateDemoComponent {
|
|
|
9137
9172
|
this.stateManagerDemoService.deleteClient(this.sampleClientData);
|
|
9138
9173
|
}
|
|
9139
9174
|
onStreamRequest() {
|
|
9140
|
-
console.log('[COMPONENT] onStreamRequest called')
|
|
9175
|
+
// console.log('[COMPONENT] onStreamRequest called')
|
|
9141
9176
|
if (!this.isValid) {
|
|
9142
|
-
console.log('[COMPONENT] Form invalid, aborting')
|
|
9177
|
+
// console.log('[COMPONENT] Form invalid, aborting')
|
|
9143
9178
|
return;
|
|
9144
9179
|
}
|
|
9145
|
-
console.log('[COMPONENT] Compiling request...')
|
|
9180
|
+
// console.log('[COMPONENT] Compiling request...')
|
|
9146
9181
|
const reqParams = this.compileRequest();
|
|
9147
|
-
console.log('[COMPONENT] Setting stream options:', reqParams.apiOptions)
|
|
9182
|
+
// console.log('[COMPONENT] Setting stream options:', reqParams.apiOptions)
|
|
9148
9183
|
reqParams.apiOptions.stream = true;
|
|
9149
9184
|
reqParams.apiOptions.streamType = this.streamType;
|
|
9150
9185
|
this.requestType = 'STREAM';
|
|
9151
|
-
console.log('[COMPONENT] Calling streamRequest...')
|
|
9186
|
+
// console.log('[COMPONENT] Calling streamRequest...')
|
|
9152
9187
|
this.stateManagerDemoService.streamRequest();
|
|
9153
9188
|
}
|
|
9154
9189
|
errorHandling(err, type) {
|
|
@@ -9173,11 +9208,11 @@ class RequestManagerStateDemoComponent {
|
|
|
9173
9208
|
this.prompts = [];
|
|
9174
9209
|
}
|
|
9175
9210
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerStateDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9176
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo", inputs: { server: "server", adapter: "adapter", mapper: "mapper" }, providers: [StateManagerDemoService, HTTPManagerService], 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 @for (adapter of sampleAdaptors; track adapter) {\n <mat-option [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n }\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 @for (mapper of sampleMappers; track mapper) {\n <mat-option [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (adapterSelect.value || mapperSelect.value) {\n <div style=\"display: flex; margin-bottom: 2rem;\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n @if (adapterSelect.value) {\n <div>\n {{ props(adapterSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n @if (mapperSelect.value) {\n <div>\n {{ props(mapperSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n </div>\n }\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 @for (task of headers.controls; track task; let i = $index) {\n <div [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 }\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 @if (failedState.checked) {\n <div 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 }\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n @if (pollingState.checked) {\n <div>\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 }\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n @if (DBState.checked) {\n <div 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 }\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 @if ((error$ | async); as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n @if ((isPending$ | async)) {\n <mat-progress-bar mode=\"indeterminate\"\n ></mat-progress-bar>\n }\n @if (pollingState.checked) {\n <div>\n @if (!(isPending$ | async) && (this.countdown$ | async) || -1 > 0) {\n <mat-progress-bar mode=\"determinate\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n }\n </div>\n }\n\n </div>\n\n @if ((GET$ | async); as data) {\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n @if (data.length > 1) {\n <div>\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 @for (item of data; track item) {\n <mat-option [value]=\"item\">\n {{item.name || (item.first_name) | titlecase}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n }\n @if ((dataObservable$ | async); as dataRecord) {\n <div>\n @if ((selectedRecord$ | async); as record) {\n <div>\n {{ record | json }}\n </div>\n } @else {\n No Record Selected from State\n }\n </div>\n }\n <div style=\"margin-top: 1rem;\">\n @if (data !== null && data?.length > 0) {\n <span>\n State contains a Total of {{ data.length }} Records\n </span>\n } @else {\n No Records\n }\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 </div>\n </div>\n </div>\n }\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 @if ((GET_error$ | async); as get_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n @if ((GET$ | async); as getData) {\n <div>{{ getData | json }}</div>\n }\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 @if ((POST_error$ | async); as post_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n @if ((POST$ | async); as postData) {\n <div>{{ postData | json }}</div>\n }\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 @if ((PUT_error$ | async); as put_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n @if ((PUT$ | async); as putData) {\n <div>{{ putData | json }}</div>\n }\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 @if ((DELETE_error$ | async); as delete_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n @if ((DELETE$ | async); as deleteData) {\n <div>{{ deleteData | json }}</div>\n }\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 style=\"display: flex; gap: 1rem; align-items: center;\">\n <div style=\"display: flex; gap: 1rem; align-items: center;\">\n {{ streamType }}\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>data_usage</mat-icon>\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item *ngFor=\"let item of streamTypes\" (click)=\"onStreamType(item.id)\">{{ item.value }}</button>\n </mat-menu>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\" [disabled]=\"hasChanged\">Request</button>\n </div>\n </div>\n\n @if ((STREAM_error$ | async); as stream_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n @if ((STREAM$ | async) && (isStreamingPending$ | async); as data) {\n <mat-progress-bar mode=\"determinate\" [value]=\"(progress$ | async)?.percent ?? 0\"></mat-progress-bar>\n <div class=\"container\">\n <table mat-table [dataSource]=\"data\">\n\n <!-- Dynamic columns -->\n <ng-container *ngFor=\"let column of displayedColumns\" [matColumnDef]=\"column\">\n <th mat-header-cell *matHeaderCellDef> {{ column | titlecase }} </th>\n <td mat-cell *matCellDef=\"let element\">\n @if (isObject(element[column]); as objValue) {\n <pre style=\"margin: 0; font-size: 0.8em; white-space: pre-wrap;\">{{ objValue | json }}</pre>\n } @else {\n {{ element[column] }}\n }\n </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\n <!-- Debug info -->\n <div style=\"margin-top: 1rem; font-size: 0.8em; color: #666;\">\n Columns: {{ displayedColumns.join(', ') }} | Data received\n </div>\n </div>\n }\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: i2$1.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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.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: i8$1.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" }] }); }
|
|
9211
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo", inputs: { server: "server", adapter: "adapter", mapper: "mapper" }, providers: [StateManagerDemoService, HTTPManagerService], 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 @for (adapter of sampleAdaptors; track adapter) {\n <mat-option [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n }\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 @for (mapper of sampleMappers; track mapper) {\n <mat-option [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (adapterSelect.value || mapperSelect.value) {\n <div style=\"display: flex; margin-bottom: 2rem;\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n @if (adapterSelect.value) {\n <div>\n {{ props(adapterSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n @if (mapperSelect.value) {\n <div>\n {{ props(mapperSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n </div>\n }\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 @for (task of headers.controls; track task; let i = $index) {\n <div [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 }\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 @if (failedState.checked) {\n <div 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 }\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n @if (pollingState.checked) {\n <div>\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 }\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n @if (DBState.checked) {\n <div 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 }\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 @if ((error$ | async); as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n @if ((isPending$ | async)) {\n <mat-progress-bar mode=\"indeterminate\"\n ></mat-progress-bar>\n }\n @if (pollingState.checked) {\n <div>\n @if (!(isPending$ | async) && (this.countdown$ | async) || -1 > 0) {\n <mat-progress-bar mode=\"determinate\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n }\n </div>\n }\n\n </div>\n\n @if ((GET$ | async); as data) {\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n @if (data.length > 1) {\n <div>\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 @for (item of data; track item) {\n <mat-option [value]=\"item\">\n {{item.name || (item.first_name) | titlecase}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n }\n @if ((dataObservable$ | async); as dataRecord) {\n <div>\n @if ((selectedRecord$ | async); as record) {\n <div>\n {{ record | json }}\n </div>\n } @else {\n No Record Selected from State\n }\n </div>\n }\n <div style=\"margin-top: 1rem;\">\n @if (data !== null && data?.length > 0) {\n <span>\n State contains a Total of {{ data.length }} Records\n </span>\n } @else {\n No Records\n }\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 </div>\n </div>\n </div>\n }\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 @if ((GET_error$ | async); as get_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n @if ((GET$ | async); as getData) {\n <div>{{ getData | json }}</div>\n }\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 @if ((POST_error$ | async); as post_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n @if ((POST$ | async); as postData) {\n <div>{{ postData | json }}</div>\n }\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 @if ((PUT_error$ | async); as put_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n @if ((PUT$ | async); as putData) {\n <div>{{ putData | json }}</div>\n }\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 @if ((DELETE_error$ | async); as delete_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n @if ((DELETE$ | async); as deleteData) {\n <div>{{ deleteData | json }}</div>\n }\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 style=\"display: flex; gap: 1rem; align-items: center;\">\n <div style=\"display: flex; gap: 1rem; align-items: center;\">\n {{ streamType }}\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>data_usage</mat-icon>\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item *ngFor=\"let item of streamTypes\" (click)=\"onStreamType(item.id)\">{{ item.value }}</button>\n </mat-menu>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\" [disabled]=\"hasChanged\">Request</button>\n </div>\n </div>\n\n @if ((STREAM_error$ | async); as stream_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n @if ((isStreamingPending$ | async) || ((STREAM$ | async)?.length)) {\n <mat-progress-bar mode=\"determinate\" [value]=\"(progress$ | async)?.percent ?? 0\"></mat-progress-bar>\n }\n @if ((STREAM$ | async); as data) {\n @if (data?.length) {\n <div class=\"container\">\n <table mat-table [dataSource]=\"data\">\n\n <!-- Dynamic columns -->\n <ng-container *ngFor=\"let column of displayedColumns\" [matColumnDef]=\"column\">\n <th mat-header-cell *matHeaderCellDef> {{ column | titlecase }} </th>\n <td mat-cell *matCellDef=\"let element\">\n @if (isObject(element[column]); as objValue) {\n <pre style=\"margin: 0; font-size: 0.8em; white-space: pre-wrap;\">{{ objValue | json }}</pre>\n } @else {\n {{ element[column] }}\n }\n </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\n <!-- Debug info -->\n <div style=\"margin-top: 1rem; font-size: 0.8em; color: #666;\">\n Columns: {{ displayedColumns.join(', ') }} | Rows: {{ data.length }}\n </div>\n </div>\n }\n }\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: i2$1.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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.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: i8$1.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" }] }); }
|
|
9177
9212
|
}
|
|
9178
9213
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerStateDemoComponent, decorators: [{
|
|
9179
9214
|
type: Component,
|
|
9180
|
-
args: [{ selector: 'app-request-manager-state-demo', providers: [StateManagerDemoService, HTTPManagerService], standalone: false, 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 @for (adapter of sampleAdaptors; track adapter) {\n <mat-option [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n }\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 @for (mapper of sampleMappers; track mapper) {\n <mat-option [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (adapterSelect.value || mapperSelect.value) {\n <div style=\"display: flex; margin-bottom: 2rem;\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n @if (adapterSelect.value) {\n <div>\n {{ props(adapterSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n @if (mapperSelect.value) {\n <div>\n {{ props(mapperSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n </div>\n }\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 @for (task of headers.controls; track task; let i = $index) {\n <div [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 }\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 @if (failedState.checked) {\n <div 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 }\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n @if (pollingState.checked) {\n <div>\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 }\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n @if (DBState.checked) {\n <div 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 }\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 @if ((error$ | async); as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n @if ((isPending$ | async)) {\n <mat-progress-bar mode=\"indeterminate\"\n ></mat-progress-bar>\n }\n @if (pollingState.checked) {\n <div>\n @if (!(isPending$ | async) && (this.countdown$ | async) || -1 > 0) {\n <mat-progress-bar mode=\"determinate\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n }\n </div>\n }\n\n </div>\n\n @if ((GET$ | async); as data) {\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n @if (data.length > 1) {\n <div>\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 @for (item of data; track item) {\n <mat-option [value]=\"item\">\n {{item.name || (item.first_name) | titlecase}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n }\n @if ((dataObservable$ | async); as dataRecord) {\n <div>\n @if ((selectedRecord$ | async); as record) {\n <div>\n {{ record | json }}\n </div>\n } @else {\n No Record Selected from State\n }\n </div>\n }\n <div style=\"margin-top: 1rem;\">\n @if (data !== null && data?.length > 0) {\n <span>\n State contains a Total of {{ data.length }} Records\n </span>\n } @else {\n No Records\n }\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 </div>\n </div>\n </div>\n }\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 @if ((GET_error$ | async); as get_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n @if ((GET$ | async); as getData) {\n <div>{{ getData | json }}</div>\n }\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 @if ((POST_error$ | async); as post_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n @if ((POST$ | async); as postData) {\n <div>{{ postData | json }}</div>\n }\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 @if ((PUT_error$ | async); as put_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n @if ((PUT$ | async); as putData) {\n <div>{{ putData | json }}</div>\n }\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 @if ((DELETE_error$ | async); as delete_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n @if ((DELETE$ | async); as deleteData) {\n <div>{{ deleteData | json }}</div>\n }\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 style=\"display: flex; gap: 1rem; align-items: center;\">\n <div style=\"display: flex; gap: 1rem; align-items: center;\">\n {{ streamType }}\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>data_usage</mat-icon>\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item *ngFor=\"let item of streamTypes\" (click)=\"onStreamType(item.id)\">{{ item.value }}</button>\n </mat-menu>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\" [disabled]=\"hasChanged\">Request</button>\n </div>\n </div>\n\n @if ((STREAM_error$ | async); as stream_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n @if ((STREAM$ | async) && (isStreamingPending$ | async); as data) {\n <mat-progress-bar mode=\"determinate\" [value]=\"(progress$ | async)?.percent ?? 0\"></mat-progress-bar>\n <div class=\"container\">\n <table mat-table [dataSource]=\"data\">\n\n <!-- Dynamic columns -->\n <ng-container *ngFor=\"let column of displayedColumns\" [matColumnDef]=\"column\">\n <th mat-header-cell *matHeaderCellDef> {{ column | titlecase }} </th>\n <td mat-cell *matCellDef=\"let element\">\n @if (isObject(element[column]); as objValue) {\n <pre style=\"margin: 0; font-size: 0.8em; white-space: pre-wrap;\">{{ objValue | json }}</pre>\n } @else {\n {{ element[column] }}\n }\n </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\n <!-- Debug info -->\n <div style=\"margin-top: 1rem; font-size: 0.8em; color: #666;\">\n Columns: {{ displayedColumns.join(', ') }} | Data received\n </div>\n </div>\n }\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"] }]
|
|
9215
|
+
args: [{ selector: 'app-request-manager-state-demo', providers: [StateManagerDemoService, HTTPManagerService], standalone: false, 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 @for (adapter of sampleAdaptors; track adapter) {\n <mat-option [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n }\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 @for (mapper of sampleMappers; track mapper) {\n <mat-option [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (adapterSelect.value || mapperSelect.value) {\n <div style=\"display: flex; margin-bottom: 2rem;\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n @if (adapterSelect.value) {\n <div>\n {{ props(adapterSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n @if (mapperSelect.value) {\n <div>\n {{ props(mapperSelect.value) | json }}\n </div>\n } @else {\n No Transformation\n }\n </div>\n </div>\n }\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 @for (task of headers.controls; track task; let i = $index) {\n <div [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 }\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 @if (failedState.checked) {\n <div 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 }\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n @if (pollingState.checked) {\n <div>\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 }\n </div>\n <div>\n <mat-slide-toggle #DBState>Database Storage</mat-slide-toggle>\n @if (DBState.checked) {\n <div 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 }\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 @if ((error$ | async); as error) {\n <mat-error>\n {{ error }}\n </mat-error>\n }\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n @if ((isPending$ | async)) {\n <mat-progress-bar mode=\"indeterminate\"\n ></mat-progress-bar>\n }\n @if (pollingState.checked) {\n <div>\n @if (!(isPending$ | async) && (this.countdown$ | async) || -1 > 0) {\n <mat-progress-bar mode=\"determinate\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n }\n </div>\n }\n\n </div>\n\n @if ((GET$ | async); as data) {\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1;\">CURRENT STATE ({{ dataType }})</h2>\n </div>\n @if (data.length > 1) {\n <div>\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 @for (item of data; track item) {\n <mat-option [value]=\"item\">\n {{item.name || (item.first_name) | titlecase}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n }\n @if ((dataObservable$ | async); as dataRecord) {\n <div>\n @if ((selectedRecord$ | async); as record) {\n <div>\n {{ record | json }}\n </div>\n } @else {\n No Record Selected from State\n }\n </div>\n }\n <div style=\"margin-top: 1rem;\">\n @if (data !== null && data?.length > 0) {\n <span>\n State contains a Total of {{ data.length }} Records\n </span>\n } @else {\n No Records\n }\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 </div>\n </div>\n </div>\n }\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 @if ((GET_error$ | async); as get_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n @if ((GET$ | async); as getData) {\n <div>{{ getData | json }}</div>\n }\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 @if ((POST_error$ | async); as post_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n @if ((POST$ | async); as postData) {\n <div>{{ postData | json }}</div>\n }\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 @if ((PUT_error$ | async); as put_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n @if ((PUT$ | async); as putData) {\n <div>{{ putData | json }}</div>\n }\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 @if ((DELETE_error$ | async); as delete_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n @if ((DELETE$ | async); as deleteData) {\n <div>{{ deleteData | json }}</div>\n }\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 style=\"display: flex; gap: 1rem; align-items: center;\">\n <div style=\"display: flex; gap: 1rem; align-items: center;\">\n {{ streamType }}\n <button mat-icon-button [matMenuTriggerFor]=\"menu\">\n <mat-icon>data_usage</mat-icon>\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item *ngFor=\"let item of streamTypes\" (click)=\"onStreamType(item.id)\">{{ item.value }}</button>\n </mat-menu>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\" [disabled]=\"hasChanged\">Request</button>\n </div>\n </div>\n\n @if ((STREAM_error$ | async); as stream_error) {\n <div style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n }\n\n <div style=\"margin-top: 1rem;\">\n @if ((isStreamingPending$ | async) || ((STREAM$ | async)?.length)) {\n <mat-progress-bar mode=\"determinate\" [value]=\"(progress$ | async)?.percent ?? 0\"></mat-progress-bar>\n }\n @if ((STREAM$ | async); as data) {\n @if (data?.length) {\n <div class=\"container\">\n <table mat-table [dataSource]=\"data\">\n\n <!-- Dynamic columns -->\n <ng-container *ngFor=\"let column of displayedColumns\" [matColumnDef]=\"column\">\n <th mat-header-cell *matHeaderCellDef> {{ column | titlecase }} </th>\n <td mat-cell *matCellDef=\"let element\">\n @if (isObject(element[column]); as objValue) {\n <pre style=\"margin: 0; font-size: 0.8em; white-space: pre-wrap;\">{{ objValue | json }}</pre>\n } @else {\n {{ element[column] }}\n }\n </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\n <!-- Debug info -->\n <div style=\"margin-top: 1rem; font-size: 0.8em; color: #666;\">\n Columns: {{ displayedColumns.join(', ') }} | Rows: {{ data.length }}\n </div>\n </div>\n }\n }\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"] }]
|
|
9181
9216
|
}], ctorParameters: () => [], propDecorators: { server: [{
|
|
9182
9217
|
type: Input
|
|
9183
9218
|
}], adapter: [{
|
|
@@ -9208,7 +9243,7 @@ class RequestManagerDemoComponent {
|
|
|
9208
9243
|
// Update displayed columns when data changes
|
|
9209
9244
|
updateDisplayedColumns(data) {
|
|
9210
9245
|
this.displayedColumns = this.getColumnsFromData(data);
|
|
9211
|
-
console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
9246
|
+
// console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
9212
9247
|
}
|
|
9213
9248
|
// Helper to check if value is an object
|
|
9214
9249
|
isObject(value) {
|
|
@@ -9492,7 +9527,7 @@ class RequestManagerDemoComponent {
|
|
|
9492
9527
|
this.STREAM_error$.next('');
|
|
9493
9528
|
this.STREAM$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
9494
9529
|
.pipe(tap((data) => {
|
|
9495
|
-
console.log("API STREAM response", data)
|
|
9530
|
+
// console.log("API STREAM response", data)
|
|
9496
9531
|
if (data && data.length > 0) {
|
|
9497
9532
|
this.updateDisplayedColumns(data);
|
|
9498
9533
|
}
|