http-request-manager 18.11.23 → 18.12.3

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.
@@ -2655,6 +2655,157 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2655
2655
 
2656
2656
  // ChannelType is already exported from request-manager-state-service to avoid conflicts
2657
2657
 
2658
+ class DatabaseStorage {
2659
+ constructor(table = '', expiresIn) {
2660
+ this.table = table;
2661
+ this.expiresIn = expiresIn;
2662
+ }
2663
+ static adapt(item) {
2664
+ if (!item?.table)
2665
+ return;
2666
+ return new DatabaseStorage(item?.table, item?.expiresIn);
2667
+ }
2668
+ }
2669
+
2670
+ class RetryOptions {
2671
+ constructor(times = 0, delay = 3) {
2672
+ this.times = times;
2673
+ this.delay = delay;
2674
+ }
2675
+ static adapt(item) {
2676
+ return new RetryOptions(item?.times, item?.delay);
2677
+ }
2678
+ }
2679
+
2680
+ class BatchOptions {
2681
+ constructor(mode = 'sequential', stopOnError = false, concurrency = 3, ignoreErrors = false, logErrors = true, displaySuccess, displayError) {
2682
+ this.mode = mode;
2683
+ this.stopOnError = stopOnError;
2684
+ this.concurrency = concurrency;
2685
+ this.ignoreErrors = ignoreErrors;
2686
+ this.logErrors = logErrors;
2687
+ this.displaySuccess = displaySuccess;
2688
+ this.displayError = displayError;
2689
+ }
2690
+ static adapt(item) {
2691
+ return new BatchOptions(item?.mode ?? 'sequential', item?.stopOnError ?? false, item?.concurrency ?? 3, item?.ignoreErrors ?? false, item?.logErrors !== false, item?.displaySuccess ?? false, item?.displayError ?? false);
2692
+ }
2693
+ }
2694
+
2695
+ class BatchResult {
2696
+ constructor(request, success, data, error, index = 0, timestamp = Date.now()) {
2697
+ this.request = request;
2698
+ this.success = success;
2699
+ this.data = data;
2700
+ this.error = error;
2701
+ this.index = index;
2702
+ this.timestamp = timestamp;
2703
+ }
2704
+ static adapt(item) {
2705
+ return new BatchResult(item?.request, item?.success ?? false, item?.data, item?.error, item?.index ?? 0, item?.timestamp ?? Date.now());
2706
+ }
2707
+ }
2708
+
2709
+ function isPendingState(state) {
2710
+ return state.isPending === true;
2711
+ }
2712
+ function isSuccessState(state) {
2713
+ return state.isPending === false && state.data !== undefined;
2714
+ }
2715
+ function isErrorState(state) {
2716
+ return state.isPending === false && state.error !== undefined;
2717
+ }
2718
+
2719
+ function calculateBatchProgress(states) {
2720
+ const total = states.length;
2721
+ const pending = states.filter(s => s.isPending).length;
2722
+ const completed = states.filter(s => !s.isPending && s.data !== undefined).length;
2723
+ const failed = states.filter(s => !s.isPending && s.error !== undefined).length;
2724
+ const percent = total > 0 ? Math.round(((completed + failed) / total) * 100) : 0;
2725
+ return { total, pending, completed, failed, percent };
2726
+ }
2727
+
2728
+ var DataType;
2729
+ (function (DataType) {
2730
+ DataType[DataType["ANY"] = 0] = "ANY";
2731
+ DataType[DataType["ARRAY"] = 1] = "ARRAY";
2732
+ DataType[DataType["OBJECT"] = 2] = "OBJECT";
2733
+ })(DataType || (DataType = {}));
2734
+
2735
+ class ConfigHTTPOptions {
2736
+ constructor(server = '', path, headers, polling, retry, stream, displayError, displaySuccess) {
2737
+ this.server = server;
2738
+ this.path = path;
2739
+ this.headers = headers;
2740
+ this.polling = polling;
2741
+ this.retry = retry;
2742
+ this.stream = stream;
2743
+ this.displayError = displayError;
2744
+ this.displaySuccess = displaySuccess;
2745
+ }
2746
+ static adapt(item) {
2747
+ const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
2748
+ const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
2749
+ return new ConfigHTTPOptions(server, (item?.path) ? item.path : [], (item?.headers) ? item.headers : {}, item?.polling ? Math.floor(item.polling) : 0, retryOptions, (item?.stream) ? item.stream : false, (item?.displayError) ? item.displayError : false, (item?.displaySuccess) ? item.displaySuccess : false);
2750
+ }
2751
+ }
2752
+
2753
+ class LocalStorageOptions {
2754
+ constructor(storageName, storageSettingsName, options) {
2755
+ this.storageName = storageName;
2756
+ this.storageSettingsName = storageSettingsName;
2757
+ this.options = options;
2758
+ }
2759
+ static adapt(item) {
2760
+ return new LocalStorageOptions((item?.storageName) ? item.storageName : 'storage', (item?.storageSettingsName) ? item.storageSettingsName : 'global-storage', (item?.options) ? SettingOptions.adapt(item.options) : SettingOptions.adapt());
2761
+ }
2762
+ }
2763
+
2764
+ class ConfigOptions {
2765
+ constructor(httpRequestOptions, LocalStorageOptions) {
2766
+ this.httpRequestOptions = httpRequestOptions;
2767
+ this.LocalStorageOptions = LocalStorageOptions;
2768
+ }
2769
+ static adapt(item) {
2770
+ return new ConfigOptions((item?.httpRequestOptions) ? ConfigHTTPOptions.adapt(item.httpRequestOptions) : undefined, (item?.LocalStorageOptions) ? LocalStorageOptions.adapt(item.LocalStorageOptions) : undefined);
2771
+ }
2772
+ }
2773
+
2774
+ class InvalidFileInfoModel {
2775
+ constructor(fileName = '', fileSize = 0, fileType = '', errors = []) {
2776
+ this.fileName = fileName;
2777
+ this.fileSize = fileSize;
2778
+ this.fileType = fileType;
2779
+ this.errors = errors;
2780
+ }
2781
+ static adapt(item) {
2782
+ return new InvalidFileInfoModel(item?.fileName, item?.fileSize, item?.fileType, Array.isArray(item?.errors) ? item.errors : []);
2783
+ }
2784
+ }
2785
+ class UploadValidationErrorModel {
2786
+ constructor(invalidFiles = [], validFilesCount = 0, totalFilesCount = 0) {
2787
+ this.invalidFiles = invalidFiles;
2788
+ this.validFilesCount = validFilesCount;
2789
+ this.totalFilesCount = totalFilesCount;
2790
+ }
2791
+ static adapt(item) {
2792
+ return new UploadValidationErrorModel(Array.isArray(item?.invalidFiles) ? item.invalidFiles.map((f) => InvalidFileInfoModel.adapt(f)) : [], item?.validFilesCount, item?.totalFilesCount);
2793
+ }
2794
+ }
2795
+
2796
+ class UserData {
2797
+ constructor(ldap = '', name = '', email = '', color = RandomPaletteColor()) {
2798
+ this.ldap = ldap;
2799
+ this.name = name;
2800
+ this.email = email;
2801
+ this.color = color;
2802
+ }
2803
+ static adapt(item) {
2804
+ const userName = `${item?.first_name} ${item?.last_name}`;
2805
+ return new UserData(item?.ldap, userName, item?.email, item?.color);
2806
+ }
2807
+ }
2808
+
2658
2809
  class RequestService extends WebsocketService {
2659
2810
  constructor() {
2660
2811
  super(...arguments);
@@ -2795,6 +2946,89 @@ class RequestService extends WebsocketService {
2795
2946
  return throwError(() => err);
2796
2947
  }));
2797
2948
  }
