@webex/plugin-meetings 3.0.0-beta.202 → 3.0.0-beta.203

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.
@@ -746,6 +746,11 @@ export default class Meeting extends StatelessWebexPlugin {
746
746
  owner: object;
747
747
  };
748
748
  } | any, destination?: object | string | null): void;
749
+ /**
750
+ * Indicates whether policy can be applied
751
+ * @returns {boolean}
752
+ */
753
+ private arePolicyRestrictionsSupported;
749
754
  /**
750
755
  * Updates the meeting actions (display hints), depends on locus display hints, user policy and app api info
751
756
  * @returns {undefined}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.202",
3
+ "version": "3.0.0-beta.203",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -32,12 +32,12 @@
32
32
  "build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
33
33
  },
34
34
  "devDependencies": {
35
- "@webex/plugin-meetings": "3.0.0-beta.202",
36
- "@webex/test-helper-chai": "3.0.0-beta.202",
37
- "@webex/test-helper-mocha": "3.0.0-beta.202",
38
- "@webex/test-helper-mock-webex": "3.0.0-beta.202",
39
- "@webex/test-helper-retry": "3.0.0-beta.202",
40
- "@webex/test-helper-test-users": "3.0.0-beta.202",
35
+ "@webex/plugin-meetings": "3.0.0-beta.203",
36
+ "@webex/test-helper-chai": "3.0.0-beta.203",
37
+ "@webex/test-helper-mocha": "3.0.0-beta.203",
38
+ "@webex/test-helper-mock-webex": "3.0.0-beta.203",
39
+ "@webex/test-helper-retry": "3.0.0-beta.203",
40
+ "@webex/test-helper-test-users": "3.0.0-beta.203",
41
41
  "chai": "^4.3.4",
42
42
  "chai-as-promised": "^7.1.1",
43
43
  "jsdom-global": "3.0.2",
@@ -46,19 +46,19 @@
46
46
  "typescript": "^4.7.4"
47
47
  },
48
48
  "dependencies": {
49
- "@webex/common": "3.0.0-beta.202",
49
+ "@webex/common": "3.0.0-beta.203",
50
50
  "@webex/internal-media-core": "1.39.1",
51
- "@webex/internal-plugin-conversation": "3.0.0-beta.202",
52
- "@webex/internal-plugin-device": "3.0.0-beta.202",
53
- "@webex/internal-plugin-llm": "3.0.0-beta.202",
54
- "@webex/internal-plugin-mercury": "3.0.0-beta.202",
55
- "@webex/internal-plugin-metrics": "3.0.0-beta.202",
56
- "@webex/internal-plugin-support": "3.0.0-beta.202",
57
- "@webex/internal-plugin-user": "3.0.0-beta.202",
58
- "@webex/media-helpers": "3.0.0-beta.202",
59
- "@webex/plugin-people": "3.0.0-beta.202",
60
- "@webex/plugin-rooms": "3.0.0-beta.202",
61
- "@webex/webex-core": "3.0.0-beta.202",
51
+ "@webex/internal-plugin-conversation": "3.0.0-beta.203",
52
+ "@webex/internal-plugin-device": "3.0.0-beta.203",
53
+ "@webex/internal-plugin-llm": "3.0.0-beta.203",
54
+ "@webex/internal-plugin-mercury": "3.0.0-beta.203",
55
+ "@webex/internal-plugin-metrics": "3.0.0-beta.203",
56
+ "@webex/internal-plugin-support": "3.0.0-beta.203",
57
+ "@webex/internal-plugin-user": "3.0.0-beta.203",
58
+ "@webex/media-helpers": "3.0.0-beta.203",
59
+ "@webex/plugin-people": "3.0.0-beta.203",
60
+ "@webex/plugin-rooms": "3.0.0-beta.203",
61
+ "@webex/webex-core": "3.0.0-beta.203",
62
62
  "ampersand-collection": "^2.0.2",
63
63
  "bowser": "^2.11.0",
64
64
  "btoa": "^1.2.1",
@@ -1106,14 +1106,6 @@ export default class LocusInfo extends EventsScope {
1106
1106
  const isJoined = SelfUtils.isJoined(self || this.parsedLocus.self);
1107
1107
  const parsedInfo = InfoUtils.getInfos(this.parsedLocus.info, info, roles, isJoined);
1108
1108
 
1109
- this.emitScoped(
1110
- {
1111
- file: 'locus-info',
1112
- function: 'updateMeetingInfo',
1113
- },
1114
- LOCUSINFO.EVENTS.MEETING_INFO_UPDATED
1115
- );
1116
-
1117
1109
  if (parsedInfo.updates.isLocked) {
1118
1110
  this.emitScoped(
1119
1111
  {
@@ -1139,6 +1131,14 @@ export default class LocusInfo extends EventsScope {
1139
1131
  this.parsedLocus.info = parsedInfo.current;
1140
1132
  // Parses the info and adds necessary values
1141
1133
  this.updateMeeting(parsedInfo.current);
1134
+
1135
+ this.emitScoped(
1136
+ {
1137
+ file: 'locus-info',
1138
+ function: 'updateMeetingInfo',
1139
+ },
1140
+ LOCUSINFO.EVENTS.MEETING_INFO_UPDATED
1141
+ );
1142
1142
  }
1143
1143
  this.roles = roles;
1144
1144
  }
@@ -1,5 +1,5 @@
1
1
  import uuid from 'uuid';
2
- import {cloneDeep, isEqual, defer, isEmpty} from 'lodash';
2
+ import {cloneDeep, isEqual, isEmpty} from 'lodash';
3
3
  import jwt from 'jsonwebtoken';
4
4
  // @ts-ignore - Fix this
5
5
  import {StatelessWebexPlugin} from '@webex/webex-core';
@@ -1354,6 +1354,8 @@ export default class Meeting extends StatelessWebexPlugin {
1354
1354
 
1355
1355
  return Promise.resolve();
1356
1356
  } catch (err) {
1357
+ this.updateMeetingActions();
1358
+
1357
1359
  if (err instanceof MeetingInfoV2PolicyError) {
1358
1360
  this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.POLICY;
1359
1361
  this.meetingInfoFailureCode = err.wbxAppApiCode;
@@ -2480,15 +2482,10 @@ export default class Meeting extends StatelessWebexPlugin {
2480
2482
  * @param {String} datachannelUrl
2481
2483
  * @returns {void}
2482
2484
  */
