http-request-manager 18.16.3 → 18.16.6
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/README.md
CHANGED
|
@@ -20,7 +20,7 @@ This README is the main documentation hub for the library. Detailed service guid
|
|
|
20
20
|
| **🔄 State Management** | CRUD state, persistence, derived state | [`HTTPManagerStateService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/HTTP_STATE_MANAGER_README.md) and [`StoreStateManagerService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/STORE_STATE_MANAGER_README.md) | [`StoreStateManagerSignalsService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/STORE_STATE_SIGNALS_README.md) |
|
|
21
21
|
| **💬 Real-Time Communication** | WebSocket channels, tracking, messaging | [`WebSocketManagerService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/WS_MANAGER_README.md), [`WebSocketMessageService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/WEBSOCKET_MESSAGE_SERVICE.md), and [`MessageTrackerService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/MESSAGE_TRACKER_README.md) | [`WebSocketSignalsManagerService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/WEBSOCKET_SIGNALS_README.md) and [`MessageTrackerSignalsService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/MESSAGE_TRACKER_SIGNALS_README.md) |
|
|
22
22
|
| **💾 Data Persistence** | Local/session storage and offline caching | [`LocalStorageManagerService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/LOCAL_STORAGE_README.md) and [`DatabaseManagerService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/DATABASE_README.md) | [`LocalStorageSignalsManagerService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/LOCAL_STORAGE_SIGNALS_README.md) |
|
|
23
|
-
| **🗄️
|
|
23
|
+
| **🗄️ Database Queries** | MySQL-syntax SQL queries on IndexedDB — the recommended way to query data | [`DexieSqlService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/SQL_DIXIE_README.md) | Uses the same service |
|
|
24
24
|
| **⚡ Utility Functions** | JSON handling, encryption, headers, validation, logging | [`UtilsService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/UTILS_README.md), [`Encryption`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/ENCRYPTION_README.md), [`Logger`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/LOGGER_README.md) | Uses the same utility layer |
|
|
25
25
|
|
|
26
26
|
### Key Benefits
|
|
@@ -37,12 +37,28 @@ Note on clearing persisted data:
|
|
|
37
37
|
- **Clear full DB (fire-and-forget)**: To wipe the entire IndexedDB for this library and its associated localStorage metadata, call `DatabaseManagerService.clearDatabase()`. This method subscribes internally and is intentionally fire-and-forget — callers should simply call `databaseManager.clearDatabase()` (no `.subscribe()` required). The method also clears related localStorage metadata via `LocalStorageManagerService`.
|
|
38
38
|
- **Clear a specific table (Observable)**: To remove records from a specific table, use `DatabaseManagerService.clearTableRecords(tableName)` which returns an `Observable<void>`; callers should `.subscribe()` or use RxJS operators to react to completion.
|
|
39
39
|
|
|
40
|
-
###
|
|
40
|
+
### �️ Database Access
|
|
41
|
+
|
|
42
|
+
The library provides two complementary services for working with IndexedDB data:
|
|
43
|
+
|
|
44
|
+
| Task | Service | Example |
|
|
45
|
+
|------|---------|---------|
|
|
46
|
+
| **Query data** (recommended) | `DexieSqlService` | `sql.query('SELECT * FROM orders WHERE status = "open"')` |
|
|
47
|
+
| **Create tables** | `DatabaseManagerService` | `db.createDatabaseTable(tableDef)` |
|
|
48
|
+
| **Insert / update records** | `DatabaseManagerService` | `db.createTableRecord('orders', record)` |
|
|
49
|
+
| **Delete records** | `DatabaseManagerService` | `db.deleteTableRecord('orders', id)` |
|
|
50
|
+
| **Clear / reset database** | `DatabaseManagerService` | `db.clearDatabase()` |
|
|
51
|
+
|
|
52
|
+
Use `DexieSqlService` for all read queries — it supports SELECT with WHERE, JOIN, ORDER BY, LIMIT, COUNT, DISTINCT, and more. Use `DatabaseManagerService` for table creation and write operations.
|
|
53
|
+
|
|
54
|
+
See the full SQL syntax reference: [`DexieSqlService Guide`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/SQL_DIXIE_README.md)
|
|
55
|
+
|
|
56
|
+
### �🚀 Advanced Features
|
|
41
57
|
|
|
42
58
|
| Feature | Description | Learn More |
|
|
43
59
|
|---------|-------------|------------|
|
|
44
60
|
| **🔐 Enterprise Encryption** | AES symmetric + RSA asymmetric encryption | [`Encryption Utils`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/ENCRYPTION_README.md) |
|
|
45
|
-
| **🗄️
|
|
61
|
+
| **🗄️ Database Queries** | MySQL-syntax SQL queries on IndexedDB — the recommended way to query data (SELECT, WHERE, JOIN, ORDER BY, LIMIT, COUNT, DISTINCT) | [`DexieSqlService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/SQL_DIXIE_README.md) |
|
|
46
62
|
| **📡 Streaming Support** | NDJSON & Server-Sent Events (SSE) | [`HTTP Manager`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/HTTP_MANAGER_README.md#streaming) |
|
|
47
63
|
| **📄 File Downloads** | Progress tracking for large files | [`HTTP Manager`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/HTTP_MANAGER_README.md#file-downloads) |
|
|
48
64
|
| **📤 File Uploads** | Multi-file upload with progress, validation, and form-data config | [`Upload Request`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/UPLOAD_REQUEST_README.md) |
|
|
@@ -1868,6 +1868,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
1868
1868
|
*/
|
|
1869
1869
|
class WebSocketManagerService {
|
|
1870
1870
|
constructor() {
|
|
1871
|
+
this.isConnecting$ = WebSocketManagerService.isConnectingSubject.asObservable();
|
|
1871
1872
|
this.retryCount$ = WebSocketManagerService.retryCountSubject.asObservable();
|
|
1872
1873
|
this.maxRetries$ = WebSocketManagerService.maxRetriesSubject.asObservable();
|
|
1873
1874
|
this.messages$ = WebSocketManagerService.messages.asObservable();
|
|
@@ -1880,8 +1881,9 @@ class WebSocketManagerService {
|
|
|
1880
1881
|
// STATIC SINGLETON STATE (Shared across ALL instances)
|
|
1881
1882
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1882
1883
|
static { this.socket = null; }
|
|
1883
|
-
static { this.
|
|
1884
|
+
static { this.isConnectingSubject = new BehaviorSubject(false); }
|
|
1884
1885
|
static { this.connectionInitialized = false; }
|
|
1886
|
+
static { this.shouldRetry = true; }
|
|
1885
1887
|
// Store last options for reconnection
|
|
1886
1888
|
static { this.lastOptions = null; }
|
|
1887
1889
|
static { this.lastJwtToken = ''; }
|
|
@@ -1961,7 +1963,7 @@ class WebSocketManagerService {
|
|
|
1961
1963
|
}
|
|
1962
1964
|
}
|
|
1963
1965
|
// Prevent duplicate connection attempts
|
|
1964
|
-
if (WebSocketManagerService.
|
|
1966
|
+
if (WebSocketManagerService.isConnectingSubject.value) {
|
|
1965
1967
|
console.log('⏳ Connection already in progress...');
|
|
1966
1968
|
return;
|
|
1967
1969
|
}
|
|
@@ -1983,12 +1985,15 @@ class WebSocketManagerService {
|
|
|
1983
1985
|
else {
|
|
1984
1986
|
WebSocketManagerService.retryDelay = 5000;
|
|
1985
1987
|
}
|
|
1986
|
-
//
|
|
1987
|
-
WebSocketManagerService.
|
|
1988
|
+
// Reset shouldRetry flag for new connection attempts
|
|
1989
|
+
WebSocketManagerService.shouldRetry = true;
|
|
1990
|
+
// Mark as connecting — connectionStatus false while connecting, true only when connected
|
|
1991
|
+
WebSocketManagerService.isConnectingSubject.next(true);
|
|
1988
1992
|
WebSocketManagerService.isSubscribed = false;
|
|
1989
1993
|
WebSocketManagerService.connectionReadyNotified = false;
|
|
1990
1994
|
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
1991
|
-
|
|
1995
|
+
// Don't set connectionStatus to true here - only set to true when connection is actually established
|
|
1996
|
+
// WebSocketManagerService.connectionStatus.next(true);
|
|
1992
1997
|
const sessionId = this.getSessionId();
|
|
1993
1998
|
const URL = (jwtToken) ? `${options.wsServer}?token=${jwtToken}&sessionId=${sessionId}` : `${options.wsServer}?sessionId=${sessionId}`;
|
|
1994
1999
|
console.log(`🔌 Initiating WebSocket connection to: ${options.wsServer}`);
|
|
@@ -2002,8 +2007,9 @@ class WebSocketManagerService {
|
|
|
2002
2007
|
// Do NOT reset retryCount here — reset happens only on confirmed stable connection
|
|
2003
2008
|
// (onmessage first valid response). Resetting here would cause the counter to always
|
|
2004
2009
|
// show 1/N because onopen fires before onclose increments the counter.
|
|
2005
|
-
WebSocketManagerService.
|
|
2010
|
+
WebSocketManagerService.isConnectingSubject.next(false);
|
|
2006
2011
|
WebSocketManagerService.connectionInitialized = true;
|
|
2012
|
+
// Do NOT set connectionStatus to true here - wait for server to confirm authentication via onmessage
|
|
2007
2013
|
};
|
|
2008
2014
|
WebSocketManagerService.socket.onmessage = (event) => {
|
|
2009
2015
|
try {
|
|
@@ -2015,6 +2021,8 @@ class WebSocketManagerService {
|
|
|
2015
2021
|
WebSocketManagerService.lastOptions = null;
|
|
2016
2022
|
WebSocketManagerService.connectionError.next('Invalid or Expired JWT');
|
|
2017
2023
|
WebSocketManagerService.connectionStatus.next(false);
|
|
2024
|
+
// Stop retrying for authentication errors
|
|
2025
|
+
WebSocketManagerService.shouldRetry = false;
|
|
2018
2026
|
}
|
|
2019
2027
|
else {
|
|
2020
2028
|
console.error(`❌ Server error: ${data.error} — will retry`);
|
|
@@ -2032,6 +2040,8 @@ class WebSocketManagerService {
|
|
|
2032
2040
|
WebSocketManagerService.retryCountSubject.next(0);
|
|
2033
2041
|
}
|
|
2034
2042
|
WebSocketManagerService.connectionReadyNotified = true;
|
|
2043
|
+
// Set connection status to true only when server confirms authentication
|
|
2044
|
+
WebSocketManagerService.connectionStatus.next(true);
|
|
2035
2045
|
console.log(`🔄 Emitting reconnect event for MessageTrackerService`);
|
|
2036
2046
|
WebSocketManagerService.onReconnect.next();
|
|
2037
2047
|
}
|
|
@@ -2043,18 +2053,21 @@ class WebSocketManagerService {
|
|
|
2043
2053
|
};
|
|
2044
2054
|
WebSocketManagerService.socket.onclose = (event) => {
|
|
2045
2055
|
console.log(`🔴 WebSocket closed (code: ${event.code})`);
|
|
2046
|
-
WebSocketManagerService.
|
|
2056
|
+
WebSocketManagerService.isConnectingSubject.next(false);
|
|
2047
2057
|
WebSocketManagerService.connectionReadyNotified = false;
|
|
2048
2058
|
WebSocketManagerService.socket = null;
|
|
2049
2059
|
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
2050
2060
|
if (event.code === 4000 || event.code === 4001 || event.code === 4003) {
|
|
2051
2061
|
WebSocketManagerService.connectionError.next('Invalid or Expired JWT');
|
|
2052
2062
|
WebSocketManagerService.connectionStatus.next(false);
|
|
2063
|
+
// Stop retrying for authentication errors
|
|
2064
|
+
WebSocketManagerService.shouldRetry = false;
|
|
2053
2065
|
return;
|
|
2054
2066
|
}
|
|
2055
2067
|
const maxRetries = WebSocketManagerService.maxRetries;
|
|
2056
2068
|
const retryDelay = WebSocketManagerService.retryDelay;
|
|
2057
|
-
if
|
|
2069
|
+
// Only retry if shouldRetry is true and we haven't exceeded max retries
|
|
2070
|
+
if (WebSocketManagerService.shouldRetry && WebSocketManagerService.lastOptions && WebSocketManagerService.retryCount < maxRetries) {
|
|
2058
2071
|
WebSocketManagerService.retryCount++;
|
|
2059
2072
|
WebSocketManagerService.retryCountSubject.next(WebSocketManagerService.retryCount);
|
|
2060
2073
|
console.log(`🔄 Reconnect attempt ${WebSocketManagerService.retryCount}/${maxRetries}...`);
|
|
@@ -2064,13 +2077,19 @@ class WebSocketManagerService {
|
|
|
2064
2077
|
else {
|
|
2065
2078
|
console.error(`❌ WebSocket failed after ${maxRetries} retries. Giving up.`);
|
|
2066
2079
|
WebSocketManagerService.connectionStatus.next(false);
|
|
2080
|
+
// Set error message if not already set
|
|
2081
|
+
if (!WebSocketManagerService.connectionError.value) {
|
|
2082
|
+
WebSocketManagerService.connectionError.next('Connection failed after maximum retries');
|
|
2083
|
+
}
|
|
2067
2084
|
WebSocketManagerService.retryCount = maxRetries;
|
|
2068
2085
|
WebSocketManagerService.retryCountSubject.next(maxRetries);
|
|
2086
|
+
// Reset shouldRetry flag for future connection attempts
|
|
2087
|
+
WebSocketManagerService.shouldRetry = true;
|
|
2069
2088
|
}
|
|
2070
2089
|
};
|
|
2071
2090
|
WebSocketManagerService.socket.onerror = (error) => {
|
|
2072
2091
|
console.error('❌ WebSocket error:', error);
|
|
2073
|
-
WebSocketManagerService.
|
|
2092
|
+
WebSocketManagerService.isConnectingSubject.next(false);
|
|
2074
2093
|
// onclose will fire after onerror and drive retry/give-up logic
|
|
2075
2094
|
};
|
|
2076
2095
|
}
|
|
@@ -3794,6 +3813,7 @@ class HTTPManagerService extends RequestService {
|
|
|
3794
3813
|
this.connectionStatus$ = this.wsManager.connectionStatus$;
|
|
3795
3814
|
this.messages$ = this.messageTracker.messages$; // Messages flow through MessageTrackerService
|
|
3796
3815
|
this.subscribedChannels$ = this.wsManager.subscribedChannels$;
|
|
3816
|
+
this.isConnecting$ = this.wsManager.isConnecting$;
|
|
3797
3817
|
this.retryCount$ = this.wsManager.retryCount$;
|
|
3798
3818
|
this.maxRetries$ = this.wsManager.maxRetries$;
|
|
3799
3819
|
this.connectionError$ = this.wsManager.connectionError$;
|
|
@@ -6658,6 +6678,7 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
6658
6678
|
this.wsOptions = WSOptions.adapt();
|
|
6659
6679
|
// Expose raw WS connection status directly to UI (from singleton WebSocketManagerService)
|
|
6660
6680
|
this.connectionStatus$ = this.httpManagerService.connectionStatus$;
|
|
6681
|
+
this.isConnecting$ = this.httpManagerService.isConnecting$;
|
|
6661
6682
|
this.wsRetryCount$ = this.httpManagerService.retryCount$;
|
|
6662
6683
|
this.wsMaxRetries$ = this.httpManagerService.maxRetries$;
|
|
6663
6684
|
this.connectionError$ = this.httpManagerService.connectionError$;
|
|
@@ -7219,7 +7240,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7219
7240
|
this.createRecord = (data, options) => this.effect(() => of(data).pipe(switchMap((data) => {
|
|
7220
7241
|
this.streamedResponse = [];
|
|
7221
7242
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7222
|
-
|
|
7243
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7244
|
+
return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
|
|
7223
7245
|
.pipe(tap((data) => {
|
|
7224
7246
|
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
7225
7247
|
this.addData$(data);
|
|
@@ -7237,7 +7259,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7237
7259
|
this.updateRecord = (data, options) => this.effect(() => of(data).pipe(concatMap((data) => {
|
|
7238
7260
|
this.streamedResponse = [];
|
|
7239
7261
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7240
|
-
|
|
7262
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7263
|
+
return this.httpManagerService.putRequest(data, requestOptions, effectiveParams)
|
|
7241
7264
|
.pipe(tap((data) => {
|
|
7242
7265
|
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
7243
7266
|
this.updateData$(data);
|
|
@@ -7255,7 +7278,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7255
7278
|
this.deleteRecord = (options) => this.effect(() => of(options).pipe(concatMap((data) => {
|
|
7256
7279
|
this.streamedResponse = [];
|
|
7257
7280
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7258
|
-
|
|
7281
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7282
|
+
return this.httpManagerService.deleteRequest(requestOptions, effectiveParams)
|
|
7259
7283
|
.pipe(tap((data) => {
|
|
7260
7284
|
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
7261
7285
|
this.deleteData$(data);
|
|
@@ -7273,7 +7297,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7273
7297
|
// FETCH STREAM
|
|
7274
7298
|
this.createStream = (data, options) => this.effect(() => of(data).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((data) => {
|
|
7275
7299
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7276
|
-
|
|
7300
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7301
|
+
return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
|
|
7277
7302
|
.pipe(tap((res) => {
|
|
7278
7303
|
if (res.length > 0)
|
|
7279
7304
|
this.setData$(res);
|
|
@@ -8070,12 +8095,9 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8070
8095
|
const effective = this.getEffectiveParams(params);
|
|
8071
8096
|
return effective ? [...basePath, ...effective] : [...basePath];
|
|
8072
8097
|
}
|
|
8073
|
-
|
|
8074
|
-
if (!Array.isArray(params) || params.length === 0) {
|
|
8075
|
-
return undefined;
|
|
8076
|
-
}
|
|
8098
|
+
stripBasePathPrefix(params) {
|
|
8077
8099
|
const basePath = Array.isArray(this.apiOptions.path) ? this.apiOptions.path : [];
|
|
8078
|
-
if (basePath.length
|
|
8100
|
+
if (basePath.length === 0 || params.length < basePath.length) {
|
|
8079
8101
|
return params;
|
|
8080
8102
|
}
|
|
8081
8103
|
const normalizePart = (value) => {
|
|
@@ -8084,8 +8106,25 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8084
8106
|
}
|
|
8085
8107
|
return String(value);
|
|
8086
8108
|
};
|
|
8087
|
-
const
|
|
8088
|
-
return
|
|
8109
|
+
const startsWithBase = basePath.every((part, index) => normalizePart(part) === normalizePart(params[index]));
|
|
8110
|
+
return startsWithBase ? params.slice(basePath.length) : params;
|
|
8111
|
+
}
|
|
8112
|
+
getEffectiveParams(params) {
|
|
8113
|
+
if (!Array.isArray(params) || params.length === 0) {
|
|
8114
|
+
return undefined;
|
|
8115
|
+
}
|
|
8116
|
+
const basePath = Array.isArray(this.apiOptions.path) ? this.apiOptions.path : [];
|
|
8117
|
+
if (basePath.length === params.length) {
|
|
8118
|
+
const normalizePart = (value) => {
|
|
8119
|
+
if (value && typeof value === 'object') {
|
|
8120
|
+
return JSON.stringify(this.normalizeObject(value));
|
|
8121
|
+
}
|
|
8122
|
+
return String(value);
|
|
8123
|
+
};
|
|
8124
|
+
const samePath = params.every((part, index) => normalizePart(part) === normalizePart(basePath[index]));
|
|
8125
|
+
return samePath ? undefined : params;
|
|
8126
|
+
}
|
|
8127
|
+
return this.stripBasePathPrefix(params);
|
|
8089
8128
|
}
|
|
8090
8129
|
buildRequestSignature(method, requestOptions, params) {
|
|
8091
8130
|
const signaturePayload = {
|
|
@@ -8693,10 +8732,11 @@ class SqlParser {
|
|
|
8693
8732
|
if (ast.type !== 'select') {
|
|
8694
8733
|
throw new SqlParseError('Only SELECT statements are supported');
|
|
8695
8734
|
}
|
|
8735
|
+
const stripPrefix = (list) => list.map(entry => entry.split('::').pop() ?? entry);
|
|
8696
8736
|
return {
|
|
8697
8737
|
ast,
|
|
8698
|
-
tableList: result.tableList ?? [],
|
|
8699
|
-
columnList: result.columnList ?? [],
|
|
8738
|
+
tableList: stripPrefix(result.tableList ?? []),
|
|
8739
|
+
columnList: stripPrefix(result.columnList ?? []),
|
|
8700
8740
|
};
|
|
8701
8741
|
}
|
|
8702
8742
|
}
|
|
@@ -8967,7 +9007,9 @@ class QueryPlanner {
|
|
|
8967
9007
|
const where = ast.where;
|
|
8968
9008
|
const boundedFilters = [];
|
|
8969
9009
|
if (where) {
|
|
8970
|
-
this._flattenAnd(where.operator === 'AND'
|
|
9010
|
+
this._flattenAnd(where.operator === 'AND'
|
|
9011
|
+
? where
|
|
9012
|
+
: { type: 'binary_expr', operator: 'AND', left: where, right: null })
|
|
8971
9013
|
.filter(Boolean)
|
|
8972
9014
|
.forEach((c) => boundedFilters.push(this._nodeToStep(c, aliases, mainTable)));
|
|
8973
9015
|
}
|
|
@@ -9000,6 +9042,7 @@ class QueryPlanner {
|
|
|
9000
9042
|
}
|
|
9001
9043
|
else if (vals.length === 1) {
|
|
9002
9044
|
plan.limit = vals[0].value;
|
|
9045
|
+
plan.offset = null;
|
|
9003
9046
|
}
|
|
9004
9047
|
}
|
|
9005
9048
|
// Projection
|
|
@@ -11915,13 +11958,24 @@ class WsDataControlComponent {
|
|
|
11915
11958
|
.pipe(switchMap$1((action) => timer(3 * 1000).pipe(map$1(() => null), startWith$1(action))));
|
|
11916
11959
|
this.data$ = this.stateDataRequestService.data$;
|
|
11917
11960
|
this.isUser = (user, userItem) => {
|
|
11918
|
-
return user.
|
|
11961
|
+
return user.id === userItem?.id;
|
|
11962
|
+
};
|
|
11963
|
+
this.getUserLabel = (user) => {
|
|
11964
|
+
const name = user.name || user.ldap || 'Anonymous';
|
|
11965
|
+
const shortId = user.id ? user.id.substring(0, 8) : '';
|
|
11966
|
+
return shortId ? `${name} (${shortId})` : name;
|
|
11919
11967
|
};
|
|
11920
11968
|
}
|
|
11921
11969
|
ngOnInit() {
|
|
11922
11970
|
this.stateDataRequestService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
11923
11971
|
this.stateDataRequestService.getData();
|
|
11924
11972
|
}
|
|
11973
|
+
ngOnChanges(changes) {
|
|
11974
|
+
if (changes['jwtToken'] && !changes['jwtToken'].firstChange) {
|
|
11975
|
+
this.stateDataRequestService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
11976
|
+
this.stateDataRequestService.getData();
|
|
11977
|
+
}
|
|
11978
|
+
}
|
|
11925
11979
|
onGetData() {
|
|
11926
11980
|
this.stateDataRequestService.getData();
|
|
11927
11981
|
}
|
|
@@ -11930,12 +11984,15 @@ class WsDataControlComponent {
|
|
|
11930
11984
|
}
|
|
11931
11985
|
onUpdateData(data) {
|
|
11932
11986
|
const num = RandomNumber(1000, 9999);
|
|
11987
|
+
const firstName = this.user?.name?.split(' ')[0] || 'mike';
|
|
11988
|
+
const lastName = this.user?.name?.split(' ').slice(1).join(' ') || 'boni';
|
|
11989
|
+
const email = this.user?.email || 'mikeboni@hotmail.com';
|
|
11933
11990
|
const newData = {
|
|
11934
11991
|
"spiffe": `wavecoders.com/developer/${num}`,
|
|
11935
11992
|
"id": 63,
|
|
11936
|
-
"last_name":
|
|
11937
|
-
"email":
|
|
11938
|
-
"first_name":
|
|
11993
|
+
"last_name": lastName,
|
|
11994
|
+
"email": email,
|
|
11995
|
+
"first_name": firstName
|
|
11939
11996
|
};
|
|
11940
11997
|
this.stateDataRequestService.updateData(newData);
|
|
11941
11998
|
}
|
|
@@ -12002,11 +12059,11 @@ class WsDataControlComponent {
|
|
|
12002
12059
|
});
|
|
12003
12060
|
}
|
|
12004
12061
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsDataControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12005
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: WsDataControlComponent, selector: "app-ws-data-control", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, ngImport: i0, template: "@if ((data$ | async); as data) {\n <div style=\"margin: 1rem;\">\n @if ((users$ |async); as users) {\n <div>\n @if (users.length > 0) {\n <h3 style=\"margin: 0;\">Connected Users</h3>\n } @else {\n <h3 style=\"margin: 0;\">No Users</h3>\n }\n <mat-chip-set>\n @for (user of users; track $index) {\n <mat-chip\n [class.user-chip--primary]=\"isUser(user, (user$ | async))\"\n [style.color]=\"isUser(user, (user$ | async)) ? '#fff' : null\"\n [disableRipple]=\"true\"\n >\n {{ user
|
|
12062
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: WsDataControlComponent, selector: "app-ws-data-control", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, usesOnChanges: true, ngImport: i0, template: "@if ((data$ | async); as data) {\n <div style=\"margin: 1rem;\">\n @if ((users$ |async); as users) {\n <div>\n @if (users.length > 0) {\n <h3 style=\"margin: 0;\">Connected Users</h3>\n } @else {\n <h3 style=\"margin: 0;\">No Users</h3>\n }\n <mat-chip-set>\n @for (user of users; track $index) {\n <mat-chip\n [class.user-chip--primary]=\"isUser(user, (user$ | async))\"\n [style.color]=\"isUser(user, (user$ | async)) ? '#fff' : null\"\n [disableRipple]=\"true\"\n >\n {{ getUserLabel(user) }}\n </mat-chip>\n }\n </mat-chip-set>\n </div>\n }\n <div style=\"margin-top: 1rem; margin-bottom: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div class=\"box\" style=\"margin-bottom: 1rem;\" *ngIf=\"(userAction$ | async) as userAction\">\n {{ userAction?.content?.user?.name }} has {{ userAction?.content?.method }}\n </div>\n\n <h3 style=\"margin: 0;\">Data Actions</h3>\n <div style=\"display: flex; gap: 1rem; margin-bottom: 1rem;\">\n <button mat-stroked-button (click)=\"onGetData()\">Get Data</button>\n <div style=\"flex:1\"></div>\n <button mat-stroked-button color=\"accent\" (click)=\"onUpdateData(data)\">Update Data</button>\n <button mat-stroked-button color=\"warn\" (click)=\"onRemoveData(data)\">Remove Data</button>\n <button mat-stroked-button color=\"primary\" (click)=\"onAddData()\">Add Data</button>\n </div>\n\n <h3 style=\"margin: 0; margin-top: 1rem;\">WebSocketMessageService Test</h3>\n\n <p style=\"font-size: 0.875rem; color: #666; margin: 0;\">\n <strong>Note:</strong> \"Fake SessionId\" will be received and processed. \"Current SessionId\" will be filtered out (self-message).\n @if (data.length > 0) {\n <div>\n <table mat-table [dataSource]=\"data\" style=\"border: 1px solid grey;\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n <ng-container matColumnDef=\"spiffe\">\n <th mat-header-cell *matHeaderCellDef> Spiffe </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.spiffe}} </td>\n </ng-container>\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.first_name}} {{element.last_name}}</td>\n </ng-container>\n <ng-container matColumnDef=\"email\">\n <th mat-header-cell *matHeaderCellDef> Email </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.email}} </td>\n </ng-container>\n <tr mat-header-row *matHeaderRowDef=\"['id', 'spiffe', 'name', 'email']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['id', 'spiffe', 'name', 'email'];\"></tr>\n </table>\n <div style=\"border: 1px solid grey; padding: .5rem; border-top: none;\">\n <h3 style=\"margin: 0;\">Total Records {{ data.length }}</h3>\n </div>\n </div>\n } @else {\n <div style=\"margin-top: 1rem; font-style: italic;\">\n No Data Available\n </div>\n }\n\n <div style=\"margin-bottom: 1rem; margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"display: flex; gap: 0.5rem; margin-bottom: 1rem;\">\n <button mat-flat-button color=\"primary\" (click)=\"onTestDirectStateMessage(63, true)\">\n Test UPDATE (Fake Id)\n </button>\n <button mat-stroked-button (click)=\"onTestDirectStateMessage(63, false)\">\n Test UPDATE (Current Id)\n </button>\n <button mat-stroked-button (click)=\"onTestDirectStateMessage(63, false, 'custom-session-123')\">\n Test UPDATE (Custom Id)\n </button>\n </div>\n\n </div>\n}\n\n", styles: [".user-chip--primary{background-color:var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5))!important;color:#fff!important;--mdc-evolution-chip-container-color: var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5));--mdc-evolution-chip-label-text-color: #fff}.user-chip--primary :is(.mdc-evolution-chip__text-label,.mdc-evolution-chip__action,.mdc-evolution-chip__cell,.mat-mdc-chip-action-label){color:#fff!important}.user-chip--primary,.user-chip--primary *{color:#fff!important}:host ::ng-deep .user-chip--primary{background-color:var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5))!important;color:#fff!important;--mdc-evolution-chip-container-color: var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5));--mdc-evolution-chip-label-text-color: #fff}:host ::ng-deep .user-chip--primary .mdc-evolution-chip__text-label,:host ::ng-deep .user-chip--primary .mdc-evolution-chip__action,:host ::ng-deep .user-chip--primary .mdc-evolution-chip__cell,:host ::ng-deep .user-chip--primary .mat-mdc-chip-action-label,:host ::ng-deep .user-chip--primary *{color:#fff!important}.box{padding:.5rem;border:1px solid rgb(174,174,13);background-color:#ececaf}\n"], dependencies: [{ 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: i3$1.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i3$1.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
|
|
12006
12063
|
}
|
|
12007
12064
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsDataControlComponent, decorators: [{
|
|
12008
12065
|
type: Component,
|
|
12009
|
-
args: [{ selector: 'app-ws-data-control', standalone: false, template: "@if ((data$ | async); as data) {\n <div style=\"margin: 1rem;\">\n @if ((users$ |async); as users) {\n <div>\n @if (users.length > 0) {\n <h3 style=\"margin: 0;\">Connected Users</h3>\n } @else {\n <h3 style=\"margin: 0;\">No Users</h3>\n }\n <mat-chip-set>\n @for (user of users; track $index) {\n <mat-chip\n [class.user-chip--primary]=\"isUser(user, (user$ | async))\"\n [style.color]=\"isUser(user, (user$ | async)) ? '#fff' : null\"\n [disableRipple]=\"true\"\n >\n {{ user
|
|
12066
|
+
args: [{ selector: 'app-ws-data-control', standalone: false, template: "@if ((data$ | async); as data) {\n <div style=\"margin: 1rem;\">\n @if ((users$ |async); as users) {\n <div>\n @if (users.length > 0) {\n <h3 style=\"margin: 0;\">Connected Users</h3>\n } @else {\n <h3 style=\"margin: 0;\">No Users</h3>\n }\n <mat-chip-set>\n @for (user of users; track $index) {\n <mat-chip\n [class.user-chip--primary]=\"isUser(user, (user$ | async))\"\n [style.color]=\"isUser(user, (user$ | async)) ? '#fff' : null\"\n [disableRipple]=\"true\"\n >\n {{ getUserLabel(user) }}\n </mat-chip>\n }\n </mat-chip-set>\n </div>\n }\n <div style=\"margin-top: 1rem; margin-bottom: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div class=\"box\" style=\"margin-bottom: 1rem;\" *ngIf=\"(userAction$ | async) as userAction\">\n {{ userAction?.content?.user?.name }} has {{ userAction?.content?.method }}\n </div>\n\n <h3 style=\"margin: 0;\">Data Actions</h3>\n <div style=\"display: flex; gap: 1rem; margin-bottom: 1rem;\">\n <button mat-stroked-button (click)=\"onGetData()\">Get Data</button>\n <div style=\"flex:1\"></div>\n <button mat-stroked-button color=\"accent\" (click)=\"onUpdateData(data)\">Update Data</button>\n <button mat-stroked-button color=\"warn\" (click)=\"onRemoveData(data)\">Remove Data</button>\n <button mat-stroked-button color=\"primary\" (click)=\"onAddData()\">Add Data</button>\n </div>\n\n <h3 style=\"margin: 0; margin-top: 1rem;\">WebSocketMessageService Test</h3>\n\n <p style=\"font-size: 0.875rem; color: #666; margin: 0;\">\n <strong>Note:</strong> \"Fake SessionId\" will be received and processed. \"Current SessionId\" will be filtered out (self-message).\n @if (data.length > 0) {\n <div>\n <table mat-table [dataSource]=\"data\" style=\"border: 1px solid grey;\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n <ng-container matColumnDef=\"spiffe\">\n <th mat-header-cell *matHeaderCellDef> Spiffe </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.spiffe}} </td>\n </ng-container>\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.first_name}} {{element.last_name}}</td>\n </ng-container>\n <ng-container matColumnDef=\"email\">\n <th mat-header-cell *matHeaderCellDef> Email </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.email}} </td>\n </ng-container>\n <tr mat-header-row *matHeaderRowDef=\"['id', 'spiffe', 'name', 'email']\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['id', 'spiffe', 'name', 'email'];\"></tr>\n </table>\n <div style=\"border: 1px solid grey; padding: .5rem; border-top: none;\">\n <h3 style=\"margin: 0;\">Total Records {{ data.length }}</h3>\n </div>\n </div>\n } @else {\n <div style=\"margin-top: 1rem; font-style: italic;\">\n No Data Available\n </div>\n }\n\n <div style=\"margin-bottom: 1rem; margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"display: flex; gap: 0.5rem; margin-bottom: 1rem;\">\n <button mat-flat-button color=\"primary\" (click)=\"onTestDirectStateMessage(63, true)\">\n Test UPDATE (Fake Id)\n </button>\n <button mat-stroked-button (click)=\"onTestDirectStateMessage(63, false)\">\n Test UPDATE (Current Id)\n </button>\n <button mat-stroked-button (click)=\"onTestDirectStateMessage(63, false, 'custom-session-123')\">\n Test UPDATE (Custom Id)\n </button>\n </div>\n\n </div>\n}\n\n", styles: [".user-chip--primary{background-color:var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5))!important;color:#fff!important;--mdc-evolution-chip-container-color: var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5));--mdc-evolution-chip-label-text-color: #fff}.user-chip--primary :is(.mdc-evolution-chip__text-label,.mdc-evolution-chip__action,.mdc-evolution-chip__cell,.mat-mdc-chip-action-label){color:#fff!important}.user-chip--primary,.user-chip--primary *{color:#fff!important}:host ::ng-deep .user-chip--primary{background-color:var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5))!important;color:#fff!important;--mdc-evolution-chip-container-color: var(--mdc-theme-primary, var(--md-sys-color-primary, #3f51b5));--mdc-evolution-chip-label-text-color: #fff}:host ::ng-deep .user-chip--primary .mdc-evolution-chip__text-label,:host ::ng-deep .user-chip--primary .mdc-evolution-chip__action,:host ::ng-deep .user-chip--primary .mdc-evolution-chip__cell,:host ::ng-deep .user-chip--primary .mat-mdc-chip-action-label,:host ::ng-deep .user-chip--primary *{color:#fff!important}.box{padding:.5rem;border:1px solid rgb(174,174,13);background-color:#ececaf}\n"] }]
|
|
12010
12067
|
}], propDecorators: { server: [{
|
|
12011
12068
|
type: Input
|
|
12012
12069
|
}], wsServer: [{
|
|
@@ -12419,6 +12476,7 @@ class RequestManagerWsDemoComponent {
|
|
|
12419
12476
|
this.retryCount$ = this.stateService.wsRetryCount$;
|
|
12420
12477
|
this.maxRetries$ = this.stateService.wsMaxRetries$;
|
|
12421
12478
|
this.connectionStatus$ = this.stateService.connectionStatus$;
|
|
12479
|
+
this.isConnecting$ = this.stateService.isConnecting$;
|
|
12422
12480
|
this.connectionError$ = this.stateService.connectionError$;
|
|
12423
12481
|
this.data$ = this.stateService.data$;
|
|
12424
12482
|
this.isPending$ = this.stateService.isPending$;
|
|
@@ -12426,12 +12484,17 @@ class RequestManagerWsDemoComponent {
|
|
|
12426
12484
|
ngOnInit() {
|
|
12427
12485
|
this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
12428
12486
|
}
|
|
12487
|
+
ngOnChanges(changes) {
|
|
12488
|
+
if (changes['jwtToken'] && !changes['jwtToken'].firstChange) {
|
|
12489
|
+
this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
12490
|
+
}
|
|
12491
|
+
}
|
|
12429
12492
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12430
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">
|
|
12493
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, usesOnChanges: true, ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else if (connectionError$ | async) {\n <span style=\"color: red;\">{{ connectionError$ | async }}</span>\n } @else if (isConnecting$ | async) {\n <span style=\"color: orange;\">Connecting... {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n } @else {\n <span style=\"color: red;\">Disconnected</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if ((isConnecting$ | async) && !(connectionStatus$ | async) && !(connectionError$ | async)) {\n <div style=\"display: flex; align-items: center; gap: 1rem; padding: 0.5rem; background: #e3f2fd; border-radius: 4px; margin-bottom: 0.5rem;\">\n <span>Connecting to WebSocket...</span>\n <mat-progress-bar mode=\"indeterminate\" style=\"flex: 1;\"></mat-progress-bar>\n </div>\n }\n\n @if (connectionError$ | async; as errorMsg) {\n <div style=\"padding: 0.75rem 1rem; background: #fdecea; color: #b00020; border-left: 4px solid #b00020; border-radius: 2px; margin-bottom: 0.5rem;\">\n {{ errorMsg }}\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n", styles: [""], dependencies: [{ kind: "component", type: i1$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i1$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: i8$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i3$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: WsDataControlComponent, selector: "app-ws-data-control", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsNotificationsComponent, selector: "app-ws-notifications", inputs: ["server", "wsServer", "jwtToken", "user"] }, { kind: "component", type: WsAiMessagingComponent, selector: "app-ws-ai-messaging" }, { kind: "component", type: WsChatsComponent, selector: "app-ws-chats" }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
|
|
12431
12494
|
}
|
|
12432
12495
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
|
|
12433
12496
|
type: Component,
|
|
12434
|
-
args: [{ selector: 'app-request-manager-ws-demo', standalone: false, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">
|
|
12497
|
+
args: [{ selector: 'app-request-manager-ws-demo', standalone: false, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else if (connectionError$ | async) {\n <span style=\"color: red;\">{{ connectionError$ | async }}</span>\n } @else if (isConnecting$ | async) {\n <span style=\"color: orange;\">Connecting... {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n } @else {\n <span style=\"color: red;\">Disconnected</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if ((isConnecting$ | async) && !(connectionStatus$ | async) && !(connectionError$ | async)) {\n <div style=\"display: flex; align-items: center; gap: 1rem; padding: 0.5rem; background: #e3f2fd; border-radius: 4px; margin-bottom: 0.5rem;\">\n <span>Connecting to WebSocket...</span>\n <mat-progress-bar mode=\"indeterminate\" style=\"flex: 1;\"></mat-progress-bar>\n </div>\n }\n\n @if (connectionError$ | async; as errorMsg) {\n <div style=\"padding: 0.75rem 1rem; background: #fdecea; color: #b00020; border-left: 4px solid #b00020; border-radius: 2px; margin-bottom: 0.5rem;\">\n {{ errorMsg }}\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n" }]
|
|
12435
12498
|
}], propDecorators: { server: [{
|
|
12436
12499
|
type: Input
|
|
12437
12500
|
}], wsServer: [{
|