2949
+ uploadFileRequest(options) {
2950
+ this.isPending.next(true);
2951
+ const files = options.uploadFiles ? (Array.isArray(options.uploadFiles) ? options.uploadFiles : [options.uploadFiles]) : [];
2952
+ const validation = this.validateUploadFiles(files, options);
2953
+ if (validation.validFiles.length === 0) {
2954
+ this.isPending.next(false);
2955
+ return throwError(() => new UploadValidationErrorModel(validation.invalidFiles, 0, files.length));
2956
+ }
2957
+ const fieldName = options.uploadFieldName || (files.length === 1 ? 'file' : 'files');
2958
+ const formData = this.buildFormData(validation.validFiles, fieldName);
2959
+ const urlPath = this.buildUrlPath(options);
2960
+ const method = options.uploadHttpMethod || 'POST';
2961
+ return this.http.request(method, urlPath, {
2962
+ body: formData,
2963
+ observe: 'events',
2964
+ reportProgress: true
2965
+ }).pipe(map((event) => {
2966
+ this.isPending.next(true);
2967
+ switch (event.type) {
2968
+ case HttpEventType.UploadProgress:
2969
+ const status = event.total ? Math.round(event.loaded / (event.total || 1) * 100) : 0;
2970
+ this.progress.next(status);
2971
+ return null;
2972
+ case HttpEventType.Response:
2973
+ this.isPending.next(false);
2974
+ this.progress.next(0);
2975
+ return event.body;
2976
+ default:
2977
+ return null;
2978
+ }
2979
+ }), filter((body) => body !== null), catchError(err => {
2980
+ this.isPending.next(false);
2981
+ this.progress.next(0);
2982
+ return throwError(() => err);
2983
+ }));
2984
+ }
2985
+ validateUploadFiles(files, options) {
2986
+ const validFiles = [];
2987
+ const invalidFiles = [];
2988
+ let totalSize = 0;
2989
+ for (const file of files) {
2990
+ const errors = [];
2991
+ if (options.allowedTypes && options.allowedTypes.length > 0) {
2992
+ const isAllowed = options.allowedTypes.some(type => {
2993
+ if (type.endsWith('/*')) {
2994
+ return file.type.startsWith(type.replace('/*', '/'));
2995
+ }
2996
+ return file.type === type;
2997
+ });
2998
+ if (!isAllowed) {
2999
+ errors.push('type not allowed');
3000
+ }
3001
+ }
3002
+ const maxFileSize = options.maxFileSize !== undefined ? options.maxFileSize : Infinity;
3003
+ if (file.size > maxFileSize) {
3004
+ errors.push('exceeds maxFileSize');
3005
+ }
3006
+ if (errors.length > 0) {
3007
+ invalidFiles.push(new InvalidFileInfoModel(file.name, file.size, file.type, errors));
3008
+ }
3009
+ else {
3010
+ validFiles.push(file);
3011
+ totalSize += file.size;
3012
+ }
3013
+ }
3014
+ const maxTotalSize = options.maxTotalSize !== undefined ? options.maxTotalSize : Infinity;
3015
+ if (totalSize > maxTotalSize) {
3016
+ return {
3017
+ validFiles: [],
3018
+ invalidFiles: [
3019
+ new InvalidFileInfoModel('total', totalSize, '', ['exceeds maxTotalSize'])
3020
+ ]
3021
+ };
3022
+ }
3023
+ return { validFiles, invalidFiles };
3024
+ }
3025
+ buildFormData(files, fieldName) {
3026
+ const formData = new FormData();
3027
+ files.forEach((file) => {
3028
+ formData.append(fieldName, file);
3029
+ });
3030
+ return formData;
3031
+ }
2798
3032
  handleFinalize() {
2799
3033
  return finalize(() => this.isPending.next(false));
2800
3034
  }
@@ -2912,135 +3146,6 @@ function requestPolling(pollInterval, stopCondition$, isPending$) {
2912
3146
  };
2913
3147
  }
2914
3148
 
