@webex/plugin-meetings 3.6.0-next.11 → 3.6.0-next.13

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 (63) hide show
  1. package/README.md +2 -1
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.js +24 -2
  5. package/dist/constants.js.map +1 -1
  6. package/dist/controls-options-manager/enums.js +1 -0
  7. package/dist/controls-options-manager/enums.js.map +1 -1
  8. package/dist/controls-options-manager/index.js +10 -3
  9. package/dist/controls-options-manager/index.js.map +1 -1
  10. package/dist/controls-options-manager/types.js.map +1 -1
  11. package/dist/controls-options-manager/util.js +12 -0
  12. package/dist/controls-options-manager/util.js.map +1 -1
  13. package/dist/interpretation/index.js +1 -1
  14. package/dist/interpretation/siLanguage.js +1 -1
  15. package/dist/locus-info/controlsUtils.js +28 -4
  16. package/dist/locus-info/controlsUtils.js.map +1 -1
  17. package/dist/locus-info/fullState.js +2 -1
  18. package/dist/locus-info/fullState.js.map +1 -1
  19. package/dist/locus-info/index.js +61 -3
  20. package/dist/locus-info/index.js.map +1 -1
  21. package/dist/meeting/in-meeting-actions.js +19 -1
  22. package/dist/meeting/in-meeting-actions.js.map +1 -1
  23. package/dist/meeting/index.js +366 -277
  24. package/dist/meeting/index.js.map +1 -1
  25. package/dist/members/index.js +3 -2
  26. package/dist/members/index.js.map +1 -1
  27. package/dist/members/util.js +9 -5
  28. package/dist/members/util.js.map +1 -1
  29. package/dist/types/constants.d.ts +19 -0
  30. package/dist/types/controls-options-manager/enums.d.ts +2 -1
  31. package/dist/types/controls-options-manager/index.d.ts +2 -1
  32. package/dist/types/controls-options-manager/types.d.ts +2 -0
  33. package/dist/types/locus-info/index.d.ts +9 -0
  34. package/dist/types/meeting/in-meeting-actions.d.ts +18 -0
  35. package/dist/types/meeting/index.d.ts +11 -1
  36. package/dist/types/members/index.d.ts +2 -1
  37. package/dist/types/members/util.d.ts +3 -1
  38. package/dist/webinar/index.js +32 -19
  39. package/dist/webinar/index.js.map +1 -1
  40. package/package.json +10 -10
  41. package/src/constants.ts +25 -0
  42. package/src/controls-options-manager/enums.ts +1 -0
  43. package/src/controls-options-manager/index.ts +19 -2
  44. package/src/controls-options-manager/types.ts +2 -0
  45. package/src/controls-options-manager/util.ts +12 -0
  46. package/src/locus-info/controlsUtils.ts +46 -2
  47. package/src/locus-info/fullState.ts +1 -0
  48. package/src/locus-info/index.ts +60 -0
  49. package/src/meeting/in-meeting-actions.ts +37 -0
  50. package/src/meeting/index.ts +93 -7
  51. package/src/members/index.ts +4 -2
  52. package/src/members/util.ts +3 -1
  53. package/src/webinar/index.ts +31 -17
  54. package/test/unit/spec/controls-options-manager/index.js +56 -32
  55. package/test/unit/spec/controls-options-manager/util.js +44 -0
  56. package/test/unit/spec/locus-info/controlsUtils.js +80 -4
  57. package/test/unit/spec/locus-info/index.js +59 -2
  58. package/test/unit/spec/meeting/in-meeting-actions.ts +18 -0
  59. package/test/unit/spec/meeting/index.js +100 -16
  60. package/test/unit/spec/members/index.js +25 -2
  61. package/test/unit/spec/members/request.js +37 -3
  62. package/test/unit/spec/members/utils.js +15 -1
  63. package/test/unit/spec/webinar/index.ts +82 -16
@@ -2014,6 +2014,7 @@ export default class Meeting extends StatelessWebexPlugin {
2014
2014
  this.setUpLocusInfoSelfListener();
2015
2015
  this.setUpLocusInfoMeetingListener();
2016
2016
  this.setUpLocusServicesListener();
2017
+ this.setUpLocusResourcesListener();
2017
2018
  // members update listeners
2018
2019
  this.setUpLocusFullStateListener();
2019
2020
  this.setUpLocusUrlListener();
@@ -2635,6 +2636,42 @@ export default class Meeting extends StatelessWebexPlugin {
2635
2636
  );
2636
2637
  });
