@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 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
@@ -4,7 +4,8 @@
4
4
  "target": "es5",
5
5
  "outDir": "../../../../../confluence/tsDist/@atlaskit__smart-user-picker",
6
6
  "rootDir": "../",
7
- "composite": true
7
+ "composite": true,
8
+ "noCheck": true
8
9
  },
9
10
  "include": [
10
11
  "../src/**/*.ts",
@@ -4,7 +4,8 @@
4
4
  "target": "es5",
5
5
  "outDir": "../../../../../jira/tsDist/@atlaskit__smart-user-picker/app",
6
6
  "rootDir": "../",
7
- "composite": true
7
+ "composite": true,
8
+ "noCheck": true
8
9
  },
9
10
  "include": [
10
11
  "../src/**/*.ts",
@@ -4,7 +4,8 @@
4
4
  "target": "es5",
5
5
  "outDir": "../../../../../tsDist/@atlaskit__smart-user-picker/app",
6
6
  "rootDir": "../",
7
- "composite": true
7
+ "composite": true,
8
+ "noCheck": true
8
9
  },
9
10
  "include": [
10
11
  "../src/**/*.ts",
@@ -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 = 21;
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 = 14;
189
+ _context.next = 20;
178
190
  return Promise.all([userRecommendationsPromise].concat((0, _toConsumableArray2.default)(userResolversPromises)));
179
- case 14:
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 = 24;
197
+ _context.next = 30;
186
198
  break;
187
- case 21:
188
- _context.next = 23;
199
+ case 27:
200
+ _context.next = 29;
189
201
  return (0, _service.getUserRecommendations)(recommendationsRequest, intl);
190
- case 23:
202
+ case 29:
191
203
  recommendedUsers = _context.sent;
192
- case 24:
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 = 35;
277
+ _context.next = 42;
253
278
  break;
254
279
  }
255
- _context.next = 32;
280
+ _context.next = 39;
256
281
  return transformOptions(recommendedUsers, _query);
257
- case 32:
282
+ case 39:
258
283
  _context.t0 = _context.sent;
259
- _context.next = 36;
284
+ _context.next = 43;
260
285
  break;
261
- case 35:
286
+ case 42:
262
287
  _context.t0 = recommendedUsers;
263
- case 36:
288
+ case 43:
264
289
  transformedOptions = _context.t0;
265
290
  if (!(transformedOptions.length === 0 && onEmpty)) {
266
- _context.next = 52;
291
+ _context.next = 59;
267
292
  break;
268
293
  }
269
- _context.next = 40;
294
+ _context.next = 47;
270
295
  return onEmpty(_query);
271
- case 40:
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 = 44;
300
+ _context.next = 51;
276
301
  break;
277
302
  }
278
303
  _context.t2 = _yield$onEmpty !== void 0;
279
- case 44:
304
+ case 51:
280
305
  if (!_context.t2) {
281
- _context.next = 48;
306
+ _context.next = 55;
282
307
  break;
283
308
  }
284
309
  _context.t4 = _yield$onEmpty;
285
- _context.next = 49;
310
+ _context.next = 56;
286
311
  break;
287
- case 48:
312
+ case 55:
288
313
  _context.t4 = [];
289
- case 49:
314
+ case 56:
290
315
  _context.t1 = _context.t4;
291
- _context.next = 53;
316
+ _context.next = 60;
292
317
  break;
293
- case 52:
318
+ case 59:
294
319
  _context.t1 = transformedOptions;
295
- case 53:
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 = 86;
342
+ _context.next = 93;
318
343
  break;
319
- case 57:
320
- _context.prev = 57;
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 = 64;
358
+ _context.prev = 71;
334
359
  if (!onError) {
335
- _context.next = 74;
360
+ _context.next = 81;
336
361
  break;
337
362
  }
338
- _context.next = 68;
363
+ _context.next = 75;
339
364
  return onError(_context.t5, recommendationsRequest);
340
- case 68:
365
+ case 75:
341
366
  _context.t7 = _context.sent;
342
367
  if (_context.t7) {
343
- _context.next = 71;
368
+ _context.next = 78;
344
369
  break;
345
370
  }
346
371
  _context.t7 = [];
347
- case 71:
372
+ case 78:
348
373
  _context.t6 = _context.t7;
349
- _context.next = 75;
374
+ _context.next = 82;
350
375
  break;
351
- case 74:
376
+ case 81:
352
377
  _context.t6 = [];
353
- case 75:
378
+ case 82:
354
379
  defaultUsers = _context.t6;