2915
- class DatabaseStorage {
2916
- constructor(table = '', expiresIn) {
2917
- this.table = table;
2918
- this.expiresIn = expiresIn;
2919
- }
2920
- static adapt(item) {
2921
- if (!item?.table)
2922
- return;
2923
- return new DatabaseStorage(item?.table, item?.expiresIn);
2924
- }
2925
- }
2926
-
2927
- class RetryOptions {
2928
- constructor(times = 0, delay = 3) {
2929
- this.times = times;
2930
- this.delay = delay;
2931
- }
2932
- static adapt(item) {
2933
- return new RetryOptions(item?.times, item?.delay);
2934
- }
2935
- }
2936
-
2937
- class BatchOptions {
2938
- constructor(mode = 'sequential', stopOnError = false, concurrency = 3, ignoreErrors = false, logErrors = true, displaySuccess, displayError) {
2939
- this.mode = mode;
2940
- this.stopOnError = stopOnError;
2941
- this.concurrency = concurrency;
2942
- this.ignoreErrors = ignoreErrors;
2943
- this.logErrors = logErrors;
2944
- this.displaySuccess = displaySuccess;
2945
- this.displayError = displayError;
2946
- }
2947
- static adapt(item) {
2948
- return new BatchOptions(item?.mode ?? 'sequential', item?.stopOnError ?? false, item?.concurrency ?? 3, item?.ignoreErrors ?? false, item?.logErrors !== false, item?.displaySuccess ?? false, item?.displayError ?? false);
2949
- }
2950
- }
2951
-
2952
- class BatchResult {
2953
- constructor(request, success, data, error, index = 0, timestamp = Date.now()) {
2954
- this.request = request;
2955
- this.success = success;
2956
- this.data = data;
2957
- this.error = error;
2958
- this.index = index;
2959
- this.timestamp = timestamp;
2960
- }
2961
- static adapt(item) {
2962
- return new BatchResult(item?.request, item?.success ?? false, item?.data, item?.error, item?.index ?? 0, item?.timestamp ?? Date.now());
2963
- }
2964
- }
2965
-
2966
- function isPendingState(state) {
2967
- return state.isPending === true;
2968
- }
2969
- function isSuccessState(state) {
2970
- return state.isPending === false && state.data !== undefined;
2971
- }
2972
- function isErrorState(state) {
2973
- return state.isPending === false && state.error !== undefined;
2974
- }
2975
-
2976
- function calculateBatchProgress(states) {
2977
- const total = states.length;
2978
- const pending = states.filter(s => s.isPending).length;
2979
- const completed = states.filter(s => !s.isPending && s.data !== undefined).length;
2980
- const failed = states.filter(s => !s.isPending && s.error !== undefined).length;
2981
- const percent = total > 0 ? Math.round(((completed + failed) / total) * 100) : 0;
2982
- return { total, pending, completed, failed, percent };
2983
- }
2984
-
2985
- var DataType;
2986
- (function (DataType) {
2987
- DataType[DataType["ANY"] = 0] = "ANY";
2988
- DataType[DataType["ARRAY"] = 1] = "ARRAY";
2989
- DataType[DataType["OBJECT"] = 2] = "OBJECT";
2990
- })(DataType || (DataType = {}));
2991
-
2992
- class ConfigHTTPOptions {
2993
- constructor(server = '', path, headers, polling, retry, stream, displayError, displaySuccess) {
2994
- this.server = server;
2995
- this.path = path;
2996
- this.headers = headers;
2997
- this.polling = polling;
2998
- this.retry = retry;
2999
- this.stream = stream;
3000
- this.displayError = displayError;
3001
- this.displaySuccess = displaySuccess;
3002
- }
3003
- static adapt(item) {
3004
- const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
3005
- const retryOptions = item?.retry ? RetryOptions.adapt(item.retry) : RetryOptions.adapt();
3006
- return new ConfigHTTPOptions(server, (item?.path) ? item.path : [], (item?.headers) ? item.headers : {}, item?.polling ? Math.floor(item.polling) : 0, retryOptions, (item?.stream) ? item.stream : false, (item?.displayError) ? item.displayError : false, (item?.displaySuccess) ? item.displaySuccess : false);
3007
- }
3008
- }
3009
-
3010
- class LocalStorageOptions {
3011
- constructor(storageName, storageSettingsName, options) {
3012
- this.storageName = storageName;
3013
- this.storageSettingsName = storageSettingsName;
3014
- this.options = options;
3015
- }
3016
- static adapt(item) {
3017
- return new LocalStorageOptions((item?.storageName) ? item.storageName : 'storage', (item?.storageSettingsName) ? item.storageSettingsName : 'global-storage', (item?.options) ? SettingOptions.adapt(item.options) : SettingOptions.adapt());
3018
- }
3019
- }
3020
-
3021
- class ConfigOptions {
3022
- constructor(httpRequestOptions, LocalStorageOptions) {
3023
- this.httpRequestOptions = httpRequestOptions;
3024
- this.LocalStorageOptions = LocalStorageOptions;
3025
- }
3026
- static adapt(item) {
3027
- return new ConfigOptions((item?.httpRequestOptions) ? ConfigHTTPOptions.adapt(item.httpRequestOptions) : undefined, (item?.LocalStorageOptions) ? LocalStorageOptions.adapt(item.LocalStorageOptions) : undefined);
3028
- }
3029
- }
3030
-
3031
- class UserData {
3032
- constructor(ldap = '', name = '', email = '', color = RandomPaletteColor()) {
3033
- this.ldap = ldap;
3034
- this.name = name;
3035
- this.email = email;
3036
- this.color = color;
3037
- }
3038
- static adapt(item) {
3039
- const userName = `${item?.first_name} ${item?.last_name}`;
3040
- return new UserData(item?.ldap, userName, item?.email, item?.color);
3041
- }
3042
- }
3043
-
3044
3149
  /**
3045
3150
  * Message Tracker Service - Guaranteed Message Delivery
3046
3151
  *
@@ -3695,6 +3800,24 @@ class HTTPManagerService extends RequestService {
3695
3800
  return this.handleError(err);
3696
3801
  }));
3697
3802
  }
3803
+ uploadRequest(files, options, params) {
3804
+ this.isPending.next(true);
3805
+ this.data.next(null);
3806
+ const updatedOptions = this.defineReqOptions(options, params);
3807
+ updatedOptions.uploadFiles = files;
3808
+ const func = this.uploadFileRequest;
3809
+ const requests = this.createRequest(func, updatedOptions);
3810
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => {
3811
+ this.data.next(data);
3812
+ if (updatedOptions.displaySuccess)
3813
+ this.handleSuccessWithSnackBar(updatedOptions.successMessage);
3814
+ }), finalize(() => this.isPending.next(false)), catchError((err) => {
3815
+ if (updatedOptions.displayError)
3816
+ this.handleErrorWithSnackBar(err, updatedOptions.errorMessage || err?.message);
3817
+ this.isPending.next(false);
3818
+ return this.handleError(err);
3819
+ }));
3820
+ }
3698
3821
  createObservable(options, request$, funcName) {
3699
3822
  const polling = options.polling ? (options.polling > 0 ? true : false) : false;
3700
3823
  const isPolling = polling &&
@@ -4084,6 +4207,89 @@ class RequestSignalsService extends WebsocketService {
4084
4207
  return throwError(() => err);
4085
4208
  }));
4086
4209
  }
4210
+ uploadFileRequest(options) {
4211
+ this.isPending.set(true);
4212
+ const files = options.uploadFiles ? (Array.isArray(options.uploadFiles) ? options.uploadFiles : [options.uploadFiles]) : [];
4213
+ const validation = this.validateUploadFiles(files, options);
4214
+ if (validation.validFiles.length === 0) {
4215
+ this.isPending.set(false);
4216
+ return throwError(() => new UploadValidationErrorModel(validation.invalidFiles, 0, files.length));
4217
+ }
4218
+ const fieldName = options.uploadFieldName || (files.length === 1 ? 'file' : 'files');
4219
+ const formData = this.buildFormData(validation.validFiles, fieldName);
4220
+ const urlPath = this.buildUrlPath(options);
4221
+ const method = options.uploadHttpMethod || 'POST';
4222
+ return this.http.request(method, urlPath, {
4223
+ body: formData,
4224
+ observe: 'events',
4225
+ reportProgress: true
4226
+ }).pipe(map((event) => {
4227
+ this.isPending.set(true);
4228
+ switch (event.type) {
4229
+ case HttpEventType.UploadProgress:
4230
+ const status = event.total ? Math.round(event.loaded / (event.total || 1) * 100) : 0;
4231
+ this.progress.set(status);
4232
+ return null;
4233
+ case HttpEventType.Response:
4234
+ this.isPending.set(false);
4235
+ this.progress.set(0);
4236
+ return event.body;
4237
+ default:
4238
+ return null;
4239
+ }
4240
+ }), filter((body) => body !== null), catchError(err => {
4241
+ this.isPending.set(false);
4242
+ this.progress.set(0);
4243
+ return throwError(() => err);
4244
+ }));
4245
+ }
4246
+ validateUploadFiles(files, options) {
4247
+ const validFiles = [];
4248
+ const invalidFiles = [];
4249
+ let totalSize = 0;
4250
+ for (const file of files) {
4251
+ const errors = [];
4252
+ if (options.allowedTypes && options.allowedTypes.length > 0) {
4253
+ const isAllowed = options.allowedTypes.some(type => {
4254
+ if (type.endsWith('/*')) {
4255
+ return file.type.startsWith(type.replace('/*', '/'));
4256
+ }
4257
+ return file.type === type;
4258
+ });
4259
+ if (!isAllowed) {
4260
+ errors.push('type not allowed');
4261
+ }
4262
+ }
4263
+ const maxFileSize = options.maxFileSize !== undefined ? options.maxFileSize : Infinity;
4264
+ if (file.size > maxFileSize) {
4265
+ errors.push('exceeds maxFileSize');
4266
+ }
4267
+ if (errors.length > 0) {
4268
+ invalidFiles.push(new InvalidFileInfoModel(file.name, file.size, file.type, errors));
4269
+ }
4270
+ else {
4271
+ validFiles.push(file);
4272
+ totalSize += file.size;
4273
+ }
4274
+ }
4275
+ const maxTotalSize = options.maxTotalSize !== undefined ? options.maxTotalSize : Infinity;
4276
+ if (totalSize > maxTotalSize) {
4277
+ return {
4278
+ validFiles: [],
4279
+ invalidFiles: [
4280
+ new InvalidFileInfoModel('total', totalSize, '', ['exceeds maxTotalSize'])
4281
+ ]
4282
+ };
4283
+ }
4284
+ return { validFiles, invalidFiles };
4285
+ }
4286
+ buildFormData(files, fieldName) {
4287
+ const formData = new FormData();
4288
+ files.forEach((file, index) => {
4289
+ formData.append(`${fieldName}[${index}]`, file);
4290
+ });
4291
+ return formData;
4292
+ }
4087
4293
  handleFinalize() {
4088
4294
  return finalize(() => this.isPending.set(false));
4089
4295
  }
@@ -4378,6 +4584,24 @@ class HTTPManagerSignalsService extends RequestSignalsService {
4378
4584
  return this.handleError(err);
4379
4585
  }));
4380
4586
  }
4587
+ uploadRequest(files, options, params) {
4588
+ this.isPending.set(true);
4589
+ this.data.set(null);
4590
+ const updatedOptions = this.defineReqOptions(options, params);
4591
+ updatedOptions.uploadFiles = files;
4592
+ const func = this.uploadFileRequest;
4593
+ const requests = this.createRequest(func, updatedOptions);
4594
+ return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => {
4595
+ this.data.set(data);
4596
+ if (updatedOptions.displaySuccess)
4597
+ this.handleSuccessWithSnackBar(updatedOptions.successMessage);
4598
+ }), finalize(() => this.isPending.set(false)), catchError((err) => {
4599
+ if (updatedOptions.displayError)
4600
+ this.handleErrorWithSnackBar(err, updatedOptions.errorMessage || err?.message);
4601
+ this.isPending.set(false);
4602
+ return this.handleError(err);
4603
+ }));
4604
+ }
4381
4605
  // --- private helpers ---
4382
4606
  createObservable(options, request$, funcName) {
4383
4607
  const polling = options.polling ? (options.polling > 0 ? true : false) : false;
@@ -4635,7 +4859,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4635
4859
  }] }] });
4636
4860
 
4637
4861
  class ApiRequest {
4638
- constructor(server = '', path, headers, adapter, mapper, polling, retry, stream, streamType, displayError, displaySuccess, successMessage, errorMessage, saveAs, fileContentHeader, ws, env) {
4862
+ constructor(server = '', path, headers, adapter, mapper, polling, retry, stream, streamType, displayError, displaySuccess, successMessage, errorMessage, saveAs, fileContentHeader, ws, env, uploadFiles, uploadFieldName, uploadHttpMethod, allowedTypes, maxFileSize, maxTotalSize) {
4639
4863
  this.server = server;
4640
4864
  this.path = path;
4641
4865
  this.headers = headers;
@@ -4653,10 +4877,16 @@ class ApiRequest {
4653
4877
  this.fileContentHeader = fileContentHeader;
4654
4878
  this.ws = ws;
4655
4879
  this.env = env;
4880
+ this.uploadFiles = uploadFiles;
4881
+ this.uploadFieldName = uploadFieldName;
4882
+ this.uploadHttpMethod = uploadHttpMethod;
4883
+ this.allowedTypes = allowedTypes;
4884
+ this.maxFileSize = maxFileSize;
4885
+ this.maxTotalSize = maxTotalSize;
4656
4886
  }
4657
4887
  static adapt(item) {
4658
4888
  const server = Array.isArray(item?.server) ? item.server.join('/') : item?.server || '';
4659
- 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?.streamType || StreamType.AI_STREAMING, item?.displayError ? item.displayError : false, item?.displaySuccess ? item.displaySuccess : false, item?.successMessage, item?.errorMessage, item?.saveAs, item?.fileContentHeader, item?.ws, item?.env || 'dev');
4889
+ 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?.streamType || StreamType.AI_STREAMING, item?.displayError ? item.displayError : false, item?.displaySuccess ? item.displaySuccess : false, item?.successMessage, item?.errorMessage, item?.saveAs, item?.fileContentHeader, item?.ws, item?.env || 'dev', item?.uploadFiles, item?.uploadFieldName, item?.uploadHttpMethod, Array.isArray(item?.allowedTypes) ? item.allowedTypes : [], item?.maxFileSize, item?.maxTotalSize);
4660
4890
  }
4661
4891
  }
4662
4892
 
@@ -4686,6 +4916,16 @@ class WSOptions {
4686
4916
  }
4687
4917
  }
4688
4918
 
4919
+ class OperationResultModel {
4920
+ constructor(success = false, operation = 'UPDATE') {
4921
+ this.success = success;
4922
+ this.operation = operation;
4923
+ }
4924
+ static adapt(item) {
4925
+ return new OperationResultModel(item?.success ?? false, item?.operation || 'UPDATE');
4926
+ }
4927
+ }
4928
+
4689
4929
  class ObjectMergerService {
4690
4930
  constructor(configOptions) {
4691
4931
  this.configOptions = configOptions;
@@ -5854,6 +6094,8 @@ class HTTPManagerStateService extends ComponentStore {
5854
6094
  this.logger = inject(LoggerService);
5855
6095
  this.error$ = this.httpManagerService.error$;
5856
6096
  this.isPending$ = this.httpManagerService.isPending$.pipe(delay(1));
6097
+ this.operationSuccess = new BehaviorSubject(null);
6098
+ this.operationSuccess$ = this.operationSuccess.asObservable();
5857
6099
  // PAGINATION
5858
6100
  this.page = new BehaviorSubject(0);
5859
6101
  this.page$ = this.page.asObservable();
@@ -6362,6 +6604,7 @@ class HTTPManagerStateService extends ComponentStore {
6362
6604
  .pipe(tap((data) => {
6363
6605
  data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
6364
6606
  this.addData$(data);
6607
+ this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'CREATE' }));
6365
6608
  // Always call wsCommunication - it will queue if not connected
6366
6609
  this.wsCommunication('CREATE', [...options?.path || [], data.id]);
6367
6610
  }), concatMap((data) => {
@@ -6379,6 +6622,7 @@ class HTTPManagerStateService extends ComponentStore {
6379
6622
  .pipe(tap((data) => {
6380
6623
  data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
6381
6624
  this.updateData$(data);
6625
+ this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'UPDATE' }));
6382
6626
  // Always call wsCommunication - it will queue if not connected
6383
6627
  this.wsCommunication('UPDATE', [...options?.path || []]);
6384
6628
  }), concatMap((data) => {
@@ -6396,6 +6640,7 @@ class HTTPManagerStateService extends ComponentStore {
6396
6640
  .pipe(tap((data) => {
6397
6641
  data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
6398
6642
  this.deleteData$(data);
6643
+ this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'DELETE' }));
6399
6644
  // Always call wsCommunication - it will queue if not connected
6400
6645
  this.wsCommunication('DELETE', [...options?.path || []]);
6401
6646
  }), concatMap((data) => {
@@ -7039,6 +7284,20 @@ class StateStorageOptions {
7039
7284
  }
7040
7285
  }
7041
7286
 
7287
+ class StateOperationResult {
7288
+ constructor(success = false, operation = 'UPDATE', key, value, timestamp = Date.now(), error) {
7289
+ this.success = success;
7290
+ this.operation = operation;
7291
+ this.key = key;
7292
+ this.value = value;
7293
+ this.timestamp = timestamp;
7294
+ this.error = error;
7295
+ }
7296
+ static adapt(item) {
7297
+ return new StateOperationResult(item?.success ?? false, item?.operation || 'UPDATE', item?.key, item?.value, item?.timestamp || Date.now(), item?.error);
7298
+ }
7299
+ }
7300
+
7042
7301
  class StoreStateManagerService extends ComponentStore {
7043
7302
  constructor(options = StateStorageOptions.adapt()) {
7044
7303
  super(StoreStateManagerService.init(options));
@@ -7047,6 +7306,8 @@ class StoreStateManagerService extends ComponentStore {
7047
7306
  this.subscriptions = new Subscription;
7048
7307
  this.settings = null;
7049
7308
  this.isRestoring = false;
7309
+ this.operationResult = new BehaviorSubject(null);
7310
+ this.operationResult$ = this.operationResult.asObservable();
7050
7311
  // Selectors
7051
7312
  this.data$ = this.select((state) => {
7052
7313
  const model = this.options.model;
@@ -7093,6 +7354,67 @@ class StoreStateManagerService extends ComponentStore {
7093
7354
  data: state
7094
7355
  });
7095
7356
  }
7357
+ createRecord(key, value) {
7358
+ try {
7359
+ this.updateData({ [key]: value });
7360
+ this.operationResult.next(StateOperationResult.adapt({
7361
+ success: true,
7362
+ operation: 'CREATE',
7363
+ key,
7364
+ value,
7365
+ }));
7366
+ }
7367
+ catch (error) {
7368
+ this.operationResult.next(StateOperationResult.adapt({
7369
+ success: false,
7370
+ operation: 'CREATE',
7371
+ key,
7372
+ error: error?.message || 'Create failed',
7373
+ }));
7374
+ }
7375
+ }
7376
+ updateRecord(key, value) {
7377
+ try {
7378
+ this.updateData({ [key]: value });
7379
+ this.operationResult.next(StateOperationResult.adapt({
7380
+ success: true,
7381
+ operation: 'UPDATE',
7382
+ key,
7383
+ value,
7384
+ }));
7385
+ }
7386
+ catch (error) {
7387
+ this.operationResult.next(StateOperationResult.adapt({
7388
+ success: false,
7389
+ operation: 'UPDATE',
7390
+ key,
7391
+ error: error?.message || 'Update failed',
7392
+ }));
7393
+ }
7394
+ }
7395
+ deleteRecord(key) {
7396
+ try {
7397
+ const currentState = this.get();
7398
+ if (currentState && key in currentState) {
7399
+ const { [key]: removed, ...rest } = currentState;
7400
+ this.setState(rest);
7401
+ this.updateState(rest);
7402
+ }
7403
+ this.operationResult.next(StateOperationResult.adapt({
7404
+ success: true,
7405
+ operation: 'DELETE',
7406
+ key,
7407
+ }));
7408
+ }
7409
+ catch (error) {
7410
+ this.operationResult.next(StateOperationResult.adapt({
7411
+ success: false,
7412
+ operation: 'DELETE',
7413
+ key,
7414
+ error: error?.message || 'Delete failed',
7415
+ }));
7416
+ }
7417
+ }
7096
7418
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StoreStateManagerService, deps: [{ token: StateStorageOptions }], target: i0.ɵɵFactoryTarget.Injectable }); }
7097
7419
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StoreStateManagerService, providedIn: 'root' }); }
7098
7420
  }
@@ -7109,6 +7431,8 @@ class StoreStateManagerSignalsService {
7109
7431
  this.state = signal(null);
7110
7432
  this.isRestoring = false;
7111
7433
  this.settings = null;
7434
+ this.operationResultSignal = signal(null);
7435
+ this.operationResult = this.operationResultSignal.asReadonly();
7112
7436
  // Public readonly signals for consumers
7113
7437
  this.data = this.state.asReadonly();
7114
7438
  // Computed signal for transformed data
@@ -7172,6 +7496,67 @@ class StoreStateManagerSignalsService {
7172
7496
  this.state.set(newState);
7173
7497
  this.updateState(newState);
7174
7498
  }
7499
+ createRecord(key, value) {
7500
+ try {
7501
+ this.updateData({ [key]: value });
7502
+ this.operationResultSignal.set(StateOperationResult.adapt({
7503
+ success: true,
7504
+ operation: 'CREATE',
7505
+ key,
7506
+ value,
7507
+ }));
7508
+ }
7509
+ catch (error) {
7510
+ this.operationResultSignal.set(StateOperationResult.adapt({
7511
+ success: false,
7512
+ operation: 'CREATE',
7513
+ key,
7514
+ error: error?.message || 'Create failed',
7515
+ }));
7516
+ }
7517
+ }
7518
+ updateRecord(key, value) {
7519
+ try {
7520
+ this.updateData({ [key]: value });
7521
+ this.operationResultSignal.set(StateOperationResult.adapt({
7522
+ success: true,
7523
+ operation: 'UPDATE',
7524
+ key,
7525
+ value,
7526
+ }));
7527
+ }
7528
+ catch (error) {
7529
+ this.operationResultSignal.set(StateOperationResult.adapt({
7530
+ success: false,
7531
+ operation: 'UPDATE',
7532
+ key,
7533
+ error: error?.message || 'Update failed',
7534
+ }));
7535
+ }
7536
+ }
7537
+ deleteRecord(key) {
7538
+ try {
7539
+ const currentState = this.state();
7540
+ if (currentState && key in currentState) {
7541
+ const { [key]: removed, ...rest } = currentState;
7542
+ this.state.set(rest);
7543
+ this.updateState(rest);
7544
+ }
7545
+ this.operationResultSignal.set(StateOperationResult.adapt({
7546
+ success: true,
7547
+ operation: 'DELETE',
7548
+ key,
7549
+ }));
7550
+ }
7551
+ catch (error) {
7552
+ this.operationResultSignal.set(StateOperationResult.adapt({
7553
+ success: false,
7554
+ operation: 'DELETE',
7555
+ key,
7556
+ error: error?.message || 'Delete failed',
7557
+ }));
7558
+ }
7559
+ }
7175
7560
  resetState() {
7176
7561
  if (!this.settings)
7177
7562
  return;
@@ -7235,9 +7620,11 @@ class RequestHeadersInterceptor {
7235
7620
  }));
7236
7621
  }
7237
7622
  intercept(request, next) {
7623
+ // Don't override Content-Type for FormData (file uploads) — let browser set multipart/form-data
7624
+ const skipContentType = request.body instanceof FormData;
7238
7625
  request = request.clone({
7239
7626
  setHeaders: {
7240
- 'Content-Type': 'application/json',
7627
+ ...(skipContentType ? {} : { 'Content-Type': 'application/json' }),
7241
7628
  'Accept-Language': this.language || 'en-CA',
7242
7629
  'Current-Date': this.currentDate
7243
7630
  }
@@ -10387,6 +10774,133 @@ class DatabaseDataSource extends DataSource {
10387
10774
  }
10388
10775
  }
10389
10776
 
10777
+ class UploadStateModel {
10778
+ constructor(selectedFiles = [], isUploading = false, progress = 0, currentFile = null, errorMessage = null, successMessage = null) {
10779
+ this.selectedFiles = selectedFiles;
10780
+ this.isUploading = isUploading;
10781
+ this.progress = progress;
10782
+ this.currentFile = currentFile;
10783
+ this.errorMessage = errorMessage;
10784
+ this.successMessage = successMessage;
10785
+ }
10786
+ static adapt(item) {
10787
+ return new UploadStateModel(Array.isArray(item?.selectedFiles) ? item.selectedFiles : [], item?.isUploading ?? false, item?.progress ?? 0, item?.currentFile ?? null, item?.errorMessage ?? null, item?.successMessage ?? null);
10788
+ }
10789
+ }
10790
+
10791
+ class UploadDemoComponent {
10792
+ constructor() {
10793
+ this.httpManager = inject(HTTPManagerService);
10794
+ this.toastService = inject(ToastMessageDisplayService);
10795
+ this.uploadState = UploadStateModel.adapt();
10796
+ this.allowedTypes = ['image/jpeg', 'image/png'];
10797
+ this.maxFileSize = 40 * 1024 * 1024; // 40MB
10798
+ }
10799
+ ngOnInit() {
10800
+ // Initialize component
10801
+ }
10802
+ ngOnDestroy() {
10803
+ // Clean up subscriptions
10804
+ }
10805
+ onFileSelected(event) {
10806
+ const input = event.target;
10807
+ const files = input.files;
10808
+ if (!files || files.length === 0) {
10809
+ return;
10810
+ }
10811
+ this.uploadState.selectedFiles = [];
10812
+ this.uploadState.errorMessage = null;
10813
+ for (let i = 0; i < files.length; i++) {
10814
+ const file = files[i];
10815
+ const validationError = this.validateFile(file);
10816
+ if (validationError) {
10817
+ this.uploadState.errorMessage = validationError;
10818
+ continue;
10819
+ }
10820
+ this.uploadState.selectedFiles.push(file);
10821
+ }
10822
+ if (this.uploadState.selectedFiles.length === 0 && !this.uploadState.errorMessage) {
10823
+ this.uploadState.errorMessage = 'Please select at least one valid file (JPG or PNG)';
10824
+ }
10825
+ }
10826
+ validateFile(file) {
10827
+ // Check file type
10828
+ if (!this.allowedTypes.includes(file.type)) {
10829
+ return `File "${file.name}" is not a valid type. Only JPG and PNG files are allowed.`;
10830
+ }
10831
+ // Check file size
10832
+ if (file.size > this.maxFileSize) {
10833
+ return `File "${file.name}" exceeds maximum size of 10MB.`;
10834
+ }
10835
+ return null;
10836
+ }
10837
+ clearSelection() {
10838
+ this.uploadState.selectedFiles = [];
10839
+ this.uploadState.errorMessage = null;
10840
+ this.uploadState.successMessage = null;
10841
+ this.uploadState.progress = 0;
10842
+ this.uploadState.currentFile = null;
10843
+ }
10844
+ startUpload() {
10845
+ if (this.uploadState.selectedFiles.length === 0) {
10846
+ this.uploadState.errorMessage = 'Please select at least one file to upload';
10847
+ return;
10848
+ }
10849
+ if (this.uploadState.errorMessage) {
10850
+ return;
10851
+ }
10852
+ this.uploadState.isUploading = true;
10853
+ this.uploadState.progress = 0;
10854
+ this.uploadState.errorMessage = null;
10855
+ this.uploadState.successMessage = null;
10856
+ const options = ApiRequest.adapt({
10857
+ server: 'gtlcApi',
10858
+ path: ['uploader'],
10859
+ uploadFieldName: 'files',
10860
+ allowedTypes: this.allowedTypes,
10861
+ maxFileSize: this.maxFileSize
10862
+ });
10863
+ this.httpManager.uploadRequest(this.uploadState.selectedFiles, options, ['upload'])
10864
+ .subscribe({
10865
+ next: (response) => {
10866
+ this.uploadState.progress = 100;
10867
+ this.uploadState.successMessage = `Successfully uploaded ${this.uploadState.selectedFiles.length} file(s)`;
10868
+ this.toastService.toastMessage({
10869
+ message: this.uploadState.successMessage || '',
10870
+ color: ToastColors.SUCCESS
10871
+ });
10872
+ this.uploadState.isUploading = false;
10873
+ },
10874
+ error: (error) => {
10875
+ this.uploadState.errorMessage = error.message || 'Upload failed. Please try again.';
10876
+ this.toastService.toastMessage({
10877
+ message: this.uploadState.errorMessage || '',
10878
+ color: ToastColors.ERROR
10879
+ });
10880
+ this.uploadState.isUploading = false;
10881
+ this.uploadState.progress = 0;
10882
+ }
10883
+ });
10884
+ }
10885
+ getFileSizeString(size) {
10886
+ if (size < 1024) {
10887
+ return `${size} bytes`;
10888
+ }
10889
+ else if (size < 1024 * 1024) {
10890
+ return `${(size / 1024).toFixed(1)} KB`;
10891
+ }
10892
+ else {
10893
+ return `${(size / (1024 * 1024)).toFixed(1)} MB`;
10894
+ }
10895
+ }
10896
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UploadDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10897
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: UploadDemoComponent, selector: "lib-upload-demo", ngImport: i0, template: "<div class=\"upload-demo-container\">\n <h2>File Upload Demo</h2>\n <p class=\"demo-description\">Upload multiple JPG or PNG files with progress tracking</p>\n\n <!-- Upload Button & File Input -->\n <div class=\"upload-controls\">\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"fileInput.click()\"\n [disabled]=\"uploadState.isUploading\"\n class=\"upload-button\">\n <span class=\"material-icons\">upload_file</span>\n Select Files\n </button>\n <input\n #fileInput\n type=\"file\"\n multiple\n accept=\"image/jpeg,image/png\"\n (change)=\"onFileSelected($event)\"\n [disabled]=\"uploadState.isUploading\"\n hidden>\n\n <button\n mat-button\n color=\"warn\"\n (click)=\"clearSelection()\"\n [disabled]=\"uploadState.selectedFiles.length === 0 || uploadState.isUploading\"\n class=\"clear-button\">\n Clear\n </button>\n </div>\n\n <!-- Selected Files Display -->\n <div class=\"selected-files\" *ngIf=\"uploadState.selectedFiles.length > 0\">\n <h3>Selected Files ({{uploadState.selectedFiles.length}})</h3>\n <ul class=\"file-list\">\n <li *ngFor=\"let file of uploadState.selectedFiles\" class=\"file-item\">\n <span class=\"file-icon\">\n <span class=\"material-icons\">insert_drive_file</span>\n </span>\n <span class=\"file-name\">{{file.name}}</span>\n <span class=\"file-size\">{{getFileSizeString(file.size)}}</span>\n <span class=\"file-status valid\">\u2713</span>\n </li>\n </ul>\n </div>\n\n <!-- Validation Errors -->\n <div class=\"error-message\" *ngIf=\"uploadState.errorMessage && !uploadState.isUploading\">\n <span class=\"material-icons\">error</span>\n <span>{{uploadState.errorMessage}}</span>\n </div>\n\n <!-- Progress Bar -->\n <div class=\"progress-container\" *ngIf=\"uploadState.isUploading\">\n <div class=\"progress-header\">\n <span>Uploading...</span>\n <span class=\"progress-percentage\">{{uploadState.progress}}%</span>\n </div>\n <mat-progress-bar\n mode=\"determinate\"\n [value]=\"uploadState.progress\"\n color=\"primary\">\n </mat-progress-bar>\n <div class=\"current-file\" *ngIf=\"uploadState.currentFile\">\n Current: {{uploadState.currentFile}}\n </div>\n </div>\n\n <!-- Success Message -->\n <div class=\"success-message\" *ngIf=\"uploadState.successMessage\">\n <span class=\"material-icons\">check_circle</span>\n <span>{{uploadState.successMessage}}</span>\n </div>\n\n <!-- Upload Action Button -->\n <div class=\"upload-actions\" *ngIf=\"uploadState.selectedFiles.length > 0 && !uploadState.isUploading\">\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"startUpload()\"\n [disabled]=\"uploadState.selectedFiles.length === 0 || uploadState.errorMessage !== null\"\n class=\"start-upload-button\">\n Upload {{uploadState.selectedFiles.length}} File{{uploadState.selectedFiles.length > 1 ? 's' : ''}}\n </button>\n </div>\n</div>\n", styles: [".upload-demo-container{padding:1rem;max-width:60rem;margin:0 auto}.upload-demo-container h2{font-size:2rem;font-weight:700;color:#333;margin-bottom:.75rem}.upload-demo-container .demo-description{font-size:1rem;color:#666;margin-bottom:1.5rem}.upload-demo-container .upload-controls{display:flex;gap:1rem;margin-bottom:1.5rem;align-items:center}.upload-demo-container .upload-controls .upload-button,.upload-demo-container .upload-controls .clear-button{min-width:10rem}.upload-demo-container .selected-files{background-color:#fbfbfb;border:1px solid #ccc;border-radius:.25rem;padding:1rem;margin-bottom:1.5rem}.upload-demo-container .selected-files h3{font-size:1.125rem;font-weight:500;color:#333;margin-bottom:.5rem}.upload-demo-container .selected-files .file-list{list-style:none;padding:0;margin:0}.upload-demo-container .selected-files .file-list .file-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;border-bottom:1px solid #e5e5e5}.upload-demo-container .selected-files .file-list .file-item:last-child{border-bottom:none}.upload-demo-container .selected-files .file-list .file-item .file-icon{color:#286fad;display:flex;align-items:center}.upload-demo-container .selected-files .file-list .file-item .file-name{flex:1;font-size:.875rem;color:#333;font-weight:500}.upload-demo-container .selected-files .file-list .file-item .file-size{font-size:.875rem;color:#666}.upload-demo-container .selected-files .file-list .file-item .file-status.valid{color:#1c8150;font-weight:700}.upload-demo-container .error-message{display:flex;align-items:center;gap:.5rem;padding:1rem;background-color:#d400031a;border:1px solid #d40003;border-radius:.25rem;color:#d40003;margin-bottom:1.5rem;font-size:.875rem}.upload-demo-container .error-message .material-icons{font-size:2.5rem}.upload-demo-container .progress-container{margin-bottom:1.5rem}.upload-demo-container .progress-container .progress-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.25rem}.upload-demo-container .progress-container .progress-header span:first-child{font-size:.875rem;font-weight:500;color:#333}.upload-demo-container .progress-container .progress-header .progress-percentage{font-size:.875rem;font-weight:700;color:#286fad}.upload-demo-container .progress-container .current-file{font-size:.875rem;color:#666;margin-top:.25rem;font-style:italic}.upload-demo-container .success-message{display:flex;align-items:center;gap:.5rem;padding:1rem;background-color:#1c81501a;border:1px solid #1c8150;border-radius:.25rem;color:#1c8150;margin-bottom:1.5rem;font-size:.875rem}.upload-demo-container .success-message .material-icons{font-size:2.5rem}.upload-demo-container .upload-actions{text-align:center;margin-top:1.5rem}.upload-demo-container .upload-actions .start-upload-button{min-width:15rem;padding:.5rem 1.5rem}\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: "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: i8$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }] }); }
10898
+ }
10899
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UploadDemoComponent, decorators: [{
10900
+ type: Component,
10901
+ args: [{ selector: 'lib-upload-demo', standalone: false, template: "<div class=\"upload-demo-container\">\n <h2>File Upload Demo</h2>\n <p class=\"demo-description\">Upload multiple JPG or PNG files with progress tracking</p>\n\n <!-- Upload Button & File Input -->\n <div class=\"upload-controls\">\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"fileInput.click()\"\n [disabled]=\"uploadState.isUploading\"\n class=\"upload-button\">\n <span class=\"material-icons\">upload_file</span>\n Select Files\n </button>\n <input\n #fileInput\n type=\"file\"\n multiple\n accept=\"image/jpeg,image/png\"\n (change)=\"onFileSelected($event)\"\n [disabled]=\"uploadState.isUploading\"\n hidden>\n\n <button\n mat-button\n color=\"warn\"\n (click)=\"clearSelection()\"\n [disabled]=\"uploadState.selectedFiles.length === 0 || uploadState.isUploading\"\n class=\"clear-button\">\n Clear\n </button>\n </div>\n\n <!-- Selected Files Display -->\n <div class=\"selected-files\" *ngIf=\"uploadState.selectedFiles.length > 0\">\n <h3>Selected Files ({{uploadState.selectedFiles.length}})</h3>\n <ul class=\"file-list\">\n <li *ngFor=\"let file of uploadState.selectedFiles\" class=\"file-item\">\n <span class=\"file-icon\">\n <span class=\"material-icons\">insert_drive_file</span>\n </span>\n <span class=\"file-name\">{{file.name}}</span>\n <span class=\"file-size\">{{getFileSizeString(file.size)}}</span>\n <span class=\"file-status valid\">\u2713</span>\n </li>\n </ul>\n </div>\n\n <!-- Validation Errors -->\n <div class=\"error-message\" *ngIf=\"uploadState.errorMessage && !uploadState.isUploading\">\n <span class=\"material-icons\">error</span>\n <span>{{uploadState.errorMessage}}</span>\n </div>\n\n <!-- Progress Bar -->\n <div class=\"progress-container\" *ngIf=\"uploadState.isUploading\">\n <div class=\"progress-header\">\n <span>Uploading...</span>\n <span class=\"progress-percentage\">{{uploadState.progress}}%</span>\n </div>\n <mat-progress-bar\n mode=\"determinate\"\n [value]=\"uploadState.progress\"\n color=\"primary\">\n </mat-progress-bar>\n <div class=\"current-file\" *ngIf=\"uploadState.currentFile\">\n Current: {{uploadState.currentFile}}\n </div>\n </div>\n\n <!-- Success Message -->\n <div class=\"success-message\" *ngIf=\"uploadState.successMessage\">\n <span class=\"material-icons\">check_circle</span>\n <span>{{uploadState.successMessage}}</span>\n </div>\n\n <!-- Upload Action Button -->\n <div class=\"upload-actions\" *ngIf=\"uploadState.selectedFiles.length > 0 && !uploadState.isUploading\">\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"startUpload()\"\n [disabled]=\"uploadState.selectedFiles.length === 0 || uploadState.errorMessage !== null\"\n class=\"start-upload-button\">\n Upload {{uploadState.selectedFiles.length}} File{{uploadState.selectedFiles.length > 1 ? 's' : ''}}\n </button>\n </div>\n</div>\n", styles: [".upload-demo-container{padding:1rem;max-width:60rem;margin:0 auto}.upload-demo-container h2{font-size:2rem;font-weight:700;color:#333;margin-bottom:.75rem}.upload-demo-container .demo-description{font-size:1rem;color:#666;margin-bottom:1.5rem}.upload-demo-container .upload-controls{display:flex;gap:1rem;margin-bottom:1.5rem;align-items:center}.upload-demo-container .upload-controls .upload-button,.upload-demo-container .upload-controls .clear-button{min-width:10rem}.upload-demo-container .selected-files{background-color:#fbfbfb;border:1px solid #ccc;border-radius:.25rem;padding:1rem;margin-bottom:1.5rem}.upload-demo-container .selected-files h3{font-size:1.125rem;font-weight:500;color:#333;margin-bottom:.5rem}.upload-demo-container .selected-files .file-list{list-style:none;padding:0;margin:0}.upload-demo-container .selected-files .file-list .file-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;border-bottom:1px solid #e5e5e5}.upload-demo-container .selected-files .file-list .file-item:last-child{border-bottom:none}.upload-demo-container .selected-files .file-list .file-item .file-icon{color:#286fad;display:flex;align-items:center}.upload-demo-container .selected-files .file-list .file-item .file-name{flex:1;font-size:.875rem;color:#333;font-weight:500}.upload-demo-container .selected-files .file-list .file-item .file-size{font-size:.875rem;color:#666}.upload-demo-container .selected-files .file-list .file-item .file-status.valid{color:#1c8150;font-weight:700}.upload-demo-container .error-message{display:flex;align-items:center;gap:.5rem;padding:1rem;background-color:#d400031a;border:1px solid #d40003;border-radius:.25rem;color:#d40003;margin-bottom:1.5rem;font-size:.875rem}.upload-demo-container .error-message .material-icons{font-size:2.5rem}.upload-demo-container .progress-container{margin-bottom:1.5rem}.upload-demo-container .progress-container .progress-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.25rem}.upload-demo-container .progress-container .progress-header span:first-child{font-size:.875rem;font-weight:500;color:#333}.upload-demo-container .progress-container .progress-header .progress-percentage{font-size:.875rem;font-weight:700;color:#286fad}.upload-demo-container .progress-container .current-file{font-size:.875rem;color:#666;margin-top:.25rem;font-style:italic}.upload-demo-container .success-message{display:flex;align-items:center;gap:.5rem;padding:1rem;background-color:#1c81501a;border:1px solid #1c8150;border-radius:.25rem;color:#1c8150;margin-bottom:1.5rem;font-size:.875rem}.upload-demo-container .success-message .material-icons{font-size:2.5rem}.upload-demo-container .upload-actions{text-align:center;margin-top:1.5rem}.upload-demo-container .upload-actions .start-upload-button{min-width:15rem;padding:.5rem 1.5rem}\n"] }]
10902
+ }] });
10903
+
10390
10904
  class HttpRequestServicesDemoComponent {
10391
10905
  constructor(configOptions) {
10392
10906
  this.configOptions = configOptions;
@@ -10399,6 +10913,7 @@ class HttpRequestServicesDemoComponent {
10399
10913
  // { name: "Http Signals Service", value: 'http_signals_service', new: true },
10400
10914
  { name: "Http State Service", value: 'http_state_service' },
10401
10915
  { name: "Http State Service - Websockets", value: 'http_state_service_ws', new: false },
10916
+ { name: "File Upload Demo", value: 'file_upload_demo', new: true, divider: true },
10402
10917
  { name: "Database Service", value: 'database_service', divider: true, disabled: false },
10403
10918
  { name: "Local Storage Service", value: 'local_storage_service' },
10404
10919
  // { name: "Local Signals Storage Service", value: 'local_storage_signals_service', new: true },
@@ -10415,11 +10930,11 @@ class HttpRequestServicesDemoComponent {
10415
10930
  this.selectedService = this.requestTypes[type].value;
10416
10931
  }
10417
10932
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HttpRequestServicesDemoComponent, deps: [{ token: CONFIG_SETTINGS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
10418
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: HttpRequestServicesDemoComponent, selector: "app-http-request-services-demo", inputs: { wsServer: "wsServer", jwtToken: "jwtToken", server: "server", user: "user", path: "path", adapter: "adapter", mapper: "mapper" }, 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 @for (type of requestTypes; track type; let i = $index) {\n @if (type?.divider) {\n <div\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n }\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n }\n\n </mat-menu>\n</mat-toolbar>\n\n<span>\n @switch (selectedService) {\n @case ('basic_http_service') {\n <p>\n <app-request-manager-basic-demo></app-request-manager-basic-demo>\n </p>\n }\n @case ('http_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-demo>\n </p>\n }\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 @case ('http_state_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-state-demo>\n </p>\n }\n @case ('http_state_service_ws') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-ws-demo\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-request-manager-ws-demo>\n </p>\n }\n @case ('database_service') {\n <p>\n <app-database-data-demo></app-database-data-demo>\n </p>\n }\n @case ('local_storage_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n }\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@case ('store_state_manager') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-store-state-manager-demo></app-store-state-manager-demo>\n </p>\n}\n@default {\n <p>\n Other\n </p>\n}\n}\n</span>\n\n<ng-template #HTTP_OPTIONS>\n @if (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 }\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n @if (injectionOptions?.LocalStorageOptions) {\n <ng-container class=\"box\">\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 }\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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: 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: i3$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: RequestManagerBasicDemoComponent, selector: "app-request-manager-basic-demo" }, { kind: "component", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo", inputs: ["server", "adapter", "mapper"] }, { kind: "component", type: RequestManagerDemoComponent, selector: "app-request-manager-demo", inputs: ["server", "adapter", "mapper"] }, { kind: "component", type: LocalStorageDemoComponent, selector: "app-local-storage-demo" }, { kind: "component", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: StoreStateManagerDemoComponent, selector: "app-store-state-manager-demo" }, { kind: "component", type: DatabaseDataDemoComponent, selector: "app-database-data-demo" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
10933
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: HttpRequestServicesDemoComponent, selector: "app-http-request-services-demo", inputs: { wsServer: "wsServer", jwtToken: "jwtToken", server: "server", user: "user", path: "path", adapter: "adapter", mapper: "mapper" }, 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 @for (type of requestTypes; track type; let i = $index) {\n @if (type?.divider) {\n <div\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n }\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n }\n\n </mat-menu>\n</mat-toolbar>\n\n<span>\n @switch (selectedService) {\n @case ('basic_http_service') {\n <p>\n <app-request-manager-basic-demo></app-request-manager-basic-demo>\n </p>\n }\n @case ('http_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-demo>\n </p>\n }\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 @case ('http_state_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-state-demo>\n </p>\n }\n @case ('http_state_service_ws') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-ws-demo\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-request-manager-ws-demo>\n </p>\n }\n @case ('file_upload_demo') {\n <p>\n <lib-upload-demo></lib-upload-demo>\n </p>\n }\n @case ('database_service') {\n <p>\n <app-database-data-demo></app-database-data-demo>\n </p>\n }\n @case ('local_storage_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n }\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@case ('store_state_manager') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-store-state-manager-demo></app-store-state-manager-demo>\n </p>\n}\n@default {\n <p>\n Other\n </p>\n}\n}\n</span>\n\n<ng-template #HTTP_OPTIONS>\n @if (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 }\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n @if (injectionOptions?.LocalStorageOptions) {\n <ng-container class=\"box\">\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 }\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.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: 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: i3$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: RequestManagerBasicDemoComponent, selector: "app-request-manager-basic-demo" }, { kind: "component", type: RequestManagerStateDemoComponent, selector: "app-request-manager-state-demo", inputs: ["server", "adapter", "mapper"] }, { kind: "component", type: RequestManagerDemoComponent, selector: "app-request-manager-demo", inputs: ["server", "adapter", "mapper"] }, { kind: "component", type: LocalStorageDemoComponent, selector: "app-local-storage-demo" }, { kind: "component", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: StoreStateManagerDemoComponent, selector: "app-store-state-manager-demo" }, { kind: "component", type: DatabaseDataDemoComponent, selector: "app-database-data-demo" }, { kind: "component", type: UploadDemoComponent, selector: "lib-upload-demo" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
10419
10934
  }
10420
10935
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HttpRequestServicesDemoComponent, decorators: [{
10421
10936
  type: Component,
10422
- args: [{ selector: 'app-http-request-services-demo', standalone: false, 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 @for (type of requestTypes; track type; let i = $index) {\n @if (type?.divider) {\n <div\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n }\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n }\n\n </mat-menu>\n</mat-toolbar>\n\n<span>\n @switch (selectedService) {\n @case ('basic_http_service') {\n <p>\n <app-request-manager-basic-demo></app-request-manager-basic-demo>\n </p>\n }\n @case ('http_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-demo>\n </p>\n }\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 @case ('http_state_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-state-demo>\n </p>\n }\n @case ('http_state_service_ws') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-ws-demo\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-request-manager-ws-demo>\n </p>\n }\n @case ('database_service') {\n <p>\n <app-database-data-demo></app-database-data-demo>\n </p>\n }\n @case ('local_storage_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n }\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@case ('store_state_manager') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-store-state-manager-demo></app-store-state-manager-demo>\n </p>\n}\n@default {\n <p>\n Other\n </p>\n}\n}\n</span>\n\n<ng-template #HTTP_OPTIONS>\n @if (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 }\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n @if (injectionOptions?.LocalStorageOptions) {\n <ng-container class=\"box\">\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 }\n</ng-template>\n\n\n", styles: [".box{padding:1rem;background-color:#f5f5f5;border:thin gray solid;margin-top:1rem}\n"] }]
10937
+ args: [{ selector: 'app-http-request-services-demo', standalone: false, 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 @for (type of requestTypes; track type; let i = $index) {\n @if (type?.divider) {\n <div\n style=\"margin-top: .5rem; margin-bottom: .5rem;\"\n >\n <mat-divider></mat-divider>\n </div>\n }\n <button\n mat-menu-item\n (click)=\"onSelected(i)\"\n [disabled]=\"type.disabled\"\n >\n {{ type.name }}\n </button>\n }\n\n </mat-menu>\n</mat-toolbar>\n\n<span>\n @switch (selectedService) {\n @case ('basic_http_service') {\n <p>\n <app-request-manager-basic-demo></app-request-manager-basic-demo>\n </p>\n }\n @case ('http_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-demo>\n </p>\n }\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 @case ('http_state_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-state-demo\n [server]=\"server\"\n [adapter]=\"adapter\"\n [mapper]=\"mapper\"\n ></app-request-manager-state-demo>\n </p>\n }\n @case ('http_state_service_ws') {\n <p>\n <ng-container *ngTemplateOutlet=\"HTTP_OPTIONS\"></ng-container>\n <app-request-manager-ws-demo\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-request-manager-ws-demo>\n </p>\n }\n @case ('file_upload_demo') {\n <p>\n <lib-upload-demo></lib-upload-demo>\n </p>\n }\n @case ('database_service') {\n <p>\n <app-database-data-demo></app-database-data-demo>\n </p>\n }\n @case ('local_storage_service') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-local-storage-demo></app-local-storage-demo>\n </p>\n }\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@case ('store_state_manager') {\n <p>\n <ng-container *ngTemplateOutlet=\"LOCAL_OPTIONS\"></ng-container>\n <app-store-state-manager-demo></app-store-state-manager-demo>\n </p>\n}\n@default {\n <p>\n Other\n </p>\n}\n}\n</span>\n\n<ng-template #HTTP_OPTIONS>\n @if (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 }\n</ng-template>\n\n<ng-template #LOCAL_OPTIONS>\n @if (injectionOptions?.LocalStorageOptions) {\n <ng-container class=\"box\">\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 }\n</ng-template>\n\n\n", styles: [".box{padding:1rem;background-color:#f5f5f5;border:thin gray solid;margin-top:1rem}\n"] }]
10423
10938
  }], ctorParameters: () => [{ type: ConfigOptions, decorators: [{
10424
10939
  type: Inject,
10425
10940
  args: [CONFIG_SETTINGS_TOKEN]
@@ -10979,7 +11494,8 @@ class HttpRequestManagerModule {
10979
11494
  WsMessagingComponent,
10980
11495
  WsNotificationsComponent,
10981
11496
  WsAiMessagingComponent,
10982
- WsChatsComponent], imports: [CommonModule,
11497
+ WsChatsComponent,
11498
+ UploadDemoComponent], imports: [CommonModule,
10983
11499
  ToastMessageDisplayModule,
10984
11500
  FormsModule,
10985
11501
  ReactiveFormsModule,
@@ -11003,7 +11519,8 @@ class HttpRequestManagerModule {
11003
11519
  MatDatepickerModule,
11004
11520
  MatNativeDateModule,
11005
11521
  MatCardModule,
11006
- FileDownloaderModule], exports: [HttpRequestServicesDemoComponent] }); }
11522
+ FileDownloaderModule], exports: [HttpRequestServicesDemoComponent,
11523
+ UploadDemoComponent] }); }
11007
11524
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HttpRequestManagerModule, providers: [
11008
11525
  { provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
11009
11526
  { provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
@@ -11091,9 +11608,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
11091
11608
  WsNotificationsComponent,
11092
11609
  WsAiMessagingComponent,
11093
11610
  WsChatsComponent,
11611
+ UploadDemoComponent,
11094
11612
  ],
11095
11613
  exports: [
11096
11614
  HttpRequestServicesDemoComponent,
11615
+ UploadDemoComponent,
11097
11616
  ],
11098
11617
  providers: [
11099
11618
  { provide: HTTP_INTERCEPTORS, useClass: WithCredentialsInterceptor, multi: true },
@@ -11244,5 +11763,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
11244
11763
  * Generated bundle index. Do not edit.
11245
11764
  */
