agora-appbuilder-core 4.1.22-beta.2 → 4.1.22-beta.3

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.
Files changed (43) hide show
  1. package/package.json +2 -2
  2. package/template/.eslintrc.js +20 -0
  3. package/template/.prettierrc.js +18 -0
  4. package/template/.watchmanconfig +1 -0
  5. package/template/agora-rn-uikit/src/Views/MaxVideoView.tsx +2 -0
  6. package/template/agora-rn-uikit/src/Views/MinVideoView.tsx +12 -2
  7. package/template/bridge/rtc/webNg/RtcEngine.ts +639 -251
  8. package/template/bridge/rtc/webNg/RtcSurfaceView.tsx +203 -16
  9. package/template/bridge/rtc/webNg/__tests__/screenshareLifecycle.test.ts +358 -0
  10. package/template/bridge/rtc/webNg/__tests__/screenshareMediaHealth.test.ts +49 -0
  11. package/template/bridge/rtc/webNg/screenshareMediaHealth.ts +49 -0
  12. package/template/bridge/rtm/web/index.ts +22 -31
  13. package/template/config.json +101 -0
  14. package/template/customization-api/atoms.ts +0 -2
  15. package/template/customization-api/customEvents.ts +1 -4
  16. package/template/customization-api/index.ts +0 -1
  17. package/template/customization-api/typeDefinition.ts +1 -6
  18. package/template/defaultConfig.js +2 -2
  19. package/template/src/components/Controls.tsx +12 -6
  20. package/template/src/components/CustomSidePanel.tsx +13 -13
  21. package/template/src/components/RTMConfigure.tsx +0 -14
  22. package/template/src/components/participants/UserActionMenuOptions.tsx +1 -28
  23. package/template/src/logger/transports/__tests__/agora-transport.test.ts +48 -0
  24. package/template/src/logger/transports/agora-transport.ts +18 -6
  25. package/template/src/pages/Create.tsx +19 -31
  26. package/template/src/pages/video-call/ActionSheet.native.tsx +0 -2
  27. package/template/src/pages/video-call/ActionSheet.tsx +0 -2
  28. package/template/src/pages/video-call/ActionSheetHandle.tsx +0 -1
  29. package/template/src/pages/video-call/SidePanelHeader.tsx +1 -3
  30. package/template/src/pages/video-call/VideoCallScreen.tsx +0 -3
  31. package/template/src/pages/video-call/VideoRenderer.tsx +0 -4
  32. package/template/src/rtm-events-api/Events.ts +3 -1
  33. package/template/src/rtm-events-api/__tests__/Events.test.ts +55 -0
  34. package/template/src/subComponents/SidePanelHeader.tsx +2 -16
  35. package/template/src/subComponents/screenshare/ScreenshareButton.tsx +38 -4
  36. package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +280 -34
  37. package/template/src/subComponents/screenshare/__tests__/screenshareJourney.test.ts +10 -0
  38. package/template/src/subComponents/screenshare/__tests__/screenshareOperation.test.ts +31 -0
  39. package/template/src/subComponents/screenshare/screenshareJourney.ts +6 -0
  40. package/template/src/subComponents/screenshare/screenshareOperation.ts +21 -0
  41. package/template/src/subComponents/screenshare/useScreenshare.tsx +8 -0
  42. package/template/theme.json +91 -0
  43. package/template/customization-api/ai-agent.ts +0 -4