2483
-
2484
2485
  handleDataChannelUrlChange(datachannelUrl) {
2485
2486
  // @ts-ignore - config coming from registerPlugin
2486
2487
  if (datachannelUrl && this.config.enableAutomaticLLM) {
2487
- // Defer this as updateLLMConnection relies upon this.locusInfo.url which is only set
2488
- // after the MEETING_INFO_UPDATED callback finishes
2489
- defer(() => {
2490
- this.updateLLMConnection();
2491
- });
2488
+ this.updateLLMConnection();
2492
2489
  }
2493
2490
  }
2494
2491
 
@@ -3030,6 +3027,31 @@ export default class Meeting extends StatelessWebexPlugin {
3030
3027
  MeetingUtil.parseInterpretationInfo(this, webexMeetingInfo);
3031
3028
  }
3032
3029
 
3030
+ /**
3031
+ * Indicates whether policy can be applied
3032
+ * @returns {boolean}
3033
+ */
3034
+ private arePolicyRestrictionsSupported() {
3035
+ // Locus calls do not return the correct display hints
3036
+ if (this.isLocusCall()) {
3037
+ return false;
3038
+ }
3039
+
3040
+ // 1-2-1 calls and SIP dialling will have no meeting info
3041
+ // so cannot support policy information
3042
+ if (isEmpty(this.meetingInfo)) {
3043
+ return false;
3044
+ }
3045
+
3046
+ // Old locus info api does not return policy information
3047
+ // @ts-ignore
3048
+ if (!this.config.experimental.enableUnifiedMeetings) {
3049
+ return false;
3050
+ }
3051
+
3052
+ return true;
3053
+ }
3054
+
3033
3055
  /**
3034
3056
  * Updates the meeting actions (display hints), depends on locus display hints, user policy and app api info
3035
3057
  * @returns {undefined}
@@ -3050,9 +3072,7 @@ export default class Meeting extends StatelessWebexPlugin {
3050
3072
  requiredPolicies: [SELF_POLICY.SUPPORT_VOIP],
3051
3073
  policies: this.selfUserPolicies,
3052
3074
  })) ||
3053
- // @ts-ignore
3054
- !this.config.experimental.enableUnifiedMeetings ||
3055
- this.isLocusCall(),
3075
+ !this.arePolicyRestrictionsSupported(),
3056
3076
  });
3057
3077
  if (this.userDisplayHints !== undefined) {
3058
3078
  changed =
@@ -3189,13 +3209,11 @@ export default class Meeting extends StatelessWebexPlugin {
3189
3209
  requiredHints: [DISPLAY_HINTS.SHARE_FILE],
3190
3210
  displayHints: this.userDisplayHints,
3191
3211
  }) &&
3192
- (ControlsOptionsUtil.hasPolicies({
3212
+ ControlsOptionsUtil.hasPolicies({
3193
3213
  requiredPolicies: [SELF_POLICY.SUPPORT_FILE_SHARE],
3194
3214
  policies: this.selfUserPolicies,
3195
- }) ||
3196
- // @ts-ignore
3197
- !this.config.experimental.enableUnifiedMeetings)) ||
3198
- this.isLocusCall(),
3215
+ })) ||
3216
+ !this.arePolicyRestrictionsSupported,
3199
3217
  canTransferFile: ControlsOptionsUtil.hasPolicies({
3200
3218
  requiredPolicies: [SELF_POLICY.SUPPORT_FILE_TRANSFER],
3201
3219
  policies: this.selfUserPolicies,
@@ -3205,13 +3223,11 @@ export default class Meeting extends StatelessWebexPlugin {
3205
3223
  requiredHints: [DISPLAY_HINTS.SHARE_APPLICATION],
3206
3224
  displayHints: this.userDisplayHints,
3207
3225
  }) &&
3208
- (ControlsOptionsUtil.hasPolicies({
3226
+ ControlsOptionsUtil.hasPolicies({
3209
3227
  requiredPolicies: [SELF_POLICY.SUPPORT_APP_SHARE],
3210
3228
  policies: this.selfUserPolicies,
3211
- }) ||
3212
- // @ts-ignore
3213
- !this.config.experimental.enableUnifiedMeetings)) ||
3214
- this.isLocusCall(),
3229
+ })) ||
3230
+ !this.arePolicyRestrictionsSupported(),
3215
3231
  canShareCamera:
3216
3232
  ControlsOptionsUtil.hasHints({
3217
3233
  requiredHints: [DISPLAY_HINTS.SHARE_CAMERA],
@@ -3226,18 +3242,16 @@ export default class Meeting extends StatelessWebexPlugin {
3226
3242
  requiredHints: [DISPLAY_HINTS.SHARE_DESKTOP],
3227
3243
  displayHints: this.userDisplayHints,
3228
3244
  }) &&
3229
- (ControlsOptionsUtil.hasPolicies({
3245
+ ControlsOptionsUtil.hasPolicies({
3230
3246
  requiredPolicies: [SELF_POLICY.SUPPORT_DESKTOP_SHARE],
3231
3247
  policies: this.selfUserPolicies,
3232
- }) ||
3233
- // @ts-ignore
3234
- !this.config.experimental.enableUnifiedMeetings)) ||
3235
- this.isLocusCall(),
3248
+ })) ||
3249
+ !this.arePolicyRestrictionsSupported(),
3236
3250
  canShareContent:
3237
3251
  ControlsOptionsUtil.hasHints({
3238
3252
  requiredHints: [DISPLAY_HINTS.SHARE_CONTENT],
3239
3253
  displayHints: this.userDisplayHints,
3240
- }) || this.isLocusCall(),
3254
+ }) || !this.arePolicyRestrictionsSupported(),
3241
3255
  canAnnotate: ControlsOptionsUtil.hasPolicies({
3242
3256
  requiredPolicies: [SELF_POLICY.SUPPORT_ANNOTATION],
3243
3257
  policies: this.selfUserPolicies,
@@ -1409,14 +1409,19 @@ describe('plugin-meetings', () => {
1409
1409
  it('emits MEETING_INFO_UPDATED and updates the meeting if the info changes', () => {
1410
1410
  const initialInfo = cloneDeep(meetingInfo);
1411
1411
 
1412
- locusInfo.emitScoped = sinon.stub();
1412
+ let expectedMeeting;
1413
1413
 
1414
- // set the info initially as locusInfo.info starts as undefined
1415
- locusInfo.updateMeetingInfo(initialInfo, self);
1414
+ /*
1415
+ When the event is triggered, it is required that the meeting has already
1416
+ been updated. This is why the meeting is being checked within the stubbed event emitter
1417
+ */
1418
+ sinon.stub(locusInfo, 'emitScoped').callsFake(() => {
1419
+ assert.deepEqual(mockMeeting, expectedMeeting);
1420
+ })
1416
1421
 
