http-request-manager 18.5.19 → 18.5.21
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,24 @@ class ChannelInfo {
|
|
|
736
736
|
}
|
|
737
737
|
|
|
738
738
|
class WSUser {
|
|
739
|
-
constructor(
|
|
740
|
-
this.
|
|
741
|
-
this.
|
|
739
|
+
constructor(id = '', ldap = '', name = '', email = '') {
|
|
740
|
+
this.id = id;
|
|
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?.id || item?.sessionId, // Support both for backward compatibility
|
|
747
|
+
item?.ldap, item?.name, item?.email);
|
|
748
|
+
// Copy any additional properties
|
|
749
|
+
if (item) {
|
|
750
|
+
Object.keys(item).forEach(key => {
|
|
751
|
+
if (!['id', 'sessionId', 'ldap', 'name', 'email'].includes(key)) {
|
|
752
|
+
user[key] = item[key];
|
|
753
|
+
}
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
return user;
|
|
745
757
|
}
|
|
746
758
|
}
|
|
747
759
|
|
|
@@ -760,6 +772,11 @@ class WebsocketService {
|
|
|
760
772
|
this.connectionStatus = new BehaviorSubject(false);
|
|
761
773
|
this.connectionStatus$ = this.connectionStatus.asObservable();
|
|
762
774
|
this.isSubscribed = false;
|
|
775
|
+
// Track currently subscribed channels
|
|
776
|
+
this.subscribedChannels = new BehaviorSubject(new Set());
|
|
777
|
+
this.subscribedChannels$ = this.subscribedChannels.asObservable();
|
|
778
|
+
// Store last options for reconnection
|
|
779
|
+
this.lastOptions = null;
|
|
763
780
|
}
|
|
764
781
|
getSessionId() {
|
|
765
782
|
return sessionStorage.getItem('WSID') ?? (() => {
|
|
@@ -773,7 +790,10 @@ class WebsocketService {
|
|
|
773
790
|
const message = {
|
|
774
791
|
type: 'subscribe',
|
|
775
792
|
subscribedChannel: channelName,
|
|
776
|
-
content:
|
|
793
|
+
content: {
|
|
794
|
+
id: this.getSessionId(),
|
|
795
|
+
...user
|
|
796
|
+
}
|
|
777
797
|
};
|
|
778
798
|
this.socket.send(JSON.stringify(message));
|
|
779
799
|
this.isSubscribed = true; // Set the flag immediately after sending
|
|
@@ -806,7 +826,26 @@ class WebsocketService {
|
|
|
806
826
|
this.socket.onopen = () => {
|
|
807
827
|
console.log(`📡 Connected to WebSocket`);
|
|
808
828
|
this.connectionStatus.next(true);
|
|
829
|
+
this.lastOptions = options;
|
|
830
|
+
// Subscribe to primary channel
|
|
809
831
|
this.sendSubscribe(options.id, options.user);
|
|
832
|
+
// Auto-subscribe to additional channels from options.channels[]
|
|
833
|
+
if (options.channels && options.channels.length > 0) {
|
|
834
|
+
options.channels.forEach(channel => {
|
|
835
|
+
if (channel !== options.id) {
|
|
836
|
+
this.subscribeToChannel(channel);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
// Re-subscribe to any previously subscribed channels (reconnection scenario)
|
|
841
|
+
const previousChannels = this.subscribedChannels.value;
|
|
842
|
+
if (previousChannels.size > 0) {
|
|
843
|
+
previousChannels.forEach(channel => {
|
|
844
|
+
if (channel !== options.id && (!options.channels || !options.channels.includes(channel))) {
|
|
845
|
+
this.subscribeToChannel(channel);
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
}
|
|
810
849
|
};
|
|
811
850
|
this.socket.onmessage = (event) => {
|
|
812
851
|
try {
|
|
@@ -848,20 +887,44 @@ class WebsocketService {
|
|
|
848
887
|
content: {}
|
|
849
888
|
};
|
|
850
889
|
this.socket.send(JSON.stringify(message));
|
|
890
|
+
// Track locally
|
|
891
|
+
const current = this.subscribedChannels.value;
|
|
892
|
+
current.add(channelName);
|
|
893
|
+
this.subscribedChannels.next(current);
|
|
894
|
+
console.log(`📝 Subscribed to channel: ${channelName}`);
|
|
851
895
|
}
|
|
852
896
|
else {
|
|
853
897
|
console.warn('Cannot subscribe: WebSocket not yet open.');
|
|
854
898
|
}
|
|
855
899
|
}
|
|
856
|
-
|
|
900
|
+
subscribeToChannels(channelNames) {
|
|
901
|
+
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
902
|
+
channelNames.forEach(channel => this.subscribeToChannel(channel));
|
|
903
|
+
}
|
|
904
|
+
else {
|
|
905
|
+
console.warn('Cannot subscribe: WebSocket not yet open.');
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
unsubscribeFromChannel(channel) {
|
|
857
909
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
858
910
|
this.socket.send(JSON.stringify({ type: 'unsubscribe', subscribedChannel: channel }));
|
|
859
|
-
|
|
911
|
+
// Remove from local tracking
|
|
912
|
+
const current = this.subscribedChannels.value;
|
|
913
|
+
current.delete(channel);
|
|
914
|
+
this.subscribedChannels.next(current);
|
|
915
|
+
console.log(`💬 Unsubscribed from channel: ${channel}`);
|
|
860
916
|
}
|
|
861
917
|
else {
|
|
862
|
-
console.error('WebSocket is not open. Cannot
|
|
918
|
+
console.error('WebSocket is not open. Cannot unsubscribe from channel.');
|
|
863
919
|
}
|
|
864
920
|
}
|
|
921
|
+
unsubscribeToChannel(channel) {
|
|
922
|
+
// Deprecated: Use unsubscribeFromChannel instead
|
|
923
|
+
this.unsubscribeFromChannel(channel);
|
|
924
|
+
}
|
|
925
|
+
getSubscribedChannels() {
|
|
926
|
+
return this.subscribedChannels.value;
|
|
927
|
+
}
|
|
865
928
|
sendBroadcast(content) {
|
|
866
929
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
867
930
|
this.socket.send(JSON.stringify({ type: 'broadcast', content }));
|
|
@@ -880,6 +943,19 @@ class WebsocketService {
|
|
|
880
943
|
console.error('WebSocket is not open. Cannot send message.');
|
|
881
944
|
}
|
|
882
945
|
}
|
|
946
|
+
/**
|
|
947
|
+
* Send a message to a specific channel for channel-based messaging
|
|
948
|
+
* This uses the 'message' type which broadcasts to all subscribers in the channel
|
|
949
|
+
*/
|
|
950
|
+
sendChannelMessage(channel, content) {
|
|
951
|
+
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
952
|
+
this.socket.send(JSON.stringify({ type: 'message', subscribedChannel: channel, content }));
|
|
953
|
+
console.log(`💬 Send channel message to [${channel}]:`, content);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
console.error('WebSocket is not open. Cannot send channel message.');
|
|
957
|
+
}
|
|
958
|
+
}
|
|
883
959
|
sendMessageToUser(user, content) {
|
|
884
960
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
885
961
|
this.socket.send(JSON.stringify({ type: 'userMessage', subscribedChannel: user, content }));
|
|
@@ -2812,15 +2888,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2812
2888
|
}], ctorParameters: () => [] });
|
|
2813
2889
|
|
|
2814
2890
|
class ChannelMessage {
|
|
2815
|
-
constructor(sessionId =
|
|
2891
|
+
constructor(sessionId = null, content = null) {
|
|
2816
2892
|
this.sessionId = sessionId;
|
|
2817
2893
|
this.content = content;
|
|
2818
|
-
this.message = message;
|
|
2819
|
-
this.users = users;
|
|
2820
|
-
this.issued = issued;
|
|
2821
2894
|
}
|
|
2822
2895
|
static adapt(item) {
|
|
2823
|
-
return new ChannelMessage(item?.sessionId
|
|
2896
|
+
return new ChannelMessage(item?.sessionId || item?.id, // Support both for backward compatibility
|
|
2897
|
+
item?.content);
|
|
2824
2898
|
}
|
|
2825
2899
|
}
|
|
2826
2900
|
|
|
@@ -2890,7 +2964,7 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
2890
2964
|
this.httpManagerService.disconnect();
|
|
2891
2965
|
}
|
|
2892
2966
|
if (message.type === 'success') {
|
|
2893
|
-
if (message.data.
|
|
2967
|
+
if (message.data.id !== this.user.value?.id) {
|
|
2894
2968
|
const user = WSUser.adapt(message.data);
|
|
2895
2969
|
this.user.next(user);
|
|
2896
2970
|
}
|
|
@@ -2906,25 +2980,40 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
2906
2980
|
// }
|
|
2907
2981
|
this.channels.next(message.channels);
|
|
2908
2982
|
break;
|
|
2983
|
+
case 'subscribed':
|
|
2984
|
+
console.log(`✅ Subscription confirmed: ${message.channel}`);
|
|
2985
|
+
break;
|
|
2986
|
+
case 'unsubscribed':
|
|
2987
|
+
console.log(`🔓 Unsubscription confirmed: ${message.channel}`);
|
|
2988
|
+
break;
|
|
2989
|
+
case 'info':
|
|
2990
|
+
// Already subscribed or other info messages
|
|
2991
|
+
console.log(`ℹ️ Info: ${message.message}`);
|
|
2992
|
+
break;
|
|
2909
2993
|
case 'stateMangerMessage':
|
|
2910
2994
|
;
|
|
2911
|
-
if (message.data.sessionId !== this.user.value?.
|
|
2995
|
+
if (message.data.sessionId !== this.user.value?.id) {
|
|
2912
2996
|
console.log('💬 Message:', message.data);
|
|
2913
2997
|
this.userAction.next(message.data);
|
|
2914
2998
|
this.fetchRecord(RequestOptions.adapt({ path: message.data.content.path }), message.data.content.method);
|
|
2915
2999
|
}
|
|
2916
3000
|
break;
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
3001
|
+
case 'channelMessage':
|
|
3002
|
+
// Handle channel-based messages (from sendChannelMessage)
|
|
3003
|
+
// Structure: { type: 'channelMessage', channels: [...], sessionId: {id, ldap, name, email}, content: {message payload} }
|
|
3004
|
+
// Skip messages from self
|
|
3005
|
+
const senderSessionId = message.sessionId?.id;
|
|
3006
|
+
if (senderSessionId === this.user.value?.id) {
|
|
3007
|
+
break;
|
|
3008
|
+
}
|
|
3009
|
+
console.log('💬 Channel Message received:', message);
|
|
3010
|
+
if (message.content) {
|
|
3011
|
+
this.appendMessages(ChannelMessage.adapt({
|
|
3012
|
+
sessionId: message.sessionId,
|
|
3013
|
+
content: message.content,
|
|
3014
|
+
}));
|
|
3015
|
+
}
|
|
3016
|
+
break;
|
|
2928
3017
|
case 'usersInChannel':
|
|
2929
3018
|
console.log('👥 Users:', message.data.users);
|
|
2930
3019
|
this.userList.next(message.data.users);
|
|
@@ -3404,17 +3493,119 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
3404
3493
|
}
|
|
3405
3494
|
}
|
|
3406
3495
|
wsMessaging(message, channels) {
|
|
3407
|
-
const user = this.user.value
|
|
3496
|
+
const user = this.user.value;
|
|
3408
3497
|
const messageInfo = ChannelMessage.adapt({ ...message, fromUser: user });
|
|
3498
|
+
console.log('📤 wsMessaging called with channels:', channels);
|
|
3409
3499
|
if (this.wsConnection && this.apiOptions.ws) {
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3500
|
+
// If specific channels provided, send to each channel
|
|
3501
|
+
if (channels && channels.length > 0) {
|
|
3502
|
+
console.log(`📤 Sending to ${channels.length} channel(s):`, channels);
|
|
3503
|
+
channels.forEach(channel => {
|
|
3504
|
+
if (channel === 'allChannels') {
|
|
3505
|
+
this.httpManagerService.sendBroadcast(messageInfo);
|
|
3506
|
+
}
|
|
3507
|
+
else {
|
|
3508
|
+
this.httpManagerService.sendChannelMessage(channel, messageInfo);
|
|
3509
|
+
}
|
|
3510
|
+
});
|
|
3511
|
+
}
|
|
3512
|
+
else {
|
|
3513
|
+
// Fallback to the primary WS channel
|
|
3514
|
+
const wsChannel = this.apiOptions.ws.id;
|
|
3515
|
+
console.log(`📤 Sending to fallback channel:`, wsChannel);
|
|
3516
|
+
this.httpManagerService.sendChannelMessage(wsChannel, messageInfo);
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
// --------------------------------------------------------------------------------------------------
|
|
3521
|
+
// CHANNEL MANAGEMENT
|
|
3522
|
+
/**
|
|
3523
|
+
* Subscribe to a single channel
|
|
3524
|
+
*/
|
|
3525
|
+
subscribeToChannel(channel) {
|
|
3526
|
+
if (this.wsConnection) {
|
|
3527
|
+
this.httpManagerService.subscribeToChannel(channel);
|
|
3528
|
+
}
|
|
3529
|
+
else {
|
|
3530
|
+
console.warn('Cannot subscribe: WebSocket not connected.');
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
/**
|
|
3534
|
+
* Subscribe to multiple channels at once
|
|
3535
|
+
*/
|
|
3536
|
+
subscribeToChannels(channels) {
|
|
3537
|
+
if (this.wsConnection) {
|
|
3538
|
+
this.httpManagerService.subscribeToChannels(channels);
|
|
3539
|
+
}
|
|
3540
|
+
else {
|
|
3541
|
+
console.warn('Cannot subscribe: WebSocket not connected.');
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
/**
|
|
3545
|
+
* Unsubscribe from a channel
|
|
3546
|
+
*/
|
|
3547
|
+
unsubscribeFromChannel(channel) {
|
|
3548
|
+
if (this.wsConnection) {
|
|
3549
|
+
this.httpManagerService.unsubscribeFromChannel(channel);
|
|
3550
|
+
}
|
|
3551
|
+
else {
|
|
3552
|
+
console.warn('Cannot unsubscribe: WebSocket not connected.');
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
/**
|
|
3556
|
+
* Get observable of currently subscribed channels
|
|
3557
|
+
*/
|
|
3558
|
+
get subscribedChannels$() {
|
|
3559
|
+
return this.httpManagerService.subscribedChannels$;
|
|
3560
|
+
}
|
|
3561
|
+
/**
|
|
3562
|
+
* Get current subscribed channels synchronously
|
|
3563
|
+
*/
|
|
3564
|
+
getSubscribedChannels() {
|
|
3565
|
+
return this.httpManagerService.getSubscribedChannels();
|
|
3566
|
+
}
|
|
3567
|
+
/**
|
|
3568
|
+
* Create a new channel on the server
|
|
3569
|
+
*/
|
|
3570
|
+
createChannel(channel) {
|
|
3571
|
+
if (this.wsConnection) {
|
|
3572
|
+
this.httpManagerService.createChannel(channel);
|
|
3573
|
+
}
|
|
3574
|
+
else {
|
|
3575
|
+
console.warn('Cannot create channel: WebSocket not connected.');
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
/**
|
|
3579
|
+
* Delete a channel from the server
|
|
3580
|
+
*/
|
|
3581
|
+
deleteChannel(channel) {
|
|
3582
|
+
if (this.wsConnection) {
|
|
3583
|
+
this.httpManagerService.deleteChannel(channel);
|
|
3584
|
+
}
|
|
3585
|
+
else {
|
|
3586
|
+
console.warn('Cannot delete channel: WebSocket not connected.');
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
/**
|
|
3590
|
+
* Request list of all channels from server
|
|
3591
|
+
*/
|
|
3592
|
+
getAllChannels() {
|
|
3593
|
+
if (this.wsConnection) {
|
|
3594
|
+
this.httpManagerService.getAllChannels();
|
|
3595
|
+
}
|
|
3596
|
+
else {
|
|
3597
|
+
console.warn('Cannot get channels: WebSocket not connected.');
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
/**
|
|
3601
|
+
* Get users in a specific channel
|
|
3602
|
+
*/
|
|
3603
|
+
getUsersInChannel(channel) {
|
|
3604
|
+
if (this.wsConnection) {
|
|
3605
|
+
this.httpManagerService.getUsersInChannel(channel);
|
|
3606
|
+
}
|
|
3607
|
+
else {
|
|
3608
|
+
console.warn('Cannot get users: WebSocket not connected.');
|
|
3418
3609
|
}
|
|
3419
3610
|
}
|
|
3420
3611
|
// --------------------------------------------------------------------------------------------------
|
|
@@ -4109,10 +4300,9 @@ class StateRequestServiceDemo extends HTTPManagerStateService {
|
|
|
4109
4300
|
console.log('User Action:', user);
|
|
4110
4301
|
});
|
|
4111
4302
|
}
|
|
4112
|
-
sendMessage(data) {
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
this.wsMessaging(data);
|
|
4303
|
+
sendMessage(data, channels) {
|
|
4304
|
+
console.log('sendMessage', data, 'to channels:', channels);
|
|
4305
|
+
this.wsMessaging(data, channels);
|
|
4116
4306
|
}
|
|
4117
4307
|
getAllChannels() {
|
|
4118
4308
|
this.httpManagerService.getAllChannels();
|
|
@@ -4200,7 +4390,6 @@ class StateDataRequestService extends HTTPManagerStateService {
|
|
|
4200
4390
|
this.createRecord(newData, RequestOptions.adapt({ path: this.path }));
|
|
4201
4391
|
}
|
|
4202
4392
|
sendMessage(data) {
|
|
4203
|
-
debugger;
|
|
4204
4393
|
console.log('sendMessage', data);
|
|
4205
4394
|
this.wsMessaging(data);
|
|
4206
4395
|
}
|
|
@@ -4267,11 +4456,11 @@ class WsDataControlComponent {
|
|
|
4267
4456
|
this.stateDataRequestService.deleteData(lastRec);
|
|
4268
4457
|
}
|
|
4269
4458
|
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.
|
|
4459
|
+
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
4460
|
}
|
|
4272
4461
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsDataControlComponent, decorators: [{
|
|
4273
4462
|
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.
|
|
4463
|
+
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
4464
|
}], propDecorators: { server: [{
|
|
4276
4465
|
type: Input
|
|
4277
4466
|
}], wsServer: [{
|
|
@@ -4286,6 +4475,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4286
4475
|
type: Input
|
|
4287
4476
|
}] } });
|
|
4288
4477
|
|
|
4478
|
+
class WsMessagingComponent {
|
|
4479
|
+
constructor() {
|
|
4480
|
+
this.destroy$ = new Subject();
|
|
4481
|
+
this.fb = inject(FormBuilder);
|
|
4482
|
+
this.stateRequestServiceDemo = inject(StateRequestServiceDemo);
|
|
4483
|
+
// Filter out private stateManager channels (channels starting with "WS-")
|
|
4484
|
+
this.channels$ = this.stateRequestServiceDemo.channels$.pipe(map$1(channels => channels?.filter(channel => !channel.startsWith('WS-')) || []));
|
|
4485
|
+
this.user$ = this.stateRequestServiceDemo.user$;
|
|
4486
|
+
this.data$ = this.stateRequestServiceDemo.data$;
|
|
4487
|
+
this.connectionStatus$ = this.stateRequestServiceDemo.connectionStatus$;
|
|
4488
|
+
this.messages = this.fb.group({
|
|
4489
|
+
channels: this.fb.control(null, Validators.required),
|
|
4490
|
+
content: this.fb.control(null, Validators.required),
|
|
4491
|
+
});
|
|
4492
|
+
this.communicationMessages$ = this.stateRequestServiceDemo.communicationMessages$;
|
|
4493
|
+
this.latestCommunicationMessages$ = this.stateRequestServiceDemo.latestCommunicationMessages$;
|
|
4494
|
+
this.chat$ = combineLatest([this.user$, this.communicationMessages$])
|
|
4495
|
+
.pipe(map$1(([user, messages]) => ({ user, messages })), map$1(obj => {
|
|
4496
|
+
if (!obj.user)
|
|
4497
|
+
return EMPTY;
|
|
4498
|
+
const mainUser = '';
|
|
4499
|
+
const messages = obj.messages.map((item) => {
|
|
4500
|
+
// Message transformation logic
|
|
4501
|
+
});
|
|
4502
|
+
return { user: mainUser, messages };
|
|
4503
|
+
}));
|
|
4504
|
+
}
|
|
4505
|
+
get channels() {
|
|
4506
|
+
return this.messages.get('channels');
|
|
4507
|
+
}
|
|
4508
|
+
get content() {
|
|
4509
|
+
return this.messages.get('content');
|
|
4510
|
+
}
|
|
4511
|
+
get isValid() {
|
|
4512
|
+
return this.channels.valid;
|
|
4513
|
+
}
|
|
4514
|
+
get selectedChannels() {
|
|
4515
|
+
return this.channels.value || [];
|
|
4516
|
+
}
|
|
4517
|
+
ngOnInit() {
|
|
4518
|
+
this.stateRequestServiceDemo.updateConnection(this.server, this.wsServer, this.jwtToken, this.user);
|
|
4519
|
+
// Only trigger once when connection becomes true
|
|
4520
|
+
this.connectionStatus$.pipe(filter$1(status => status === true), take$1(1), takeUntil$1(this.destroy$)).subscribe(() => {
|
|
4521
|
+
// Create a public messaging channel when connected
|
|
4522
|
+
this.stateRequestServiceDemo.createChannel('general');
|
|
4523
|
+
this.stateRequestServiceDemo.getAllChannels();
|
|
4524
|
+
});
|
|
4525
|
+
}
|
|
4526
|
+
ngOnDestroy() {
|
|
4527
|
+
this.destroy$.next();
|
|
4528
|
+
this.destroy$.complete();
|
|
4529
|
+
}
|
|
4530
|
+
onSendMessage(user) {
|
|
4531
|
+
this.messages.markAllAsTouched();
|
|
4532
|
+
if (this.messages.invalid)
|
|
4533
|
+
return;
|
|
4534
|
+
const selectedChannels = this.channels.value;
|
|
4535
|
+
const message = ChannelMessage.adapt({
|
|
4536
|
+
sessionId: {
|
|
4537
|
+
id: user.id,
|
|
4538
|
+
ldap: user.ldap,
|
|
4539
|
+
name: user.name,
|
|
4540
|
+
email: user.email,
|
|
4541
|
+
},
|
|
4542
|
+
content: { message: this.messages.value.content },
|
|
4543
|
+
});
|
|
4544
|
+
this.stateRequestServiceDemo.sendMessage(message, selectedChannels);
|
|
4545
|
+
this.content.reset();
|
|
4546
|
+
}
|
|
4547
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsMessagingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4548
|
+
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" }] }); }
|
|
4549
|
+
}
|
|
4550
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WsMessagingComponent, decorators: [{
|
|
4551
|
+
type: Component,
|
|
4552
|
+
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" }]
|
|
4553
|
+
}], propDecorators: { server: [{
|
|
4554
|
+
type: Input
|
|
4555
|
+
}], wsServer: [{
|
|
4556
|
+
type: Input
|
|
4557
|
+
}], jwtToken: [{
|
|
4558
|
+
type: Input
|
|
4559
|
+
}], user: [{
|
|
4560
|
+
type: Input
|
|
4561
|
+
}] } });
|
|
4562
|
+
|
|
4289
4563
|
class WsNotificationsComponent {
|
|
4290
4564
|
constructor() { }
|
|
4291
4565
|
ngOnInit() {
|
|
@@ -4385,11 +4659,11 @@ class RequestManagerWsDemoComponent {
|
|
|
4385
4659
|
this.stateRequestServiceDemo.updateConnection(this.server, this.wsServer, this.jwtToken, this.user);
|
|
4386
4660
|
}
|
|
4387
4661
|
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.
|
|
4662
|
+
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
4663
|
}
|
|
4390
4664
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
|
|
4391
4665
|
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.
|
|
4666
|
+
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
4667
|
}], propDecorators: { server: [{
|
|
4394
4668
|
type: Input
|
|
4395
4669
|
}], wsServer: [{
|
|
@@ -4822,117 +5096,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4822
5096
|
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
5097
|
}] });
|
|
4824
5098
|
|
|
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
5099
|
// import { MessengerChatModule } from 'src/app/components/messenger-chat/messenger-chat.module';
|
|
4937
5100
|
// import { StoreStateManagerModule } from "src/app/beta_components/store-state-manager/store-state-manager.module";
|
|
4938
5101
|
class HttpRequestManagerModule {
|