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
- | **🗄️ SQL on IndexedDB** | MySQL-syntax SQL queries against DexieJS IndexedDB | [`DexieSqlService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/SQL_DIXIE_README.md) | Uses the same service |
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
- ### 🚀 Advanced Features
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
- | **🗄️ SQL on IndexedDB** | MySQL-syntax SELECT queries against DexieJSfilters, joins, ORDER BY, LIMIT, COUNT | [`DexieSqlService`](https://github.com/micheleboni/npm-angular/tree/main/projects/http-request-manager/src/docs/SQL_DIXIE_README.md) |
61
+ | **🗄️ Database Queries** | MySQL-syntax SQL queries on IndexedDBthe 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
- return this.httpManagerService.postRequest(data, requestOptions, options?.path)
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
- return this.httpManagerService.putRequest(data, requestOptions, options?.path)
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
- return this.httpManagerService.deleteRequest(requestOptions, options?.path)
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
- return this.httpManagerService.postRequest(data, requestOptions, options?.path)
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
- getEffectiveParams(params) {
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 !== params.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 samePath = params.every((part, index) => normalizePart(part) === normalizePart(basePath[index]));
8109
- return samePath ? undefined : params;
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' ? where : { operator: 'AND', left: where, right: null })
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.sessionId === userItem.sessionId;
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": "boni",
11958
- "email": "mikeboni@hotmail.com",
11959
- "first_name": "mike"
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.name || user.ldap || user.id || 'Anonymous' }}\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" }] }); }
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.name || user.ldap || user.id || 'Anonymous' }}\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"] }]
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,