1417
- // since it was initially undefined, this should trigger the event
1418
- checkMeetingInfoUpdatedCalled(true);
1419
- assert.deepEqual(mockMeeting, {
1422
+
1423
+ // set the info initially as locusInfo.info starts as undefined
1424
+ expectedMeeting = {
1420
1425
  coHost: {
1421
1426
  LOWER_SOMEONE_ELSES_HAND: true,
1422
1427
  },
@@ -1430,17 +1435,19 @@ describe('plugin-meetings', () => {
1430
1435
  ROSTER_IN_MEETING: true,
1431
1436
  },
1432
1437
  userDisplayHints: ['ROSTER_IN_MEETING', 'LOCK_STATUS_UNLOCKED'],
1433
- });
1438
+ };
1439
+ locusInfo.updateMeetingInfo(initialInfo, self);
1440
+
1441
+ // since it was initially undefined, this should trigger the event
1442
+
1443
+ checkMeetingInfoUpdatedCalled(true);
1434
1444
 
1435
1445
  const newInfo = cloneDeep(meetingInfo);
1436
1446
 
1437
1447
  newInfo.displayHints.coHost = [DISPLAY_HINTS.LOCK_CONTROL_LOCK];
1438
1448
 
1439
1449
  // Updating with different info should trigger the event
1440
- locusInfo.updateMeetingInfo(newInfo, self);
1441
-
1442
- checkMeetingInfoUpdatedCalled(true);
1443
- assert.deepEqual(mockMeeting, {
1450
+ expectedMeeting = {
1444
1451
  coHost: {
1445
1452
  LOWER_SOMEONE_ELSES_HAND: true,
1446
1453
  LOCK_CONTROL_LOCK: true,
@@ -1455,14 +1462,13 @@ describe('plugin-meetings', () => {
1455
1462
  ROSTER_IN_MEETING: true,
1456
1463
  },
1457
1464
  userDisplayHints: ['ROSTER_IN_MEETING', 'LOCK_STATUS_UNLOCKED'],
1458
- });
1459
-
1460
- // update it with the same info
1465
+ };
1461
1466
  locusInfo.updateMeetingInfo(newInfo, self);
1462
1467
 
1463
- // since the info is the same it should not call trigger the event
1464
- checkMeetingInfoUpdatedCalled(false);
1465
- assert.deepEqual(mockMeeting, {
1468
+ checkMeetingInfoUpdatedCalled(true);
1469
+
1470
+ // update it with the same info
1471
+ expectedMeeting = {
1466
1472
  coHost: {
1467
1473
  LOWER_SOMEONE_ELSES_HAND: true,
1468
1474
  LOCK_CONTROL_LOCK: true,
@@ -1477,7 +1483,11 @@ describe('plugin-meetings', () => {
1477
1483
  ROSTER_IN_MEETING: true,
1478
1484
  },
1479
1485
  userDisplayHints: ['ROSTER_IN_MEETING', 'LOCK_STATUS_UNLOCKED'],
1480
- });
1486
+ };
1487
+ locusInfo.updateMeetingInfo(newInfo, self);
1488
+
1489
+ // since the info is the same it should not call trigger the event
1490
+ checkMeetingInfoUpdatedCalled(false);
1481
1491
 
1482
1492
  // update it with the same info, but roles changed
1483
1493
  const updateSelf = cloneDeep(self);
@@ -1485,10 +1495,7 @@ describe('plugin-meetings', () => {
1485
1495
  type: 'COHOST',
1486
1496
  hasRole: true,
1487
1497
  });
1488
- locusInfo.updateMeetingInfo(newInfo, updateSelf);
1489
- // since the info is the same but roles changed, it should call trigger the event
1490
- checkMeetingInfoUpdatedCalledForRoles(true);
1491
- assert.deepEqual(mockMeeting, {
1498
+ expectedMeeting = {
1492
1499
  coHost: {
1493
1500
  LOWER_SOMEONE_ELSES_HAND: true,
1494
1501
  LOCK_CONTROL_LOCK: true,
@@ -1508,7 +1515,10 @@ describe('plugin-meetings', () => {
1508
1515
  'LOCK_CONTROL_LOCK',
1509
1516
  'LOWER_SOMEONE_ELSES_HAND',
1510
1517
  ],
1511
- });
1518
+ };
1519
+ locusInfo.updateMeetingInfo(newInfo, updateSelf);
1520
+ // since the info is the same but roles changed, it should call trigger the event
1521
+ checkMeetingInfoUpdatedCalledForRoles(true);
1512
1522
  });
1513
1523
 
1514
1524
  it('gets roles from self if available', () => {
@@ -5947,6 +5947,7 @@ describe('plugin-meetings', () => {
5947
5947
  it(`${actionName} is ${expectedEnabled} when the call type is ${callType}`, () => {
5948
5948
  meeting.type = callType;
5949
5949
  meeting.userDisplayHints = [];
5950
+ meeting.meetingInfo = {some: 'info'};
5950
5951
 
5951
5952
  meeting.updateMeetingActions();
5952
5953
 
@@ -6005,7 +6006,7 @@ describe('plugin-meetings', () => {
6005
6006
  requiredPolicies: [SELF_POLICY.SUPPORT_ANNOTATION],
6006
6007
  },
6007
6008
  ],
6008
- ({actionName, requiredDisplayHints, requiredPolicies, enableUnifiedMeetings}) => {
6009
+ ({actionName, requiredDisplayHints, requiredPolicies, enableUnifiedMeetings, meetingInfo}) => {
6009
6010
  it(`${actionName} is enabled when the conditions are met`, () => {
6010
6011
  meeting.userDisplayHints = requiredDisplayHints;
6011
6012
  meeting.selfUserPolicies = {};
@@ -6014,6 +6015,8 @@ describe('plugin-meetings', () => {
6014
6015
  ? true
6015
6016
  : enableUnifiedMeetings;
6016
6017
 
6018
+ meeting.meetingInfo = isUndefined(meetingInfo) ? {some: 'info'} : meetingInfo;
6019
+
6017
6020
  forEach(requiredPolicies, (policy) => {
6018
6021
  meeting.selfUserPolicies[policy] = true;
6019
6022
  });
@@ -6028,6 +6031,8 @@ describe('plugin-meetings', () => {
6028
6031
  meeting.userDisplayHints = [];
6029
6032
  meeting.selfUserPolicies = {};
6030
6033
 
6034
+ meeting.meetingInfo = isUndefined(meetingInfo) ? {some: 'info'} : meetingInfo;
6035
+
6031
6036
  forEach(requiredPolicies, (policy) => {
6032
6037
  meeting.selfUserPolicies[policy] = true;
6033
6038
  });
@@ -6042,6 +6047,8 @@ describe('plugin-meetings', () => {
6042
6047
  meeting.userDisplayHints = requiredDisplayHints;
6043
6048
  meeting.selfUserPolicies = {};
6044
6049
 
6050
+ meeting.meetingInfo = isUndefined(meetingInfo) ? {some: 'info'} : meetingInfo;
6051
+
6045
6052
  meeting.updateMeetingActions();
6046
6053
 
6047
6054
  assert.isFalse(meeting.inMeetingActions.get()[actionName]);
@@ -6093,6 +6100,24 @@ describe('plugin-meetings', () => {
6093
6100
  assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
6094
6101
  });
6095
6102
 
6103
+ it('canUseVoip is enabled when there is no meeting info', () => {
6104
+ meeting.config.experimental.enableUnifiedMeetings = true;
6105
+
6106
+ meeting.updateMeetingActions();
6107
+
6108
+ assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
6109
+ });
6110
+
6111
+ it('canUseVoip is enabled when it is a locus call', () => {
6112
+ meeting.config.experimental.enableUnifiedMeetings = true;
6113
+ meeting.meetingInfo = {some: 'info'};
6114
+ meeting.type = 'CALL';
6115
+
6116
+ meeting.updateMeetingActions();
6117
+
6118
+ assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
6119
+ });
6120
+
6096
6121
  it('canUseVoip is disabled based on api info when supportVoip is false', () => {
6097
6122
  meeting.userDisplayHints = undefined;
6098
6123
  meeting.selfUserPolicies = {[SELF_POLICY.SUPPORT_VOIP]: true};
@@ -6283,13 +6308,9 @@ describe('plugin-meetings', () => {
6283
6308
  updateLLMConnectionSpy = sinon.spy(meeting, 'updateLLMConnection');
6284
6309
  });
6285
6310
 
6286
- const check = async (url, expectedCalled) => {
6311
+ const check = (url, expectedCalled) => {
6287
6312
  meeting.handleDataChannelUrlChange(url);
6288
6313
 
6289
- assert.notCalled(updateLLMConnectionSpy);
6290
-
6291
- await testUtils.waitUntil(0);
6292
-
6293
6314
  if (expectedCalled) {
6294
6315
  assert.calledWith(updateLLMConnectionSpy);
6295
6316
  } else {
@@ -6297,17 +6318,17 @@ describe('plugin-meetings', () => {
6297
6318
  }
6298
6319
  };
6299
6320
 
6300
- it('calls deferred updateLLMConnection if datachannelURL is set and the enableAutomaticLLM is true', async () => {
6321
+ it('calls deferred updateLLMConnection if datachannelURL is set and the enableAutomaticLLM is true', () => {
6301
6322
  meeting.config.enableAutomaticLLM = true;
6302
6323
  check('some url', true);
6303
6324
  });
6304
6325
 
6305
- it('does not call updateLLMConnection if datachannelURL is undefined', async () => {
6326
+ it('does not call updateLLMConnection if datachannelURL is undefined', () => {
6306
6327
  meeting.config.enableAutomaticLLM = true;
6307
6328
  check(undefined, false);
6308
6329
  });
6309
6330
 
6310
- it('does not call updateLLMConnection if enableAutomaticLLM is false', async () => {
6331
+ it('does not call updateLLMConnection if enableAutomaticLLM is false', () => {
6311
6332
  check('some url', false);
6312
6333
  });
6313
6334
  });
@@ -1371,7 +1371,7 @@ describe('plugin-meetings', () => {
1371
1371
  );
1372
1372
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1373
1373
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1374
- assert.calledTwice(TriggerProxy.trigger);
1374
+ assert.calledThrice(TriggerProxy.trigger);
1375
1375
  assert.calledWith(
1376
1376
  webex.meetings.meetingInfo.fetchMeetingInfo,
1377
1377
  'test destination',