11246
11765
 
11247
- export { ApiRequest, AppService, AsymmetricalEncryptionService, BatchOptions, BatchResult, CONFIG_SETTINGS_TOKEN, ChannelType, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseDataDemoComponent, DatabaseManagerService, DatabaseStorage, DbService, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerSignalsService, HTTPManagerStateService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, LocalStorageDemoComponent, LocalStorageManagerService, LocalStorageOptions, LocalStorageSignalsDemoComponent, LocalStorageSignalsManagerService, LoggerService, NotificationMessage, PathQueryService, PublicMessage, Random, RandomHSLColor, RandomHexColor, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomPaletteColor, RandomSignature, RandomStr, RandomVisibleColor, RequestErrorInterceptor, RequestHeadersInterceptor, RequestManagerDemoComponent, RequestManagerStateDemoComponent, RequestOptions, RequestService, RequestSignalsService, RetryOptions, SettingOptions, StateMessage, StateStorageOptions, StorageData, StorageOption, StorageType, StoreStateManagerService, StoreStateManagerSignalsService, StoreStateSignalsDemoComponent, StreamType, SymmetricalEncryptionService, TableSchemaDef, UUID, UUID_STR, UserData, UtilsService, WSOptions, WebSocketMessageService, WithCredentialsInterceptor, calculateBatchProgress, countdown, createChannelName, delayedRetry, isErrorState, isPendingState, isSuccessState, requestPolling, requestStreaming, streamAI, streamAuto, streamEvents, streamJSON, streamNDJSON };
11766
+ export { ApiRequest, AppService, AsymmetricalEncryptionService, BatchOptions, BatchResult, CONFIG_SETTINGS_TOKEN, ChannelType, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseDataDemoComponent, DatabaseManagerService, DatabaseStorage, DbService, ErrorDisplaySettings, GlobalStoreOptions, HTTPManagerService, HTTPManagerSignalsService, HTTPManagerStateService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, InvalidFileInfoModel, LocalStorageDemoComponent, LocalStorageManagerService, LocalStorageOptions, LocalStorageSignalsDemoComponent, LocalStorageSignalsManagerService, LoggerService, NotificationMessage, OperationResultModel, PathQueryService, PublicMessage, Random, RandomHSLColor, RandomHexColor, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomPaletteColor, RandomSignature, RandomStr, RandomVisibleColor, RequestErrorInterceptor, RequestHeadersInterceptor, RequestManagerDemoComponent, RequestManagerStateDemoComponent, RequestOptions, RequestService, RequestSignalsService, RetryOptions, SettingOptions, StateMessage, StateOperationResult, StateStorageOptions, StorageData, StorageOption, StorageType, StoreStateManagerService, StoreStateManagerSignalsService, StoreStateSignalsDemoComponent, StreamType, SymmetricalEncryptionService, TableSchemaDef, UUID, UUID_STR, UploadDemoComponent, UploadValidationErrorModel, UserData, UtilsService, WSOptions, WebSocketMessageService, WithCredentialsInterceptor, calculateBatchProgress, countdown, createChannelName, delayedRetry, isErrorState, isPendingState, isSuccessState, requestPolling, requestStreaming, streamAI, streamAuto, streamEvents, streamJSON, streamNDJSON };
11248
11767
  //# sourceMappingURL=http-request-manager.mjs.map