@atlaskit/smart-user-picker 11.3.0 → 11.3.2
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 +21 -0
- package/dist/cjs/analytics.js +1 -1
- package/dist/cjs/components/SmartUserPicker.js +77 -56
- package/dist/es2019/analytics.js +1 -1
- package/dist/es2019/components/SmartUserPicker.js +41 -9
- package/dist/esm/analytics.js +1 -1
- package/dist/esm/components/SmartUserPicker.js +77 -56
- package/dist/types/components/SmartUserPicker.d.ts +1 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @atlassian/smart-user-picker
|
|
2
2
|
|
|
3
|
+
## 11.3.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`4bdae29c77827`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4bdae29c77827) -
|
|
8
|
+
Fix suggestEmailsForDomain being suppressed for partial (non-email) input when enableEmailSearch
|
|
9
|
+
and allowEmailSelectionWhenEmailMatched=false are both set. The WAR-5498 FG cleanup (2026-03-04)
|
|
10
|
+
made the isEmailQuery restriction unconditional, breaking the domain-suggestion creatable option
|
|
11
|
+
(e.g. "asdf@atlassian.com"). Behind the new gate smart_user_picker_suggest_emails_for_domain,
|
|
12
|
+
partial queries now allow the domain suggestion to render, while the email option remains
|
|
13
|
+
suppressed when a full email query matches an existing user, or when the synthesized
|
|
14
|
+
"<query>@<domain>" address already belongs to a returned user.
|
|
15
|
+
|
|
16
|
+
## 11.3.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [`f834c7d669731`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f834c7d669731) -
|
|
21
|
+
Removed feature gate TWCG-444 for Unified Share Dialogue experiment. No change in functionality
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
|
|
3
24
|
## 11.3.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
package/dist/cjs/analytics.js
CHANGED
|
@@ -12,7 +12,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
|
|
|
12
12
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
13
13
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
14
14
|
var packageName = "@atlaskit/smart-user-picker";
|
|
15
|
-
var packageVersion = "11.
|
|
15
|
+
var packageVersion = "11.3.1";
|
|
16
16
|
var startSession = exports.startSession = function startSession() {
|
|
17
17
|
return {
|
|
18
18
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
@@ -32,7 +32,7 @@ var _MessagesIntlProvider = _interopRequireDefault(require("./MessagesIntlProvid
|
|
|
32
32
|
var _types = require("../types");
|
|
33
33
|
var _service = require("../service");
|
|
34
34
|
var _ufoExperiences = require("../ufoExperiences");
|
|
35
|
-
var _excluded = ["allowEmail", "enableEmailSearch", "allowEmailSelectionWhenEmailMatched"];
|
|
35
|
+
var _excluded = ["allowEmail", "enableEmailSearch", "allowEmailSelectionWhenEmailMatched", "suggestEmailsForDomain"];
|
|
36
36
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t1 in e) "default" !== _t1 && {}.hasOwnProperty.call(e, _t1) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t1)) && (i.get || i.set) ? o(f, _t1, i) : f[_t1] = e[_t1]); return f; })(e, t); }
|
|
37
37
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
38
38
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
@@ -93,6 +93,9 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
93
93
|
});
|
|
94
94
|
// Track if the last search was an email search that found matches
|
|
95
95
|
(0, _defineProperty2.default)(_this, "lastEmailSearchFoundMatches", false);
|
|
96
|
+
// Track if the domain-suggested email (`<query>@<suggestEmailsForDomain>`) for a partial
|
|
97
|
+
// query already belongs to a returned user, in which case the suggestion is redundant
|
|
98
|
+
(0, _defineProperty2.default)(_this, "lastDomainSuggestionMatchedUser", false);
|
|
96
99
|
(0, _defineProperty2.default)(_this, "abortOptionsShownUfoExperience", function () {
|
|
97
100
|
if (_this.optionsShownUfoExperienceInstance.state.id === _ufo.UFOExperienceState.STARTED.id) {
|
|
98
101
|
// There may be an existing UFO timing running from previous key entry or focus,
|
|
@@ -118,7 +121,7 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
118
121
|
});
|
|
119
122
|
(0, _defineProperty2.default)(_this, "memoizedFilterOptions", (0, _memoizeOne.default)(_this.filterOptions));
|
|
120
123
|
(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, fetchOptions, maxOptions, objectId, onEmpty, onError, overrideByline, displayEmailInByline, verifiedTeams, orgId, userbaseId, principalId, productAttributes, productKey, restrictTo, searchQueryFilter, siteId, isTeamSyncedToGroupDirectoryFilter, 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, userMatches, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli, _t, _t2, _t3, _t4, _t5, _t6, _t7, _t8, _t9;
|
|
124
|
+
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, userbaseId, principalId, productAttributes, productKey, restrictTo, searchQueryFilter, siteId, isTeamSyncedToGroupDirectoryFilter, 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, userMatches, suggestEmailsForDomain, suggestedEmail, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli, _t, _t2, _t3, _t4, _t5, _t6, _t7, _t8, _t9;
|
|
122
125
|
return _regenerator.default.wrap(function (_context) {
|
|
123
126
|
while (1) switch (_context.prev = _context.next) {
|
|
124
127
|
case 0:
|
|
@@ -176,13 +179,9 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
176
179
|
return fetchOptions(_query);
|
|
177
180
|
case 2:
|
|
178
181
|
recommendedUsers = _context.sent;
|
|
179
|
-
_context.next =
|
|
182
|
+
_context.next = 5;
|
|
180
183
|
break;
|
|
181
184
|
case 3:
|
|
182
|
-
if (!(0, _platformFeatureFlags.fg)('twcg-444-invite-usd-improvements-m2-gate')) {
|
|
183
|
-
_context.next = 5;
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
185
|
userRecommendationsPromise = (0, _service.getUserRecommendations)(recommendationsRequest, intl);
|
|
187
186
|
userResolversPromises = (userResolvers !== null && userResolvers !== void 0 ? userResolvers : []).map(function (resolver) {
|
|
188
187
|
return resolver(_query).catch(function (error) {
|
|
@@ -201,14 +200,7 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
201
200
|
mainRecommendations = _yield$Promise$all2[0];
|
|
202
201
|
userResolverResults = _arrayLikeToArray(_yield$Promise$all2).slice(1);
|
|
203
202
|
recommendedUsers = [mainRecommendations].concat((0, _toConsumableArray2.default)(userResolverResults)).flat();
|
|
204
|
-
_context.next = 7;
|
|
205
|
-
break;
|
|
206
203
|
case 5:
|
|
207
|
-
_context.next = 6;
|
|
208
|
-
return (0, _service.getUserRecommendations)(recommendationsRequest, intl);
|
|
209
|
-
case 6:
|
|
210
|
-
recommendedUsers = _context.sent;
|
|
211
|
-
case 7:
|
|
212
204
|
if (overrideByline) {
|
|
213
205
|
_iterator = _createForOfIteratorHelper(recommendedUsers);
|
|
214
206
|
try {
|
|
@@ -270,52 +262,66 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
270
262
|
} else {
|
|
271
263
|
_this.lastEmailSearchFoundMatches = false;
|
|
272
264
|
}
|
|
265
|
+
|
|
266
|
+
// For a partial query with a suggested domain, check whether the email we would
|
|
267
|
+
// synthesize (`<query>@<domain>`) already belongs to one of the returned users. If so,
|
|
268
|
+
// the real user option is shown instead and the email suggestion is suppressed.
|
|
269
|
+
suggestEmailsForDomain = _this.props.suggestEmailsForDomain;
|
|
270
|
+
if (suggestEmailsForDomain && !isEmail && _query) {
|
|
271
|
+
suggestedEmail = "".concat(_query, "@").concat(suggestEmailsForDomain).toLowerCase();
|
|
272
|
+
_this.lastDomainSuggestionMatchedUser = recommendedUsers.some(function (option) {
|
|
273
|
+
var _option$email;
|
|
274
|
+
return ((0, _userPicker.isUser)(option) || (0, _userPicker.isExternalUser)(option)) && ((_option$email = option.email) === null || _option$email === void 0 ? void 0 : _option$email.toLowerCase()) === suggestedEmail;
|
|
275
|
+
});
|
|
276
|
+
} else {
|
|
277
|
+
_this.lastDomainSuggestionMatchedUser = false;
|
|
278
|
+
}
|
|
273
279
|
elapsedTimeMilli = window.performance.now() - startTime;
|
|
274
280
|
if (!transformOptions) {
|
|
275
|
-
_context.next =
|
|
281
|
+
_context.next = 7;
|
|
276
282
|
break;
|
|
277
283
|
}
|
|
278
|
-
_context.next =
|
|
284
|
+
_context.next = 6;
|
|
279
285
|
return transformOptions(recommendedUsers, _query);
|
|
280
|
-
case
|
|
286
|
+
case 6:
|
|
281
287
|
_t = _context.sent;
|
|
282
|
-
_context.next =
|
|
288
|
+
_context.next = 8;
|
|
283
289
|
break;
|
|
284
|
-
case
|
|
290
|
+
case 7:
|
|
285
291
|
_t = recommendedUsers;
|
|
286
|
-
case
|
|
292
|
+
case 8:
|
|
287
293
|
transformedOptions = _t;
|
|
288
294
|
if (!(transformedOptions.length === 0 && onEmpty)) {
|
|
289
|
-
_context.next =
|
|
295
|
+
_context.next = 13;
|
|
290
296
|
break;
|
|
291
297
|
}
|
|
292
|
-
_context.next =
|
|
298
|
+
_context.next = 9;
|
|
293
299
|
return onEmpty(_query);
|
|
294
|
-
case
|
|
300
|
+
case 9:
|
|
295
301
|
_t4 = _yield$onEmpty = _context.sent;
|
|
296
302
|
_t3 = _t4 !== null;
|
|
297
303
|
if (!_t3) {
|
|
298
|
-
_context.next =
|
|
304
|
+
_context.next = 10;
|
|
299
305
|
break;
|
|
300
306
|
}
|
|
301
307
|
_t3 = _yield$onEmpty !== void 0;
|
|
302
|
-
case
|
|
308
|
+
case 10:
|
|
303
309
|
if (!_t3) {
|
|
304
|
-
_context.next =
|
|
310
|
+
_context.next = 11;
|
|
305
311
|
break;
|
|
306
312
|
}
|
|
307
313
|
_t5 = _yield$onEmpty;
|
|
308
|
-
_context.next =
|
|
314
|
+
_context.next = 12;
|
|
309
315
|
break;
|
|
310
|
-
case
|
|
316
|
+
case 11:
|
|
311
317
|
_t5 = [];
|
|
312
|
-
case
|
|
318
|
+
case 12:
|
|
313
319
|
_t2 = _t5;
|
|
314
|
-
_context.next =
|
|
320
|
+
_context.next = 14;
|
|
315
321
|
break;
|
|
316
|
-
case
|
|
322
|
+
case 13:
|
|
317
323
|
_t2 = transformedOptions;
|
|
318
|
-
case
|
|
324
|
+
case 14:
|
|
319
325
|
displayedUsers = _t2;
|
|
320
326
|
_this.setState(function (state) {
|
|
321
327
|
var applicable = state.query === _query;
|
|
@@ -327,7 +333,7 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
327
333
|
displayedUsers: getUsersForAnalytics(displayedUsers),
|
|
328
334
|
productAttributes: productAttributes,
|
|
329
335
|
applicable: applicable
|
|
330
|
-
},
|
|
336
|
+
}, {
|
|
331
337
|
userResolvers: Array.isArray(userResolvers) ? userResolvers.map(function (resolver) {
|
|
332
338
|
return resolver.name;
|
|
333
339
|
}) : []
|
|
@@ -337,10 +343,10 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
337
343
|
loading: loading
|
|
338
344
|
};
|
|
339
345
|
});
|
|
340
|
-
_context.next =
|
|
346
|
+
_context.next = 23;
|
|
341
347
|
break;
|
|
342
|
-
case
|
|
343
|
-
_context.prev =
|
|
348
|
+
case 15:
|
|
349
|
+
_context.prev = 15;
|
|
344
350
|
_t6 = _context["catch"](1);
|
|
345
351
|
is5xxEvent = checkIf500Event(_t6.statusCode);
|
|
346
352
|
if (!closed && !onError && is5xxEvent) {
|
|
@@ -353,35 +359,35 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
353
359
|
});
|
|
354
360
|
onErrorProducedError = false;
|
|
355
361
|
defaultUsers = [];
|
|
356
|
-
_context.prev =
|
|
362
|
+
_context.prev = 16;
|
|
357
363
|
if (!onError) {
|
|
358
|
-
_context.next =
|
|
364
|
+
_context.next = 19;
|
|
359
365
|
break;
|
|
360
366
|
}
|
|
361
|
-
_context.next =
|
|
367
|
+
_context.next = 17;
|
|
362
368
|
return onError(_t6, recommendationsRequest);
|
|
363
|
-
case
|
|
369
|
+
case 17:
|
|
364
370
|
_t8 = _context.sent;
|
|
365
371
|
if (_t8) {
|
|
366
|
-
_context.next =
|
|
372
|
+
_context.next = 18;
|
|
367
373
|
break;
|
|
368
374
|
}
|
|
369
375
|
_t8 = [];
|
|
370
|
-
case
|
|
376
|
+
case 18:
|
|
371
377
|
_t7 = _t8;
|
|
372
|
-
_context.next =
|
|
378
|
+
_context.next = 20;
|
|
373
379
|
break;
|
|
374
|
-
case
|
|
380
|
+
case 19:
|
|
375
381
|
_t7 = [];
|
|
376
|
-
case
|
|
382
|
+
case 20:
|
|
377
383
|
defaultUsers = _t7;
|
|
378
|
-
_context.next =
|
|
384
|
+
_context.next = 22;
|
|
379
385
|
break;
|
|
380
|
-
case
|
|
381
|
-
_context.prev =
|
|
382
|
-
_t9 = _context["catch"](
|
|
386
|
+
case 21:
|
|
387
|
+
_context.prev = 21;
|
|
388
|
+
_t9 = _context["catch"](16);
|
|
383
389
|
onErrorProducedError = true;
|
|
384
|
-
case
|
|
390
|
+
case 22:
|
|
385
391
|
if (onErrorProducedError && is5xxEvent) {
|
|
386
392
|
// Log error from fallback data source `onError` to UFO
|
|
387
393
|
_this.optionsShownUfoExperienceInstance.failure(ufoEndStateConfig(_this.props.fieldId));
|
|
@@ -398,11 +404,11 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
398
404
|
elapsedTimeMilli: _elapsedTimeMilli,
|
|
399
405
|
productAttributes: productAttributes
|
|
400
406
|
});
|
|
401
|
-
case
|
|
407
|
+
case 23:
|
|
402
408
|
case "end":
|
|
403
409
|
return _context.stop();
|
|
404
410
|
}
|
|
405
|
-
}, _callee, null, [[1,
|
|
411
|
+
}, _callee, null, [[1, 15], [16, 21]]);
|
|
406
412
|
})), (_this$props$debounceT = _this.props.debounceTime) !== null && _this$props$debounceT !== void 0 ? _this$props$debounceT : 0));
|
|
407
413
|
(0, _defineProperty2.default)(_this, "onInputChange", function (newQuery, sessionId) {
|
|
408
414
|
var query = newQuery || '';
|
|
@@ -577,19 +583,34 @@ var SmartUserPickerWithoutAnalytics = exports.SmartUserPickerWithoutAnalytics =
|
|
|
577
583
|
allowEmail = _this$props2.allowEmail,
|
|
578
584
|
enableEmailSearch = _this$props2.enableEmailSearch,
|
|
579
585
|
allowEmailSelectionWhenEmailMatched = _this$props2.allowEmailSelectionWhenEmailMatched,
|
|
586
|
+
suggestEmailsForDomain = _this$props2.suggestEmailsForDomain,
|
|
580
587
|
restProps = (0, _objectWithoutProperties2.default)(_this$props2, _excluded);
|
|
581
588
|
|
|
582
589
|
// Determine whether to allow email selection based on allowEmailSelectionWhenEmailMatched, if needed
|
|
583
590
|
var shouldAllowEmail = allowEmail;
|
|
591
|
+
|
|
592
|
+
// When suggestEmailsForDomain is active, partial (non-email) input must still reach the base
|
|
593
|
+
// picker's domain-suggestion creatable logic, so the isEmailQuery restriction is relaxed for
|
|
594
|
+
// those queries only. Full email queries that matched an existing user remain suppressed.
|
|
595
|
+
var isDomainSuggestionEnabled = (0, _platformFeatureFlags.fg)('smart_user_picker_suggest_emails_for_domain') && !!suggestEmailsForDomain;
|
|
584
596
|
if (allowEmail && enableEmailSearch && !allowEmailSelectionWhenEmailMatched) {
|
|
585
597
|
var isCurrentQueryEmail = isEmailQuery(this.state.query);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
598
|
+
if (isDomainSuggestionEnabled) {
|
|
599
|
+
// Allow email for partial queries so the "<query>@<domain>" suggestion can render,
|
|
600
|
+
// but still suppress selection when a full email query matched an existing user,
|
|
601
|
+
// or when the synthesized "<query>@<domain>" is itself an existing user's email.
|
|
602
|
+
shouldAllowEmail = isCurrentQueryEmail ? !this.lastEmailSearchFoundMatches // full email: suppress when user matched
|
|
603
|
+
: !this.lastDomainSuggestionMatchedUser; // partial: suppress when synth email matched a user
|
|
604
|
+
} else {
|
|
605
|
+
// Only allow email selection when:
|
|
606
|
+
// 1. The query matches email format (validated by regex)
|
|
607
|
+
// 2. No user/external user matches were found (only teams/groups suggested)
|
|
608
|
+
shouldAllowEmail = isCurrentQueryEmail && !this.lastEmailSearchFoundMatches;
|
|
609
|
+
}
|
|
590
610
|
}
|
|
591
611
|
return /*#__PURE__*/_react.default.createElement(_MessagesIntlProvider.default, null, /*#__PURE__*/_react.default.createElement(_userPicker.default, (0, _extends2.default)({}, restProps, {
|
|
592
612
|
allowEmail: shouldAllowEmail,
|
|
613
|
+
suggestEmailsForDomain: suggestEmailsForDomain,
|
|
593
614
|
onInputChange: this.onInputChange,
|
|
594
615
|
onBlur: this.onBlur,
|
|
595
616
|
onFocus: this.onFocus,
|
package/dist/es2019/analytics.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createAndFireEvent } from '@atlaskit/analytics-next';
|
|
|
3
3
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
4
4
|
import { v4 as uuid } from 'uuid';
|
|
5
5
|
const packageName = "@atlaskit/smart-user-picker";
|
|
6
|
-
const packageVersion = "11.
|
|
6
|
+
const packageVersion = "11.3.1";
|
|
7
7
|
export const startSession = () => ({
|
|
8
8
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
9
9
|
id: uuid(),
|
|
@@ -58,6 +58,9 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
58
58
|
});
|
|
59
59
|
// Track if the last search was an email search that found matches
|
|
60
60
|
_defineProperty(this, "lastEmailSearchFoundMatches", false);
|
|
61
|
+
// Track if the domain-suggested email (`<query>@<suggestEmailsForDomain>`) for a partial
|
|
62
|
+
// query already belongs to a returned user, in which case the suggestion is redundant
|
|
63
|
+
_defineProperty(this, "lastDomainSuggestionMatchedUser", false);
|
|
61
64
|
_defineProperty(this, "abortOptionsShownUfoExperience", () => {
|
|
62
65
|
if (this.optionsShownUfoExperienceInstance.state.id === UFOExperienceState.STARTED.id) {
|
|
63
66
|
// There may be an existing UFO timing running from previous key entry or focus,
|
|
@@ -171,7 +174,7 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
171
174
|
let recommendedUsers;
|
|
172
175
|
if (fetchOptions && fg('smart-user-picker-load-options-gate')) {
|
|
173
176
|
recommendedUsers = await fetchOptions(query);
|
|
174
|
-
} else
|
|
177
|
+
} else {
|
|
175
178
|
const userRecommendationsPromise = getUserRecommendations(recommendationsRequest, intl);
|
|
176
179
|
const userResolversPromises = (userResolvers !== null && userResolvers !== void 0 ? userResolvers : []).map(resolver => resolver(query).catch(error => {
|
|
177
180
|
this.fireEvent(failedUserResolversEvent, {
|
|
@@ -182,8 +185,6 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
182
185
|
}));
|
|
183
186
|
const [mainRecommendations, ...userResolverResults] = await Promise.all([userRecommendationsPromise, ...userResolversPromises]);
|
|
184
187
|
recommendedUsers = [mainRecommendations, ...userResolverResults].flat();
|
|
185
|
-
} else {
|
|
186
|
-
recommendedUsers = await getUserRecommendations(recommendationsRequest, intl);
|
|
187
188
|
}
|
|
188
189
|
if (overrideByline) {
|
|
189
190
|
for (let option of recommendedUsers) {
|
|
@@ -220,6 +221,22 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
220
221
|
} else {
|
|
221
222
|
this.lastEmailSearchFoundMatches = false;
|
|
222
223
|
}
|
|
224
|
+
|
|
225
|
+
// For a partial query with a suggested domain, check whether the email we would
|
|
226
|
+
// synthesize (`<query>@<domain>`) already belongs to one of the returned users. If so,
|
|
227
|
+
// the real user option is shown instead and the email suggestion is suppressed.
|
|
228
|
+
const {
|
|
229
|
+
suggestEmailsForDomain
|
|
230
|
+
} = this.props;
|
|
231
|
+
if (suggestEmailsForDomain && !isEmail && query) {
|
|
232
|
+
const suggestedEmail = `${query}@${suggestEmailsForDomain}`.toLowerCase();
|
|
233
|
+
this.lastDomainSuggestionMatchedUser = recommendedUsers.some(option => {
|
|
234
|
+
var _option$email;
|
|
235
|
+
return (isUser(option) || isExternalUser(option)) && ((_option$email = option.email) === null || _option$email === void 0 ? void 0 : _option$email.toLowerCase()) === suggestedEmail;
|
|
236
|
+
});
|
|
237
|
+
} else {
|
|
238
|
+
this.lastDomainSuggestionMatchedUser = false;
|
|
239
|
+
}
|
|
223
240
|
const elapsedTimeMilli = window.performance.now() - startTime;
|
|
224
241
|
const transformedOptions = transformOptions ? await transformOptions(recommendedUsers, query) : recommendedUsers;
|
|
225
242
|
const displayedUsers = transformedOptions.length === 0 && onEmpty ? (_await$onEmpty = await onEmpty(query)) !== null && _await$onEmpty !== void 0 ? _await$onEmpty : [] : transformedOptions;
|
|
@@ -233,9 +250,9 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
233
250
|
displayedUsers: getUsersForAnalytics(displayedUsers),
|
|
234
251
|
productAttributes,
|
|
235
252
|
applicable,
|
|
236
|
-
...
|
|
253
|
+
...{
|
|
237
254
|
userResolvers: Array.isArray(userResolvers) ? userResolvers.map(resolver => resolver.name) : []
|
|
238
|
-
}
|
|
255
|
+
}
|
|
239
256
|
});
|
|
240
257
|
return {
|
|
241
258
|
users,
|
|
@@ -421,20 +438,35 @@ export class SmartUserPickerWithoutAnalytics extends React.Component {
|
|
|
421
438
|
allowEmail,
|
|
422
439
|
enableEmailSearch,
|
|
423
440
|
allowEmailSelectionWhenEmailMatched,
|
|
441
|
+
suggestEmailsForDomain,
|
|
424
442
|
...restProps
|
|
425
443
|
} = this.props;
|
|
426
444
|
|
|
427
445
|
// Determine whether to allow email selection based on allowEmailSelectionWhenEmailMatched, if needed
|
|
428
446
|
let shouldAllowEmail = allowEmail;
|
|
447
|
+
|
|
448
|
+
// When suggestEmailsForDomain is active, partial (non-email) input must still reach the base
|
|
449
|
+
// picker's domain-suggestion creatable logic, so the isEmailQuery restriction is relaxed for
|
|
450
|
+
// those queries only. Full email queries that matched an existing user remain suppressed.
|
|
451
|
+
const isDomainSuggestionEnabled = fg('smart_user_picker_suggest_emails_for_domain') && !!suggestEmailsForDomain;
|
|
429
452
|
if (allowEmail && enableEmailSearch && !allowEmailSelectionWhenEmailMatched) {
|
|
430
453
|
const isCurrentQueryEmail = isEmailQuery(this.state.query);
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
454
|
+
if (isDomainSuggestionEnabled) {
|
|
455
|
+
// Allow email for partial queries so the "<query>@<domain>" suggestion can render,
|
|
456
|
+
// but still suppress selection when a full email query matched an existing user,
|
|
457
|
+
// or when the synthesized "<query>@<domain>" is itself an existing user's email.
|
|
458
|
+
shouldAllowEmail = isCurrentQueryEmail ? !this.lastEmailSearchFoundMatches // full email: suppress when user matched
|
|
459
|
+
: !this.lastDomainSuggestionMatchedUser; // partial: suppress when synth email matched a user
|
|
460
|
+
} else {
|
|
461
|
+
// Only allow email selection when:
|
|
462
|
+
// 1. The query matches email format (validated by regex)
|
|
463
|
+
// 2. No user/external user matches were found (only teams/groups suggested)
|
|
464
|
+
shouldAllowEmail = isCurrentQueryEmail && !this.lastEmailSearchFoundMatches;
|
|
465
|
+
}
|
|
435
466
|
}
|
|
436
467
|
return /*#__PURE__*/React.createElement(MessagesIntlProvider, null, /*#__PURE__*/React.createElement(UserPicker, _extends({}, restProps, {
|
|
437
468
|
allowEmail: shouldAllowEmail,
|
|
469
|
+
suggestEmailsForDomain: suggestEmailsForDomain,
|
|
438
470
|
onInputChange: this.onInputChange,
|
|
439
471
|
onBlur: this.onBlur,
|
|
440
472
|
onFocus: this.onFocus,
|
package/dist/esm/analytics.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createAndFireEvent } from '@atlaskit/analytics-next';
|
|
|
6
6
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
7
7
|
import { v4 as uuid } from 'uuid';
|
|
8
8
|
var packageName = "@atlaskit/smart-user-picker";
|
|
9
|
-
var packageVersion = "11.
|
|
9
|
+
var packageVersion = "11.3.1";
|
|
10
10
|
export var startSession = function startSession() {
|
|
11
11
|
return {
|
|
12
12
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
@@ -9,7 +9,7 @@ import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstruct
|
|
|
9
9
|
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
|
|
10
10
|
import _inherits from "@babel/runtime/helpers/inherits";
|
|
11
11
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
12
|
-
var _excluded = ["allowEmail", "enableEmailSearch", "allowEmailSelectionWhenEmailMatched"];
|
|
12
|
+
var _excluded = ["allowEmail", "enableEmailSearch", "allowEmailSelectionWhenEmailMatched", "suggestEmailsForDomain"];
|
|
13
13
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
14
14
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
15
15
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
@@ -85,6 +85,9 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
85
85
|
});
|
|
86
86
|
// Track if the last search was an email search that found matches
|
|
87
87
|
_defineProperty(_this, "lastEmailSearchFoundMatches", false);
|
|
88
|
+
// Track if the domain-suggested email (`<query>@<suggestEmailsForDomain>`) for a partial
|
|
89
|
+
// query already belongs to a returned user, in which case the suggestion is redundant
|
|
90
|
+
_defineProperty(_this, "lastDomainSuggestionMatchedUser", false);
|
|
88
91
|
_defineProperty(_this, "abortOptionsShownUfoExperience", function () {
|
|
89
92
|
if (_this.optionsShownUfoExperienceInstance.state.id === UFOExperienceState.STARTED.id) {
|
|
90
93
|
// There may be an existing UFO timing running from previous key entry or focus,
|
|
@@ -110,7 +113,7 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
110
113
|
});
|
|
111
114
|
_defineProperty(_this, "memoizedFilterOptions", memoizeOne(_this.filterOptions));
|
|
112
115
|
_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, fetchOptions, maxOptions, objectId, onEmpty, onError, overrideByline, displayEmailInByline, verifiedTeams, orgId, userbaseId, principalId, productAttributes, productKey, restrictTo, searchQueryFilter, siteId, isTeamSyncedToGroupDirectoryFilter, 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, userMatches, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli, _t, _t2, _t3, _t4, _t5, _t6, _t7, _t8, _t9;
|
|
116
|
+
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, userbaseId, principalId, productAttributes, productKey, restrictTo, searchQueryFilter, siteId, isTeamSyncedToGroupDirectoryFilter, 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, userMatches, suggestEmailsForDomain, suggestedEmail, elapsedTimeMilli, transformedOptions, displayedUsers, is5xxEvent, onErrorProducedError, defaultUsers, _elapsedTimeMilli, _t, _t2, _t3, _t4, _t5, _t6, _t7, _t8, _t9;
|
|
114
117
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
115
118
|
while (1) switch (_context.prev = _context.next) {
|
|
116
119
|
case 0:
|
|
@@ -168,13 +171,9 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
168
171
|
return fetchOptions(_query);
|
|
169
172
|
case 2:
|
|
170
173
|
recommendedUsers = _context.sent;
|
|
171
|
-
_context.next =
|
|
174
|
+
_context.next = 5;
|
|
172
175
|
break;
|
|
173
176
|
case 3:
|
|
174
|
-
if (!fg('twcg-444-invite-usd-improvements-m2-gate')) {
|
|
175
|
-
_context.next = 5;
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
177
|
userRecommendationsPromise = getUserRecommendations(recommendationsRequest, intl);
|
|
179
178
|
userResolversPromises = (userResolvers !== null && userResolvers !== void 0 ? userResolvers : []).map(function (resolver) {
|
|
180
179
|
return resolver(_query).catch(function (error) {
|
|
@@ -193,14 +192,7 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
193
192
|
mainRecommendations = _yield$Promise$all2[0];
|
|
194
193
|
userResolverResults = _arrayLikeToArray(_yield$Promise$all2).slice(1);
|
|
195
194
|
recommendedUsers = [mainRecommendations].concat(_toConsumableArray(userResolverResults)).flat();
|
|
196
|
-
_context.next = 7;
|
|
197
|
-
break;
|
|
198
195
|
case 5:
|
|
199
|
-
_context.next = 6;
|
|
200
|
-
return getUserRecommendations(recommendationsRequest, intl);
|
|
201
|
-
case 6:
|
|
202
|
-
recommendedUsers = _context.sent;
|
|
203
|
-
case 7:
|
|
204
196
|
if (overrideByline) {
|
|
205
197
|
_iterator = _createForOfIteratorHelper(recommendedUsers);
|
|
206
198
|
try {
|
|
@@ -262,52 +254,66 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
262
254
|
} else {
|
|
263
255
|
_this.lastEmailSearchFoundMatches = false;
|
|
264
256
|
}
|
|
257
|
+
|
|
258
|
+
// For a partial query with a suggested domain, check whether the email we would
|
|
259
|
+
// synthesize (`<query>@<domain>`) already belongs to one of the returned users. If so,
|
|
260
|
+
// the real user option is shown instead and the email suggestion is suppressed.
|
|
261
|
+
suggestEmailsForDomain = _this.props.suggestEmailsForDomain;
|
|
262
|
+
if (suggestEmailsForDomain && !isEmail && _query) {
|
|
263
|
+
suggestedEmail = "".concat(_query, "@").concat(suggestEmailsForDomain).toLowerCase();
|
|
264
|
+
_this.lastDomainSuggestionMatchedUser = recommendedUsers.some(function (option) {
|
|
265
|
+
var _option$email;
|
|
266
|
+
return (isUser(option) || isExternalUser(option)) && ((_option$email = option.email) === null || _option$email === void 0 ? void 0 : _option$email.toLowerCase()) === suggestedEmail;
|
|
267
|
+
});
|
|
268
|
+
} else {
|
|
269
|
+
_this.lastDomainSuggestionMatchedUser = false;
|
|
270
|
+
}
|
|
265
271
|
elapsedTimeMilli = window.performance.now() - startTime;
|
|
266
272
|
if (!transformOptions) {
|
|
267
|
-
_context.next =
|
|
273
|
+
_context.next = 7;
|
|
268
274
|
break;
|
|
269
275
|
}
|
|
270
|
-
_context.next =
|
|
276
|
+
_context.next = 6;
|
|
271
277
|
return transformOptions(recommendedUsers, _query);
|
|
272
|
-
case
|
|
278
|
+
case 6:
|
|
273
279
|
_t = _context.sent;
|
|
274
|
-
_context.next =
|
|
280
|
+
_context.next = 8;
|
|
275
281
|
break;
|
|
276
|
-
case
|
|
282
|
+
case 7:
|
|
277
283
|
_t = recommendedUsers;
|
|
278
|
-
case
|
|
284
|
+
case 8:
|
|
279
285
|
transformedOptions = _t;
|
|
280
286
|
if (!(transformedOptions.length === 0 && onEmpty)) {
|
|
281
|
-
_context.next =
|
|
287
|
+
_context.next = 13;
|
|
282
288
|
break;
|
|
283
289
|
}
|
|
284
|
-
_context.next =
|
|
290
|
+
_context.next = 9;
|
|
285
291
|
return onEmpty(_query);
|
|
286
|
-
case
|
|
292
|
+
case 9:
|
|
287
293
|
_t4 = _yield$onEmpty = _context.sent;
|
|
288
294
|
_t3 = _t4 !== null;
|
|
289
295
|
if (!_t3) {
|
|
290
|
-
_context.next =
|
|
296
|
+
_context.next = 10;
|
|
291
297
|
break;
|
|
292
298
|
}
|
|
293
299
|
_t3 = _yield$onEmpty !== void 0;
|
|
294
|
-
case
|
|
300
|
+
case 10:
|
|
295
301
|
if (!_t3) {
|
|
296
|
-
_context.next =
|
|
302
|
+
_context.next = 11;
|
|
297
303
|
break;
|
|
298
304
|
}
|
|
299
305
|
_t5 = _yield$onEmpty;
|
|
300
|
-
_context.next =
|
|
306
|
+
_context.next = 12;
|
|
301
307
|
break;
|
|
302
|
-
case
|
|
308
|
+
case 11:
|
|
303
309
|
_t5 = [];
|
|
304
|
-
case
|
|
310
|
+
case 12:
|
|
305
311
|
_t2 = _t5;
|
|
306
|
-
_context.next =
|
|
312
|
+
_context.next = 14;
|
|
307
313
|
break;
|
|
308
|
-
case
|
|
314
|
+
case 13:
|
|
309
315
|
_t2 = transformedOptions;
|
|
310
|
-
case
|
|
316
|
+
case 14:
|
|
311
317
|
displayedUsers = _t2;
|
|
312
318
|
_this.setState(function (state) {
|
|
313
319
|
var applicable = state.query === _query;
|
|
@@ -319,7 +325,7 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
319
325
|
displayedUsers: getUsersForAnalytics(displayedUsers),
|
|
320
326
|
productAttributes: productAttributes,
|
|
321
327
|
applicable: applicable
|
|
322
|
-
},
|
|
328
|
+
}, {
|
|
323
329
|
userResolvers: Array.isArray(userResolvers) ? userResolvers.map(function (resolver) {
|
|
324
330
|
return resolver.name;
|
|
325
331
|
}) : []
|
|
@@ -329,10 +335,10 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
329
335
|
loading: loading
|
|
330
336
|
};
|
|
331
337
|
});
|
|
332
|
-
_context.next =
|
|
338
|
+
_context.next = 23;
|
|
333
339
|
break;
|
|
334
|
-
case
|
|
335
|
-
_context.prev =
|
|
340
|
+
case 15:
|
|
341
|
+
_context.prev = 15;
|
|
336
342
|
_t6 = _context["catch"](1);
|
|
337
343
|
is5xxEvent = checkIf500Event(_t6.statusCode);
|
|
338
344
|
if (!closed && !onError && is5xxEvent) {
|
|
@@ -345,35 +351,35 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
345
351
|
});
|
|
346
352
|
onErrorProducedError = false;
|
|
347
353
|
defaultUsers = [];
|
|
348
|
-
_context.prev =
|
|
354
|
+
_context.prev = 16;
|
|
349
355
|
if (!onError) {
|
|
350
|
-
_context.next =
|
|
356
|
+
_context.next = 19;
|
|
351
357
|
break;
|
|
352
358
|
}
|
|
353
|
-
_context.next =
|
|
359
|
+
_context.next = 17;
|
|
354
360
|
return onError(_t6, recommendationsRequest);
|
|
355
|
-
case
|
|
361
|
+
case 17:
|
|
356
362
|
_t8 = _context.sent;
|
|
357
363
|
if (_t8) {
|
|
358
|
-
_context.next =
|
|
364
|
+
_context.next = 18;
|
|
359
365
|
break;
|
|
360
366
|
}
|
|
361
367
|
_t8 = [];
|
|
362
|
-
case
|
|
368
|
+
case 18:
|
|
363
369
|
_t7 = _t8;
|
|
364
|
-
_context.next =
|
|
370
|
+
_context.next = 20;
|
|
365
371
|
break;
|
|
366
|
-
case
|
|
372
|
+
case 19:
|
|
367
373
|
_t7 = [];
|
|
368
|
-
case
|
|
374
|
+
case 20:
|
|
369
375
|
defaultUsers = _t7;
|
|
370
|
-
_context.next =
|
|
376
|
+
_context.next = 22;
|
|
371
377
|
break;
|
|
372
|
-
case
|
|
373
|
-
_context.prev =
|
|
374
|
-
_t9 = _context["catch"](
|
|
378
|
+
case 21:
|
|
379
|
+
_context.prev = 21;
|
|
380
|
+
_t9 = _context["catch"](16);
|
|
375
381
|
onErrorProducedError = true;
|
|
376
|
-
case
|
|
382
|
+
case 22:
|
|
377
383
|
if (onErrorProducedError && is5xxEvent) {
|
|
378
384
|
// Log error from fallback data source `onError` to UFO
|
|
379
385
|
_this.optionsShownUfoExperienceInstance.failure(ufoEndStateConfig(_this.props.fieldId));
|
|
@@ -390,11 +396,11 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
390
396
|
elapsedTimeMilli: _elapsedTimeMilli,
|
|
391
397
|
productAttributes: productAttributes
|
|
392
398
|
});
|
|
393
|
-
case
|
|
399
|
+
case 23:
|
|
394
400
|
case "end":
|
|
395
401
|
return _context.stop();
|
|
396
402
|
}
|
|
397
|
-
}, _callee, null, [[1,
|
|
403
|
+
}, _callee, null, [[1, 15], [16, 21]]);
|
|
398
404
|
})), (_this$props$debounceT = _this.props.debounceTime) !== null && _this$props$debounceT !== void 0 ? _this$props$debounceT : 0));
|
|
399
405
|
_defineProperty(_this, "onInputChange", function (newQuery, sessionId) {
|
|
400
406
|
var query = newQuery || '';
|
|
@@ -569,19 +575,34 @@ export var SmartUserPickerWithoutAnalytics = /*#__PURE__*/function (_React$Compo
|
|
|
569
575
|
allowEmail = _this$props2.allowEmail,
|
|
570
576
|
enableEmailSearch = _this$props2.enableEmailSearch,
|
|
571
577
|
allowEmailSelectionWhenEmailMatched = _this$props2.allowEmailSelectionWhenEmailMatched,
|
|
578
|
+
suggestEmailsForDomain = _this$props2.suggestEmailsForDomain,
|
|
572
579
|
restProps = _objectWithoutProperties(_this$props2, _excluded);
|
|
573
580
|
|
|
574
581
|
// Determine whether to allow email selection based on allowEmailSelectionWhenEmailMatched, if needed
|
|
575
582
|
var shouldAllowEmail = allowEmail;
|
|
583
|
+
|
|
584
|
+
// When suggestEmailsForDomain is active, partial (non-email) input must still reach the base
|
|
585
|
+
// picker's domain-suggestion creatable logic, so the isEmailQuery restriction is relaxed for
|
|
586
|
+
// those queries only. Full email queries that matched an existing user remain suppressed.
|
|
587
|
+
var isDomainSuggestionEnabled = fg('smart_user_picker_suggest_emails_for_domain') && !!suggestEmailsForDomain;
|
|
576
588
|
if (allowEmail && enableEmailSearch && !allowEmailSelectionWhenEmailMatched) {
|
|
577
589
|
var isCurrentQueryEmail = isEmailQuery(this.state.query);
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
590
|
+
if (isDomainSuggestionEnabled) {
|
|
591
|
+
// Allow email for partial queries so the "<query>@<domain>" suggestion can render,
|
|
592
|
+
// but still suppress selection when a full email query matched an existing user,
|
|
593
|
+
// or when the synthesized "<query>@<domain>" is itself an existing user's email.
|
|
594
|
+
shouldAllowEmail = isCurrentQueryEmail ? !this.lastEmailSearchFoundMatches // full email: suppress when user matched
|
|
595
|
+
: !this.lastDomainSuggestionMatchedUser; // partial: suppress when synth email matched a user
|
|
596
|
+
} else {
|
|
597
|
+
// Only allow email selection when:
|
|
598
|
+
// 1. The query matches email format (validated by regex)
|
|
599
|
+
// 2. No user/external user matches were found (only teams/groups suggested)
|
|
600
|
+
shouldAllowEmail = isCurrentQueryEmail && !this.lastEmailSearchFoundMatches;
|
|
601
|
+
}
|
|
582
602
|
}
|
|
583
603
|
return /*#__PURE__*/React.createElement(MessagesIntlProvider, null, /*#__PURE__*/React.createElement(UserPicker, _extends({}, restProps, {
|
|
584
604
|
allowEmail: shouldAllowEmail,
|
|
605
|
+
suggestEmailsForDomain: suggestEmailsForDomain,
|
|
585
606
|
onInputChange: this.onInputChange,
|
|
586
607
|
onBlur: this.onBlur,
|
|
587
608
|
onFocus: this.onFocus,
|
|
@@ -8,6 +8,7 @@ import type { DebouncedFunc } from 'lodash';
|
|
|
8
8
|
export declare class SmartUserPickerWithoutAnalytics extends React.Component<Props & WrappedComponentProps, State> {
|
|
9
9
|
state: State;
|
|
10
10
|
private lastEmailSearchFoundMatches;
|
|
11
|
+
private lastDomainSuggestionMatchedUser;
|
|
11
12
|
optionsShownUfoExperienceInstance: UFOExperience;
|
|
12
13
|
static defaultProps: {
|
|
13
14
|
baseUrl: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/smart-user-picker",
|
|
3
|
-
"version": "11.3.
|
|
3
|
+
"version": "11.3.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@atlaskit/select": "^22.6.0",
|
|
46
46
|
"@atlaskit/util-data-test": "^19.1.0",
|
|
47
|
-
"@atlassian/a11y-jest-testing": "^0.
|
|
47
|
+
"@atlassian/a11y-jest-testing": "^0.14.0",
|
|
48
48
|
"@testing-library/dom": "^10.1.0",
|
|
49
49
|
"@testing-library/react": "^16.3.0",
|
|
50
50
|
"@testing-library/user-event": "^14.4.3",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"react-intl": "^7.0.0"
|
|
58
58
|
},
|
|
59
59
|
"platform-feature-flags": {
|
|
60
|
-
"
|
|
60
|
+
"smart_user_picker_suggest_emails_for_domain": {
|
|
61
61
|
"type": "boolean"
|
|
62
62
|
},
|
|
63
63
|
"smart-user-picker-load-options-gate": {
|