http-request-manager 18.16.4 → 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) |
|
|
@@ -7240,7 +7240,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7240
7240
|
this.createRecord = (data, options) => this.effect(() => of(data).pipe(switchMap((data) => {
|
|
7241
7241
|
this.streamedResponse = [];
|
|
7242
7242
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7243
|
-
|
|
7243
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7244
|
+
return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
|
|
7244
7245
|
.pipe(tap((data) => {
|
|
7245
7246
|
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
7246
7247
|
this.addData$(data);
|
|
@@ -7258,7 +7259,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7258
7259
|
this.updateRecord = (data, options) => this.effect(() => of(data).pipe(concatMap((data) => {
|
|
7259
7260
|
this.streamedResponse = [];
|
|
7260
7261
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7261
|
-
|
|
7262
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7263
|
+
return this.httpManagerService.putRequest(data, requestOptions, effectiveParams)
|
|
7262
7264
|
.pipe(tap((data) => {
|
|
7263
7265
|
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
7264
7266
|
this.updateData$(data);
|
|
@@ -7276,7 +7278,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7276
7278
|
this.deleteRecord = (options) => this.effect(() => of(options).pipe(concatMap((data) => {
|
|
7277
7279
|
this.streamedResponse = [];
|
|
7278
7280
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7279
|
-
|
|
7281
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7282
|
+
return this.httpManagerService.deleteRequest(requestOptions, effectiveParams)
|
|
7280
7283
|
.pipe(tap((data) => {
|
|
7281
7284
|
data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
|
|
7282
7285
|
this.deleteData$(data);
|
|
@@ -7294,7 +7297,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7294
7297
|
// FETCH STREAM
|
|
7295
7298
|
this.createStream = (data, options) => this.effect(() => of(data).pipe(tap(() => this.httpManagerService.isPending.next(true)), switchMap((data) => {
|
|
7296
7299
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7297
|
-
|
|
7300
|
+
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7301
|
+
return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
|
|
7298
7302
|
.pipe(tap((res) => {
|
|
7299
7303
|
if (res.length > 0)
|
|
7300
7304
|
this.setData$(res);
|
|
@@ -8091,12 +8095,9 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8091
8095
|
const effective = this.getEffectiveParams(params);
|
|
8092
8096
|
return effective ? [...basePath, ...effective] : [...basePath];
|
|
8093
8097
|
}
|
|
8094
|
-
|
|
8095
|
-
if (!Array.isArray(params) || params.length === 0) {
|
|
8096
|
-
return undefined;
|
|
8097
|
-
}
|
|
8098
|
+
stripBasePathPrefix(params) {
|
|
8098
8099
|
const basePath = Array.isArray(this.apiOptions.path) ? this.apiOptions.path : [];
|
|
8099
|
-
if (basePath.length
|
|
8100
|
+
if (basePath.length === 0 || params.length < basePath.length) {
|
|
8100
8101
|
return params;
|
|
8101
8102
|
}
|
|
8102
8103
|
const normalizePart = (value) => {
|
|
@@ -8105,8 +8106,25 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8105
8106
|
}
|
|
8106
8107
|
return String(value);
|
|
8107
8108
|
};
|
|
8108
|
-
const
|
|
8109
|
-
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);
|
|
8110
8128
|
}
|
|
8111
8129
|
buildRequestSignature(method, requestOptions, params) {
|
|
8112
8130
|
const signaturePayload = {
|
|
@@ -8714,10 +8732,11 @@ class SqlParser {
|
|
|
8714
8732
|
if (ast.type !== 'select') {
|
|
8715
8733
|
throw new SqlParseError('Only SELECT statements are supported');
|
|
8716
8734
|
}
|
|
8735
|
+
const stripPrefix = (list) => list.map(entry => entry.split('::').pop() ?? entry);
|
|
8717
8736
|
return {
|
|
8718
8737
|
ast,
|
|
8719
|
-
tableList: result.tableList ?? [],
|
|
8720
|
-
columnList: result.columnList ?? [],
|
|
8738
|
+
tableList: stripPrefix(result.tableList ?? []),
|
|
8739
|
+
columnList: stripPrefix(result.columnList ?? []),
|
|
8721
8740
|
};
|
|
8722
8741
|
}
|
|
8723
8742
|
}
|
|
@@ -8988,7 +9007,9 @@ class QueryPlanner {
|
|
|
8988
9007
|
const where = ast.where;
|
|
8989
9008
|
const boundedFilters = [];
|
|
8990
9009
|
if (where) {
|
|
8991
|
-
this._flattenAnd(where.operator === 'AND'
|
|
9010
|
+
this._flattenAnd(where.operator === 'AND'
|
|
9011
|
+
? where
|
|
9012
|
+
: { type: 'binary_expr', operator: 'AND', left: where, right: null })
|
|
8992
9013
|
.filter(Boolean)
|
|
8993
9014
|
.forEach((c) => boundedFilters.push(this._nodeToStep(c, aliases, mainTable)));
|
|
8994
9015
|
}
|
|
@@ -9021,6 +9042,7 @@ class QueryPlanner {
|
|
|
9021
9042
|
}
|
|
9022
9043
|
else if (vals.length === 1) {
|
|
9023
9044
|
plan.limit = vals[0].value;
|
|
9045
|
+
plan.offset = null;
|
|
9024
9046
|
}
|
|
9025
9047
|
}
|
|
9026
9048
|
// Projection
|
|
@@ -11936,13 +11958,24 @@ class WsDataControlComponent {
|
|
|
11936
11958
|
.pipe(switchMap$1((action) => timer(3 * 1000).pipe(map$1(() => null), startWith$1(action))));
|
|
11937
11959
|
this.data$ = this.stateDataRequestService.data$;
|
|
11938
11960
|
this.isUser = (user, userItem) => {
|
|
11939
|
-
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;
|
|
11940
11967
|
};
|
|
11941
11968
|
}
|
|
11942
11969
|
ngOnInit() {
|
|
11943
11970
|
this.stateDataRequestService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
11944
11971
|
this.stateDataRequestService.getData();
|
|
11945
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
|
+
}
|
|
11946
11979
|
onGetData() {
|
|
11947
11980
|
this.stateDataRequestService.getData();
|
|
11948
11981
|
}
|
|
@@ -11951,12 +11984,15 @@ class WsDataControlComponent {
|
|
|
11951
11984
|
}
|
|
11952
11985
|
onUpdateData(data) {
|
|
11953
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';
|
|
11954
11990
|
const newData = {
|
|
11955
11991
|
"spiffe": `wavecoders.com/developer/${num}`,
|
|
11956
11992
|
"id": 63,
|
|
11957
|
-
"last_name":
|
|
11958
|
-
"email":
|
|
11959
|
-
"first_name":
|
|
11993
|
+
"last_name": lastName,
|
|
11994
|
+
"email": email,
|
|
11995
|
+
"first_name": firstName
|
|
11960
11996
|
};
|
|
11961
11997
|
this.stateDataRequestService.updateData(newData);
|
|
11962
11998
|
}
|
|
@@ -12023,11 +12059,11 @@ class WsDataControlComponent {
|
|
|
12023
12059
|
});
|
|
12024
12060
|
}
|
|
12025
12061
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsDataControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12026
|
-
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" }] }); }
|
|
12027
12063
|
}
|
|
12028
12064
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsDataControlComponent, decorators: [{
|
|
12029
12065
|
type: Component,
|
|
12030
|
-
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"] }]
|
|
12031
12067
|
}], propDecorators: { server: [{
|
|
12032
12068
|
type: Input
|
|
12033
12069
|
}], wsServer: [{
|
|
@@ -12448,8 +12484,13 @@ class RequestManagerWsDemoComponent {
|
|
|
12448
12484
|
ngOnInit() {
|
|
12449
12485
|
this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
12450
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
|
+
}
|
|
12451
12492
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12452
|
-
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 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" }] }); }
|
|
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" }] }); }
|
|
12453
12494
|
}
|
|
12454
12495
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
|
|
12455
12496
|
type: Component,
|