@@ -0,0 +1,49 @@
1
+ export type ScreenshareMediaHealthOutcome =
2
+ | 'healthy'
3
+ | 'suspected_blank'
4
+ | 'track_ended'
5
+ | 'stats_unavailable';
6
+
7
+ export const getScreenshareMediaHealthOutcome = ({
8
+ trackReadyState,
9
+ bitrate,
10
+ frameRate,
11
+ width,
12
+ height,
13
+ videoElementPresent = true,
14
+ renderedWidth,
15
+ renderedHeight,
16
+ }: {
17
+ trackReadyState?: MediaStreamTrackState;
18
+ bitrate?: number;
19
+ frameRate?: number;
20
+ width?: number;
21
+ height?: number;
22
+ videoElementPresent?: boolean;
23
+ renderedWidth?: number;
24
+ renderedHeight?: number;
25
+ }): ScreenshareMediaHealthOutcome => {
26
+ if (trackReadyState === 'ended') {
27
+ return 'track_ended';
28
+ }
29
+ if (
30
+ bitrate === undefined &&
31
+ frameRate === undefined &&
32
+ width === undefined &&
33
+ height === undefined
34
+ ) {
35
+ return 'stats_unavailable';
36
+ }
37
+ if (
38
+ !videoElementPresent ||
39
+ !bitrate ||
40
+ !frameRate ||
41
+ !width ||
42
+ !height ||
43
+ renderedWidth === 0 ||
44
+ renderedHeight === 0
45
+ ) {
46
+ return 'suspected_blank';
47
+ }
48
+ return 'healthy';
49
+ };
@@ -72,24 +72,12 @@ export class RTMWebClient {
72
72
  private client: RTMClient;
73
73
  private appId: string;
74
74
  private userId: string;
75
- private eventsMap = new Map<keyof NativeRTMClientEventMap, Set<CallbackType>>(
76
- [
77
- ['linkState', new Set()],
78
- ['storage', new Set()],
79
- ['presence', new Set()],
80
- ['message', new Set()],
81
- ],
82
- );
83
-
84
- private emitEvent(event: keyof NativeRTMClientEventMap, data: any) {
85
- const listeners = this.eventsMap.get(event);
86
-
87
- if (!listeners) {
88
- return;
89
- }
90
-
91
- listeners.forEach(listener => listener(data));
92
- }
75
+ private eventsMap = new Map<keyof NativeRTMClientEventMap, CallbackType>([
76
+ ['linkState', () => null],
77
+ ['storage', () => null],
78
+ ['presence', () => null],
79
+ ['message', () => null],
80
+ ]);
93
81
 
94
82
  constructor(appId: string, userId: string) {
95
83
  this.appId = appId;
@@ -109,7 +97,7 @@ export class RTMWebClient {
109
97
  nativeLinkStateMapping.IDLE,
110
98
  reasonCode: linkStatusReasonCodeMapping[data.reasonCode] || 0,
111
99
  };
112
- this.emitEvent('linkState', nativeState);
100
+ (this.eventsMap.get('linkState') ?? (() => {}))(nativeState);
113
101
  });
114
102
 
115
103
  this.client.addEventListener('storage', data => {
@@ -120,7 +108,7 @@ export class RTMWebClient {
120
108
  data: convertWebToNativeMetadata(data.data),
121
109
  timestamp: data.timestamp,
122
110
  };
123
- this.emitEvent('storage', nativeStorageEvent);
111
+ (this.eventsMap.get('storage') ?? (() => {}))(nativeStorageEvent);
124
112
  });
125
113
 
126
114
  this.client.addEventListener('presence', data => {
@@ -131,7 +119,7 @@ export class RTMWebClient {
131
119
  publisher: data.publisher,
132
120
  timestamp: data.timestamp,
133
121
  };
134
- this.emitEvent('presence', nativePresenceEvent);
122
+ (this.eventsMap.get('presence') ?? (() => {}))(nativePresenceEvent);
135
123
  });
136
124
 
137
125
  this.client.addEventListener('message', data => {
@@ -141,7 +129,7 @@ export class RTMWebClient {
141
129
  messageType: nativeMessageEventTypeMapping[data.messageType],
142
130
  message: `${data.message}`,
143
131
  };
144
- this.emitEvent('message', nativeMessageEvent);
132
+ (this.eventsMap.get('message') ?? (() => {}))(nativeMessageEvent);
145
133
  });