2637
2638
 
2639
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED, ({state}) => {
2640
+ Trigger.trigger(
2641
+ this,
2642
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2643
+ EVENT_TRIGGERS.MEETING_CONTROLS_WEBCAST_UPDATED,
2644
+ {state}
2645
+ );
2646
+ });
2647
+
2648
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_FULL_CHANGED, ({state}) => {
2649
+ Trigger.trigger(
2650
+ this,
2651
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2652
+ EVENT_TRIGGERS.MEETING_CONTROLS_MEETING_FULL_UPDATED,
2653
+ {state}
2654
+ );
2655
+ });
2656
+
2657
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_PRACTICE_SESSION_STATUS_UPDATED, ({state}) => {
2658
+ Trigger.trigger(
2659
+ this,
2660
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2661
+ EVENT_TRIGGERS.MEETING_CONTROLS_PRACTICE_SESSION_STATUS_UPDATED,
2662
+ {state}
2663
+ );
2664
+ });
2665
+
2666
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_STAGE_VIEW_UPDATED, ({state}) => {
2667
+ Trigger.trigger(
2668
+ this,
2669
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2670
+ EVENT_TRIGGERS.MEETING_CONTROLS_STAGE_VIEW_UPDATED,
2671
+ {state}
2672
+ );
2673
+ });
2674
+
2638
2675
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_VIDEO_CHANGED, ({state}) => {
2639
2676
  Trigger.trigger(
2640
2677
  this,
@@ -2996,10 +3033,20 @@ export default class Meeting extends StatelessWebexPlugin {
2996
3033
  this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
2997
3034
  this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
2998
3035
  this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
2999
- this.webinar.webcastUrlUpdate(payload?.services?.webcast?.url);
3000
- this.webinar.webinarAttendeesSearchingUrlUpdate(
3001
- payload?.services?.webinarAttendeesSearching?.url
3002
- );
3036
+ });
3037
+ }
3038
+
3039
+ /**
3040
+ * Set up the locus info resources link listener
3041
+ * update the locusInfo for webcast instance url
3042
+ * @param {Object} payload - The event payload
3043
+ * @returns {undefined}
3044
+ * @private
3045
+ * @memberof Meeting
3046
+ */
3047
+ private setUpLocusResourcesListener() {
3048
+ this.locusInfo.on(LOCUSINFO.EVENTS.LINKS_RESOURCES, (payload) => {
3049
+ this.webinar.updateWebcastUrl(payload);
3003
3050
  });
3004
3051
  }
3005
3052
 
