http-request-manager 18.16.3 → 18.16.4

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.
@@ -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.isConnecting = false; }
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.isConnecting) {
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
- // Mark as connecting connectionStatus true while connecting/retrying, false only when exhausted
1987
- WebSocketManagerService.isConnecting = true;
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
- WebSocketManagerService.connectionStatus.next(true);
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.isConnecting = false;
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.isConnecting = false;
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 (WebSocketManagerService.lastOptions && WebSocketManagerService.retryCount < maxRetries) {
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.isConnecting = false;
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$;
@@ -12419,6 +12440,7 @@ class RequestManagerWsDemoComponent {
12419
12440
  this.retryCount$ = this.stateService.wsRetryCount$;
12420
12441
  this.maxRetries$ = this.stateService.wsMaxRetries$;
12421
12442
  this.connectionStatus$ = this.stateService.connectionStatus$;
12443
+ this.isConnecting$ = this.stateService.isConnecting$;
12422
12444
  this.connectionError$ = this.stateService.connectionError$;
12423
12445
  this.data$ = this.stateService.data$;
12424
12446
  this.isPending$ = this.stateService.isPending$;
@@ -12427,11 +12449,11 @@ class RequestManagerWsDemoComponent {
12427
12449
  this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
12428
12450
  }
12429
12451
  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;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</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 (!(connectionStatus$ | async) && !(connectionError$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></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" }] }); }
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" }] }); }
12431
12453
  }
12432
12454
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
12433
12455
  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;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</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 (!(connectionStatus$ | async) && !(connectionError$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></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" }]
12456
+ 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
12457
  }], propDecorators: { server: [{
12436
12458
  type: Input
12437
12459
  }], wsServer: [{