355
- _context.next = 81;
380
+ _context.next = 88;
356
381
  break;
357
- case 78:
358
- _context.prev = 78;
359
- _context.t8 = _context["catch"](64);
382
+ case 85:
383
+ _context.prev = 85;
384
+ _context.t8 = _context["catch"](71);
360
385
  onErrorProducedError = true;
361
- case 81:
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 86:
403
+ case 93:
379
404
  case "end":
380
405
  return _context.stop();
381
406
  }
382
- }, _callee, null, [[6, 57], [64, 78]]);
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('twcg-444-invite-usd-improvements-m2-gate')) {
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 (error) {
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 = 21;
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 = 14;
181
+ _context.next = 20;
170
182
  return Promise.all([userRecommendationsPromise].concat(_toConsumableArray(userResolversPromises)));
171
- case 14:
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 = 24;
189
+ _context.next = 30;
178
190
  break;
179
- case 21:
180
- _context.next = 23;
191
+ case 27:
192
+ _context.next = 29;
181
193
  return getUserRecommendations(recommendationsRequest, intl);
182
- case 23:
194
+ case 29:
183
195
  recommendedUsers = _context.sent;
184
- case 24:
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 = 35;
269
+ _context.next = 42;
245
270
  break;
246
271
  }
247
- _context.next = 32;
272
+ _context.next = 39;
248
273
  return transformOptions(recommendedUsers, _query);
249
- case 32:
274
+ case 39:
250
275
  _context.t0 = _context.sent;
251
- _context.next = 36;
276
+ _context.next = 43;
252
277
  break;
253
- case 35:
278
+ case 42:
254
279
  _context.t0 = recommendedUsers;
255
- case 36:
280
+ case 43:
256
281
  transformedOptions = _context.t0;
257
282
  if (!(transformedOptions.length === 0 && onEmpty)) {
258
- _context.next = 52;
283
+ _context.next = 59;
259
284
  break;
260
285
  }
261
- _context.next = 40;
286
+ _context.next = 47;
262
287
  return onEmpty(_query);
263
- case 40:
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 = 44;
292
+ _context.next = 51;
268
293
  break;
269
294
  }
270
295
  _context.t2 = _yield$onEmpty !== void 0;
271
- case 44:
296
+ case 51:
272
297
  if (!_context.t2) {
273
- _context.next = 48;
298
+ _context.next = 55;
274
299
  break;
275
300
  }
276
301
  _context.t4 = _yield$onEmpty;
277
- _context.next = 49;
302
+ _context.next = 56;
278
303
  break;
279
- case 48:
304
+ case 55:
280
305
  _context.t4 = [];
281
- case 49:
306
+ case 56:
282
307
  _context.t1 = _context.t4;
283
- _context.next = 53;
308
+ _context.next = 60;
284
309
  break;
285
- case 52:
310
+ case 59:
286
311
  _context.t1 = transformedOptions;
287
- case 53:
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 = 86;
334
+ _context.next = 93;
310
335
  break;
311
- case 57:
312
- _context.prev = 57;
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 = 64;
350
+ _context.prev = 71;
326
351
  if (!onError) {
327
- _context.next = 74;
352
+ _context.next = 81;
328
353
  break;
329
354
  }
330
- _context.next = 68;
355
+ _context.next = 75;
331
356
  return onError(_context.t5, recommendationsRequest);
332
- case 68:
357
+ case 75:
333
358
  _context.t7 = _context.sent;
334
359
  if (_context.t7) {
335
- _context.next = 71;
360
+ _context.next = 78;
336
361
  break;
337
362
  }
338
363
  _context.t7 = [];
339
- case 71:
364
+ case 78:
340
365
  _context.t6 = _context.t7;
341
- _context.next = 75;
366
+ _context.next = 82;
342
367
  break;
343
- case 74:
368
+ case 81:
344
369
  _context.t6 = [];
345
- case 75:
370
+ case 82:
346
371
  defaultUsers = _context.t6;
347
- _context.next = 81;
372
+ _context.next = 88;
348
373
  break;
349
- case 78:
350
- _context.prev = 78;
351
- _context.t8 = _context["catch"](64);
374
+ case 85:
375
+ _context.prev = 85;
376
+ _context.t8 = _context["catch"](71);
352
377
  onErrorProducedError = true;
353
- case 81:
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 86:
395
+ case 93:
371
396
  case "end":
372
397
  return _context.stop();
373
398
  }
374
- }, _callee, null, [[6, 57], [64, 78]]);
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>;
@@ -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.5.0",
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.17.0",
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.4.0",
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
  }