146
134
  } catch (error) {
147
135
  const contextError = new Error(
@@ -408,18 +396,21 @@ export class RTMWebClient {
408
396
  listener: (event: any) => void,
409
397
  ) {
410
398
  if (this.client) {
411
- // Web SDK listeners are fixed in the constructor; keep app-level
412
- // subscribers multiplexed here.
413
- this.eventsMap.get(event)?.add(listener as CallbackType);
399
+ // Simply replace the handler in our map - web client listeners are fixed in constructor
400
+ this.eventsMap.set(event, listener as CallbackType);
414
401
  }
415
402
  }
416
403
 
417
404
  removeEventListener(
418
405
  event: keyof NativeRTMClientEventMap,
419
- listener: (event: any) => void,
406
+ _listener: (event: any) => void,
420
407
  ) {
421
408
  if (this.client && this.eventsMap.has(event)) {
422
- this.eventsMap.get(event)?.delete(listener as CallbackType);
409
+ const prevListener = this.eventsMap.get(event);
410
+ if (prevListener) {
411
+ this.client.removeEventListener(event, prevListener);
412
+ }
413
+ this.eventsMap.set(event, () => null); // reset to no-op
423
414
  }
424
415
  }
425
416
 
@@ -482,10 +473,10 @@ export class RTMWebClient {
482
473
 
483
474
  removeAllListeners() {
484
475
  this.eventsMap = new Map([
485
- ['linkState', new Set()],
486
- ['storage', new Set()],
487
- ['presence', new Set()],
488
- ['message', new Set()],
476
+ ['linkState', () => null],
477
+ ['storage', () => null],
478
+ ['presence', () => null],
479
+ ['message', () => null],
489
480
  ]);
490
481
  return this.client.removeAllListeners();
491
482
  }
@@ -0,0 +1,101 @@
1
+ {
2
+ "PROJECT_ID": "49c705c1c9efb71000d7",
3
+ "APP_ID": "a569f8fb0309417780b793786b534a86",
4
+ "PRODUCT_ID": "helloworld",
5
+ "APP_NAME": "HelloWorld",
6
+ "LOGO": "data:image/png;base64,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",
7
+ "ICON": "logoSquare.png",
8
+ "FRONTEND_ENDPOINT": "https://app-builder-core-git-preprod-agoraio.vercel.app",
9
+ "BACKEND_ENDPOINT": "https://managedservices-preprod.rteappbuilder.com",
10
+ "PSTN": true,
11
+ "PRECALL": true,
12
+ "CHAT": true,
13
+ "CLOUD_RECORDING": true,
14
+ "RECORDING_MODE": "MIX",
15
+ "SCREEN_SHARING": true,
16
+ "LANDING_SUB_HEADING": "The Real-Time Engagement Platform",
17
+ "ENCRYPTION_ENABLED": true,
18
+ "ENABLE_GOOGLE_OAUTH": false,
19
+ "ENABLE_APPLE_OAUTH": false,
20
+ "ENABLE_SLACK_OAUTH": false,
21
+ "ENABLE_MICROSOFT_OAUTH": false,
22
+ "GOOGLE_CLIENT_ID": "",
23
+ "MICROSOFT_CLIENT_ID": "",
24
+ "SLACK_CLIENT_ID": "",
25
+ "APPLE_CLIENT_ID": "",
26
+ "BUCKET_NAME": "",
27
+ "BUCKET_ACCESS_KEY": "",
28
+ "BUCKET_ACCESS_SECRET": "",
29
+ "GOOGLE_CLIENT_SECRET": "",
30
+ "MICROSOFT_CLIENT_SECRET": "",
31
+ "SLACK_CLIENT_SECRET": "",
32
+ "APPLE_PRIVATE_KEY": "",
33
+ "APPLE_KEY_ID": "",
34
+ "APPLE_TEAM_ID": "",
35
+ "PSTN_EMAIL": "",
36
+ "PSTN_ACCOUNT": "",
37
+ "PSTN_PASSWORD": "",
38
+ "RECORDING_REGION": 0,
39
+ "GEO_FENCING": true,
40
+ "GEO_FENCING_INCLUDE_AREA": "GLOBAL",
41
+ "GEO_FENCING_EXCLUDE_AREA": "CHINA",
42
+ "LOG_ENABLED": true,
43
+ "EVENT_MODE": false,
44
+ "RAISE_HAND": false,
45
+ "AUDIO_ROOM": false,
46
+ "BG": "",
47
+ "PRIMARY_FONT_COLOR": "#363636",
48
+ "SECONDARY_FONT_COLOR": "#FFFFFF",
49
+ "PROFILE": "720p_3",
50
+ "SCREEN_SHARE_PROFILE": "1080p_2",
51
+ "ICON_TEXT": true,
52
+ "PRIMARY_ACTION_BRAND_COLOR": "#099DFD",
53
+ "PRIMARY_ACTION_TEXT_COLOR": "#FFFFFF",
54
+ "SECONDARY_ACTION_COLOR": "#FFFFFF",
55
+ "FONT_COLOR": "#FFFFFF",
56
+ "BACKGROUND_COLOR": "#111111",
57
+ "VIDEO_AUDIO_TILE_COLOR": "#222222",
58
+ "VIDEO_AUDIO_TILE_OVERLAY_COLOR": "#000004",
59
+ "VIDEO_AUDIO_TILE_TEXT_COLOR": "#FFFFFF",
60
+ "VIDEO_AUDIO_TILE_AVATAR_COLOR": "#BDD0DB",
61
+ "SEMANTIC_ERROR": "#FF414D",
62
+ "SEMANTIC_SUCCESS": "#36B37E",
63
+ "SEMANTIC_WARNING": "#FFAB00",
64
+ "SEMANTIC_NEUTRAL": "#808080",
65
+ "INPUT_FIELD_BACKGROUND_COLOR": "#181818",
66
+ "INPUT_FIELD_BORDER_COLOR": "#262626",
67
+ "CARD_LAYER_1_COLOR": "#1D1D1D",
68
+ "CARD_LAYER_2_COLOR": "#262626",
69
+ "CARD_LAYER_3_COLOR": "#2D2D2D",
70
+ "CARD_LAYER_4_COLOR": "#333333",
71
+ "CARD_LAYER_5_COLOR": "#808080",
72
+ "HARD_CODED_BLACK_COLOR": "#000000",
73
+ "ICON_BG_COLOR": "#242529",
74
+ "TOOLBAR_COLOR": "#111111",
75
+ "ACTIVE_SPEAKER": true,
76
+ "ENABLE_IDP_AUTH": false,
77
+ "ENABLE_TOKEN_AUTH": false,
78
+ "ENABLE_STT": true,
79
+ "ENABLE_CAPTION": true,
80
+ "ENABLE_MEETING_TRANSCRIPT": true,
81
+ "ENABLE_NOISE_CANCELLATION": true,
82
+ "ENABLE_VIRTUAL_BACKGROUND": true,
83
+ "ENABLE_WHITEBOARD": true,
84
+ "ENABLE_WHITEBOARD_FILE_UPLOAD": false,
85
+ "ENABLE_WAITING_ROOM": false,
86
+ "WHITEBOARD_APPIDENTIFIER": "EEJBQPVbEe2Bao8ZShuoHQ/hgB5eo0qcDbVig",
87
+ "WHITEBOARD_REGION": "us-sv",
88
+ "CHAT_ORG_NAME": "41754367",
89
+ "CHAT_APP_NAME": "1042822",
90
+ "CHAT_URL": "https://a41.chat.agora.io",
91
+ "ENABLE_NOISE_CANCELLATION_BY_DEFAULT": true,
92
+ "DISABLE_LANDSCAPE_MODE": false,
93
+ "STT_AUTO_START": false,
94
+ "CLOUD_RECORDING_AUTO_START": false,
95
+ "ENABLE_SPOTLIGHT": false,
96
+ "ENABLE_LIVE_REACTIONS": true,
97
+ "AUTO_CONNECT_RTM": false,
98
+ "ENABLE_CONVERSATIONAL_AI": false,
99
+ "CUSTOMIZE_AGENT": false,
100
+ "ENABLE_TEXT_TRACKS": true
101
+ }
@@ -8,5 +8,3 @@ export {default as TertiaryButton} from '../src/atoms/TertiaryButton';
8
8
  export {default as ActionMenu} from '../src/atoms/ActionMenu';
9
9
  export {default as IconButton} from '../src/atoms/IconButton';
10
10
  export {default as Dropdown} from '../src/atoms/Dropdown';
11
- export {default as Popup} from '../src/atoms/Popup';
12
- export {default as Tooltip} from '../src/atoms/Tooltip';
@@ -5,13 +5,10 @@ import {
5
5
  PersistanceLevel,
6
6
  EventCallback,
7
7
  } from '../src/rtm-events-api';
8
- import LocalEventEmitter, {
9
- LocalEventsEnum,
10
- } from '../src/rtm-events-api/LocalEvents';
11
8
 
12
9
  // 2. Initialize with source "fpe"
13
10
  const customEvents = new Events(EventSource.fpe);
14
11
 
15
12
  // 3. export
16
- export {customEvents, PersistanceLevel, LocalEventEmitter, LocalEventsEnum};
13
+ export {customEvents, PersistanceLevel};
17
14
  export type {EventCallback};
@@ -26,7 +26,6 @@ export * from './typeDefinition';
26
26
  export * from './utils';
27
27
  export * from './types';
28
28
  export * from './atoms';
29
- export * from './ai-agent';
30
29
 
31
30
  //TODO: hari remove later - used for simple-practice demo
32
31
  export * from './temp';
@@ -53,7 +53,6 @@ export interface SidePanelItem {
53
53
  name: string;
54
54
  title: string;
55
55
  component: React.ComponentType;
56
- headerRightSlot?: React.ReactNode;
57
56
  onClose?: () => void;
58
57
  }
59
58
 
@@ -75,10 +74,6 @@ export type CustomLogger = (
75
74
  export interface CustomAgentInterfaceProps {
76
75
  connectionState: AIAgentState;
77
76
  }
78
- export interface CreateInterface extends BeforeAndAfterInterface {
79
- headerRightSlot?: React.ComponentType;
80
- }
81
-
82
77
  export interface VideoCallInterface extends BeforeAndAfterInterface {
83
78
  // commented for v1 release
84
79
  topToolBar?: ToolbarType;
@@ -114,7 +109,7 @@ export type ComponentsInterface = {
114
109
  precall?: PreCallInterface;
115
110
  preferenceWrapper?: React.ComponentType;
116
111
  //precall?: React.ComponentType;
117
- create?: React.ComponentType | CreateInterface;
112
+ create?: React.ComponentType;
118
113
  //share?: React.ComponentType;
119
114
  //join?: React.ComponentType;
120
115
  videoCall?: VideoCallInterface;
@@ -77,8 +77,8 @@ const DefaultConfig = {
77
77
  CHAT_ORG_NAME: "",
78
78
  CHAT_APP_NAME: "",
79
79
  CHAT_URL: "",
80
- CLI_VERSION: "3.1.22-beta.2",
81
- CORE_VERSION: "4.1.22-beta.2",
80
+ CLI_VERSION: "3.1.22-beta.3",
81
+ CORE_VERSION: "4.1.22-beta.3",
82
82
  DISABLE_LANDSCAPE_MODE: false,
83
83
  STT_AUTO_START: false,
84
84
  CLOUD_RECORDING_AUTO_START: false,
@@ -344,8 +344,12 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
344
344
  } = useRoomInfo();
345
345
  const {setShowInvitePopup, setShowStopRecordingPopup, setShowLayoutOption} =
346
346
  useVideoCall();
347
- const {isScreenshareActive, startScreenshare, stopScreenshare} =
348
- useScreenshare();
347
+ const {
348
+ isScreenshareActive,
349
+ operationState = isScreenshareActive ? 'active' : 'inactive',
350
+ startScreenshare,
351
+ stopScreenshare,
352
+ } = useScreenshare();
349
353
  const {isRecordingActive, startRecording, inProgress, deleteRecording} =
350
354
  useRecording();
351
355
  const {setChatType} = useChatUIControls();
@@ -705,10 +709,12 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
705
709
  componentName: 'screenshare',
706
710
  order: 8,
707
711
  disabled:
708
- rtcProps.role == ClientRoleType.ClientRoleAudience &&
709
- $config.EVENT_MODE &&
710
- $config.RAISE_HAND &&
711
- !isHost,
712
+ operationState === 'starting' ||
713
+ operationState === 'stopping' ||
714
+ (rtcProps.role == ClientRoleType.ClientRoleAudience &&
715
+ $config.EVENT_MODE &&
716
+ $config.RAISE_HAND &&
717
+ !isHost),
712
718
  icon: isScreenshareActive ? 'stop-screen-share' : 'screen-share',
713
719
  iconColor: isScreenshareActive
714
720
  ? $config.SEMANTIC_ERROR
@@ -10,18 +10,23 @@
10
10
  *********************************************
11
11
  */
12
12
  import React from 'react';
13
- import {View, StyleSheet, ScrollView} from 'react-native';
13
+ import {View, Text, StyleSheet, ScrollView} from 'react-native';
14
14
  import {isMobileUA, isWebInternal, useIsSmall} from '../utils/common';
15
15
  import CommonStyles from './CommonStyles';
16
- import useCaptionWidth from '../subComponents/caption/useCaptionWidth';
17
- import {CustomSidePanelHeader} from '../pages/video-call/SidePanelHeader';
16
+ import SidePanelHeader, {
17
+ SidePanelStyles,
18
+ } from '../subComponents/SidePanelHeader';
18
19
  import {useLayout} from '../utils/useLayout';
19
20
  import {getGridLayoutName} from '../pages/video-call/DefaultLayouts';
21
+ import useCaptionWidth from '../subComponents/caption/useCaptionWidth';
22
+ import {useSidePanel} from '../utils/useSidePanel';
23
+ import {SidePanelType} from '../subComponents/SidePanelEnum';
24
+ import {CustomSidePanelHeader} from '../pages/video-call/SidePanelHeader';
25
+
20
26
  export interface CustomSidePanelViewInterface {
21
27
  name: string;
22
28
  title?: string;
23
29
  content: React.ComponentType;
24
- headerRightSlot?: React.ReactNode;
25
30
  onClose?: () => void;
26
31
  showHeader?: boolean;
27
32
  }
@@ -32,12 +37,12 @@ const CustomSidePanelView = (props: CustomSidePanelViewInterface) => {
32
37
  showHeader = true,
33
38
  name,
34
39
  title,
35
- headerRightSlot,
36
40
  onClose,
37
41
  } = props;
42
+ const {currentLayout} = useLayout();
38
43
  const {transcriptHeight} = useCaptionWidth();
44
+ const {setSidePanel} = useSidePanel();
39
45
  const isSmall = useIsSmall();
40
- const {currentLayout} = useLayout();
41
46
 
42
47
  return (
43
48
  <View
@@ -52,18 +57,13 @@ const CustomSidePanelView = (props: CustomSidePanelViewInterface) => {
52
57
  : // desktop maximized
53
58
  CommonStyles.sidePanelContainerWeb,
54
59
  isWebInternal() && !isSmall() && currentLayout === getGridLayoutName()
55
- ? {marginTop: 4}
60
+ ? {marginVertical: 4}
56
61
  : {},
57
62
  //@ts-ignore
58
63
  transcriptHeight && !isMobileUA() && {height: transcriptHeight},
59
64
  ]}>
60
65
  {showHeader && (
61
- <CustomSidePanelHeader
62
- name={name}
63
- title={title}
64
- headerRightSlot={headerRightSlot}
65
- onClose={onClose}
66
- />
66
+ <CustomSidePanelHeader name={name} title={title} onClose={onClose} />
67
67
  )}
68
68
  <ScrollView contentContainerStyle={[style.bodyContainer]}>
69
69
  {CustomSidePanelContent ? <CustomSidePanelContent /> : <></>}
@@ -950,20 +950,6 @@ const RtmConfigure = (props: any) => {
950
950
  }
951
951
  }
952
952
 
953
- if (
954
- typeof evt !== 'string' ||
955
- evt.trim() === '' ||
956
- typeof value === 'undefined'
957
- ) {
958
- logger.debug(
959
- LogSource.Events,
960
- 'CUSTOM_EVENTS',
961
- 'Ignoring RTM payload: not an AppBuilder custom-event envelope',
962
- {data, sender, ts},
963
- );
964
- return;
965
- }
966
-
967
953
  try {
968
954
  let parsedValue;
969
955
  try {
@@ -87,7 +87,6 @@ interface UserActionMenuOptionsOptionsProps {
87
87
  spotlightUid?: UidType;
88
88
  setSpotlightUid?: (uid: UidType) => void;
89
89
  items?: UserActionMenuItemsConfig;
90
- extraMenuItems?: ActionMenuItem[];
91
90
  }
92
91
 
93
92
  export default function UserActionMenuOptionsOptions(
@@ -103,13 +102,7 @@ export default function UserActionMenuOptionsOptions(
103
102
  useState(false);
104
103
  const [actionMenuitems, setActionMenuitems] = useState<ActionMenuItem[]>([]);
105
104
  const {setSidePanel} = useSidePanel();
106
- const {
107
- user,
108
- actionMenuVisible,
109
- setActionMenuVisible,
110
- spotlightUid,
111
- extraMenuItems,
112
- } = props;
105
+ const {user, actionMenuVisible, setActionMenuVisible, spotlightUid} = props;
113
106
  const {currentLayout} = useLayout();
114
107
  const {pinnedUid, activeUids, customContent, secondaryPinnedUid} =
115
108
  useContent();
@@ -723,24 +716,6 @@ export default function UserActionMenuOptionsOptions(
723
716
  items.push(...customItems);
724
717
  }
725
718
 
726
- if (extraMenuItems?.length) {
727
- items.push(
728
- ...extraMenuItems.map(item => ({
729
- ...item,
730
- closeActionMenu: () => {
731
- item.closeActionMenu?.();
732
- setActionMenuVisible(false);
733
- },
734
- onPress: item.onPress
735
- ? () => {
736
- item.onPress?.();
737
- setActionMenuVisible(false);
738
- }
739
- : item.onPress,
740
- })),
741
- );
742
- }
743
-
744
719
  items.sort((a, b) => (a.order ?? 999) - (b.order ?? 999));
745
720
 
746
721
  setActionMenuitems(items);
@@ -754,8 +729,6 @@ export default function UserActionMenuOptionsOptions(
754
729
  secondaryPinnedUid,
755
730
  currentLayout,
756
731
  spotlightUid,
757
- extraMenuItems,
758
- setActionMenuVisible,
759
732
  ]);
760
733
 
761
734
  const {width: globalWidth, height: globalHeight} = useWindowDimensions();
@@ -0,0 +1,48 @@
1
+ const mockDatadogLog = jest.fn();
2
+
3
+ jest.mock('@datadog/browser-logs', () => ({
4
+ datadogLogs: {
5
+ init: jest.fn(),
6
+ logger: {log: mockDatadogLog},
7
+ },
8
+ }));
9
+
10
+ const {getTransportLogger} = jest.requireActual('../agora-transport.ts');
11
+
12
+ describe('Agora Datadog transport structured content', () => {
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ });
16
+
17
+ it('emits screen-share journey fields as an object that Datadog can filter', () => {
18
+ const transport = getTransportLogger();
19
+ const journey = {
20
+ screenshareSessionId: 'screen-session-1',
21
+ screenshareAttemptId: 'attempt-1',
22
+ action: 'start',
23
+ };
24
+
25
+ transport('[SCREENSHARE_JOURNEY] start', 'info', {}, {}, [journey]);
26
+
27
+ expect(mockDatadogLog).toHaveBeenCalledWith(
28
+ '[SCREENSHARE_JOURNEY] start',
29
+ expect.objectContaining({logContent: journey}),
30
+ 'info',
31
+ undefined,
32
+ );
33
+ });
34
+
35
+ it('preserves the existing array shape for unrelated logs', () => {
36
+ const transport = getTransportLogger();
37
+ const content = [{value: 'unchanged'}];
38
+
39
+ transport('other log', 'info', {}, {}, content);
40
+
41
+ expect(mockDatadogLog).toHaveBeenCalledWith(
42
+ 'other log',
43
+ expect.objectContaining({logContent: content}),
44
+ 'info',
45
+ undefined,
46
+ );
47
+ });
48
+ });
@@ -22,15 +22,27 @@ export const getTransportLogger = () => {
22
22
  contextInfo: Object,
23
23
  logContent: any[],
24
24
  ) => {
25
+ const primaryLogContent =
26
+ logContent?.length === 1 &&
27
+ logContent[0] &&
28
+ typeof logContent[0] === 'object'
29
+ ? logContent[0]
30
+ : undefined;
31
+ const datadogLogContent = primaryLogContent?.screenshareSessionId
32
+ ? primaryLogContent
33
+ : logContent;
34
+
25
35
  datadogLogs.logger.log(
26
36
  logMessage,
27
- {...columns, logMessage, logType, contextInfo, logContent},
37
+ {
38
+ ...columns,
39
+ logMessage,
40
+ logType,
41
+ contextInfo,
42
+ logContent: datadogLogContent,
43
+ },
28
44
  logType,
29
- logType === 'error'
30
- ? logContent?.length
31
- ? logContent[0]
32
- : undefined
33
- : undefined,
45
+ logType === 'error' ? primaryLogContent : undefined,
34
46
  );
35
47
  };
36
48
  };