@codex-ts/core-lib 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core-lib/fesm2022/core-lib.mjs +2349 -0
- package/dist/core-lib/fesm2022/core-lib.mjs.map +1 -0
- package/dist/core-lib/index.d.ts +29 -0
- package/dist/core-lib/lib/components/base-form.component.d.ts +62 -0
- package/dist/core-lib/lib/components/base-list-page.component.d.ts +132 -0
- package/dist/core-lib/lib/components/base-page.component.d.ts +25 -0
- package/dist/core-lib/lib/components/base-tabbed-form.component.d.ts +54 -0
- package/dist/core-lib/lib/components/formly/core-formly.module.d.ts +7 -0
- package/dist/core-lib/lib/components/formly/form-field.wrapper.d.ts +21 -0
- package/dist/core-lib/lib/components/formly/formly.constants.d.ts +13 -0
- package/dist/core-lib/lib/components/formly/types/checkbox.type.d.ts +12 -0
- package/dist/core-lib/lib/components/formly/types/date.type.d.ts +20 -0
- package/dist/core-lib/lib/components/formly/types/multiselect.type.d.ts +26 -0
- package/dist/core-lib/lib/components/formly/types/numeric-input.type.d.ts +17 -0
- package/dist/core-lib/lib/components/formly/types/radio.type.d.ts +13 -0
- package/dist/core-lib/lib/components/formly/types/select.type.d.ts +25 -0
- package/dist/core-lib/lib/components/formly/types/text-input.type.d.ts +12 -0
- package/dist/core-lib/lib/components/formly/types/textarea.type.d.ts +14 -0
- package/dist/core-lib/lib/constants/app.constants.d.ts +13 -0
- package/dist/core-lib/lib/constants/app.messages.d.ts +36 -0
- package/dist/core-lib/lib/enums/component-context.enum.d.ts +6 -0
- package/dist/core-lib/lib/enums/tabbed-form-type.enum.d.ts +4 -0
- package/dist/core-lib/lib/models/pagination/filter-criteria.interface.d.ts +9 -0
- package/dist/core-lib/lib/models/pagination/page-request.interface.d.ts +10 -0
- package/dist/core-lib/lib/models/pagination/page.interface.d.ts +9 -0
- package/dist/core-lib/lib/models/pagination/sort-criteria.interface.d.ts +4 -0
- package/dist/core-lib/lib/pipes/indian-date.pipe.d.ts +12 -0
- package/dist/core-lib/lib/services/base-crud.service.d.ts +36 -0
- package/dist/core-lib/lib/services/entity-registry.service.d.ts +26 -0
- package/dist/core-lib/lib/services/entity.service.d.ts +9 -0
- package/dist/core-lib/lib/services/enum-registry.service.d.ts +41 -0
- package/dist/core-lib/lib/services/formly-config.service.d.ts +11 -0
- package/dist/core-lib/lib/services/http-utility.service.d.ts +130 -0
- package/dist/core-lib/lib/services/notification.service.d.ts +13 -0
- package/dist/core-lib/lib/services/reference-data-provider.service.d.ts +8 -0
- package/dist/core-lib/lib/services/utils.service.d.ts +72 -0
- package/ng-package.json +7 -0
- package/package.json +63 -0
- package/src/index.ts +44 -0
- package/src/lib/components/base-form.component.ts +328 -0
- package/src/lib/components/base-list-page.component.ts +327 -0
- package/src/lib/components/base-page.component.ts +33 -0
- package/src/lib/components/base-tabbed-form.component.ts +345 -0
- package/src/lib/components/formly/core-formly.module.ts +34 -0
- package/src/lib/components/formly/field.interface.ts +15 -0
- package/src/lib/components/formly/form-field.wrapper.ts +94 -0
- package/src/lib/components/formly/formly.constants.ts +14 -0
- package/src/lib/components/formly/primeng-formly.module.ts +77 -0
- package/src/lib/components/formly/types/checkbox.type.ts +43 -0
- package/src/lib/components/formly/types/date.type.ts +88 -0
- package/src/lib/components/formly/types/multiselect.type.ts +61 -0
- package/src/lib/components/formly/types/numeric-input.type.ts +45 -0
- package/src/lib/components/formly/types/radio.type.ts +47 -0
- package/src/lib/components/formly/types/select.type.ts +54 -0
- package/src/lib/components/formly/types/text-input.type.ts +33 -0
- package/src/lib/components/formly/types/textarea.type.ts +37 -0
- package/src/lib/constants/app.constants.ts +15 -0
- package/src/lib/constants/app.messages.ts +36 -0
- package/src/lib/enums/component-context.enum.ts +6 -0
- package/src/lib/enums/tabbed-form-type.enum.ts +4 -0
- package/src/lib/models/pagination/filter-criteria.interface.ts +19 -0
- package/src/lib/models/pagination/page-request.interface.ts +13 -0
- package/src/lib/models/pagination/page.interface.ts +9 -0
- package/src/lib/models/pagination/sort-criteria.interface.ts +4 -0
- package/src/lib/pipes/indian-date.pipe.ts +46 -0
- package/src/lib/services/base-crud.service.ts +81 -0
- package/src/lib/services/entity-registry.service.ts +51 -0
- package/src/lib/services/entity.service.ts +10 -0
- package/src/lib/services/enum-registry.service.ts +66 -0
- package/src/lib/services/formly-config.service.ts +50 -0
- package/src/lib/services/http-utility.service.example.ts +253 -0
- package/src/lib/services/http-utility.service.md +175 -0
- package/src/lib/services/http-utility.service.ts +389 -0
- package/src/lib/services/notification.service.ts +35 -0
- package/src/lib/services/reference-data-provider.service.ts +28 -0
- package/src/lib/services/utils.service.ts +154 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# HttpUtilityService
|
|
2
|
+
|
|
3
|
+
A general-purpose HTTP utility service that extends Angular's HttpClient with additional functionality for common HTTP operations.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Enhanced HTTP Methods**: Typed GET, POST, PUT, DELETE methods with additional options
|
|
8
|
+
- **Loading State Management**: Built-in loading state tracking
|
|
9
|
+
- **Error Handling**: Standardized error handling with message display
|
|
10
|
+
- **Request Configuration**:
|
|
11
|
+
- Timeout configuration
|
|
12
|
+
- Retry capabilities
|
|
13
|
+
- Custom headers and params support
|
|
14
|
+
- **Specialized Operations**:
|
|
15
|
+
- File uploads with progress tracking
|
|
16
|
+
- File downloads
|
|
17
|
+
- Batch request handling
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
The service is part of the core library. It's already registered with the Angular DI system, so you can inject it directly into your components and services.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Basic Import
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { HttpUtilityService } from '@core/core-lib';
|
|
29
|
+
|
|
30
|
+
@Component({
|
|
31
|
+
// ...
|
|
32
|
+
})
|
|
33
|
+
export class MyComponent {
|
|
34
|
+
constructor(private httpUtil: HttpUtilityService) {}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### GET Requests
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// Simple GET request
|
|
42
|
+
this.httpUtil.get<UserData>('/api/users/123').subscribe({
|
|
43
|
+
next: (data) => console.log('User data:', data),
|
|
44
|
+
error: (err) => console.error('Error fetching user:', err)
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// GET with parameters and options
|
|
48
|
+
const params = this.httpUtil.createParams({
|
|
49
|
+
filter: 'active',
|
|
50
|
+
sort: 'name',
|
|
51
|
+
page: 1
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.httpUtil.get<PagedResponse<UserData>>('/api/users', {
|
|
55
|
+
params,
|
|
56
|
+
retries: 2,
|
|
57
|
+
timeoutMs: 5000
|
|
58
|
+
}).subscribe({
|
|
59
|
+
next: (data) => this.handleData(data),
|
|
60
|
+
error: (err) => this.handleError(err)
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### POST Requests
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const newUser = {
|
|
68
|
+
name: 'John Doe',
|
|
69
|
+
email: 'john@example.com'
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
this.httpUtil.post<UserData>('/api/users', newUser).subscribe({
|
|
73
|
+
next: (data) => console.log('User created:', data),
|
|
74
|
+
error: (err) => console.error('Error creating user:', err)
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### PUT Requests
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const updatedUser = {
|
|
82
|
+
id: '123',
|
|
83
|
+
name: 'John Smith',
|
|
84
|
+
email: 'john@example.com'
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
this.httpUtil.put<UserData>(`/api/users/${updatedUser.id}`, updatedUser).subscribe({
|
|
88
|
+
next: (data) => console.log('User updated:', data),
|
|
89
|
+
error: (err) => console.error('Error updating user:', err)
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### DELETE Requests
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
this.httpUtil.delete<void>('/api/users/123').subscribe({
|
|
97
|
+
next: () => console.log('User deleted successfully'),
|
|
98
|
+
error: (err) => console.error('Error deleting user:', err)
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### File Upload with Progress
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Get file from a file input
|
|
106
|
+
const fileInput = event.target.files[0];
|
|
107
|
+
|
|
108
|
+
// Additional form data
|
|
109
|
+
const metadata = {
|
|
110
|
+
description: 'Profile photo',
|
|
111
|
+
userId: '123'
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
this.httpUtil.uploadFile<{url: string}>('/api/upload', fileInput, metadata, {
|
|
115
|
+
onProgress: (percent) => this.uploadProgress = percent
|
|
116
|
+
}).subscribe({
|
|
117
|
+
next: (response) => this.imageUrl = response.url,
|
|
118
|
+
error: (err) => console.error('Upload failed:', err)
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### File Download
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
this.httpUtil.downloadFile('/api/reports/123', 'report.pdf').subscribe({
|
|
126
|
+
next: (blob) => {
|
|
127
|
+
// Create download link
|
|
128
|
+
const url = window.URL.createObjectURL(blob);
|
|
129
|
+
const a = document.createElement('a');
|
|
130
|
+
a.href = url;
|
|
131
|
+
a.download = 'report.pdf';
|
|
132
|
+
document.body.appendChild(a);
|
|
133
|
+
a.click();
|
|
134
|
+
window.URL.revokeObjectURL(url);
|
|
135
|
+
a.remove();
|
|
136
|
+
},
|
|
137
|
+
error: (err) => console.error('Download failed:', err)
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Batch Requests
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Create multiple requests
|
|
145
|
+
const userRequest = this.httpUtil.get<UserData>('/api/users/123');
|
|
146
|
+
const ordersRequest = this.httpUtil.get<Order[]>(`/api/users/123/orders`);
|
|
147
|
+
|
|
148
|
+
// Execute all requests in parallel
|
|
149
|
+
this.httpUtil.batchRequests([userRequest, ordersRequest]).subscribe({
|
|
150
|
+
next: ([user, orders]) => {
|
|
151
|
+
this.user = user;
|
|
152
|
+
this.orders = orders;
|
|
153
|
+
},
|
|
154
|
+
error: (err) => console.error('Error fetching data:', err)
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Loading State
|
|
159
|
+
|
|
160
|
+
The service exposes a loading state observable that you can subscribe to:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
this.httpUtil.loading$.subscribe(isLoading => {
|
|
164
|
+
this.isLoading = isLoading;
|
|
165
|
+
// Update UI based on loading state
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Error Handling
|
|
170
|
+
|
|
171
|
+
The service automatically handles common HTTP errors and displays appropriate messages using the MessageService if it's provided in the constructor.
|
|
172
|
+
|
|
173
|
+
## Advanced Usage
|
|
174
|
+
|
|
175
|
+
For more complex usage examples, see the `http-utility.service.example.ts` file.
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { HttpClient, HttpParams, HttpHeaders, HttpErrorResponse, HttpEvent } from '@angular/common/http';
|
|
3
|
+
import { Observable, throwError, BehaviorSubject, finalize, forkJoin } from 'rxjs';
|
|
4
|
+
import { catchError, retry, timeout } from 'rxjs/operators';
|
|
5
|
+
import { MessageService } from 'primeng/api';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A general-purpose HTTP utility service that provides enhanced HTTP operations
|
|
9
|
+
* beyond the standard Angular HttpClient. This service includes features such as:
|
|
10
|
+
* - Loading state management
|
|
11
|
+
* - Standardized error handling
|
|
12
|
+
* - Request timeouts and retries
|
|
13
|
+
* - File upload capabilities
|
|
14
|
+
* - Batch request handling
|
|
15
|
+
*/
|
|
16
|
+
@Injectable({
|
|
17
|
+
providedIn: 'root'
|
|
18
|
+
})
|
|
19
|
+
export class HttpUtilityService {
|
|
20
|
+
private loading = new BehaviorSubject<boolean>(false);
|
|
21
|
+
loading$ = this.loading.asObservable();
|
|
22
|
+
|
|
23
|
+
constructor(
|
|
24
|
+
private http: HttpClient,
|
|
25
|
+
private messageService?: MessageService
|
|
26
|
+
) {}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Perform a GET request with enhanced options
|
|
30
|
+
* @param url The endpoint URL
|
|
31
|
+
* @param options Additional request options
|
|
32
|
+
* @returns An observable of the response
|
|
33
|
+
*/
|
|
34
|
+
get<T>(url: string, options?: {
|
|
35
|
+
params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
|
|
36
|
+
headers?: HttpHeaders | Record<string, string | string[]>,
|
|
37
|
+
responseType?: 'json',
|
|
38
|
+
withCredentials?: boolean,
|
|
39
|
+
retries?: number,
|
|
40
|
+
timeoutMs?: number
|
|
41
|
+
}): Observable<T> {
|
|
42
|
+
this.loading.next(true);
|
|
43
|
+
|
|
44
|
+
let request$ = this.http.get<T>(url, {
|
|
45
|
+
params: options?.params,
|
|
46
|
+
headers: options?.headers,
|
|
47
|
+
responseType: options?.responseType as 'json',
|
|
48
|
+
withCredentials: options?.withCredentials
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (options?.retries) {
|
|
52
|
+
request$ = request$.pipe(retry(options.retries));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options?.timeoutMs) {
|
|
56
|
+
request$ = request$.pipe(timeout(options.timeoutMs));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return request$.pipe(
|
|
60
|
+
catchError(this.handleError.bind(this)),
|
|
61
|
+
finalize(() => this.loading.next(false))
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Perform a POST request with enhanced options
|
|
67
|
+
* @param url The endpoint URL
|
|
68
|
+
* @param body The request payload
|
|
69
|
+
* @param options Additional request options
|
|
70
|
+
* @returns An observable of the response
|
|
71
|
+
*/
|
|
72
|
+
post<T>(url: string, body: any, options?: {
|
|
73
|
+
params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
|
|
74
|
+
headers?: HttpHeaders | Record<string, string | string[]>,
|
|
75
|
+
responseType?: 'json',
|
|
76
|
+
withCredentials?: boolean,
|
|
77
|
+
retries?: number,
|
|
78
|
+
timeoutMs?: number
|
|
79
|
+
}): Observable<T> {
|
|
80
|
+
this.loading.next(true);
|
|
81
|
+
|
|
82
|
+
let request$ = this.http.post<T>(url, body, {
|
|
83
|
+
params: options?.params,
|
|
84
|
+
headers: options?.headers,
|
|
85
|
+
responseType: options?.responseType as 'json',
|
|
86
|
+
withCredentials: options?.withCredentials
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (options?.retries) {
|
|
90
|
+
request$ = request$.pipe(retry(options.retries));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (options?.timeoutMs) {
|
|
94
|
+
request$ = request$.pipe(timeout(options.timeoutMs));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return request$.pipe(
|
|
98
|
+
catchError(this.handleError.bind(this)),
|
|
99
|
+
finalize(() => this.loading.next(false))
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Perform a PUT request with enhanced options
|
|
105
|
+
* @param url The endpoint URL
|
|
106
|
+
* @param body The request payload
|
|
107
|
+
* @param options Additional request options
|
|
108
|
+
* @returns An observable of the response
|
|
109
|
+
*/
|
|
110
|
+
put<T>(url: string, body: any, options?: {
|
|
111
|
+
params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
|
|
112
|
+
headers?: HttpHeaders | Record<string, string | string[]>,
|
|
113
|
+
responseType?: 'json',
|
|
114
|
+
withCredentials?: boolean,
|
|
115
|
+
retries?: number,
|
|
116
|
+
timeoutMs?: number
|
|
117
|
+
}): Observable<T> {
|
|
118
|
+
this.loading.next(true);
|
|
119
|
+
|
|
120
|
+
let request$ = this.http.put<T>(url, body, {
|
|
121
|
+
params: options?.params,
|
|
122
|
+
headers: options?.headers,
|
|
123
|
+
responseType: options?.responseType as 'json',
|
|
124
|
+
withCredentials: options?.withCredentials
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (options?.retries) {
|
|
128
|
+
request$ = request$.pipe(retry(options.retries));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (options?.timeoutMs) {
|
|
132
|
+
request$ = request$.pipe(timeout(options.timeoutMs));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return request$.pipe(
|
|
136
|
+
catchError(this.handleError.bind(this)),
|
|
137
|
+
finalize(() => this.loading.next(false))
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Perform a DELETE request with enhanced options
|
|
143
|
+
* @param url The endpoint URL
|
|
144
|
+
* @param options Additional request options
|
|
145
|
+
* @returns An observable of the response
|
|
146
|
+
*/
|
|
147
|
+
delete<T>(url: string, options?: {
|
|
148
|
+
params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
|
|
149
|
+
headers?: HttpHeaders | Record<string, string | string[]>,
|
|
150
|
+
responseType?: 'json',
|
|
151
|
+
withCredentials?: boolean,
|
|
152
|
+
retries?: number,
|
|
153
|
+
timeoutMs?: number
|
|
154
|
+
}): Observable<T> {
|
|
155
|
+
this.loading.next(true);
|
|
156
|
+
|
|
157
|
+
let request$ = this.http.delete<T>(url, {
|
|
158
|
+
params: options?.params,
|
|
159
|
+
headers: options?.headers,
|
|
160
|
+
responseType: options?.responseType as 'json',
|
|
161
|
+
withCredentials: options?.withCredentials
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (options?.retries) {
|
|
165
|
+
request$ = request$.pipe(retry(options.retries));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (options?.timeoutMs) {
|
|
169
|
+
request$ = request$.pipe(timeout(options.timeoutMs));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return request$.pipe(
|
|
173
|
+
catchError(this.handleError.bind(this)),
|
|
174
|
+
finalize(() => this.loading.next(false))
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Upload a file with optional additional data
|
|
180
|
+
* @param url The upload endpoint URL
|
|
181
|
+
* @param file The file to upload
|
|
182
|
+
* @param additionalData Additional form data to include
|
|
183
|
+
* @param options Additional request options
|
|
184
|
+
* @returns An observable of the response
|
|
185
|
+
*/
|
|
186
|
+
uploadFile<T>(url: string, file: File, additionalData?: Record<string, any>, options?: {
|
|
187
|
+
headers?: HttpHeaders | Record<string, string | string[]>,
|
|
188
|
+
withCredentials?: boolean,
|
|
189
|
+
retries?: number,
|
|
190
|
+
timeoutMs?: number,
|
|
191
|
+
onProgress?: (percentage: number) => void
|
|
192
|
+
}): Observable<T> {
|
|
193
|
+
this.loading.next(true);
|
|
194
|
+
|
|
195
|
+
const formData = new FormData();
|
|
196
|
+
formData.append('file', file, file.name);
|
|
197
|
+
|
|
198
|
+
if (additionalData) {
|
|
199
|
+
Object.keys(additionalData).forEach(key => {
|
|
200
|
+
formData.append(key, additionalData[key]);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let httpOptions: any = {
|
|
205
|
+
headers: options?.headers,
|
|
206
|
+
withCredentials: options?.withCredentials
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// If progress tracking is requested
|
|
210
|
+
if (options?.onProgress) {
|
|
211
|
+
httpOptions.reportProgress = true;
|
|
212
|
+
httpOptions.observe = 'events';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Create the request
|
|
216
|
+
let request$ = this.http.post<any>(url, formData, httpOptions);
|
|
217
|
+
|
|
218
|
+
// Add retries if specified
|
|
219
|
+
if (options?.retries) {
|
|
220
|
+
request$ = request$.pipe(retry(options.retries));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Add timeout if specified
|
|
224
|
+
if (options?.timeoutMs) {
|
|
225
|
+
request$ = request$.pipe(timeout(options.timeoutMs));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Track progress if a callback is provided
|
|
229
|
+
if (options?.onProgress) {
|
|
230
|
+
return new Observable<T>(observer => {
|
|
231
|
+
request$.subscribe({
|
|
232
|
+
next: (event: HttpEvent<any>) => {
|
|
233
|
+
if (event.type === 1 && event.total) { // HttpEventType.UploadProgress
|
|
234
|
+
const percentDone = Math.round(100 * event.loaded / event.total);
|
|
235
|
+
options.onProgress!(percentDone);
|
|
236
|
+
} else if (event.type === 4) { // HttpEventType.Response
|
|
237
|
+
observer.next(event.body);
|
|
238
|
+
observer.complete();
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
error: (error) => {
|
|
242
|
+
observer.error(this.handleError(error));
|
|
243
|
+
this.loading.next(false);
|
|
244
|
+
},
|
|
245
|
+
complete: () => {
|
|
246
|
+
this.loading.next(false);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Standard request without progress tracking
|
|
253
|
+
return request$.pipe(
|
|
254
|
+
catchError(this.handleError.bind(this)),
|
|
255
|
+
finalize(() => this.loading.next(false))
|
|
256
|
+
) as Observable<T>;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Execute multiple HTTP requests in parallel
|
|
261
|
+
* @param requests Array of HTTP request observables
|
|
262
|
+
* @returns An observable that emits when all requests complete
|
|
263
|
+
*/
|
|
264
|
+
batchRequests<T>(requests: Observable<T>[]): Observable<T[]> {
|
|
265
|
+
this.loading.next(true);
|
|
266
|
+
return forkJoin(requests).pipe(
|
|
267
|
+
catchError(this.handleError.bind(this)),
|
|
268
|
+
finalize(() => this.loading.next(false))
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Download a file from the server
|
|
274
|
+
* @param url The file URL
|
|
275
|
+
* @param filename Optional filename to save as
|
|
276
|
+
* @param options Additional request options
|
|
277
|
+
*/
|
|
278
|
+
downloadFile(url: string, filename?: string, options?: {
|
|
279
|
+
params?: HttpParams | Record<string, string | number | boolean | readonly (string | number | boolean)[]>,
|
|
280
|
+
headers?: HttpHeaders | Record<string, string | string[]>,
|
|
281
|
+
withCredentials?: boolean,
|
|
282
|
+
timeoutMs?: number
|
|
283
|
+
}): Observable<Blob> {
|
|
284
|
+
this.loading.next(true);
|
|
285
|
+
|
|
286
|
+
let request$ = this.http.get(url, {
|
|
287
|
+
params: options?.params,
|
|
288
|
+
headers: options?.headers,
|
|
289
|
+
responseType: 'blob',
|
|
290
|
+
withCredentials: options?.withCredentials
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (options?.timeoutMs) {
|
|
294
|
+
request$ = request$.pipe(timeout(options.timeoutMs));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return request$.pipe(
|
|
298
|
+
catchError(this.handleError.bind(this)),
|
|
299
|
+
finalize(() => this.loading.next(false))
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Create parameter string from an object
|
|
305
|
+
* @param params Object containing parameters
|
|
306
|
+
* @returns HttpParams object
|
|
307
|
+
*/
|
|
308
|
+
createParams(params: Record<string, any>): HttpParams {
|
|
309
|
+
let httpParams = new HttpParams();
|
|
310
|
+
|
|
311
|
+
Object.keys(params).forEach(key => {
|
|
312
|
+
const value = params[key];
|
|
313
|
+
if (value !== undefined && value !== null) {
|
|
314
|
+
httpParams = httpParams.append(key, value.toString());
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
return httpParams;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Standardized error handler for HTTP requests
|
|
323
|
+
* @param error The HTTP error
|
|
324
|
+
* @returns An observable that errors with the processed error object
|
|
325
|
+
*/
|
|
326
|
+
private handleError(error: HttpErrorResponse) {
|
|
327
|
+
console.error('An HTTP error occurred:', error);
|
|
328
|
+
|
|
329
|
+
let errorMessage = 'An error occurred';
|
|
330
|
+
let errorCode: string | undefined;
|
|
331
|
+
|
|
332
|
+
if (error.error instanceof ErrorEvent) {
|
|
333
|
+
// Client-side error
|
|
334
|
+
errorMessage = error.error.message;
|
|
335
|
+
} else {
|
|
336
|
+
// Server-side error
|
|
337
|
+
errorCode = error.status.toString();
|
|
338
|
+
|
|
339
|
+
switch (error.status) {
|
|
340
|
+
case 400:
|
|
341
|
+
errorMessage = error.error?.message || 'Bad request';
|
|
342
|
+
break;
|
|
343
|
+
case 401:
|
|
344
|
+
errorMessage = 'Unauthorized';
|
|
345
|
+
break;
|
|
346
|
+
case 403:
|
|
347
|
+
errorMessage = 'Access denied';
|
|
348
|
+
break;
|
|
349
|
+
case 404:
|
|
350
|
+
errorMessage = 'Resource not found';
|
|
351
|
+
break;
|
|
352
|
+
case 408:
|
|
353
|
+
errorMessage = 'Request timeout';
|
|
354
|
+
break;
|
|
355
|
+
case 500:
|
|
356
|
+
errorMessage = 'Server error';
|
|
357
|
+
break;
|
|
358
|
+
case 503:
|
|
359
|
+
errorMessage = 'Service unavailable';
|
|
360
|
+
break;
|
|
361
|
+
default:
|
|
362
|
+
errorMessage = error.error?.message || `Error ${error.status}`;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
this.showError(errorMessage);
|
|
368
|
+
return throwError(() => ({
|
|
369
|
+
error,
|
|
370
|
+
message: errorMessage,
|
|
371
|
+
code: errorCode
|
|
372
|
+
}));
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Display an error message using the message service
|
|
377
|
+
* @param message Error message to display
|
|
378
|
+
*/
|
|
379
|
+
private showError(message: string) {
|
|
380
|
+
if (this.messageService) {
|
|
381
|
+
this.messageService.add({
|
|
382
|
+
severity: 'error',
|
|
383
|
+
summary: 'Error',
|
|
384
|
+
detail: message,
|
|
385
|
+
life: 3000
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { MessageService } from 'primeng/api';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class NotificationService {
|
|
7
|
+
private messageSubject = new BehaviorSubject<any>(null);
|
|
8
|
+
message$ = this.messageSubject.asObservable();
|
|
9
|
+
|
|
10
|
+
constructor(private messageService: MessageService) {}
|
|
11
|
+
|
|
12
|
+
showSuccess(message: string) {
|
|
13
|
+
const msgObj = {
|
|
14
|
+
severity: 'success',
|
|
15
|
+
summary: 'Success',
|
|
16
|
+
detail: message,
|
|
17
|
+
life: 3000
|
|
18
|
+
};
|
|
19
|
+
this.messageSubject.next(msgObj);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
showError(message: string) {
|
|
23
|
+
const msgObj = {
|
|
24
|
+
severity: 'error',
|
|
25
|
+
summary: 'Error',
|
|
26
|
+
detail: message,
|
|
27
|
+
life: 3000
|
|
28
|
+
};
|
|
29
|
+
this.messageSubject.next(msgObj);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
clearMessage() {
|
|
33
|
+
this.messageSubject.next(null);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Injectable({
|
|
4
|
+
providedIn: 'root'
|
|
5
|
+
})
|
|
6
|
+
export class ReferenceDataProviderService {
|
|
7
|
+
|
|
8
|
+
private endpoints: Record<string, string> = {};
|
|
9
|
+
|
|
10
|
+
// Method to set/update endpoints
|
|
11
|
+
setEndpoints(endpoints: Record<string, string>) {
|
|
12
|
+
this.endpoints = { ...this.endpoints, ...endpoints };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getReferenceEndpoint(entityName: string): string | null {
|
|
16
|
+
console.log('getReferenceEndpoint', entityName, this.endpoints);
|
|
17
|
+
let endpoint = this.endpoints[entityName];
|
|
18
|
+
if (endpoint != null && endpoint.length > 0) {
|
|
19
|
+
if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {
|
|
20
|
+
return endpoint; // Absolute URL
|
|
21
|
+
} else {
|
|
22
|
+
// Relative URL, assume it's within the application's base context
|
|
23
|
+
return endpoint;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|