@atlaskit/smart-user-picker 8.5.0 → 8.7.0
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.
- package/CHANGELOG.md +17 -0
- package/afm-cc/tsconfig.json +2 -1
- package/afm-jira/tsconfig.json +2 -1
- package/afm-products/tsconfig.json +2 -1
- package/dist/cjs/components/SmartUserPicker.js +74 -48
- package/dist/es2019/components/SmartUserPicker.js +22 -3
- package/dist/esm/components/SmartUserPicker.js +74 -48
- package/dist/types/components/SmartUserPicker.d.ts +1 -0
- package/dist/types/types.d.ts +11 -0
- package/dist/types-ts4.5/components/SmartUserPicker.d.ts +1 -0
- package/dist/types-ts4.5/types.d.ts +11 -0
- package/package.json +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlassian/smart-user-picker
|
|
2
2
|
|
|
3
|
+
## 8.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`ae3f597598ae8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ae3f597598ae8) -
|
|
8
|
+
Added prop to toggle the ability to return only verified teams. Only applies when includeTeams is
|
|
9
|
+
true.
|
|
10
|
+
|
|
11
|
+
## 8.6.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [`0d41d4c92fe89`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0d41d4c92fe89) -
|
|
16
|
+
[ux] Added `fetchOptions` prop to SmartUserPicker to support custom option fetching. When
|
|
17
|
+
provided, this function will be called instead of the default recommendation API, allowing
|
|
18
|
+
consumers to override the default fetching behavior with their own implementation.
|
|
19
|
+
|
|
3
20
|
## 8.5.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/afm-cc/tsconfig.json
CHANGED
package/afm-jira/tsconfig.json
CHANGED
|
@@ -118,12 +118,12 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
118
118
|
});
|
|
119
119
|
(0, _defineProperty2.default)(_this, "memoizedFilterOptions", (0, _memoizeOne.default)(_this.filterOptions));
|
|
120
120
|
(0, _defineProperty2.default)(_this, "getUsers", (0, _debounce.default)( /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
121
|
-
var _this$state, query, sessionId, closed, _this$props, baseUrl, childObjectId, containerId, fieldId, includeGroups, includeTeams, includeTeamsUpdates, includeUsers, includeNonLicensedUsers, intl, maxOptions, objectId, onEmpty, onError, overrideByline, displayEmailInByline, orgId, principalId, productAttributes, productKey, searchQueryFilter, siteId, transformOptions, userResolvers, enableEmailSearch, maxNumberOfResults, startTime, isEmail, recommendationsRequest, _yield$onEmpty, _query, recommendedUsers, userRecommendationsPromise, userResolversPromises, _yield$Promise$all, _yield$Promise$all2, mainRecommendations, userResolverResults, _iterator, _step, option, _iterator2, _step2, _option, _iterator3, _step3, _option2, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli;
|
|
121
|
+
var _this$state, query, sessionId, closed, _this$props, baseUrl, childObjectId, containerId, fieldId, includeGroups, includeTeams, includeTeamsUpdates, includeUsers, includeNonLicensedUsers, intl, fetchOptions, maxOptions, objectId, onEmpty, onError, overrideByline, displayEmailInByline, verifiedTeams, orgId, principalId, productAttributes, productKey, searchQueryFilter, siteId, transformOptions, userResolvers, enableEmailSearch, maxNumberOfResults, startTime, isEmail, recommendationsRequest, _yield$onEmpty, _query, recommendedUsers, userRecommendationsPromise, userResolversPromises, _yield$Promise$all, _yield$Promise$all2, mainRecommendations, userResolverResults, _iterator, _step, option, _iterator2, _step2, _option, _iterator3, _step3, _option2, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli;
|
|
122
122
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
123
123
|
while (1) switch (_context.prev = _context.next) {
|
|
124
124
|
case 0:
|
|
125
125
|
_this$state = _this.state, query = _this$state.query, sessionId = _this$state.sessionId, closed = _this$state.closed;
|
|
126
|
-
_this$props = _this.props, baseUrl = _this$props.baseUrl, childObjectId = _this$props.childObjectId, containerId = _this$props.containerId, fieldId = _this$props.fieldId, includeGroups = _this$props.includeGroups, includeTeams = _this$props.includeTeams, includeTeamsUpdates = _this$props.includeTeamsUpdates, includeUsers = _this$props.includeUsers, includeNonLicensedUsers = _this$props.includeNonLicensedUsers, intl = _this$props.intl, maxOptions = _this$props.maxOptions, objectId = _this$props.objectId, onEmpty = _this$props.onEmpty, onError = _this$props.onError, overrideByline = _this$props.overrideByline, displayEmailInByline = _this$props.displayEmailInByline, orgId = _this$props.orgId, principalId = _this$props.principalId, productAttributes = _this$props.productAttributes, productKey = _this$props.productKey, searchQueryFilter = _this$props.searchQueryFilter, siteId = _this$props.siteId, transformOptions = _this$props.transformOptions, userResolvers = _this$props.userResolvers, enableEmailSearch = _this$props.enableEmailSearch;
|
|
126
|
+
_this$props = _this.props, baseUrl = _this$props.baseUrl, childObjectId = _this$props.childObjectId, containerId = _this$props.containerId, fieldId = _this$props.fieldId, includeGroups = _this$props.includeGroups, includeTeams = _this$props.includeTeams, includeTeamsUpdates = _this$props.includeTeamsUpdates, includeUsers = _this$props.includeUsers, includeNonLicensedUsers = _this$props.includeNonLicensedUsers, intl = _this$props.intl, fetchOptions = _this$props.fetchOptions, maxOptions = _this$props.maxOptions, objectId = _this$props.objectId, onEmpty = _this$props.onEmpty, onError = _this$props.onError, overrideByline = _this$props.overrideByline, displayEmailInByline = _this$props.displayEmailInByline, verifiedTeams = _this$props.verifiedTeams, orgId = _this$props.orgId, principalId = _this$props.principalId, productAttributes = _this$props.productAttributes, productKey = _this$props.productKey, searchQueryFilter = _this$props.searchQueryFilter, siteId = _this$props.siteId, transformOptions = _this$props.transformOptions, userResolvers = _this$props.userResolvers, enableEmailSearch = _this$props.enableEmailSearch;
|
|
127
127
|
maxNumberOfResults = maxOptions || 100;
|
|
128
128
|
startTime = window.performance.now(); // Check if this is an email search
|
|
129
129
|
isEmail = enableEmailSearch && isEmailQuery(query);
|
|
@@ -149,6 +149,7 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
149
149
|
maxNumberOfResults: maxNumberOfResults,
|
|
150
150
|
query: query,
|
|
151
151
|
searchEmail: isEmail,
|
|
152
|
+
verifiedTeams: verifiedTeams,
|
|
152
153
|
/*
|
|
153
154
|
For email-based searches, we have decided to filter out apps.
|
|
154
155
|
Also - because the other 2 filters ((NOT not_mentionable:true) AND (account_status:active)) are included
|
|
@@ -160,8 +161,19 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
160
161
|
_context.prev = 6;
|
|
161
162
|
_query = _this.state.query;
|
|
162
163
|
_this.fireEvent(_analytics.requestUsersEvent);
|
|
164
|
+
if (!(fetchOptions && (0, _platformFeatureFlags.fg)('smart-user-picker-load-options-gate'))) {
|
|
165
|
+
_context.next = 15;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
_context.next = 12;
|
|
169
|
+
return fetchOptions(_query);
|
|
170
|
+
case 12:
|
|
171
|
+
recommendedUsers = _context.sent;
|
|
172
|
+
_context.next = 30;
|
|
173
|
+
break;
|
|
174
|
+
case 15:
|
|
163
175
|
if (!(0, _platformFeatureFlags.fg)('twcg-444-invite-usd-improvements-m2-gate')) {
|
|
164
|
-
_context.next =
|
|
176
|
+
_context.next = 27;
|
|
165
177
|
break;
|
|
166
178
|
}
|
|
167
179
|
userRecommendationsPromise = (0, _service.getUserRecommendations)(recommendationsRequest, intl);
|
|
@@ -174,22 +186,22 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
174
186
|
return [];
|
|
175
187
|
});
|
|
176
188
|
});
|
|
177
|
-
_context.next =
|
|
189
|
+
_context.next = 20;
|
|
178
190
|
return Promise.all([userRecommendationsPromise].concat((0, _toConsumableArray2.default)(userResolversPromises)));
|
|
179
|
-
case
|
|
191
|
+
case 20:
|
|
180
192
|
_yield$Promise$all = _context.sent;
|
|
181
193
|
_yield$Promise$all2 = (0, _toArray2.default)(_yield$Promise$all);
|
|
182
194
|
mainRecommendations = _yield$Promise$all2[0];
|
|
183
195
|
userResolverResults = _yield$Promise$all2.slice(1);
|
|
184
196
|
recommendedUsers = [mainRecommendations].concat((0, _toConsumableArray2.default)(userResolverResults)).flat();
|
|
185
|
-
_context.next =
|
|
197
|
+
_context.next = 30;
|
|
186
198
|
break;
|
|
187
|
-
case
|
|
188
|
-
_context.next =
|
|
199
|
+
case 27:
|
|
200
|
+
_context.next = 29;
|
|
189
201
|
return (0, _service.getUserRecommendations)(recommendationsRequest, intl);
|
|
190
|
-
case
|
|
202
|
+
case 29:
|
|
191
203
|
recommendedUsers = _context.sent;
|
|
192
|
-
case
|
|
204
|
+
case 30:
|
|
193
205
|
if (overrideByline) {
|
|
194
206
|
_iterator = _createForOfIteratorHelper(recommendedUsers);
|
|
195
207
|
try {
|
|
@@ -241,6 +253,19 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
241
253
|
}
|
|
242
254
|
}
|
|
243
255
|
|
|
256
|
+
// Filter to only verified teams when verifiedTeams is true and feature flag is enabled
|
|
257
|
+
if (verifiedTeams && includeTeams && (0, _platformFeatureFlags.fg)('smart-user-picker-managed-teams-gate')) {
|
|
258
|
+
recommendedUsers = recommendedUsers.filter(function (option) {
|
|
259
|
+
if ((0, _userPicker.isTeam)(option)) {
|
|
260
|
+
// Only include teams that are verified
|
|
261
|
+
// The verified property is set by the transformer from the server response
|
|
262
|
+
var team = option;
|
|
263
|
+
return team.verified === true;
|
|
264
|
+
}
|
|
265
|
+
return true; // Keep non-team options
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
244
269
|
// Track if email search found matches for conditional allowEmail logic
|
|
245
270
|
if (isEmail) {
|
|
246
271
|
_this.lastEmailSearchFoundMatches = recommendedUsers.length > 0;
|
|
@@ -249,50 +274,50 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
249
274
|
}
|
|
250
275
|
elapsedTimeMilli = window.performance.now() - startTime;
|
|
251
276
|
if (!transformOptions) {
|
|
252
|
-
_context.next =
|
|
277
|
+
_context.next = 42;
|
|
253
278
|
break;
|
|
254
279
|
}
|
|
255
|
-
_context.next =
|
|
280
|
+
_context.next = 39;
|
|
256
281
|
return transformOptions(recommendedUsers, _query);
|
|
257
|
-
case
|
|
282
|
+
case 39:
|
|
258
283
|
_context.t0 = _context.sent;
|
|
259
|
-
_context.next =
|
|
284
|
+
_context.next = 43;
|
|
260
285
|
break;
|
|
261
|
-
case
|
|
286
|
+
case 42:
|
|
262
287
|
_context.t0 = recommendedUsers;
|
|
263
|
-
case
|
|
288
|
+
case 43:
|
|
264
289
|
transformedOptions = _context.t0;
|
|
265
290
|
if (!(transformedOptions.length === 0 && onEmpty)) {
|
|
266
|
-
_context.next =
|
|
291
|
+
_context.next = 59;
|
|
267
292
|
break;
|
|
268
293
|
}
|
|
269
|
-
_context.next =
|
|
294
|
+
_context.next = 47;
|
|
270
295
|
return onEmpty(_query);
|
|
271
|
-
case
|
|
296
|
+
case 47:
|
|
272
297
|
_context.t3 = _yield$onEmpty = _context.sent;
|
|
273
298
|
_context.t2 = _context.t3 !== null;
|
|
274
299
|
if (!_context.t2) {
|
|
275
|
-
_context.next =
|
|
300
|
+
_context.next = 51;
|
|
276
301
|
break;
|
|
277
302
|
}
|
|
278
303
|
_context.t2 = _yield$onEmpty !== void 0;
|
|
279
|
-
case
|
|
304
|
+
case 51:
|
|
280
305
|
if (!_context.t2) {
|
|
281
|
-
_context.next =
|
|
306
|
+
_context.next = 55;
|
|
282
307
|
break;
|
|
283
308
|
}
|
|
284
309
|
_context.t4 = _yield$onEmpty;
|
|
285
|
-
_context.next =
|
|
310
|
+
_context.next = 56;
|
|
286
311
|
break;
|
|
287
|
-
case
|
|
312
|
+
case 55:
|
|
288
313
|
_context.t4 = [];
|
|
289
|
-
case
|
|
314
|
+
case 56:
|
|
290
315
|
_context.t1 = _context.t4;
|
|
291
|
-
_context.next =
|
|
316
|
+
_context.next = 60;
|
|
292
317
|
break;
|
|
293
|
-
case
|
|
318
|
+
case 59:
|
|
294
319
|
_context.t1 = transformedOptions;
|
|
295
|
-
case
|
|
320
|
+
case 60:
|
|
296
321
|
displayedUsers = _context.t1;
|
|
297
322
|
_this.setState(function (state) {
|
|
298
323
|
var applicable = state.query === _query;
|
|
@@ -314,10 +339,10 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
314
339
|
loading: loading
|
|
315
340
|
};
|
|
316
341
|
});
|
|
317
|
-
_context.next =
|
|
342
|
+
_context.next = 93;
|
|
318
343
|
break;
|
|
319
|
-
case
|
|
320
|
-
_context.prev =
|
|
344
|
+
case 64:
|
|
345
|
+
_context.prev = 64;
|
|
321
346
|
_context.t5 = _context["catch"](6);
|
|
322
347
|
is5xxEvent = checkIf500Event(_context.t5.statusCode);
|
|
323
348
|
if (!closed && !onError && is5xxEvent) {
|
|
@@ -330,35 +355,35 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
330
355
|
});
|
|
331
356
|
onErrorProducedError = false;
|
|
332
357
|
defaultUsers = [];
|
|
333
|
-
_context.prev =
|
|
358
|
+
_context.prev = 71;
|
|
334
359
|
if (!onError) {
|
|
335
|
-
_context.next =
|
|
360
|
+
_context.next = 81;
|
|
336
361
|
break;
|
|
337
362
|
}
|
|
338
|
-
_context.next =
|
|
363
|
+
_context.next = 75;
|
|
339
364
|
return onError(_context.t5, recommendationsRequest);
|
|
340
|
-
case
|
|
365
|
+
case 75:
|
|
341
366
|
_context.t7 = _context.sent;
|
|
342
367
|
if (_context.t7) {
|
|
343
|
-
_context.next =
|
|
368
|
+
_context.next = 78;
|
|
344
369
|
break;
|
|
345
370
|
}
|
|
346
371
|
_context.t7 = [];
|
|
347
|
-
case
|
|
372
|
+
case 78:
|
|
348
373
|
_context.t6 = _context.t7;
|
|
349
|
-
_context.next =
|
|
374
|
+
_context.next = 82;
|
|
350
375
|
break;
|
|
351
|
-
case
|
|
376
|
+
case 81:
|
|
352
377
|
_context.t6 = [];
|
|
353
|
-
case
|
|
378
|
+
case 82:
|
|
354
379
|
defaultUsers = _context.t6;
|
|
355
|
-
_context.next =
|
|
380
|
+
_context.next = 88;
|
|
356
381
|
break;
|
|
357
|
-
case
|
|
358
|
-
_context.prev =
|
|
359
|
-
_context.t8 = _context["catch"](
|
|
382
|
+
case 85:
|
|
383
|
+
_context.prev = 85;
|
|
384
|
+
_context.t8 = _context["catch"](71);
|
|
360
385
|
onErrorProducedError = true;
|
|
361
|
-
case
|
|
386
|
+
case 88:
|
|
362
387
|
if (onErrorProducedError && is5xxEvent) {
|
|
363
388
|
// Log error from fallback data source `onError` to UFO
|
|
364
389
|
_this.optionsShownUfoExperienceInstance.failure(ufoEndStateConfig(_this.props.fieldId));
|
|
@@ -375,11 +400,11 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
375
400
|
elapsedTimeMilli: _elapsedTimeMilli,
|
|
376
401
|
productAttributes: productAttributes
|
|
377
402
|
});
|
|
378
|
-
case
|
|
403
|
+
case 93:
|
|
379
404
|
case "end":
|
|
380
405
|
return _context.stop();
|
|
381
406
|
}
|
|
382
|
-
}, _callee, null, [[6,
|
|
407
|
+
}, _callee, null, [[6, 64], [71, 85]]);
|
|
383
408
|
})), (_this$props$debounceT = _this.props.debounceTime) !== null && _this$props$debounceT !== void 0 ? _this$props$debounceT : 0));
|
|
384
409
|
(0, _defineProperty2.default)(_this, "onInputChange", function (newQuery, sessionId) {
|
|
385
410
|
var query = newQuery || '';
|
|
@@ -586,6 +611,7 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
586
611
|
debounceTime: DEFAULT_DEBOUNCE_TIME_MS,
|
|
587
612
|
userResolvers: [],
|
|
588
613
|
enableEmailSearch: false,
|
|
589
|
-
allowEmailSelectionWhenEmailMatched: true
|
|
614
|
+
allowEmailSelectionWhenEmailMatched: true,
|
|
615
|
+
verifiedTeams: false
|
|
590
616
|
});
|
|
591
617
|
var SmartUserPicker = exports.SmartUserPicker = (0, _analyticsNext.withAnalyticsEvents)()((0, _reactIntlNext.injectIntl)(SmartUserPickerWithoutAnalytics));
|
|
@@ -96,12 +96,14 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
96
96
|
includeUsers,
|
|
97
97
|
includeNonLicensedUsers,
|
|
98
98
|
intl,
|
|
99
|
+
fetchOptions,
|
|
99
100
|
maxOptions,
|
|
100
101
|
objectId,
|
|
101
102
|
onEmpty,
|
|
102
103
|
onError,
|
|
103
104
|
overrideByline,
|
|
104
105
|
displayEmailInByline,
|
|
106
|
+
verifiedTeams,
|
|
105
107
|
orgId,
|
|
106
108
|
principalId,
|
|
107
109
|
productAttributes,
|
|
@@ -139,6 +141,7 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
139
141
|
maxNumberOfResults,
|
|
140
142
|
query,
|
|
141
143
|
searchEmail: isEmail,
|
|
144
|
+
verifiedTeams,
|
|
142
145
|
/*
|
|
143
146
|
For email-based searches, we have decided to filter out apps.
|
|
144
147
|
Also - because the other 2 filters ((NOT not_mentionable:true) AND (account_status:active)) are included
|
|
@@ -154,7 +157,9 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
154
157
|
} = this.state;
|
|
155
158
|
this.fireEvent(requestUsersEvent);
|
|
156
159
|
let recommendedUsers;
|
|
157
|
-
if (fg('
|
|
160
|
+
if (fetchOptions && fg('smart-user-picker-load-options-gate')) {
|
|
161
|
+
recommendedUsers = await fetchOptions(query);
|
|
162
|
+
} else if (fg('twcg-444-invite-usd-improvements-m2-gate')) {
|
|
158
163
|
const userRecommendationsPromise = getUserRecommendations(recommendationsRequest, intl);
|
|
159
164
|
const userResolversPromises = (userResolvers !== null && userResolvers !== void 0 ? userResolvers : []).map(resolver => resolver(query).catch(error => {
|
|
160
165
|
this.fireEvent(failedUserResolversEvent, {
|
|
@@ -195,6 +200,19 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
195
200
|
}
|
|
196
201
|
}
|
|
197
202
|
|
|
203
|
+
// Filter to only verified teams when verifiedTeams is true and feature flag is enabled
|
|
204
|
+
if (verifiedTeams && includeTeams && fg('smart-user-picker-managed-teams-gate')) {
|
|
205
|
+
recommendedUsers = recommendedUsers.filter(option => {
|
|
206
|
+
if (isTeam(option)) {
|
|
207
|
+
// Only include teams that are verified
|
|
208
|
+
// The verified property is set by the transformer from the server response
|
|
209
|
+
const team = option;
|
|
210
|
+
return team.verified === true;
|
|
211
|
+
}
|
|
212
|
+
return true; // Keep non-team options
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
198
216
|
// Track if email search found matches for conditional allowEmail logic
|
|
199
217
|
if (isEmail) {
|
|
200
218
|
this.lastEmailSearchFoundMatches = recommendedUsers.length > 0;
|
|
@@ -237,7 +255,7 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
237
255
|
let defaultUsers = [];
|
|
238
256
|
try {
|
|
239
257
|
defaultUsers = onError ? (await onError(e, recommendationsRequest)) || [] : [];
|
|
240
|
-
} catch
|
|
258
|
+
} catch {
|
|
241
259
|
onErrorProducedError = true;
|
|
242
260
|
}
|
|
243
261
|
if (onErrorProducedError && is5xxEvent) {
|
|
@@ -436,6 +454,7 @@ _defineProperty(SmartUserPickerWithoutAnalytics, "defaultProps", {
|
|
|
436
454
|
debounceTime: DEFAULT_DEBOUNCE_TIME_MS,
|
|
437
455
|
userResolvers: [],
|
|
438
456
|
enableEmailSearch: false,
|
|
439
|
-
allowEmailSelectionWhenEmailMatched: true
|
|
457
|
+
allowEmailSelectionWhenEmailMatched: true,
|
|
458
|
+
verifiedTeams: false
|
|
440
459
|
});
|
|
441
460
|
export const SmartUserPicker = withAnalyticsEvents()(injectIntl(SmartUserPickerWithoutAnalytics));
|
|
@@ -110,12 +110,12 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
110
110
|
});
|
|
111
111
|
_defineProperty(_this, "memoizedFilterOptions", memoizeOne(_this.filterOptions));
|
|
112
112
|
_defineProperty(_this, "getUsers", debounce( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
113
|
-
var _this$state, query, sessionId, closed, _this$props, baseUrl, childObjectId, containerId, fieldId, includeGroups, includeTeams, includeTeamsUpdates, includeUsers, includeNonLicensedUsers, intl, maxOptions, objectId, onEmpty, onError, overrideByline, displayEmailInByline, orgId, principalId, productAttributes, productKey, searchQueryFilter, siteId, transformOptions, userResolvers, enableEmailSearch, maxNumberOfResults, startTime, isEmail, recommendationsRequest, _yield$onEmpty, _query, recommendedUsers, userRecommendationsPromise, userResolversPromises, _yield$Promise$all, _yield$Promise$all2, mainRecommendations, userResolverResults, _iterator, _step, option, _iterator2, _step2, _option, _iterator3, _step3, _option2, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli;
|
|
113
|
+
var _this$state, query, sessionId, closed, _this$props, baseUrl, childObjectId, containerId, fieldId, includeGroups, includeTeams, includeTeamsUpdates, includeUsers, includeNonLicensedUsers, intl, fetchOptions, maxOptions, objectId, onEmpty, onError, overrideByline, displayEmailInByline, verifiedTeams, orgId, principalId, productAttributes, productKey, searchQueryFilter, siteId, transformOptions, userResolvers, enableEmailSearch, maxNumberOfResults, startTime, isEmail, recommendationsRequest, _yield$onEmpty, _query, recommendedUsers, userRecommendationsPromise, userResolversPromises, _yield$Promise$all, _yield$Promise$all2, mainRecommendations, userResolverResults, _iterator, _step, option, _iterator2, _step2, _option, _iterator3, _step3, _option2, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli;
|
|
114
114
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
115
115
|
while (1) switch (_context.prev = _context.next) {
|
|
116
116
|
case 0:
|
|
117
117
|
_this$state = _this.state, query = _this$state.query, sessionId = _this$state.sessionId, closed = _this$state.closed;
|
|
118
|
-
_this$props = _this.props, baseUrl = _this$props.baseUrl, childObjectId = _this$props.childObjectId, containerId = _this$props.containerId, fieldId = _this$props.fieldId, includeGroups = _this$props.includeGroups, includeTeams = _this$props.includeTeams, includeTeamsUpdates = _this$props.includeTeamsUpdates, includeUsers = _this$props.includeUsers, includeNonLicensedUsers = _this$props.includeNonLicensedUsers, intl = _this$props.intl, maxOptions = _this$props.maxOptions, objectId = _this$props.objectId, onEmpty = _this$props.onEmpty, onError = _this$props.onError, overrideByline = _this$props.overrideByline, displayEmailInByline = _this$props.displayEmailInByline, orgId = _this$props.orgId, principalId = _this$props.principalId, productAttributes = _this$props.productAttributes, productKey = _this$props.productKey, searchQueryFilter = _this$props.searchQueryFilter, siteId = _this$props.siteId, transformOptions = _this$props.transformOptions, userResolvers = _this$props.userResolvers, enableEmailSearch = _this$props.enableEmailSearch;
|
|
118
|
+
_this$props = _this.props, baseUrl = _this$props.baseUrl, childObjectId = _this$props.childObjectId, containerId = _this$props.containerId, fieldId = _this$props.fieldId, includeGroups = _this$props.includeGroups, includeTeams = _this$props.includeTeams, includeTeamsUpdates = _this$props.includeTeamsUpdates, includeUsers = _this$props.includeUsers, includeNonLicensedUsers = _this$props.includeNonLicensedUsers, intl = _this$props.intl, fetchOptions = _this$props.fetchOptions, maxOptions = _this$props.maxOptions, objectId = _this$props.objectId, onEmpty = _this$props.onEmpty, onError = _this$props.onError, overrideByline = _this$props.overrideByline, displayEmailInByline = _this$props.displayEmailInByline, verifiedTeams = _this$props.verifiedTeams, orgId = _this$props.orgId, principalId = _this$props.principalId, productAttributes = _this$props.productAttributes, productKey = _this$props.productKey, searchQueryFilter = _this$props.searchQueryFilter, siteId = _this$props.siteId, transformOptions = _this$props.transformOptions, userResolvers = _this$props.userResolvers, enableEmailSearch = _this$props.enableEmailSearch;
|
|
119
119
|
maxNumberOfResults = maxOptions || 100;
|
|
120
120
|
startTime = window.performance.now(); // Check if this is an email search
|
|
121
121
|
isEmail = enableEmailSearch && isEmailQuery(query);
|
|
@@ -141,6 +141,7 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
141
141
|
maxNumberOfResults: maxNumberOfResults,
|
|
142
142
|
query: query,
|
|
143
143
|
searchEmail: isEmail,
|
|
144
|
+
verifiedTeams: verifiedTeams,
|
|
144
145
|
/*
|
|
145
146
|
For email-based searches, we have decided to filter out apps.
|
|
146
147
|
Also - because the other 2 filters ((NOT not_mentionable:true) AND (account_status:active)) are included
|
|
@@ -152,8 +153,19 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
152
153
|
_context.prev = 6;
|
|
153
154
|
_query = _this.state.query;
|
|
154
155
|
_this.fireEvent(requestUsersEvent);
|
|
156
|
+
if (!(fetchOptions && fg('smart-user-picker-load-options-gate'))) {
|
|
157
|
+
_context.next = 15;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
_context.next = 12;
|
|
161
|
+
return fetchOptions(_query);
|
|
162
|
+
case 12:
|
|
163
|
+
recommendedUsers = _context.sent;
|
|
164
|
+
_context.next = 30;
|
|
165
|
+
break;
|
|
166
|
+
case 15:
|
|
155
167
|
if (!fg('twcg-444-invite-usd-improvements-m2-gate')) {
|
|
156
|
-
_context.next =
|
|
168
|
+
_context.next = 27;
|
|
157
169
|
break;
|
|
158
170
|
}
|
|
159
171
|
userRecommendationsPromise = getUserRecommendations(recommendationsRequest, intl);
|
|
@@ -166,22 +178,22 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
166
178
|
return [];
|
|
167
179
|
});
|
|
168
180
|
});
|
|
169
|
-
_context.next =
|
|
181
|
+
_context.next = 20;
|
|
170
182
|
return Promise.all([userRecommendationsPromise].concat(_toConsumableArray(userResolversPromises)));
|
|
171
|
-
case
|
|
183
|
+
case 20:
|
|
172
184
|
_yield$Promise$all = _context.sent;
|
|
173
185
|
_yield$Promise$all2 = _toArray(_yield$Promise$all);
|
|
174
186
|
mainRecommendations = _yield$Promise$all2[0];
|
|
175
187
|
userResolverResults = _yield$Promise$all2.slice(1);
|
|
176
188
|
recommendedUsers = [mainRecommendations].concat(_toConsumableArray(userResolverResults)).flat();
|
|
177
|
-
_context.next =
|
|
189
|
+
_context.next = 30;
|
|
178
190
|
break;
|
|
179
|
-
case
|
|
180
|
-
_context.next =
|
|
191
|
+
case 27:
|
|
192
|
+
_context.next = 29;
|
|
181
193
|
return getUserRecommendations(recommendationsRequest, intl);
|
|
182
|
-
case
|
|
194
|
+
case 29:
|
|
183
195
|
recommendedUsers = _context.sent;
|
|
184
|
-
case
|
|
196
|
+
case 30:
|
|
185
197
|
if (overrideByline) {
|
|
186
198
|
_iterator = _createForOfIteratorHelper(recommendedUsers);
|
|
187
199
|
try {
|
|
@@ -233,6 +245,19 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
233
245
|
}
|
|
234
246
|
}
|
|
235
247
|
|
|
248
|
+
// Filter to only verified teams when verifiedTeams is true and feature flag is enabled
|
|
249
|
+
if (verifiedTeams && includeTeams && fg('smart-user-picker-managed-teams-gate')) {
|
|
250
|
+
recommendedUsers = recommendedUsers.filter(function (option) {
|
|
251
|
+
if (isTeam(option)) {
|
|
252
|
+
// Only include teams that are verified
|
|
253
|
+
// The verified property is set by the transformer from the server response
|
|
254
|
+
var team = option;
|
|
255
|
+
return team.verified === true;
|
|
256
|
+
}
|
|
257
|
+
return true; // Keep non-team options
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
236
261
|
// Track if email search found matches for conditional allowEmail logic
|
|
237
262
|
if (isEmail) {
|
|
238
263
|
_this.lastEmailSearchFoundMatches = recommendedUsers.length > 0;
|
|
@@ -241,50 +266,50 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
241
266
|
}
|
|
242
267
|
elapsedTimeMilli = window.performance.now() - startTime;
|
|
243
268
|
if (!transformOptions) {
|
|
244
|
-
_context.next =
|
|
269
|
+
_context.next = 42;
|
|
245
270
|
break;
|
|
246
271
|
}
|
|
247
|
-
_context.next =
|
|
272
|
+
_context.next = 39;
|
|
248
273
|
return transformOptions(recommendedUsers, _query);
|
|
249
|
-
case
|
|
274
|
+
case 39:
|
|
250
275
|
_context.t0 = _context.sent;
|
|
251
|
-
_context.next =
|
|
276
|
+
_context.next = 43;
|
|
252
277
|
break;
|
|
253
|
-
case
|
|
278
|
+
case 42:
|
|
254
279
|
_context.t0 = recommendedUsers;
|
|
255
|
-
case
|
|
280
|
+
case 43:
|
|
256
281
|
transformedOptions = _context.t0;
|
|
257
282
|
if (!(transformedOptions.length === 0 && onEmpty)) {
|
|
258
|
-
_context.next =
|
|
283
|
+
_context.next = 59;
|
|
259
284
|
break;
|
|
260
285
|
}
|
|
261
|
-
_context.next =
|
|
286
|
+
_context.next = 47;
|
|
262
287
|
return onEmpty(_query);
|
|
263
|
-
case
|
|
288
|
+
case 47:
|
|
264
289
|
_context.t3 = _yield$onEmpty = _context.sent;
|
|
265
290
|
_context.t2 = _context.t3 !== null;
|
|
266
291
|
if (!_context.t2) {
|
|
267
|
-
_context.next =
|
|
292
|
+
_context.next = 51;
|
|
268
293
|
break;
|
|
269
294
|
}
|
|
270
295
|
_context.t2 = _yield$onEmpty !== void 0;
|
|
271
|
-
case
|
|
296
|
+
case 51:
|
|
272
297
|
if (!_context.t2) {
|
|
273
|
-
_context.next =
|
|
298
|
+
_context.next = 55;
|
|
274
299
|
break;
|
|
275
300
|
}
|
|
276
301
|
_context.t4 = _yield$onEmpty;
|
|
277
|
-
_context.next =
|
|
302
|
+
_context.next = 56;
|
|
278
303
|
break;
|
|
279
|
-
case
|
|
304
|
+
case 55:
|
|
280
305
|
_context.t4 = [];
|
|
281
|
-
case
|
|
306
|
+
case 56:
|
|
282
307
|
_context.t1 = _context.t4;
|
|
283
|
-
_context.next =
|
|
308
|
+
_context.next = 60;
|
|
284
309
|
break;
|
|
285
|
-
case
|
|
310
|
+
case 59:
|
|
286
311
|
_context.t1 = transformedOptions;
|
|
287
|
-
case
|
|
312
|
+
case 60:
|
|
288
313
|
displayedUsers = _context.t1;
|
|
289
314
|
_this.setState(function (state) {
|
|
290
315
|
var applicable = state.query === _query;
|
|
@@ -306,10 +331,10 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
306
331
|
loading: loading
|
|
307
332
|
};
|
|
308
333
|
});
|
|
309
|
-
_context.next =
|
|
334
|
+
_context.next = 93;
|
|
310
335
|
break;
|
|
311
|
-
case
|
|
312
|
-
_context.prev =
|
|
336
|
+
case 64:
|
|
337
|
+
_context.prev = 64;
|
|
313
338
|
_context.t5 = _context["catch"](6);
|
|
314
339
|
is5xxEvent = checkIf500Event(_context.t5.statusCode);
|
|
315
340
|
if (!closed && !onError && is5xxEvent) {
|
|
@@ -322,35 +347,35 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
322
347
|
});
|
|
323
348
|
onErrorProducedError = false;
|
|
324
349
|
defaultUsers = [];
|
|
325
|
-
_context.prev =
|
|
350
|
+
_context.prev = 71;
|
|
326
351
|
if (!onError) {
|
|
327
|
-
_context.next =
|
|
352
|
+
_context.next = 81;
|
|
328
353
|
break;
|
|
329
354
|
}
|
|
330
|
-
_context.next =
|
|
355
|
+
_context.next = 75;
|
|
331
356
|
return onError(_context.t5, recommendationsRequest);
|
|
332
|
-
case
|
|
357
|
+
case 75:
|
|
333
358
|
_context.t7 = _context.sent;
|
|
334
359
|
if (_context.t7) {
|
|
335
|
-
_context.next =
|
|
360
|
+
_context.next = 78;
|
|
336
361
|
break;
|
|
337
362
|
}
|
|
338
363
|
_context.t7 = [];
|
|
339
|
-
case
|
|
364
|
+
case 78:
|
|
340
365
|
_context.t6 = _context.t7;
|
|
341
|
-
_context.next =
|
|
366
|
+
_context.next = 82;
|
|
342
367
|
break;
|
|
343
|
-
case
|
|
368
|
+
case 81:
|
|
344
369
|
_context.t6 = [];
|
|
345
|
-
case
|
|
370
|
+
case 82:
|
|
346
371
|
defaultUsers = _context.t6;
|
|
347
|
-
_context.next =
|
|
372
|
+
_context.next = 88;
|
|
348
373
|
break;
|
|
349
|
-
case
|
|
350
|
-
_context.prev =
|
|
351
|
-
_context.t8 = _context["catch"](
|
|
374
|
+
case 85:
|
|
375
|
+
_context.prev = 85;
|
|
376
|
+
_context.t8 = _context["catch"](71);
|
|
352
377
|
onErrorProducedError = true;
|
|
353
|
-
case
|
|
378
|
+
case 88:
|
|
354
379
|
if (onErrorProducedError && is5xxEvent) {
|
|
355
380
|
// Log error from fallback data source `onError` to UFO
|
|
356
381
|
_this.optionsShownUfoExperienceInstance.failure(ufoEndStateConfig(_this.props.fieldId));
|
|
@@ -367,11 +392,11 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
367
392
|
elapsedTimeMilli: _elapsedTimeMilli,
|
|
368
393
|
productAttributes: productAttributes
|
|
369
394
|
});
|
|
370
|
-
case
|
|
395
|
+
case 93:
|
|
371
396
|
case "end":
|
|
372
397
|
return _context.stop();
|
|
373
398
|
}
|
|
374
|
-
}, _callee, null, [[6,
|
|
399
|
+
}, _callee, null, [[6, 64], [71, 85]]);
|
|
375
400
|
})), (_this$props$debounceT = _this.props.debounceTime) !== null && _this$props$debounceT !== void 0 ? _this$props$debounceT : 0));
|
|
376
401
|
_defineProperty(_this, "onInputChange", function (newQuery, sessionId) {
|
|
377
402
|
var query = newQuery || '';
|
|
@@ -580,6 +605,7 @@ _defineProperty(SmartUserPickerWithoutAnalytics, "defaultProps", {
|
|
|
580
605
|
debounceTime: DEFAULT_DEBOUNCE_TIME_MS,
|
|
581
606
|
userResolvers: [],
|
|
582
607
|
enableEmailSearch: false,
|
|
583
|
-
allowEmailSelectionWhenEmailMatched: true
|
|
608
|
+
allowEmailSelectionWhenEmailMatched: true,
|
|
609
|
+
verifiedTeams: false
|
|
584
610
|
});
|
|
585
611
|
export var SmartUserPicker = withAnalyticsEvents()(injectIntl(SmartUserPickerWithoutAnalytics));
|
|
@@ -21,6 +21,7 @@ export declare class SmartUserPickerWithoutAnalytics extends React.Component<Pro
|
|
|
21
21
|
userResolvers: never[];
|
|
22
22
|
enableEmailSearch: boolean;
|
|
23
23
|
allowEmailSelectionWhenEmailMatched: boolean;
|
|
24
|
+
verifiedTeams: boolean;
|
|
24
25
|
};
|
|
25
26
|
constructor(props: Props & WrappedComponentProps);
|
|
26
27
|
componentDidMount(): Promise<void>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface RecommendationRequest {
|
|
|
23
23
|
includeTeams?: boolean;
|
|
24
24
|
includeNonLicensedUsers?: boolean;
|
|
25
25
|
searchEmail?: boolean;
|
|
26
|
+
verifiedTeams?: boolean;
|
|
26
27
|
}
|
|
27
28
|
type OnError = (error: any, request: RecommendationRequest) => Promise<OptionData[]> | void;
|
|
28
29
|
type OnValueError = (error: any, defaultValue: DefaultValue) => Promise<OptionData[]> | void;
|
|
@@ -126,6 +127,10 @@ export interface SmartProps {
|
|
|
126
127
|
* Whether to include teams in the resultset. @default false
|
|
127
128
|
*/
|
|
128
129
|
includeTeams?: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* When set to true, only returns verified teams. Only applies when includeTeams is true. @default false
|
|
132
|
+
*/
|
|
133
|
+
verifiedTeams?: boolean;
|
|
129
134
|
/**
|
|
130
135
|
* Whether to include users in the resultset. @default true
|
|
131
136
|
*/
|
|
@@ -228,6 +233,12 @@ export interface SmartProps {
|
|
|
228
233
|
* Optional callback to provide additional user resolvers, such as for fetching and adding users from third party sources
|
|
229
234
|
*/
|
|
230
235
|
userResolvers?: Array<(query: string) => Promise<OptionData[]>>;
|
|
236
|
+
/**
|
|
237
|
+
* Custom fetcher function to load options. When provided, this function will be called
|
|
238
|
+
* instead of the default recommendation API. The function receives the search term
|
|
239
|
+
* and should return a Promise that resolves to an array of OptionData.
|
|
240
|
+
*/
|
|
241
|
+
fetchOptions?: (query: string) => Promise<OptionData[]>;
|
|
231
242
|
/**
|
|
232
243
|
* Whether to include teams UI updates in the resultset. @default false
|
|
233
244
|
*/
|
|
@@ -21,6 +21,7 @@ export declare class SmartUserPickerWithoutAnalytics extends React.Component<Pro
|
|
|
21
21
|
userResolvers: never[];
|
|
22
22
|
enableEmailSearch: boolean;
|
|
23
23
|
allowEmailSelectionWhenEmailMatched: boolean;
|
|
24
|
+
verifiedTeams: boolean;
|
|
24
25
|
};
|
|
25
26
|
constructor(props: Props & WrappedComponentProps);
|
|
26
27
|
componentDidMount(): Promise<void>;
|
|
@@ -23,6 +23,7 @@ export interface RecommendationRequest {
|
|
|
23
23
|
includeTeams?: boolean;
|
|
24
24
|
includeNonLicensedUsers?: boolean;
|
|
25
25
|
searchEmail?: boolean;
|
|
26
|
+
verifiedTeams?: boolean;
|
|
26
27
|
}
|
|
27
28
|
type OnError = (error: any, request: RecommendationRequest) => Promise<OptionData[]> | void;
|
|
28
29
|
type OnValueError = (error: any, defaultValue: DefaultValue) => Promise<OptionData[]> | void;
|
|
@@ -126,6 +127,10 @@ export interface SmartProps {
|
|
|
126
127
|
* Whether to include teams in the resultset. @default false
|
|
127
128
|
*/
|
|
128
129
|
includeTeams?: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* When set to true, only returns verified teams. Only applies when includeTeams is true. @default false
|
|
132
|
+
*/
|
|
133
|
+
verifiedTeams?: boolean;
|
|
129
134
|
/**
|
|
130
135
|
* Whether to include users in the resultset. @default true
|
|
131
136
|
*/
|
|
@@ -228,6 +233,12 @@ export interface SmartProps {
|
|
|
228
233
|
* Optional callback to provide additional user resolvers, such as for fetching and adding users from third party sources
|
|
229
234
|
*/
|
|
230
235
|
userResolvers?: Array<(query: string) => Promise<OptionData[]>>;
|
|
236
|
+
/**
|
|
237
|
+
* Custom fetcher function to load options. When provided, this function will be called
|
|
238
|
+
* instead of the default recommendation API. The function receives the search term
|
|
239
|
+
* and should return a Promise that resolves to an array of OptionData.
|
|
240
|
+
*/
|
|
241
|
+
fetchOptions?: (query: string) => Promise<OptionData[]>;
|
|
231
242
|
/**
|
|
232
243
|
* Whether to include teams UI updates in the resultset. @default false
|
|
233
244
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/smart-user-picker",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.7.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@atlaskit/analytics-next": "^11.1.0",
|
|
39
39
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
40
40
|
"@atlaskit/ufo": "^0.4.0",
|
|
41
|
-
"@atlaskit/user-picker": "^11.
|
|
41
|
+
"@atlaskit/user-picker": "^11.18.0",
|
|
42
42
|
"@babel/runtime": "^7.0.0",
|
|
43
43
|
"lodash": "^4.17.21",
|
|
44
44
|
"memoize-one": "^6.0.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"react-dom": "^18.2.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@atlaskit/select": "^21.
|
|
53
|
+
"@atlaskit/select": "^21.6.0",
|
|
54
54
|
"@atlaskit/util-data-test": "^18.3.0",
|
|
55
55
|
"@testing-library/dom": "^10.1.0",
|
|
56
56
|
"@testing-library/react": "^13.4.0",
|
|
@@ -63,6 +63,12 @@
|
|
|
63
63
|
"platform-feature-flags": {
|
|
64
64
|
"twcg-444-invite-usd-improvements-m2-gate": {
|
|
65
65
|
"type": "boolean"
|
|
66
|
+
},
|
|
67
|
+
"smart-user-picker-load-options-gate": {
|
|
68
|
+
"type": "boolean"
|
|
69
|
+
},
|
|
70
|
+
"smart-user-picker-managed-teams-gate": {
|
|
71
|
+
"type": "boolean"
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
}
|