http-request-manager 18.5.19 → 18.5.20
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.
|
@@ -4,7 +4,7 @@ import { ComponentStore } from '@ngrx/component-store';
|
|
|
4
4
|
import { map, catchError, filter, finalize, takeWhile, retry, startWith, tap, mergeMap, takeUntil, withLatestFrom, switchMap, delay, concatMap, take, scan, distinctUntilChanged } from 'rxjs/operators';
|
|
5
5
|
import { HttpClient, HttpHeaders, HttpEventType, HttpHeaderResponse, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
6
6
|
import * as CryptoJS from 'crypto-js';
|
|
7
|
-
import { from, BehaviorSubject, EMPTY, throwError, defer, interval, timer, Subject, merge, of, Subscription, take as take$1, catchError as catchError$1, switchMap as switchMap$1, map as map$1, startWith as startWith$1, combineLatest, tap as tap$1, ReplaySubject } from 'rxjs';
|
|
7
|
+
import { from, BehaviorSubject, EMPTY, throwError, defer, interval, timer, Subject, merge, of, Subscription, take as take$1, catchError as catchError$1, switchMap as switchMap$1, map as map$1, startWith as startWith$1, combineLatest, filter as filter$1, takeUntil as takeUntil$1, tap as tap$1, ReplaySubject } from 'rxjs';
|
|
8
8
|
import { ToastMessageDisplayService, ToastDisplay, ToastColors, ToastMessageDisplayModule } from 'toast-message-display';
|
|
9
9
|
import Dexie from 'dexie';
|
|
10
10
|
import * as i1 from '@ngx-translate/core';
|
|
@@ -736,12 +736,23 @@ class ChannelInfo {
|
|
|
736
736
|
}
|
|
737
737
|
|
|
738
738
|
class WSUser {
|
|
739
|
-
constructor(sessionId,
|
|
739
|
+
constructor(sessionId = '', ldap = '', name = '', email = '') {
|
|
740
740
|
this.sessionId = sessionId;
|
|
741
|
-
this.
|
|
741
|
+
this.ldap = ldap;
|
|
742
|
+
this.name = name;
|
|
743
|
+
this.email = email;
|
|
742
744
|
}
|
|
743
745
|
static adapt(item) {
|
|
744
|
-
|
|
746
|
+
const user = new WSUser(item?.sessionId, item?.ldap, item?.name, item?.email);
|
|
747
|
+
// Copy any additional properties
|
|
748
|
+
if (item) {
|
|
749
|
+
Object.keys(item).forEach(key => {
|
|
750
|
+
if (!['sessionId', 'ldap', 'name', 'email'].includes(key)) {
|
|
751
|
+
user[key] = item[key];
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
return user;
|
|
745
756
|
}
|
|
746
757
|
}
|
|
747
758
|
|
|
@@ -760,6 +771,11 @@ class WebsocketService {
|
|
|
760
771
|
this.connectionStatus = new BehaviorSubject(false);
|
|
761
772
|
this.connectionStatus$ = this.connectionStatus.asObservable();
|
|
762
773
|
this.isSubscribed = false;
|
|
774
|
+
// Track currently subscribed channels
|
|
775
|
+
this.subscribedChannels = new BehaviorSubject(new Set());
|
|
776
|
+
this.subscribedChannels$ = this.subscribedChannels.asObservable();
|
|
777
|
+
// Store last options for reconnection
|
|
778
|
+
this.lastOptions = null;
|
|
763
779
|
}
|
|
764
780
|
getSessionId() {
|
|
765
781
|
return sessionStorage.getItem('WSID') ?? (() => {
|
|
@@ -806,7 +822,26 @@ class WebsocketService {
|
|
|
806
822
|
this.socket.onopen = () => {
|
|
807
823
|
console.log(`📡 Connected to WebSocket`);
|
|
808
824
|
this.connectionStatus.next(true);
|
|
825
|
+
this.lastOptions = options;
|
|
826
|
+
// Subscribe to primary channel
|
|
809
827
|
this.sendSubscribe(options.id, options.user);
|
|
828
|
+
// Auto-subscribe to additional channels from options.channels[]
|
|
829
|
+
if (options.channels && options.channels.length > 0) {
|
|
830
|
+
options.channels.forEach(channel => {
|
|
831
|
+
if (channel !== options.id) {
|
|
832
|
+
this.subscribeToChannel(channel);
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
// Re-subscribe to any previously subscribed channels (reconnection scenario)
|
|
837
|
+
const previousChannels = this.subscribedChannels.value;
|
|
838
|
+
if (previousChannels.size > 0) {
|
|
839
|
+
previousChannels.forEach(channel => {
|
|
840
|
+
if (channel !== options.id && (!options.channels || !options.channels.includes(channel))) {
|
|
841
|
+
this.subscribeToChannel(channel);
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
}
|
|
810
845
|
};
|
|
811
846
|
this.socket.onmessage = (event) => {
|
|
812
847
|
try {
|
|
@@ -848,20 +883,44 @@ class WebsocketService {
|
|
|
848
883
|
content: {}
|
|
849
884
|
};
|
|
850
885
|
this.socket.send(JSON.stringify(message));
|
|
886
|
+
// Track locally
|
|
887
|
+
const current = this.subscribedChannels.value;
|
|
888
|
+
current.add(channelName);
|
|
889
|
+
this.subscribedChannels.next(current);
|
|
890
|
+
console.log(`📝 Subscribed to channel: ${channelName}`);
|
|
851
891
|
}
|
|
852
892
|
else {
|
|
853
893
|
console.warn('Cannot subscribe: WebSocket not yet open.');
|
|
854
894
|
}
|
|
855
895
|
}
|
|
856
|
-
|
|
896
|
+
subscribeToChannels(channelNames) {
|
|
897
|
+
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
898
|
+
channelNames.forEach(channel => this.subscribeToChannel(channel));
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
console.warn('Cannot subscribe: WebSocket not yet open.');
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
unsubscribeFromChannel(channel) {
|
|
857
905
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
858
906
|
this.socket.send(JSON.stringify({ type: 'unsubscribe', subscribedChannel: channel }));
|
|
859
|
-
|
|
907
|
+
// Remove from local tracking
|
|
908
|
+
const current = this.subscribedChannels.value;
|
|
909
|
+
current.delete(channel);
|
|
910
|
+
this.subscribedChannels.next(current);
|
|
911
|
+
console.log(`💬 Unsubscribed from channel: ${channel}`);
|
|
860
912
|
}
|
|
861
913
|
else {
|
|
862
|
-
console.error('WebSocket is not open. Cannot
|
|
914
|
+
console.error('WebSocket is not open. Cannot unsubscribe from channel.');
|
|
863
915
|
}
|
|
864
916
|
}
|
|
917
|
+
unsubscribeToChannel(channel) {
|
|
918
|
+
// Deprecated: Use unsubscribeFromChannel instead
|
|
919
|
+
this.unsubscribeFromChannel(channel);
|
|
920
|
+
}
|
|
921
|
+
getSubscribedChannels() {
|
|
922
|
+
return this.subscribedChannels.value;
|
|
923
|
+
}
|
|
865
924
|
sendBroadcast(content) {
|
|
866
925
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
867
926
|
this.socket.send(JSON.stringify({ type: 'broadcast', content }));
|
|
@@ -880,6 +939,19 @@ class WebsocketService {
|
|
|
880
939
|
console.error('WebSocket is not open. Cannot send message.');
|
|
881
940
|
}
|
|
882
941
|
}
|
|
942
|
+
/**
|
|
943
|
+
* Send a message to a specific channel for channel-based messaging
|
|
944
|
+
* This uses the 'message' type which broadcasts to all subscribers in the channel
|
|
945
|
+
*/
|
|
946
|
+
sendChannelMessage(channel, content) {
|
|
947
|
+
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
948
|
+
this.socket.send(JSON.stringify({ type: 'message', subscribedChannel: channel, content }));
|
|
949
|
+
console.log(`💬 Send channel message to [${channel}]:`, content);
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
console.error('WebSocket is not open. Cannot send channel message.');
|
|
953
|
+
}
|
|
954
|
+
}
|
|
883
955
|
sendMessageToUser(user, content) {
|
|
884
956
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
885
957
|
this.socket.send(JSON.stringify({ type: 'userMessage', subscribedChannel: user, content }));
|
|
@@ -2812,15 +2884,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2812
2884
|
}], ctorParameters: () => [] });
|
|
2813
2885
|
|
|
2814
2886
|
class ChannelMessage {
|
|
2815
|
-
constructor(sessionId = '', content
|
|
2887
|
+
constructor(sessionId = '', content = null) {
|
|
2816
2888
|
this.sessionId = sessionId;
|
|
2817
2889
|
this.content = content;
|
|
2818
|
-
this.message = message;
|
|
2819
|
-
this.users = users;
|
|
2820
|
-
this.issued = issued;
|
|
2821
2890
|
}
|
|
2822
2891
|
static adapt(item) {
|
|
2823
|
-
return new ChannelMessage(item?.sessionId, item?.content
|
|
2892
|
+
return new ChannelMessage(item?.sessionId, item?.content);
|
|
2824
2893
|
}
|
|
2825
2894
|
}
|
|
2826
2895
|
|
|
@@ -2906,6 +2975,16 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
2906
2975
|
// }
|
|
2907
2976
|
this.channels.next(message.channels);
|
|
2908
2977
|
break;
|
|
2978
|
+
case 'subscribed':
|
|
2979
|
+
console.log(`✅ Subscription confirmed: ${message.channel}`);
|
|
2980
|
+
break;
|
|
2981
|
+
case 'unsubscribed':
|
|
2982
|
+
console.log(`🔓 Unsubscription confirmed: ${message.channel}`);
|
|
2983
|
+
break;
|
|
2984
|
+
case 'info':
|
|
2985
|
+
// Already subscribed or other info messages
|
|
2986
|
+
console.log(`ℹ️ Info: ${message.message}`);
|
|
2987
|
+
break;
|
|
2909
2988
|
case 'stateMangerMessage':
|
|
2910
2989
|
;
|
|
2911
2990
|
if (message.data.sessionId !== this.user.value?.sessionId) {
|
|
@@ -2914,17 +2993,22 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
2914
2993
|
this.fetchRecord(RequestOptions.adapt({ path: message.data.content.path }), message.data.content.method);
|
|
2915
2994
|
}
|
|
2916
2995
|
break;
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2996
|
+
case 'channelMessage':
|
|
2997
|
+
// Handle channel-based messages (from sendChannelMessage)
|
|
2998
|
+
// Structure: { type: 'channelMessage', channel, data: { sessionId, content: ChannelMessage } }
|
|
2999
|
+
// Skip messages from self
|
|
3000
|
+
const senderSessionId = message.data?.content?.sessionId?.sessionId || message.data?.sessionId;
|
|
3001
|
+
if (senderSessionId === this.user.value?.sessionId) {
|
|
3002
|
+
break;
|
|
3003
|
+
}
|
|
3004
|
+
console.log('💬 Channel Message received:', message);
|
|
3005
|
+
if (message.data?.content) {
|
|
3006
|
+
this.appendMessages(ChannelMessage.adapt({
|
|
3007
|
+
sessionId: message.data.content.sessionId,
|
|
3008
|
+
content: message.data.content.content,
|
|
3009
|
+
}));
|
|
3010
|
+
}
|
|
3011
|
+
break;
|
|
2928
3012
|
case 'usersInChannel':
|
|
2929
3013
|
console.log('👥 Users:', message.data.users);
|
|
2930
3014
|
this.userList.next(message.data.users);
|
|
@@ -3404,17 +3488,119 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
3404
3488
|
}
|
|
3405
3489
|
}
|
|
3406
3490
|
wsMessaging(message, channels) {
|
|
3407
|
-
const user = this.user.value
|
|
3491
|
+
const user = this.user.value;
|
|
3408
3492
|
const messageInfo = ChannelMessage.adapt({ ...message, fromUser: user });
|
|
3493
|
+
console.log('📤 wsMessaging called with channels:', channels);
|
|
3409
3494
|
if (this.wsConnection && this.apiOptions.ws) {
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3495
|
+
// If specific channels provided, send to each channel
|
|
3496
|
+
if (channels && channels.length > 0) {
|
|
3497
|
+
console.log(`📤 Sending to ${channels.length} channel(s):`, channels);
|
|
3498
|
+
channels.forEach(channel => {
|
|
3499
|
+
if (channel === 'allChannels') {
|
|
3500
|
+
this.httpManagerService.sendBroadcast(messageInfo);
|
|
3501
|
+
}
|
|
3502
|
+
else {
|
|
3503
|
+
this.httpManagerService.sendChannelMessage(channel, messageInfo);
|
|
3504
|
+
}
|
|
3505
|
+
});
|
|
3506
|
+
}
|
|
3507
|
+
else {
|
|
3508
|
+
// Fallback to the primary WS channel
|
|
3509
|
+
const wsChannel = this.apiOptions.ws.id;
|
|
3510
|
+
console.log(`📤 Sending to fallback channel:`, wsChannel);
|
|
3511
|
+
this.httpManagerService.sendChannelMessage(wsChannel, messageInfo);
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
// --------------------------------------------------------------------------------------------------
|
|
3516
|
+
// CHANNEL MANAGEMENT
|
|
3517
|
+
/**
|
|
3518
|
+
* Subscribe to a single channel
|
|
3519
|
+
*/
|
|
3520
|
+
subscribeToChannel(channel) {
|
|
3521
|
+
if (this.wsConnection) {
|
|
3522
|
+
this.httpManagerService.subscribeToChannel(channel);
|
|
3523
|
+
}
|
|
3524
|
+
else {
|
|
3525
|
+
console.warn('Cannot subscribe: WebSocket not connected.');
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
/**
|
|
3529
|
+
* Subscribe to multiple channels at once
|
|
3530
|
+
*/
|
|
3531
|
+
subscribeToChannels(channels) {
|
|
3532
|
+
if (this.wsConnection) {
|
|
3533
|
+
this.httpManagerService.subscribeToChannels(channels);
|
|
3534
|
+
}
|
|
3535
|
+
else {
|
|
3536
|
+
console.warn('Cannot subscribe: WebSocket not connected.');
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
/**
|
|
3540
|
+
* Unsubscribe from a channel
|
|
3541
|
+
*/
|
|
3542
|
+
unsubscribeFromChannel(channel) {
|
|
3543
|
+
if (this.wsConnection) {
|
|
3544
|
+
this.httpManagerService.unsubscribeFromChannel(channel);
|
|
3545
|
+
}
|
|
3546
|
+
else {
|
|
3547
|
+
console.warn('Cannot unsubscribe: WebSocket not connected.');
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
/**
|
|
3551
|
+
* Get observable of currently subscribed channels
|
|
3552
|
+
*/
|
|
3553
|
+
get subscribedChannels$() {
|
|
3554
|
+
return this.httpManagerService.subscribedChannels$;
|
|
3555
|
+
}
|
|
3556
|
+
/**
|
|
3557
|
+
* Get current subscribed channels synchronously
|
|
3558
|
+
*/
|
|
3559
|
+
getSubscribedChannels() {
|
|
3560
|
+
return this.httpManagerService.getSubscribedChannels();
|
|
3561
|
+
}
|
|
3562
|
+
/**
|
|
3563
|
+
* Create a new channel on the server
|
|
3564
|
+
*/
|
|
3565
|
+
createChannel(channel) {
|
|
3566
|
+
if (this.wsConnection) {
|
|
3567
|
+
this.httpManagerService.createChannel(channel);
|
|
3568
|
+
}
|
|
3569
|
+
else {
|
|
3570
|
+
console.warn('Cannot create channel: WebSocket not connected.');
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
/**
|
|
3574
|
+
* Delete a channel from the server
|
|
3575
|
+
*/
|
|
3576
|
+
deleteChannel(channel) {
|
|
3577
|
+
if (this.wsConnection) {
|
|
3578
|
+
this.httpManagerService.deleteChannel(channel);
|
|
3579
|
+
}
|
|
3580
|
+
else {
|
|
3581
|
+
console.warn('Cannot delete channel: WebSocket not connected.');
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
/**
|
|
3585
|
+
* Request list of all channels from server
|
|
3586
|
+
*/
|
|
3587
|
+
getAllChannels() {
|
|
3588
|
+
if (this.wsConnection) {
|
|
3589
|
+
this.httpManagerService.getAllChannels();
|
|
3590
|
+
}
|
|
3591
|
+
else {
|
|
3592
|
+
console.warn('Cannot get channels: WebSocket not connected.');
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
/**
|
|
3596
|
+
* Get users in a specific channel
|
|
3597
|
+
*/
|
|
3598
|
+
getUsersInChannel(channel) {
|
|
3599
|
+
if (this.wsConnection) {
|
|
3600
|
+
this.httpManagerService.getUsersInChannel(channel);
|
|
3601
|
+
}
|
|
3602
|
+
else {
|
|
3603
|
+
console.warn('Cannot get users: WebSocket not connected.');
|
|
3418
3604
|
}
|
|
3419
3605
|
}
|
|
3420
3606
|
// --------------------------------------------------------------------------------------------------
|
|
@@ -4109,10 +4295,9 @@ class StateRequestServiceDemo extends HTTPManagerStateService {
|
|
|
4109
4295
|
console.log('User Action:', user);
|
|
4110
4296
|
});
|
|
4111
4297
|
}
|
|
4112
|
-
sendMessage(data) {
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
this.wsMessaging(data);
|
|
4298
|
+
sendMessage(data, channels) {
|
|
4299
|
+
console.log('sendMessage', data, 'to channels:', channels);
|
|
4300
|
+
this.wsMessaging(data, channels);
|
|
4116
4301
|
}
|
|
4117
4302
|
getAllChannels() {
|
|
4118
4303
|
this.httpManagerService.getAllChannels();
|
|
@@ -4200,7 +4385,6 @@ class StateDataRequestService extends HTTPManagerStateService {
|
|
|
4200
4385
|
this.createRecord(newData, RequestOptions.adapt({ path: this.path }));
|
|
4201
4386
|
}
|
|
4202
4387
|
sendMessage(data) {
|
|
4203
|
-
debugger;
|
|
4204
4388
|
console.log('sendMessage', data);
|
|
4205
4389
|
this.wsMessaging(data);
|
|
4206
4390
|
}
|
|
@@ -4267,11 +4451,11 @@ class WsDataControlComponent {
|
|
|
4267
4451
|
this.stateDataRequestService.deleteData(lastRec);
|
|
4268
4452
|
}
|
|
4269
4453
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsDataControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4270
|
-
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", wsChannel: "wsChannel" }, 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 user) {\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.
|
|
4454
|
+
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", wsChannel: "wsChannel" }, 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 user.sessionId) {\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 }}\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 @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 </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: i2$1.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: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i11.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
|
|
4271
4455
|
}
|
|
4272
4456
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsDataControlComponent, decorators: [{
|
|
4273
4457
|
type: Component,
|
|
4274
|
-
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 user) {\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.
|
|
4458
|
+
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 user.sessionId) {\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 }}\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 @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 </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"] }]
|
|
4275
4459
|
}], propDecorators: { server: [{
|
|
4276
4460
|
type: Input
|
|
4277
4461
|
}], wsServer: [{
|
|
@@ -4286,6 +4470,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4286
4470
|
type: Input
|
|
4287
4471
|
}] } });
|
|
4288
4472
|
|
|
4473
|
+
class WsMessagingComponent {
|
|
4474
|
+
constructor() {
|
|
4475
|
+
this.destroy$ = new Subject();
|
|
4476
|
+
this.fb = inject(FormBuilder);
|
|
4477
|
+
this.stateRequestServiceDemo = inject(StateRequestServiceDemo);
|
|
4478
|
+
// Filter out private stateManager channels (channels starting with "WS-")
|
|
4479
|
+
this.channels$ = this.stateRequestServiceDemo.channels$.pipe(map$1(channels => channels?.filter(channel => !channel.startsWith('WS-')) || []));
|
|
4480
|
+
this.user$ = this.stateRequestServiceDemo.user$;
|
|
4481
|
+
this.data$ = this.stateRequestServiceDemo.data$;
|
|
4482
|
+
this.connectionStatus$ = this.stateRequestServiceDemo.connectionStatus$;
|
|
4483
|
+
this.messages = this.fb.group({
|
|
4484
|
+
channels: this.fb.control(null, Validators.required),
|
|
4485
|
+
content: this.fb.control(null, Validators.required),
|
|
4486
|
+
});
|
|
4487
|
+
this.communicationMessages$ = this.stateRequestServiceDemo.communicationMessages$;
|
|
4488
|
+
this.latestCommunicationMessages$ = this.stateRequestServiceDemo.latestCommunicationMessages$;
|
|
4489
|
+
this.chat$ = combineLatest([this.user$, this.communicationMessages$])
|
|
4490
|
+
.pipe(map$1(([user, messages]) => ({ user, messages })), map$1(obj => {
|
|
4491
|
+
if (!obj.user)
|
|
4492
|
+
return EMPTY;
|
|
4493
|
+
const mainUser = '';
|
|
4494
|
+
const messages = obj.messages.map((item) => {
|
|
4495
|
+
// Message transformation logic
|
|
4496
|
+
});
|
|
4497
|
+
return { user: mainUser, messages };
|
|
4498
|
+
}));
|
|
4499
|
+
}
|
|
4500
|
+
get channels() {
|
|
4501
|
+
return this.messages.get('channels');
|
|
4502
|
+
}
|
|
4503
|
+
get content() {
|
|
4504
|
+
return this.messages.get('content');
|
|
4505
|
+
}
|
|
4506
|
+
get isValid() {
|
|
4507
|
+
return this.channels.valid;
|
|
4508
|
+
}
|
|
4509
|
+
get selectedChannels() {
|
|
4510
|
+
return this.channels.value || [];
|
|
4511
|
+
}
|
|
4512
|
+
ngOnInit() {
|
|
4513
|
+
this.stateRequestServiceDemo.updateConnection(this.server, this.wsServer, this.jwtToken, this.user);
|
|
4514
|
+
// Only trigger once when connection becomes true
|
|
4515
|
+
this.connectionStatus$.pipe(filter$1(status => status === true), take$1(1), takeUntil$1(this.destroy$)).subscribe(() => {
|
|
4516
|
+
// Create a public messaging channel when connected
|
|
4517
|
+
this.stateRequestServiceDemo.createChannel('general');
|
|
4518
|
+
this.stateRequestServiceDemo.getAllChannels();
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4521
|
+
ngOnDestroy() {
|
|
4522
|
+
this.destroy$.next();
|
|
4523
|
+
this.destroy$.complete();
|
|
4524
|
+
}
|
|
4525
|
+
onSendMessage(user) {
|
|
4526
|
+
this.messages.markAllAsTouched();
|
|
4527
|
+
if (this.messages.invalid)
|
|
4528
|
+
return;
|
|
4529
|
+
const selectedChannels = this.channels.value;
|
|
4530
|
+
const message = ChannelMessage.adapt({
|
|
4531
|
+
sessionId: {
|
|
4532
|
+
sessionId: user.sessionId,
|
|
4533
|
+
ldap: user.ldap,
|
|
4534
|
+
name: user.name,
|
|
4535
|
+
email: user.email,
|
|
4536
|
+
},
|
|
4537
|
+
content: { message: this.messages.value.content },
|
|
4538
|
+
});
|
|
4539
|
+
this.stateRequestServiceDemo.sendMessage(message, selectedChannels);
|
|
4540
|
+
this.content.reset();
|
|
4541
|
+
}
|
|
4542
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsMessagingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4543
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user" }, ngImport: i0, template: "\n @if ((data$ | async); as data) {\n @if ((user$ | async); as user) {\n <div style=\"margin: 1rem; display: flex; gap: 1rem; flex-direction: column;\">\n <div>\n\n <div>\n <div style=\"display: flex; gap: 1rem\">\n <div style=\"flex:1\" [formGroup]=\"messages\">\n\n @if ((channels$ | async); as channels) {\n <div style=\"display:flex; gap: 1rem\">\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Channels</mat-label>\n <mat-select formControlName=\"channels\" multiple #channelsSelect>\n <mat-select-trigger>\n {{ (channelsSelect.value?.[0] === 'allChannels' ? 'All Channels' : channelsSelect.value?.[0]) || '' }}\n @if ((channelsSelect.value?.length || 0) > 1) {\n <span>\n (+{{(channelsSelect.value?.length || 0) - 1}} {{channelsSelect.value?.length === 2 ? 'other' : 'others'}})\n </span>\n }\n </mat-select-trigger>\n <mat-option value=\"allChannels\">\n All Channels\n </mat-option>\n @for (channel of channels; track channel) {\n <mat-option [value]=\"channel\">\n {{ channel }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n }\n\n @if (selectedChannels.length > 0) {\n @if ((channels$ | async); as channels) {\n <div style=\"display:flex\">\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Send a Message</mat-label>\n <textarea\n matInput placeholder=\"Type your message...\"\n formControlName=\"content\"\n (keydown.enter)=\"onSendMessage(user); $event.preventDefault()\"\n ></textarea>\n </mat-form-field>\n </div>\n }\n <div style=\"display:flex; gap: .5rem;\">\n <div style=\"flex:1\"></div>\n <button mat-stroked-button (click)=\"onSendMessage(user)\">\n Send Message\n </button>\n </div>\n }\n </div>\n </div>\n @if ((chat$ | async); as chat) {\n <div style=\"border: thin gray solid; padding: 1rem; margin-top: 1rem;\">\n <!-- <app-messenger-chat\n [user]=\"chat.user\"\n [messages]=\"chat.messages\"\n ></app-messenger-chat> -->\n </div>\n }\n </div>\n\n </div>\n </div>\n }\n }\n\n @if ((channels$ | async); as channels) {\n <div style=\"margin: 1rem; padding: 1rem; background: #f5f5f5; border-radius: 4px;\">\n <strong>Available Channels:</strong> {{ channels | json }}\n </div>\n }\n", styles: [""], dependencies: [{ kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "component", type: i4.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "directive", type: i4.MatSelectTrigger, selector: "mat-select-trigger" }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
|
|
4544
|
+
}
|
|
4545
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsMessagingComponent, decorators: [{
|
|
4546
|
+
type: Component,
|
|
4547
|
+
args: [{ selector: 'app-ws-messaging', standalone: false, template: "\n @if ((data$ | async); as data) {\n @if ((user$ | async); as user) {\n <div style=\"margin: 1rem; display: flex; gap: 1rem; flex-direction: column;\">\n <div>\n\n <div>\n <div style=\"display: flex; gap: 1rem\">\n <div style=\"flex:1\" [formGroup]=\"messages\">\n\n @if ((channels$ | async); as channels) {\n <div style=\"display:flex; gap: 1rem\">\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Channels</mat-label>\n <mat-select formControlName=\"channels\" multiple #channelsSelect>\n <mat-select-trigger>\n {{ (channelsSelect.value?.[0] === 'allChannels' ? 'All Channels' : channelsSelect.value?.[0]) || '' }}\n @if ((channelsSelect.value?.length || 0) > 1) {\n <span>\n (+{{(channelsSelect.value?.length || 0) - 1}} {{channelsSelect.value?.length === 2 ? 'other' : 'others'}})\n </span>\n }\n </mat-select-trigger>\n <mat-option value=\"allChannels\">\n All Channels\n </mat-option>\n @for (channel of channels; track channel) {\n <mat-option [value]=\"channel\">\n {{ channel }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n }\n\n @if (selectedChannels.length > 0) {\n @if ((channels$ | async); as channels) {\n <div style=\"display:flex\">\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Send a Message</mat-label>\n <textarea\n matInput placeholder=\"Type your message...\"\n formControlName=\"content\"\n (keydown.enter)=\"onSendMessage(user); $event.preventDefault()\"\n ></textarea>\n </mat-form-field>\n </div>\n }\n <div style=\"display:flex; gap: .5rem;\">\n <div style=\"flex:1\"></div>\n <button mat-stroked-button (click)=\"onSendMessage(user)\">\n Send Message\n </button>\n </div>\n }\n </div>\n </div>\n @if ((chat$ | async); as chat) {\n <div style=\"border: thin gray solid; padding: 1rem; margin-top: 1rem;\">\n <!-- <app-messenger-chat\n [user]=\"chat.user\"\n [messages]=\"chat.messages\"\n ></app-messenger-chat> -->\n </div>\n }\n </div>\n\n </div>\n </div>\n }\n }\n\n @if ((channels$ | async); as channels) {\n <div style=\"margin: 1rem; padding: 1rem; background: #f5f5f5; border-radius: 4px;\">\n <strong>Available Channels:</strong> {{ channels | json }}\n </div>\n }\n" }]
|
|
4548
|
+
}], propDecorators: { server: [{
|
|
4549
|
+
type: Input
|
|
4550
|
+
}], wsServer: [{
|
|
4551
|
+
type: Input
|
|
4552
|
+
}], jwtToken: [{
|
|
4553
|
+
type: Input
|
|
4554
|
+
}], user: [{
|
|
4555
|
+
type: Input
|
|
4556
|
+
}] } });
|
|
4557
|
+
|
|
4289
4558
|
class WsNotificationsComponent {
|
|
4290
4559
|
constructor() { }
|
|
4291
4560
|
ngOnInit() {
|
|
@@ -4385,11 +4654,11 @@ class RequestManagerWsDemoComponent {
|
|
|
4385
4654
|
this.stateRequestServiceDemo.updateConnection(this.server, this.wsServer, this.jwtToken, this.user);
|
|
4386
4655
|
}
|
|
4387
4656
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4388
|
-
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", wsChannel: "wsChannel" }, 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 {{ attempts$ | async }} - {{ nextRetry$ |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.
|
|
4657
|
+
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", wsChannel: "wsChannel" }, 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 {{ attempts$ | async }} - {{ nextRetry$ |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 ((isPending$ | async)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n [wsChannel]=\"wsChannel\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"true\">\n <!-- WS - Custom Messaging -->\n <app-ws-notifications></app-ws-notifications>\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$3.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i1$3.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: i9.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", "wsChannel"] }, { kind: "component", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: ["server", "wsServer", "jwtToken", "user"] }, { kind: "component", type: WsNotificationsComponent, selector: "app-ws-notifications" }, { kind: "component", type: WsAiMessagingComponent, selector: "app-ws-ai-messaging" }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
|
|
4389
4658
|
}
|
|
4390
4659
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
|
|
4391
4660
|
type: Component,
|
|
4392
|
-
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 {{ attempts$ | async }} - {{ nextRetry$ |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.
|
|
4661
|
+
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 {{ attempts$ | async }} - {{ nextRetry$ |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 ((isPending$ | async)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n [wsChannel]=\"wsChannel\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"true\">\n <!-- WS - Custom Messaging -->\n <app-ws-notifications></app-ws-notifications>\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" }]
|
|
4393
4662
|
}], propDecorators: { server: [{
|
|
4394
4663
|
type: Input
|
|
4395
4664
|
}], wsServer: [{
|
|
@@ -4822,117 +5091,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4822
5091
|
args: [{ selector: 'app-store-state-manager-demo', providers: [SettingsStateService], standalone: false, template: "<div style=\"margin: 2rem;\">\n\n <h2>\n <span>Store State Manager</span>\n <span style=\"margin-left: .5rem;\">\n <mat-icon color=\"accent\">fiber_new</mat-icon>\n </span>\n </h2>\n\n {{ dataState$ | async | json}}\n\n <div style=\"display: flex; gap:.5rem; margin-top: 1rem; margin-bottom: 1rem;\">\n <button mat-stroked-button (click)=\"onUpdateEnum_1()\">Update Start</button>\n <button mat-stroked-button (click)=\"onUpdateEnum_2()\">Update End</button>\n <button mat-stroked-button (click)=\"onGetEnum_1()\">Dump</button>\n </div>\n\n <div>\n <h3 style=\"margin: 0;\">Enum 1</h3>\n {{ dataEnum$ | async | json}}\n </div>\n\n</div>\n" }]
|
|
4823
5092
|
}] });
|
|
4824
5093
|
|
|
4825
|
-
class WsMessagingComponent {
|
|
4826
|
-
constructor() {
|
|
4827
|
-
this.fb = inject(FormBuilder);
|
|
4828
|
-
this.stateRequestServiceDemo = inject(StateRequestServiceDemo);
|
|
4829
|
-
this.channels$ = this.stateRequestServiceDemo.channels$;
|
|
4830
|
-
this.user$ = this.stateRequestServiceDemo.user$;
|
|
4831
|
-
this.users$ = this.stateRequestServiceDemo.userList$;
|
|
4832
|
-
this.data$ = this.stateRequestServiceDemo.data$;
|
|
4833
|
-
this.connectionStatus$ = this.stateRequestServiceDemo.connectionStatus$;
|
|
4834
|
-
this.messages = this.fb.group({
|
|
4835
|
-
channels: this.fb.control(null, Validators.required),
|
|
4836
|
-
toUsers: this.fb.control(null, Validators.required),
|
|
4837
|
-
content: this.fb.control(null, Validators.required),
|
|
4838
|
-
});
|
|
4839
|
-
this.communicationMessages$ = this.stateRequestServiceDemo.communicationMessages$;
|
|
4840
|
-
this.latestCommunicationMessages$ = this.stateRequestServiceDemo.latestCommunicationMessages$;
|
|
4841
|
-
this.chat$ = combineLatest([this.user$, this.communicationMessages$])
|
|
4842
|
-
.pipe(map$1(([user, messages]) => ({ user, messages })), map$1(obj => {
|
|
4843
|
-
if (!obj.user)
|
|
4844
|
-
return EMPTY;
|
|
4845
|
-
// const mainUser = UserName.adapt({
|
|
4846
|
-
// id: obj.user.username,
|
|
4847
|
-
// first: obj.user?.name?.first,
|
|
4848
|
-
// last: obj.user?.name?.last,
|
|
4849
|
-
// })
|
|
4850
|
-
const mainUser = '';
|
|
4851
|
-
const messages = obj.messages.map((item) => {
|
|
4852
|
-
if (item.toUser === 'allChannels') {
|
|
4853
|
-
// item.toUser = UserName.adapt({
|
|
4854
|
-
// id: '',
|
|
4855
|
-
// first: 'All Users',
|
|
4856
|
-
// last: '',
|
|
4857
|
-
// })
|
|
4858
|
-
}
|
|
4859
|
-
// return Message.adapt({
|
|
4860
|
-
// fromUser: {
|
|
4861
|
-
// id: item.fromUser.username,
|
|
4862
|
-
// first: item.fromUser?.name?.first,
|
|
4863
|
-
// last: item.fromUser?.name?.last,
|
|
4864
|
-
// },
|
|
4865
|
-
// toUser: {
|
|
4866
|
-
// id: item.toUser.username,
|
|
4867
|
-
// first: item.toUser?.name?.first,
|
|
4868
|
-
// last: item.toUser?.name?.last,
|
|
4869
|
-
// },
|
|
4870
|
-
// content: item.content,
|
|
4871
|
-
// date: item.issued,
|
|
4872
|
-
// })
|
|
4873
|
-
});
|
|
4874
|
-
return { user: mainUser, messages };
|
|
4875
|
-
}));
|
|
4876
|
-
}
|
|
4877
|
-
get channels() {
|
|
4878
|
-
return this.messages.get('channels');
|
|
4879
|
-
}
|
|
4880
|
-
get toUsers() {
|
|
4881
|
-
return this.messages.get('toUsers');
|
|
4882
|
-
}
|
|
4883
|
-
get content() {
|
|
4884
|
-
return this.messages.get('content');
|
|
4885
|
-
}
|
|
4886
|
-
get isValid() {
|
|
4887
|
-
return this.toUsers.valid;
|
|
4888
|
-
}
|
|
4889
|
-
ngOnInit() {
|
|
4890
|
-
this.stateRequestServiceDemo.updateConnection(this.server, this.wsServer, this.jwtToken, this.user);
|
|
4891
|
-
// this.stateRequestServiceDemo.getData()
|
|
4892
|
-
if (this.connectionStatus$) {
|
|
4893
|
-
this.connectionStatus$
|
|
4894
|
-
.subscribe(status => {
|
|
4895
|
-
this.stateRequestServiceDemo.getAllChannels();
|
|
4896
|
-
});
|
|
4897
|
-
}
|
|
4898
|
-
}
|
|
4899
|
-
onSendMessage(user) {
|
|
4900
|
-
this.messages.markAllAsTouched();
|
|
4901
|
-
if (this.messages.invalid)
|
|
4902
|
-
return;
|
|
4903
|
-
const message = ChannelMessage.adapt({
|
|
4904
|
-
message: this.messages.value.content,
|
|
4905
|
-
...user,
|
|
4906
|
-
users: this.toUsers.value,
|
|
4907
|
-
});
|
|
4908
|
-
this.stateRequestServiceDemo.sendMessage(message);
|
|
4909
|
-
this.content.reset();
|
|
4910
|
-
}
|
|
4911
|
-
onSendAlert() {
|
|
4912
|
-
debugger;
|
|
4913
|
-
this.messages.markAllAsTouched();
|
|
4914
|
-
if (this.messages.invalid)
|
|
4915
|
-
return;
|
|
4916
|
-
const message = ChannelMessage.adapt({ ...this.messages.value, type: CommunicationType.ALERT });
|
|
4917
|
-
this.stateRequestServiceDemo.sendMessage(message);
|
|
4918
|
-
this.content.reset();
|
|
4919
|
-
}
|
|
4920
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsMessagingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4921
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user" }, ngImport: i0, template: "\n @if ((data$ | async); as data) {\n <div style=\"margin: 1rem; display: flex; gap: 1rem; flex-direction: column;\">\n <div>\n\n <div>\n <div style=\"display: flex; gap: 1rem\">\n <div style=\"flex:1\" [formGroup]=\"messages\">\n\n <div style=\"display:flex; gap: 1rem\">\n @if ((channels$ | async); as channels) {\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Channels</mat-label>\n <mat-select formControlName=\"channels\" multiple #channelsSelect>\n <mat-select-trigger>\n {{ (channelsSelect.value?.[0] === 'allChannels' ? 'All Channels' : channelsSelect.value?.[0]?.content?.name) || '' }}\n @if ((channelsSelect.value?.length || 0) > 1) {\n <span>\n (+{{(channelsSelect.value?.length || 0) - 1}} {{channelsSelect.value?.length === 2 ? 'other' : 'others'}})\n </span>\n }\n </mat-select-trigger>\n <mat-option value=\"allChannels\">\n All Channels\n </mat-option>\n @for (channel of channels; track channel) {\n <mat-option [value]=\"channel\">\n {{ channel }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n @if ((users$ | async); as users) {\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Users</mat-label>\n <mat-select formControlName=\"toUsers\" multiple #userSelect>\n <mat-select-trigger>\n {{ (userSelect.value?.[0] === 'allUsers' ? 'All Users' : userSelect.value?.[0]?.content?.name) || '' }}\n @if ((userSelect.value?.length || 0) > 1) {\n <span>\n (+{{(userSelect.value?.length || 0) - 1}} {{userSelect.value?.length === 2 ? 'other' : 'others'}})\n </span>\n }\n </mat-select-trigger>\n <mat-option value=\"allChannels\">\n All Users\n </mat-option>\n @for (user of users; track user) {\n <mat-option [value]=\"user\">\n {{ user.content.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n </div>\n\n @if ((users$ | async); as users) {\n <div style=\"display:flex\">\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Send a Message</mat-label>\n <textarea\n matInput placeholder=\"Ex. It makes me feel...\"\n formControlName=\"content\"\n (keydown.enter)=\"onSendMessage(user); $event.preventDefault()\"\n [disabled]=\"!isValid\"\n ></textarea>\n </mat-form-field>\n </div>\n }\n\n <div style=\"display:flex; gap: .5rem;\">\n <div style=\"flex:1\"></div>\n <button mat-stroked-button (click)=\"onSendAlert()\" color=\"warn\">\n Send Alert\n </button>\n <button mat-stroked-button (click)=\"onSendMessage(user)\">\n Send Message\n </button>\n </div>\n </div>\n </div>\n @if ((chat$ | async); as chat) {\n <div style=\"border: thin gray solid; padding: 1rem; margin-top: 1rem;\">\n <!-- <app-messenger-chat\n [user]=\"chat.user\"\n [messages]=\"chat.messages\"\n ></app-messenger-chat> -->\n </div>\n }\n </div>\n\n </div>\n </div>\n }\n\n\n {{ channels$ | async | json }}\n", styles: [""], dependencies: [{ kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "component", type: i4.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "directive", type: i4.MatSelectTrigger, selector: "mat-select-trigger" }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] }); }
|
|
4922
|
-
}
|
|
4923
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsMessagingComponent, decorators: [{
|
|
4924
|
-
type: Component,
|
|
4925
|
-
args: [{ selector: 'app-ws-messaging', standalone: false, template: "\n @if ((data$ | async); as data) {\n <div style=\"margin: 1rem; display: flex; gap: 1rem; flex-direction: column;\">\n <div>\n\n <div>\n <div style=\"display: flex; gap: 1rem\">\n <div style=\"flex:1\" [formGroup]=\"messages\">\n\n <div style=\"display:flex; gap: 1rem\">\n @if ((channels$ | async); as channels) {\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Channels</mat-label>\n <mat-select formControlName=\"channels\" multiple #channelsSelect>\n <mat-select-trigger>\n {{ (channelsSelect.value?.[0] === 'allChannels' ? 'All Channels' : channelsSelect.value?.[0]?.content?.name) || '' }}\n @if ((channelsSelect.value?.length || 0) > 1) {\n <span>\n (+{{(channelsSelect.value?.length || 0) - 1}} {{channelsSelect.value?.length === 2 ? 'other' : 'others'}})\n </span>\n }\n </mat-select-trigger>\n <mat-option value=\"allChannels\">\n All Channels\n </mat-option>\n @for (channel of channels; track channel) {\n <mat-option [value]=\"channel\">\n {{ channel }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n @if ((users$ | async); as users) {\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Users</mat-label>\n <mat-select formControlName=\"toUsers\" multiple #userSelect>\n <mat-select-trigger>\n {{ (userSelect.value?.[0] === 'allUsers' ? 'All Users' : userSelect.value?.[0]?.content?.name) || '' }}\n @if ((userSelect.value?.length || 0) > 1) {\n <span>\n (+{{(userSelect.value?.length || 0) - 1}} {{userSelect.value?.length === 2 ? 'other' : 'others'}})\n </span>\n }\n </mat-select-trigger>\n <mat-option value=\"allChannels\">\n All Users\n </mat-option>\n @for (user of users; track user) {\n <mat-option [value]=\"user\">\n {{ user.content.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n </div>\n\n @if ((users$ | async); as users) {\n <div style=\"display:flex\">\n <mat-form-field style=\"flex:1\" appearance=\"outline\">\n <mat-label>Send a Message</mat-label>\n <textarea\n matInput placeholder=\"Ex. It makes me feel...\"\n formControlName=\"content\"\n (keydown.enter)=\"onSendMessage(user); $event.preventDefault()\"\n [disabled]=\"!isValid\"\n ></textarea>\n </mat-form-field>\n </div>\n }\n\n <div style=\"display:flex; gap: .5rem;\">\n <div style=\"flex:1\"></div>\n <button mat-stroked-button (click)=\"onSendAlert()\" color=\"warn\">\n Send Alert\n </button>\n <button mat-stroked-button (click)=\"onSendMessage(user)\">\n Send Message\n </button>\n </div>\n </div>\n </div>\n @if ((chat$ | async); as chat) {\n <div style=\"border: thin gray solid; padding: 1rem; margin-top: 1rem;\">\n <!-- <app-messenger-chat\n [user]=\"chat.user\"\n [messages]=\"chat.messages\"\n ></app-messenger-chat> -->\n </div>\n }\n </div>\n\n </div>\n </div>\n }\n\n\n {{ channels$ | async | json }}\n" }]
|
|
4926
|
-
}], propDecorators: { server: [{
|
|
4927
|
-
type: Input
|
|
4928
|
-
}], wsServer: [{
|
|
4929
|
-
type: Input
|
|
4930
|
-
}], jwtToken: [{
|
|
4931
|
-
type: Input
|
|
4932
|
-
}], user: [{
|
|
4933
|
-
type: Input
|
|
4934
|
-
}] } });
|
|
4935
|
-
|
|
4936
5094
|
// import { MessengerChatModule } from 'src/app/components/messenger-chat/messenger-chat.module';
|
|
4937
5095
|
// import { StoreStateManagerModule } from "src/app/beta_components/store-state-manager/store-state-manager.module";
|
|
4938
5096
|
class HttpRequestManagerModule {
|