@@ -3311,7 +3358,7 @@ export default class Meeting extends StatelessWebexPlugin {
3311
3358
  this.simultaneousInterpretation.updateCanManageInterpreters(
3312
3359
  payload.newRoles?.includes(SELF_ROLES.MODERATOR)
3313
3360
  );
3314
- this.webinar.updateCanManageWebcast(payload.newRoles?.includes(SELF_ROLES.MODERATOR));
3361
+ this.webinar.updateRoleChanged(payload);
3315
3362
  Trigger.trigger(
3316
3363
  this,
3317
3364
  {
@@ -3805,6 +3852,22 @@ export default class Meeting extends StatelessWebexPlugin {
3805
3852
  requiredHints: [DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST],
3806
3853
  displayHints: this.userDisplayHints,
3807
3854
  }),
3855
+ canEnableViewTheParticipantsListPanelist: ControlsOptionsUtil.hasHints({
3856
+ requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST],
3857
+ displayHints: this.userDisplayHints,
3858
+ }),
3859
+ canDisableViewTheParticipantsListPanelist: ControlsOptionsUtil.hasHints({
3860
+ requiredHints: [DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST],
3861
+ displayHints: this.userDisplayHints,
3862
+ }),
3863
+ canEnableShowAttendeeCount: ControlsOptionsUtil.hasHints({
3864
+ requiredHints: [DISPLAY_HINTS.ENABLE_SHOW_ATTENDEE_COUNT],
3865
+ displayHints: this.userDisplayHints,
3866
+ }),
3867
+ canDisableShowAttendeeCount: ControlsOptionsUtil.hasHints({
3868
+ requiredHints: [DISPLAY_HINTS.DISABLE_SHOW_ATTENDEE_COUNT],
3869
+ displayHints: this.userDisplayHints,
3870
+ }),
3808
3871
  canEnableRaiseHand: ControlsOptionsUtil.hasHints({
3809
3872
  requiredHints: [DISPLAY_HINTS.ENABLE_RAISE_HAND],
3810
3873
  displayHints: this.userDisplayHints,
@@ -3821,6 +3884,26 @@ export default class Meeting extends StatelessWebexPlugin {
3821
3884
  requiredHints: [DISPLAY_HINTS.DISABLE_VIDEO],
3822
3885
  displayHints: this.userDisplayHints,
3823
3886
  }),
3887
+ canStartWebcast: ControlsOptionsUtil.hasHints({
3888
+ requiredHints: [DISPLAY_HINTS.WEBCAST_CONTROL_START],
3889
+ displayHints: this.userDisplayHints,
3890
+ }),
3891
+ canStopWebcast: ControlsOptionsUtil.hasHints({
3892
+ requiredHints: [DISPLAY_HINTS.WEBCAST_CONTROL_STOP],
3893
+ displayHints: this.userDisplayHints,
3894
+ }),
3895
+ canShowStageView: ControlsOptionsUtil.hasHints({
3896
+ requiredHints: [DISPLAY_HINTS.STAGE_VIEW_ACTIVE],
3897
+ displayHints: this.userDisplayHints,
3898
+ }),
3899
+ canEnableStageView: ControlsOptionsUtil.hasHints({
3900
+ requiredHints: [DISPLAY_HINTS.ENABLE_STAGE_VIEW],
3901
+ displayHints: this.userDisplayHints,
3902
+ }),
3903
+ canDisableStageView: ControlsOptionsUtil.hasHints({
3904
+ requiredHints: [DISPLAY_HINTS.DISABLE_STAGE_VIEW],
3905
+ displayHints: this.userDisplayHints,
3906
+ }),
3824
3907
  canShareFile:
3825
3908
  (ControlsOptionsUtil.hasHints({
3826
3909
  requiredHints: [DISPLAY_HINTS.SHARE_FILE],
@@ -7927,18 +8010,21 @@ export default class Meeting extends StatelessWebexPlugin {
7927
8010
  * @param {boolean} mutedEnabled
7928
8011
  * @param {boolean} disallowUnmuteEnabled
7929
8012
  * @param {boolean} muteOnEntryEnabled
8013
+ * @param {array} roles
7930
8014
  * @public
7931
8015
  * @memberof Meeting
7932
8016
  */
7933
8017
  public setMuteAll(
7934
8018
  mutedEnabled: boolean,
7935
8019
  disallowUnmuteEnabled: boolean,
7936
- muteOnEntryEnabled: boolean
8020
+ muteOnEntryEnabled: boolean,
8021
+ roles: Array<string>
7937
8022
  ) {
7938
8023
  return this.controlsOptionsManager.setMuteAll(
7939
8024
  mutedEnabled,
7940
8025
  disallowUnmuteEnabled,
7941
- muteOnEntryEnabled
8026
+ muteOnEntryEnabled,
8027
+ roles
7942
8028
  );
7943
8029
  }
7944
8030
 
@@ -915,11 +915,12 @@ export default class Members extends StatelessWebexPlugin {
915
915
  /**
916
916
  * Lower all hands of members in a meeting
917
917
  * @param {String} requestingMemberId - id of the participant which requested the lower all hands
918
+ * @param {array} roles which should be lowered
918
919
  * @returns {Promise}
919
920
  * @public
920
921
  * @memberof Members
921
922
  */
922
- public lowerAllHands(requestingMemberId: string) {
923
+ public lowerAllHands(requestingMemberId: string, roles: Array<string>) {
923
924
  if (!this.locusUrl) {
924
925
  return Promise.reject(
925
926
  new ParameterError(
@@ -936,7 +937,8 @@ export default class Members extends StatelessWebexPlugin {
936
937
  }
937
938
  const options = MembersUtil.generateLowerAllHandsMemberOptions(
938
939
  requestingMemberId,
939
- this.locusUrl
940
+ this.locusUrl,
941
+ roles
940
942
  );
941
943
 
942
944
  return this.membersRequest.lowerAllHandsMember(options);
@@ -166,9 +166,10 @@ const MembersUtil = {
166
166
  locusUrl,
167
167
  }),
168
168
 
169
- generateLowerAllHandsMemberOptions: (requestingParticipantId, locusUrl) => ({
169
+ generateLowerAllHandsMemberOptions: (requestingParticipantId, locusUrl, roles) => ({
170
170
  requestingParticipantId,
171
171
  locusUrl,
172
+ ...(roles !== undefined && {roles}),
172
173
  }),
173
174
 
174
175
  /**
@@ -253,6 +254,7 @@ const MembersUtil = {
253
254
  const body = {
254
255
  hand: {
255
256
  raised: false,
257
+ ...(options.roles !== undefined && {roles: options.roles}),
256
258
  },
257
259
  requestingParticipantId: options.requestingParticipantId,
258
260
  };
@@ -2,7 +2,8 @@
2
2
  * Copyright (c) 2015-2023 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
4
  import {WebexPlugin} from '@webex/webex-core';
5
- import {MEETINGS} from '../constants';
5
+ import {get} from 'lodash';
6
+ import {MEETINGS, SELF_ROLES} from '../constants';
6
7
 
7
8
  import WebinarCollection from './collection';
8
9
 
@@ -17,14 +18,15 @@ const Webinar = WebexPlugin.extend({
17
18
 
18
19
  props: {
19
20
  locusUrl: 'string', // appears current webinar's locus url
20
- webcastUrl: 'string', // current webinar's webcast url
21
- webinarAttendeesSearchingUrl: 'string', // current webinarAttendeesSearching url
21
+ webcastInstanceUrl: 'string', // current webinar's webcast instance url
22
22
  canManageWebcast: 'boolean', // appears the ability to manage webcast
23
+ selfIsPanelist: 'boolean', // self is panelist
24
+ selfIsAttendee: 'boolean', // self is attendee
23
25
  },
24
26
 
25
27
  /**
26
28
  * Update the current locus url of the webinar
27
- * @param {string} locusUrl // locus url
29
+ * @param {string} locusUrl
28
30
  * @returns {void}
29
31
  */
30
32
  locusUrlUpdate(locusUrl) {
@@ -32,21 +34,12 @@ const Webinar = WebexPlugin.extend({
32
34
  },
33
35
 
34
36
  /**
35
- * Update the current webcast url of the meeting
36
- * @param {string} webcastUrl // webcast url
37
+ * Update the current webcast instance url of the meeting
38
+ * @param {object} payload
37
39
  * @returns {void}
38
40
  */
39
- webcastUrlUpdate(webcastUrl) {
40
- this.set('webcastUrl', webcastUrl);
41
- },
42
-
43
- /**
44
- * Update the current webinarAttendeesSearching url of the meeting
45
- * @param {string} webinarAttendeesSearchingUrl // webinarAttendeesSearching url
46
- * @returns {void}
47
- */
48
- webinarAttendeesSearchingUrlUpdate(webinarAttendeesSearchingUrl) {
49
- this.set('webinarAttendeesSearchingUrl', webinarAttendeesSearchingUrl);
41
+ updateWebcastUrl(payload) {
42
+ this.set('webcastInstanceUrl', get(payload, 'resources.webcastInstance.url'));
50
43
  },
51
44
 
52
45
  /**
@@ -57,6 +50,27 @@ const Webinar = WebexPlugin.extend({
57
50
  updateCanManageWebcast(canManageWebcast) {
58
51
  this.set('canManageWebcast', canManageWebcast);
59
52
  },
53
+
54
+ /**
55
+ * Updates user roles and manages associated state transitions
56
+ * @param {object} payload
57
+ * @param {string[]} payload.oldRoles - Previous roles of the user
58
+ * @param {string[]} payload.newRoles - New roles of the user
59
+ * @returns {{isPromoted: boolean, isDemoted: boolean}} Role transition states
60
+ */
61
+ updateRoleChanged(payload) {
62
+ const isPromoted =
63
+ get(payload, 'oldRoles', []).includes(SELF_ROLES.ATTENDEE) &&
64
+ get(payload, 'newRoles', []).includes(SELF_ROLES.PANELIST);
65
+ const isDemoted =
66
+ get(payload, 'oldRoles', []).includes(SELF_ROLES.PANELIST) &&
67
+ get(payload, 'newRoles', []).includes(SELF_ROLES.ATTENDEE);
68
+ this.set('selfIsPanelist', get(payload, 'newRoles', []).includes(SELF_ROLES.PANELIST));
69
+ this.set('selfIsAttendee', get(payload, 'newRoles', []).includes(SELF_ROLES.ATTENDEE));
70
+ this.updateCanManageWebcast(get(payload, 'newRoles', []).includes(SELF_ROLES.MODERATOR));
71
+
72
+ return {isPromoted, isDemoted};
73
+ },
60
74
  });
61
75
 
62
76
  export default Webinar;
@@ -22,7 +22,7 @@ describe('plugin-meetings', () => {
22
22
 
23
23
  describe('Mute On Entry', () => {
24
24
  let manager;
25
-
25
+
26
26
  beforeEach(() => {
27
27
  request = {
28
28
  request: sinon.stub().returns(Promise.resolve()),
@@ -37,85 +37,85 @@ describe('plugin-meetings', () => {
37
37
  });
38
38
 
39
39
  describe('setMuteOnEntry', () => {
40
- it('rejects when correct display hint is not present enabled=false', () => {
40
+ it('rejects when correct display hint is not present enabled=false', () => {
41
41
  const result = manager.setMuteOnEntry(false);
42
-
42
+
43
43
  assert.notCalled(request.request);
44
-
44
+
45
45
  assert.isRejected(result);
46
46
  });
47
47
 
48
- it('rejects when correct display hint is not present enabled=true', () => {
48
+ it('rejects when correct display hint is not present enabled=true', () => {
49
49
  const result = manager.setMuteOnEntry(true);
50
-
50
+
51
51
  assert.notCalled(request.request);
52
-
52
+
53
53
  assert.isRejected(result);
54
54
  });
55
-
55
+
56
56
  it('can set mute on entry when the display hint is available enabled=true', () => {
57
57
  manager.setDisplayHints(['ENABLE_MUTE_ON_ENTRY']);
58
-
58
+
59
59
  const result = manager.setMuteOnEntry(true);
60
-
60
+
61
61
  assert.calledWith(request.request, { uri: 'test/id/controls',
62
62
  body: { muteOnEntry: { enabled: true } },
63
63
  method: HTTP_VERBS.PATCH});
64
-
64
+
65
65
  assert.deepEqual(result, request.request.firstCall.returnValue);
66
66
  });
67
67
 
68
68
  it('can set mute on entry when the display hint is available enabled=false', () => {
69
69
  manager.setDisplayHints(['DISABLE_MUTE_ON_ENTRY']);
70
-
70
+
71
71
  const result = manager.setMuteOnEntry(false);
72
-
72
+
73
73
  assert.calledWith(request.request, { uri: 'test/id/controls',
74
74
  body: { muteOnEntry: { enabled: false } },
75
75
  method: HTTP_VERBS.PATCH});
76
-
76
+
77
77
  assert.deepEqual(result, request.request.firstCall.returnValue);
78
78
  });
79
79
  });
80
80
 
81
81
  describe('setDisallowUnmute', () => {
82
- it('rejects when correct display hint is not present enabled=false', () => {
82
+ it('rejects when correct display hint is not present enabled=false', () => {
83
83
  const result = manager.setDisallowUnmute(false);
84
-
84
+
85
85
  assert.notCalled(request.request);
86
-
86
+
87
87
  assert.isRejected(result);
88
88
  });
89
89
 
90
- it('rejects when correct display hint is not present enabled=true', () => {
90
+ it('rejects when correct display hint is not present enabled=true', () => {
91
91
  const result = manager.setDisallowUnmute(true);
92
-
92
+
93
93
  assert.notCalled(request.request);
94
-
94
+
95
95
  assert.isRejected(result);
96
96
  });
97
-
98
- it('can set mute on entry when the display hint is available enabled=true', () => {
97
+
98
+ it('can set disallow unmute when ENABLE_HARD_MUTE display hint is available', () => {
99
99
  manager.setDisplayHints(['ENABLE_HARD_MUTE']);
100
-
100
+
101
101
  const result = manager.setDisallowUnmute(true);
102
-
102
+
103
103
  assert.calledWith(request.request, { uri: 'test/id/controls',
104
104
  body: { disallowUnmute: { enabled: true } },
105
105
  method: HTTP_VERBS.PATCH});
106
-
106
+
107
107
  assert.deepEqual(result, request.request.firstCall.returnValue);
108
108
  });
109
109
 
110
- it('can set mute on entry when the display hint is available enabled=false', () => {
110
+ it('can set allow unmute when DISABLE_HARD_MUTE display hint is available', () => {
111
111
  manager.setDisplayHints(['DISABLE_HARD_MUTE']);
112
-
112
+
113
113
  const result = manager.setDisallowUnmute(false);
114
-
114
+
115
115
  assert.calledWith(request.request, { uri: 'test/id/controls',
116
116
  body: { disallowUnmute: { enabled: false } },
117
117
  method: HTTP_VERBS.PATCH});
118
-
118
+
119
119
  assert.deepEqual(result, request.request.firstCall.returnValue);
120
120
  });
121
121
  });
@@ -218,7 +218,7 @@ describe('plugin-meetings', () => {
218
218
  })
219
219
  });
220
220
 
221
- it('rejects when correct display hint is not present mutedEnabled=false', () => {
221
+ it('rejects when correct display hint is not present mutedEnabled=false', () => {
222
222
  const result = manager.setMuteAll(false, false, false);
223
223
 
224
224
  assert.notCalled(request.request);
@@ -226,7 +226,7 @@ describe('plugin-meetings', () => {
226
226
  assert.isRejected(result);
227
227
  });
228
228
 
229
- it('rejects when correct display hint is not present mutedEnabled=true', () => {
229
+ it('rejects when correct display hint is not present mutedEnabled=true', () => {
230
230
  const result = manager.setMuteAll(true, false, false);
231
231
 
232
232
  assert.notCalled(request.request);
@@ -281,7 +281,31 @@ describe('plugin-meetings', () => {
281
281
 
282
282
  assert.deepEqual(result, request.request.firstCall.returnValue);
283
283
  });
284
+
285
+ it('can set mute all panelists when the display hint is available mutedEnabled=true', () => {
286
+ manager.setDisplayHints(['MUTE_ALL', 'DISABLE_HARD_MUTE', 'DISABLE_MUTE_ON_ENTRY']);
287
+
288
+ const result = manager.setMuteAll(true, true, true, ['panelist']);
289
+
290
+ assert.calledWith(request.request, { uri: 'test/id/controls',
291
+ body: { audio: { muted: true, disallowUnmute: true, muteOnEntry: true, roles: ['panelist'] } },
292
+ method: HTTP_VERBS.PATCH});
293
+
294
+ assert.deepEqual(result, request.request.firstCall.returnValue);
295
+ });
296
+
297
+ it('can set mute all attendees when the display hint is available mutedEnabled=true', () => {
298
+ manager.setDisplayHints(['MUTE_ALL', 'DISABLE_HARD_MUTE', 'DISABLE_MUTE_ON_ENTRY']);
299
+
300
+ const result = manager.setMuteAll(true, true, true, ['attendee']);
301
+
302
+ assert.calledWith(request.request, { uri: 'test/id/controls',
303
+ body: { audio: { muted: true, disallowUnmute: true, muteOnEntry: true, roles: ['attendee'] } },
304
+ method: HTTP_VERBS.PATCH});
305
+
306
+ assert.deepEqual(result, request.request.firstCall.returnValue);
307
+ });
284
308
  });
285
309
  });
286
310
  });
287
- });
311
+ });
@@ -348,6 +348,50 @@ describe('plugin-meetings', () => {
348
348
  });
349
349
  });
350
350
 
351
+ it('should call hasHints() with proper hints when `panelistEnabled` is true, attendeeCount is false', () => {
352
+ ControlsOptionsUtil.canUpdateViewTheParticipantsList({properties: {enabled: true, panelistEnabled: true, attendeeCount: false}}, []);
353
+
354
+ assert.calledWith(ControlsOptionsUtil.hasHints, {
355
+ requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST,
356
+ DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST,
357
+ DISPLAY_HINTS.DISABLE_SHOW_ATTENDEE_COUNT],
358
+ displayHints: [],
359
+ });
360
+ });
361
+
362
+ it('should call hasHints() with proper hints when `panelistEnabled` is true, attendeeCount is true', () => {
363
+ ControlsOptionsUtil.canUpdateViewTheParticipantsList({properties: {enabled: true, panelistEnabled: true, attendeeCount: true}}, []);
364
+
365
+ assert.calledWith(ControlsOptionsUtil.hasHints, {
366
+ requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST,
367
+ DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST,
368
+ DISPLAY_HINTS.ENABLE_SHOW_ATTENDEE_COUNT],
369
+ displayHints: [],
370
+ });
371
+ });
372
+
373
+ it('should call hasHints() with proper hints when `panelistEnabled` is false, attendeeCount is false', () => {
374
+ ControlsOptionsUtil.canUpdateViewTheParticipantsList({properties: {enabled: true, panelistEnabled: false, attendeeCount: false}}, []);
375
+
376
+ assert.calledWith(ControlsOptionsUtil.hasHints, {
377
+ requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST,
378
+ DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST,
379
+ DISPLAY_HINTS.DISABLE_SHOW_ATTENDEE_COUNT],
380
+ displayHints: [],
381
+ });
382
+ });
383
+
384
+ it('should call hasHints() with proper hints when `panelistEnabled` is false, attendeeCount is true', () => {
385
+ ControlsOptionsUtil.canUpdateViewTheParticipantsList({properties: {enabled: true, panelistEnabled: false, attendeeCount: true}}, []);
386
+
387
+ assert.calledWith(ControlsOptionsUtil.hasHints, {
388
+ requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST,
389
+ DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST,
390
+ DISPLAY_HINTS.ENABLE_SHOW_ATTENDEE_COUNT],
391
+ displayHints: [],
392
+ });
393
+ });
394
+
351
395
  it('should return the resolution of hasHints()', () => {
352
396
  const expected = 'example-return-value';
353
397
  ControlsOptionsUtil.hasHints.returns(expected);
@@ -82,11 +82,13 @@ describe('plugin-meetings', () => {
82
82
  });
83
83
 
84
84
  it('should parse the viewTheParticipantList control', () => {
85
- const newControls = {viewTheParticipantList: {enabled: true}};
85
+ const newControls = {viewTheParticipantList: {enabled: true, panelistEnabled: true, attendeeCount: false}};
86
86
 
87
87
  const parsedControls = ControlsUtils.parse(newControls);
88
88
 
89
89
  assert.equal(parsedControls.viewTheParticipantList.enabled, newControls.viewTheParticipantList.enabled);
90
+ assert.equal(parsedControls.viewTheParticipantList.panelistEnabled, newControls.viewTheParticipantList.panelistEnabled);
91
+ assert.equal(parsedControls.viewTheParticipantList.attendeeCount, newControls.viewTheParticipantList.attendeeCount);
90
92
  });
91
93
 
92
94
  it('should parse the raiseHand control', () => {
@@ -105,6 +107,42 @@ describe('plugin-meetings', () => {
105
107
  assert.equal(parsedControls.video.enabled, newControls.video.enabled);
106
108
  });
107
109
 
110
+ it('should parse the webcast control', () => {
111
+ const newControls = {webcastControl: {streaming: true}};
112
+
113
+ const parsedControls = ControlsUtils.parse(newControls);
114
+
115
+ assert.equal(parsedControls.webcastControl.streaming, newControls.webcastControl.streaming);
116
+ });
117
+
118
+ it('should parse the meeting full control', () => {
119
+ const newControls = {meetingFull: {meetingFull: true, meetingPanelistFull: false}};
120
+
121
+ const parsedControls = ControlsUtils.parse(newControls);
122
+
123
+ assert.equal(parsedControls.meetingFull.meetingFull, newControls.meetingFull.meetingFull);
124
+ assert.equal(parsedControls.meetingFull.meetingPanelistFull, newControls.meetingFull.meetingPanelistFull);
125
+ });
126
+
127
+ it('should parse the practiceSession control', () => {
128
+ const newControls = {practiceSession: {enabled: true}};
129
+
130
+ const parsedControls = ControlsUtils.parse(newControls);
131
+
132
+ assert.equal(parsedControls.practiceSession.enabled, newControls.practiceSession.enabled);
133
+ });
134
+
135
+ it('should parse the videoLayout control', () => {
136
+ const newControls = {videoLayout: {overrideDefault: true, lockAttendeeViewOnStageOnly:false, stageParameters: {}}};
137
+
138
+ const parsedControls = ControlsUtils.parse(newControls);
139
+
140
+ assert.equal(parsedControls.videoLayout.overrideDefault, newControls.videoLayout.overrideDefault);
141
+ assert.equal(parsedControls.videoLayout.lockAttendeeViewOnStageOnly, newControls.videoLayout.lockAttendeeViewOnStageOnly);
142
+ assert.equal(parsedControls.videoLayout.stageParameters, newControls.videoLayout.stageParameters);
143
+
144
+ });
145
+
108
146
  describe('videoEnabled', () => {
109
147
  it('returns expected', () => {
110
148
  const result = ControlsUtils.parse({video: {enabled: true}});
@@ -170,11 +208,21 @@ describe('plugin-meetings', () => {
170
208
  });
171
209
 
172
210
  it('returns hasViewTheParticipantListChanged = true when changed', () => {
173
- const newControls = {viewTheParticipantList: {enabled: true}};
211
+ const oldControls = {viewTheParticipantList: {enabled: true, panelistEnabled: true, attendeeCount: false}};
174
212
 
175
- const {updates} = ControlsUtils.getControls(defaultControls, newControls);
213
+ let result = ControlsUtils.getControls(oldControls, {viewTheParticipantList: {enabled: false, panelistEnabled: true, attendeeCount: false}});
214
+
215
+ assert.equal(result.updates.hasViewTheParticipantListChanged, true);
216
+
217
+ result = ControlsUtils.getControls(oldControls, {viewTheParticipantList: {enabled: true, panelistEnabled: false, attendeeCount: false}});
176
218
 
177
- assert.equal(updates.hasViewTheParticipantListChanged, true);
219
+ assert.equal(result.updates.hasViewTheParticipantListChanged, true);
220
+ result = ControlsUtils.getControls(oldControls, {viewTheParticipantList: {enabled: true, panelistEnabled: true, attendeeCount: true}});
221
+
222
+ assert.equal(result.updates.hasViewTheParticipantListChanged, true);
223
+ result = ControlsUtils.getControls(oldControls, {viewTheParticipantList: {enabled: true, panelistEnabled: true, attendeeCount: false}});
224
+
225
+ assert.equal(result.updates.hasViewTheParticipantListChanged, false);
178
226
  });
179
227
 
180
228
  it('returns hasRaiseHandChanged = true when changed', () => {
@@ -193,6 +241,34 @@ describe('plugin-meetings', () => {
193
241
  assert.equal(updates.hasVideoChanged, true);
194
242
  });
195
243
 
244
+ it('returns hasWebcastChanged = true when changed', () => {
245
+ const newControls = {webcastControl: {streaming: true}};
246
+
247
+ const {updates} = ControlsUtils.getControls(defaultControls, newControls);
248
+
249
+ assert.equal(updates.hasWebcastChanged, true);
250
+ });
251
+
252
+ it('returns hasMeetingFullChanged = true when changed', () => {
253
+ const newControls = {meetingFull: {meetingFull: true, meetingPanelistFull: false}};
254
+
255
+ let result = ControlsUtils.getControls(defaultControls, newControls);
256
+
257
+ assert.equal(result.updates.hasMeetingFullChanged, true);
258
+
259
+ result = ControlsUtils.getControls(newControls, {meetingFull: {meetingFull: true, meetingPanelistFull: true}});
260
+
261
+ assert.equal(result.updates.hasMeetingFullChanged, true);
262
+ });
263
+
264
+ it('returns hasPracticeSessionEnabledChanged = true when changed', () => {
265
+ const newControls = {practiceSession: {enabled: true}};
266
+
267
+ const {updates} = ControlsUtils.getControls(defaultControls, newControls);
268
+
269
+ assert.equal(updates.hasPracticeSessionEnabledChanged, true);
270
+ });
271
+
196
272
  it('returns hasEntryExitToneChanged = true when mode changed', () => {
197
273
  const newControls = {
198
274
  entryExitTone: {