@atlaskit/smart-hooks 0.0.2 → 0.1.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 CHANGED
@@ -1,5 +1,30 @@
1
1
  # @atlaskit/smart-hooks
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 0.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [`c7cd471ace6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/c7cd471ace6) - [ux] add abortcontrollers, replace ufo experience identifier, memoization for search query
14
+ - Updated dependencies
15
+
16
+ ## 0.1.0
17
+
18
+ ### Minor Changes
19
+
20
+ - [`6a3107dd76a`](https://bitbucket.org/atlassian/atlassian-frontend/commits/6a3107dd76a) - Adding analytics + UFO
21
+
22
+ ## 0.0.3
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies
27
+
3
28
  ## 0.0.2
4
29
 
5
30
  ### Patch Changes
@@ -11,21 +11,28 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
11
11
 
12
12
  var _react = require("react");
13
13
 
14
+ var _memoizeOne = _interopRequireDefault(require("memoize-one"));
15
+
14
16
  function useFunctionUsageTracking(trackedFunction) {
15
17
  var _useState = (0, _react.useState)(false),
16
18
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
17
19
  isUsed = _useState2[0],
18
- setIsUsed = _useState2[1];
20
+ setIsUsed = _useState2[1]; // trackingFunction needs to be stable for hook consumers...
21
+
19
22
 
20
23
  var trackingFunction = (0, _react.useMemo)(function () {
21
- return function () {
22
- if (!isUsed) {
23
- setIsUsed(true);
24
- }
25
-
26
- return trackedFunction;
27
- };
28
- }, [trackedFunction, isUsed]);
24
+ return (// ...and the function that the factory returns needs to be stable for hook consumers as well
25
+ (0, _memoizeOne.default)(function () {
26
+ if (!isUsed) {
27
+ setIsUsed(true);
28
+ }
29
+
30
+ return trackedFunction;
31
+ })
32
+ );
33
+ }, // isUsed deliberately left out to avoid new tracking fn being generated
34
+ // eslint-disable-next-line react-hooks/exhaustive-deps
35
+ [trackedFunction]);
29
36
  return {
30
37
  isUsed: isUsed,
31
38
  trackingFunction: trackingFunction
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.fireUserSelectedEvent = exports.findUserPosition = exports.createDefaultAttributes = void 0;
9
+
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+
12
+ var _analyticsGasTypes = require("@atlaskit/analytics-gas-types");
13
+
14
+ var _analyticsListeners = require("@atlaskit/analytics-listeners");
15
+
16
+ var _analyticsNext = require("@atlaskit/analytics-next");
17
+
18
+ var _version = require("../../version.json");
19
+
20
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
21
+
22
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
23
+
24
+ var createAndFireEventInElementsChannel = (0, _analyticsNext.createAndFireEvent)(_analyticsListeners.FabricChannel.elements);
25
+
26
+ var createEvent = function createEvent(eventType, action, actionSubject) {
27
+ var attributes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
28
+ return {
29
+ eventType: eventType,
30
+ action: action,
31
+ actionSubject: actionSubject,
32
+ source: '@atlaskit/smart-hooks/use-user-recommendations',
33
+ attributes: _objectSpread({
34
+ packageName: _version.name,
35
+ packageVersion: _version.version
36
+ }, attributes)
37
+ };
38
+ };
39
+
40
+ var findUserPosition = function findUserPosition(loadedUsers, userId) {
41
+ return loadedUsers.findIndex(function (val) {
42
+ return val.id === userId;
43
+ });
44
+ };
45
+
46
+ exports.findUserPosition = findUserPosition;
47
+
48
+ var createDefaultAttributes = function createDefaultAttributes(props, renderId, sessionId, query) {
49
+ var fieldId = props.fieldId,
50
+ objectId = props.objectId,
51
+ containerId = props.containerId,
52
+ childObjectId = props.childObjectId,
53
+ preload = props.preload,
54
+ includeTeams = props.includeTeams,
55
+ productKey = props.productKey,
56
+ principalId = props.principalId,
57
+ tenantId = props.tenantId,
58
+ maxNumberOfResults = props.maxNumberOfResults;
59
+ return {
60
+ context: fieldId,
61
+ childObjectId: childObjectId,
62
+ containerId: containerId,
63
+ includeTeams: includeTeams,
64
+ maxNumberOfResults: maxNumberOfResults,
65
+ objectId: objectId,
66
+ preload: preload,
67
+ principalId: principalId,
68
+ productKey: productKey,
69
+ queryLength: (query || '').length,
70
+ renderId: renderId,
71
+ sessionId: sessionId,
72
+ tenantId: tenantId
73
+ };
74
+ };
75
+
76
+ exports.createDefaultAttributes = createDefaultAttributes;
77
+
78
+ var fireUserSelectedEvent = function fireUserSelectedEvent(createAnalyticsEvent, payloadAttributes) {
79
+ return createAndFireEventInElementsChannel(createEvent(_analyticsGasTypes.TRACK_EVENT_TYPE, 'selected', 'user', payloadAttributes))(createAnalyticsEvent);
80
+ };
81
+
82
+ exports.fireUserSelectedEvent = fireUserSelectedEvent;
@@ -19,10 +19,20 @@ var _react = require("react");
19
19
 
20
20
  var _debounce = _interopRequireDefault(require("lodash/debounce"));
21
21
 
22
+ var _memoizeOne = _interopRequireDefault(require("memoize-one"));
23
+
24
+ var _uuid = require("uuid");
25
+
26
+ var _analyticsNext = require("@atlaskit/analytics-next");
27
+
22
28
  var _smartCommon = require("@atlaskit/smart-common");
23
29
 
24
30
  var _useFunctionUsageTracking = _interopRequireDefault(require("../use-function-usage-tracking"));
25
31
 
32
+ var _analytics = require("./analytics");
33
+
34
+ var _ufoExperiences = require("./ufoExperiences");
35
+
26
36
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
27
37
 
28
38
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
@@ -77,16 +87,58 @@ var useUserRecommendations = function useUserRecommendations(props) {
77
87
  error = _useState6[0],
78
88
  setError = _useState6[1];
79
89
 
90
+ var _useState7 = (0, _react.useState)(function () {
91
+ return (0, _uuid.v4)();
92
+ }),
93
+ _useState8 = (0, _slicedToArray2.default)(_useState7, 1),
94
+ renderId = _useState8[0];
95
+
96
+ var sessionId = (0, _react.useRef)('');
97
+ var currentQuery = (0, _react.useRef)('');
98
+ var lastAbortController = (0, _react.useRef)();
99
+
100
+ var _useAnalyticsEvents = (0, _analyticsNext.useAnalyticsEvents)(),
101
+ createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
102
+
103
+ var getAnalyticsAttributes = (0, _react.useCallback)(function () {
104
+ return _objectSpread({}, (0, _analytics.createDefaultAttributes)({
105
+ fieldId: fieldId,
106
+ objectId: objectId,
107
+ containerId: containerId,
108
+ childObjectId: childObjectId,
109
+ preload: preload,
110
+ includeTeams: includeTeams,
111
+ productKey: productKey,
112
+ principalId: principalId,
113
+ tenantId: tenantId,
114
+ maxNumberOfResults: maxNumberOfResults
115
+ }, renderId, sessionId.current, currentQuery.current));
116
+ }, [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, renderId, tenantId]);
80
117
  var fetchRecommendations = (0, _react.useCallback)( /*#__PURE__*/function () {
81
- var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(query, sessionId) {
82
- var recommendedUsers;
118
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(query) {
119
+ var _lastAbortController$, currentController, recommendedUsersResult;
120
+
83
121
  return _regenerator.default.wrap(function _callee$(_context) {
84
122
  while (1) {
85
123
  switch (_context.prev = _context.next) {
86
124
  case 0:
87
- setIsLoading(true);
88
- _context.prev = 1;
89
- _context.next = 4;
125
+ setIsLoading(true); // restart session
126
+
127
+ sessionId.current = (0, _uuid.v4)();
128
+
129
+ _ufoExperiences.UsersFetchedUfoExperience.getInstance(fieldId).start();
130
+
131
+ _context.prev = 3;
132
+
133
+ if (lastAbortController.current) {
134
+ (_lastAbortController$ = lastAbortController.current) === null || _lastAbortController$ === void 0 ? void 0 : _lastAbortController$.abort();
135
+ } // in case there are still IE users, check AbortController before init,
136
+ // IE has no timeout applied on fetch since AbortController isn't available
137
+
138
+
139
+ currentController = typeof AbortController !== 'undefined' ? new AbortController() : null;
140
+ lastAbortController.current = currentController;
141
+ _context.next = 9;
90
142
  return (0, _smartCommon.fetchUserRecommendations)({
91
143
  baseUrl: baseUrl,
92
144
  context: {
@@ -98,7 +150,7 @@ var useUserRecommendations = function useUserRecommendations(props) {
98
150
  productKey: productKey,
99
151
  contextType: fieldId,
100
152
  siteId: tenantId,
101
- sessionId: sessionId
153
+ sessionId: sessionId.current
102
154
  },
103
155
  includeUsers: includeUsers,
104
156
  includeGroups: includeGroups,
@@ -106,61 +158,92 @@ var useUserRecommendations = function useUserRecommendations(props) {
106
158
  maxNumberOfResults: maxNumberOfResults,
107
159
  searchQuery: cpusSearchQuery,
108
160
  query: query
161
+ }, currentController === null || currentController === void 0 ? void 0 : currentController.signal);
162
+
163
+ case 9:
164
+ recommendedUsersResult = _context.sent;
165
+ currentQuery.current = query !== null && query !== void 0 ? query : '';
166
+
167
+ _ufoExperiences.UsersFetchedUfoExperience.getInstance(fieldId).success({
168
+ metadata: _objectSpread(_objectSpread({}, getAnalyticsAttributes()), {}, {
169
+ loadedUsersSize: recommendedUsersResult.length
170
+ })
109
171
  });
110
172
 
111
- case 4:
112
- recommendedUsers = _context.sent;
113
- setRecommendations(recommendedUsers);
114
- _context.next = 11;
173
+ setRecommendations(recommendedUsersResult);
174
+ _context.next = 24;
115
175
  break;
116
176
 
117
- case 8:
118
- _context.prev = 8;
119
- _context.t0 = _context["catch"](1);
177
+ case 15:
178
+ _context.prev = 15;
179
+ _context.t0 = _context["catch"](3);
180
+
181
+ if (!(_context.t0 instanceof Error && _context.t0.name === 'AbortError')) {
182
+ _context.next = 22;
183
+ break;
184
+ }
185
+
186
+ // Request aborted client-side
187
+ _ufoExperiences.UsersFetchedUfoExperience.getInstance(fieldId).abort(); // return early to prevent disabling isLoading
188
+
189
+
190
+ return _context.abrupt("return");
191
+
192
+ case 22:
193
+ _ufoExperiences.UsersFetchedUfoExperience.getInstance(fieldId).failure({
194
+ metadata: getAnalyticsAttributes()
195
+ });
196
+
120
197
  setError(_context.t0);
121
198
 
122
- case 11:
123
- setIsLoading(false);
199
+ case 24:
200
+ setIsLoading(false); // clear abort controller
201
+
202
+ lastAbortController.current = undefined;
124
203
 
125
- case 12:
204
+ case 26:
126
205
  case "end":
127
206
  return _context.stop();
128
207
  }
129
208
  }
130
- }, _callee, null, [[1, 8]]);
209
+ }, _callee, null, [[3, 15]]);
131
210
  }));
132
211
 
133
- return function (_x, _x2) {
212
+ return function (_x) {
134
213
  return _ref.apply(this, arguments);
135
214
  };
136
- }(), [baseUrl, childObjectId, containerId, fieldId, includeGroups, includeTeams, includeUsers, maxNumberOfResults, objectId, principalId, productAttributes, productKey, cpusSearchQuery, tenantId]);
137
- var debouncedFetchRecommendations = (0, _react.useMemo)(function () {
138
- return (0, _debounce.default)(fetchRecommendations, debounceTimeMs);
215
+ }(), [baseUrl, childObjectId, containerId, objectId, principalId, productAttributes, productKey, fieldId, tenantId, includeUsers, includeGroups, includeTeams, maxNumberOfResults, cpusSearchQuery, getAnalyticsAttributes]);
216
+ var memoizedDebouncedFetchRecommendations = (0, _react.useMemo)(function () {
217
+ return (0, _memoizeOne.default)((0, _debounce.default)(fetchRecommendations, debounceTimeMs));
139
218
  }, [fetchRecommendations, debounceTimeMs]);
140
219
  (0, _react.useEffect)(function () {
141
220
  if (preload) {
142
- debouncedFetchRecommendations('');
221
+ memoizedDebouncedFetchRecommendations('');
143
222
  }
144
- }, [preload, debouncedFetchRecommendations]); // TODO - analytics
145
-
146
- var onInputChange = (0, _react.useCallback)(function (query, sessionId) {
147
- debouncedFetchRecommendations(query, sessionId);
148
- }, [debouncedFetchRecommendations]); // TODO - analytics
149
-
150
- var onChange = (0, _react.useCallback)(function (value, action) {}, []);
223
+ }, [preload, memoizedDebouncedFetchRecommendations]);
224
+ var onInputChange = (0, _react.useCallback)(function (query) {
225
+ memoizedDebouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
226
+ }, [memoizedDebouncedFetchRecommendations]);
227
+ var onUserSelect = (0, _react.useCallback)(function (userId) {
228
+ (0, _analytics.fireUserSelectedEvent)(createAnalyticsEvent, _objectSpread(_objectSpread({}, getAnalyticsAttributes()), {}, {
229
+ selectedUser: userId,
230
+ loadedUsersSize: recommendations.length,
231
+ position: (0, _analytics.findUserPosition)(recommendations, userId)
232
+ }));
233
+ }, [createAnalyticsEvent, getAnalyticsAttributes, recommendations]);
151
234
 
152
235
  var _useFunctionUsageTrac = (0, _useFunctionUsageTracking.default)(onInputChange),
153
236
  isOnInputChangeUsed = _useFunctionUsageTrac.isUsed,
154
237
  usageTrackedOnInputChange = _useFunctionUsageTrac.trackingFunction;
155
238
 
156
- var _useFunctionUsageTrac2 = (0, _useFunctionUsageTracking.default)(onChange),
157
- isOnChangeUsed = _useFunctionUsageTrac2.isUsed,
158
- usageTrackedOnChange = _useFunctionUsageTrac2.trackingFunction;
239
+ var _useFunctionUsageTrac2 = (0, _useFunctionUsageTracking.default)(onUserSelect),
240
+ isOnUserSelectUsed = _useFunctionUsageTrac2.isUsed,
241
+ usageTrackedOnUserSelect = _useFunctionUsageTrac2.trackingFunction;
159
242
 
160
243
  return {
161
- recommendations: isOnInputChangeUsed && isOnChangeUsed ? recommendations : instrumentFailureOption,
162
- onInputChange: usageTrackedOnInputChange,
163
- onChange: usageTrackedOnChange,
244
+ recommendations: isOnInputChangeUsed && isOnUserSelectUsed ? recommendations : instrumentFailureOption,
245
+ triggerSearchFactory: usageTrackedOnInputChange,
246
+ selectUserFactory: usageTrackedOnUserSelect,
164
247
  isLoading: isLoading,
165
248
  error: error
166
249
  };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.UsersFetchedUfoExperience = void 0;
7
+
8
+ var _ufo = require("@atlaskit/ufo");
9
+
10
+ var COMPONENT_NAME = 'smart-hooks.use-user-recommendations';
11
+ var UsersFetchedUfoExperience = new _ufo.ConcurrentExperience('users-fetched', {
12
+ platform: {
13
+ component: COMPONENT_NAME
14
+ },
15
+ type: _ufo.ExperienceTypes.Load,
16
+ performanceType: _ufo.ExperiencePerformanceTypes.InlineResult
17
+ });
18
+ exports.UsersFetchedUfoExperience = UsersFetchedUfoExperience;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.0.2",
3
+ "version": "0.1.2",
4
4
  "sideEffects": false
5
5
  }
@@ -1,14 +1,19 @@
1
1
  import { useMemo, useState } from 'react';
2
+ import memoizeOne from 'memoize-one';
2
3
 
3
4
  function useFunctionUsageTracking(trackedFunction) {
4
- const [isUsed, setIsUsed] = useState(false);
5
- const trackingFunction = useMemo(() => () => {
5
+ const [isUsed, setIsUsed] = useState(false); // trackingFunction needs to be stable for hook consumers...
6
+
7
+ const trackingFunction = useMemo(() => // ...and the function that the factory returns needs to be stable for hook consumers as well
8
+ memoizeOne(() => {
6
9
  if (!isUsed) {
7
10
  setIsUsed(true);
8
11
  }
9
12
 
10
13
  return trackedFunction;
11
- }, [trackedFunction, isUsed]);
14
+ }), // isUsed deliberately left out to avoid new tracking fn being generated
15
+ // eslint-disable-next-line react-hooks/exhaustive-deps
16
+ [trackedFunction]);
12
17
  return {
13
18
  isUsed,
14
19
  trackingFunction
@@ -0,0 +1,51 @@
1
+ import { TRACK_EVENT_TYPE } from '@atlaskit/analytics-gas-types';
2
+ import { FabricChannel } from '@atlaskit/analytics-listeners';
3
+ import { createAndFireEvent } from '@atlaskit/analytics-next';
4
+ import { name as packageName, version as packageVersion } from '../../version.json';
5
+ const createAndFireEventInElementsChannel = createAndFireEvent(FabricChannel.elements);
6
+
7
+ const createEvent = (eventType, action, actionSubject, attributes = {}) => ({
8
+ eventType,
9
+ action,
10
+ actionSubject,
11
+ source: '@atlaskit/smart-hooks/use-user-recommendations',
12
+ attributes: {
13
+ packageName,
14
+ packageVersion,
15
+ ...attributes
16
+ }
17
+ });
18
+
19
+ export const findUserPosition = (loadedUsers, userId) => {
20
+ return loadedUsers.findIndex(val => val.id === userId);
21
+ };
22
+ export const createDefaultAttributes = (props, renderId, sessionId, query) => {
23
+ const {
24
+ fieldId,
25
+ objectId,
26
+ containerId,
27
+ childObjectId,
28
+ preload,
29
+ includeTeams,
30
+ productKey,
31
+ principalId,
32
+ tenantId,
33
+ maxNumberOfResults
34
+ } = props;
35
+ return {
36
+ context: fieldId,
37
+ childObjectId,
38
+ containerId,
39
+ includeTeams,
40
+ maxNumberOfResults,
41
+ objectId,
42
+ preload,
43
+ principalId,
44
+ productKey,
45
+ queryLength: (query || '').length,
46
+ renderId,
47
+ sessionId,
48
+ tenantId
49
+ };
50
+ };
51
+ export const fireUserSelectedEvent = (createAnalyticsEvent, payloadAttributes) => createAndFireEventInElementsChannel(createEvent(TRACK_EVENT_TYPE, 'selected', 'user', payloadAttributes))(createAnalyticsEvent);
@@ -1,7 +1,12 @@
1
- import { useCallback, useEffect, useMemo, useState } from 'react';
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import debounce from 'lodash/debounce';
3
+ import memoizeOne from 'memoize-one';
4
+ import { v4 as uuid } from 'uuid';
5
+ import { useAnalyticsEvents } from '@atlaskit/analytics-next';
3
6
  import { EntityType, fetchUserRecommendations } from '@atlaskit/smart-common';
4
7
  import useFunctionUsageTracking from '../use-function-usage-tracking';
8
+ import { createDefaultAttributes, findUserPosition, fireUserSelectedEvent } from './analytics';
9
+ import { UsersFetchedUfoExperience } from './ufoExperiences';
5
10
  const MAX_NUMBER_RESULTS = 25;
6
11
  const DEFAULT_DEBOUNCE_TIME_MS = 150;
7
12
  const defaultProps = {
@@ -41,11 +46,44 @@ const useUserRecommendations = props => {
41
46
  const [recommendations, setRecommendations] = useState([]);
42
47
  const [isLoading, setIsLoading] = useState(false);
43
48
  const [error, setError] = useState();
44
- const fetchRecommendations = useCallback(async (query, sessionId) => {
45
- setIsLoading(true);
49
+ const [renderId] = useState(() => uuid());
50
+ const sessionId = useRef('');
51
+ const currentQuery = useRef('');
52
+ const lastAbortController = useRef();
53
+ const {
54
+ createAnalyticsEvent
55
+ } = useAnalyticsEvents();
56
+ const getAnalyticsAttributes = useCallback(() => ({ ...createDefaultAttributes({
57
+ fieldId,
58
+ objectId,
59
+ containerId,
60
+ childObjectId,
61
+ preload,
62
+ includeTeams,
63
+ productKey,
64
+ principalId,
65
+ tenantId,
66
+ maxNumberOfResults
67
+ }, renderId, sessionId.current, currentQuery.current)
68
+ }), [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, renderId, tenantId]);
69
+ const fetchRecommendations = useCallback(async query => {
70
+ setIsLoading(true); // restart session
71
+
72
+ sessionId.current = uuid();
73
+ UsersFetchedUfoExperience.getInstance(fieldId).start();
46
74
 
47
75
  try {
48
- const recommendedUsers = await fetchUserRecommendations({
76
+ if (lastAbortController.current) {
77
+ var _lastAbortController$;
78
+
79
+ (_lastAbortController$ = lastAbortController.current) === null || _lastAbortController$ === void 0 ? void 0 : _lastAbortController$.abort();
80
+ } // in case there are still IE users, check AbortController before init,
81
+ // IE has no timeout applied on fetch since AbortController isn't available
82
+
83
+
84
+ const currentController = typeof AbortController !== 'undefined' ? new AbortController() : null;
85
+ lastAbortController.current = currentController;
86
+ const recommendedUsersResult = await fetchUserRecommendations({
49
87
  baseUrl,
50
88
  context: {
51
89
  childObjectId,
@@ -56,7 +94,7 @@ const useUserRecommendations = props => {
56
94
  productKey,
57
95
  contextType: fieldId,
58
96
  siteId: tenantId,
59
- sessionId: sessionId
97
+ sessionId: sessionId.current
60
98
  },
61
99
  includeUsers,
62
100
  includeGroups,
@@ -64,38 +102,60 @@ const useUserRecommendations = props => {
64
102
  maxNumberOfResults,
65
103
  searchQuery: cpusSearchQuery,
66
104
  query
105
+ }, currentController === null || currentController === void 0 ? void 0 : currentController.signal);
106
+ currentQuery.current = query !== null && query !== void 0 ? query : '';
107
+ UsersFetchedUfoExperience.getInstance(fieldId).success({
108
+ metadata: { ...getAnalyticsAttributes(),
109
+ loadedUsersSize: recommendedUsersResult.length
110
+ }
67
111
  });
68
- setRecommendations(recommendedUsers);
112
+ setRecommendations(recommendedUsersResult);
69
113
  } catch (error) {
70
- setError(error);
114
+ if (error instanceof Error && error.name === 'AbortError') {
115
+ // Request aborted client-side
116
+ UsersFetchedUfoExperience.getInstance(fieldId).abort(); // return early to prevent disabling isLoading
117
+
118
+ return;
119
+ } else {
120
+ UsersFetchedUfoExperience.getInstance(fieldId).failure({
121
+ metadata: getAnalyticsAttributes()
122
+ });
123
+ setError(error);
124
+ }
71
125
  }
72
126
 
73
- setIsLoading(false);
74
- }, [baseUrl, childObjectId, containerId, fieldId, includeGroups, includeTeams, includeUsers, maxNumberOfResults, objectId, principalId, productAttributes, productKey, cpusSearchQuery, tenantId]);
75
- const debouncedFetchRecommendations = useMemo(() => debounce(fetchRecommendations, debounceTimeMs), [fetchRecommendations, debounceTimeMs]);
127
+ setIsLoading(false); // clear abort controller
128
+
129
+ lastAbortController.current = undefined;
130
+ }, [baseUrl, childObjectId, containerId, objectId, principalId, productAttributes, productKey, fieldId, tenantId, includeUsers, includeGroups, includeTeams, maxNumberOfResults, cpusSearchQuery, getAnalyticsAttributes]);
131
+ const memoizedDebouncedFetchRecommendations = useMemo(() => memoizeOne(debounce(fetchRecommendations, debounceTimeMs)), [fetchRecommendations, debounceTimeMs]);
76
132
  useEffect(() => {
77
133
  if (preload) {
78
- debouncedFetchRecommendations('');
134
+ memoizedDebouncedFetchRecommendations('');
79
135
  }
80
- }, [preload, debouncedFetchRecommendations]); // TODO - analytics
81
-
82
- const onInputChange = useCallback((query, sessionId) => {
83
- debouncedFetchRecommendations(query, sessionId);
84
- }, [debouncedFetchRecommendations]); // TODO - analytics
85
-
86
- const onChange = useCallback((value, action) => {}, []);
136
+ }, [preload, memoizedDebouncedFetchRecommendations]);
137
+ const onInputChange = useCallback(query => {
138
+ memoizedDebouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
139
+ }, [memoizedDebouncedFetchRecommendations]);
140
+ const onUserSelect = useCallback(userId => {
141
+ fireUserSelectedEvent(createAnalyticsEvent, { ...getAnalyticsAttributes(),
142
+ selectedUser: userId,
143
+ loadedUsersSize: recommendations.length,
144
+ position: findUserPosition(recommendations, userId)
145
+ });
146
+ }, [createAnalyticsEvent, getAnalyticsAttributes, recommendations]);
87
147
  const {
88
148
  isUsed: isOnInputChangeUsed,
89
149
  trackingFunction: usageTrackedOnInputChange
90
150
  } = useFunctionUsageTracking(onInputChange);
91
151
  const {
92
- isUsed: isOnChangeUsed,
93
- trackingFunction: usageTrackedOnChange
94
- } = useFunctionUsageTracking(onChange);
152
+ isUsed: isOnUserSelectUsed,
153
+ trackingFunction: usageTrackedOnUserSelect
154
+ } = useFunctionUsageTracking(onUserSelect);
95
155
  return {
96
- recommendations: isOnInputChangeUsed && isOnChangeUsed ? recommendations : instrumentFailureOption,
97
- onInputChange: usageTrackedOnInputChange,
98
- onChange: usageTrackedOnChange,
156
+ recommendations: isOnInputChangeUsed && isOnUserSelectUsed ? recommendations : instrumentFailureOption,
157
+ triggerSearchFactory: usageTrackedOnInputChange,
158
+ selectUserFactory: usageTrackedOnUserSelect,
99
159
  isLoading,
100
160
  error
101
161
  };
@@ -0,0 +1,9 @@
1
+ import { ConcurrentExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atlaskit/ufo';
2
+ const COMPONENT_NAME = 'smart-hooks.use-user-recommendations';
3
+ export const UsersFetchedUfoExperience = new ConcurrentExperience('users-fetched', {
4
+ platform: {
5
+ component: COMPONENT_NAME
6
+ },
7
+ type: ExperienceTypes.Load,
8
+ performanceType: ExperiencePerformanceTypes.InlineResult
9
+ });
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.0.2",
3
+ "version": "0.1.2",
4
4
  "sideEffects": false
5
5
  }
@@ -1,21 +1,27 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
2
  import { useMemo, useState } from 'react';
3
+ import memoizeOne from 'memoize-one';
3
4
 
4
5
  function useFunctionUsageTracking(trackedFunction) {
5
6
  var _useState = useState(false),
6
7
  _useState2 = _slicedToArray(_useState, 2),
7
8
  isUsed = _useState2[0],
8
- setIsUsed = _useState2[1];
9
+ setIsUsed = _useState2[1]; // trackingFunction needs to be stable for hook consumers...
10
+
9
11
 
10
12
  var trackingFunction = useMemo(function () {
11
- return function () {
12
- if (!isUsed) {
13
- setIsUsed(true);
14
- }
13
+ return (// ...and the function that the factory returns needs to be stable for hook consumers as well
14
+ memoizeOne(function () {
15
+ if (!isUsed) {
16
+ setIsUsed(true);
17
+ }
15
18
 
16
- return trackedFunction;
17
- };
18
- }, [trackedFunction, isUsed]);
19
+ return trackedFunction;
20
+ })
21
+ );
22
+ }, // isUsed deliberately left out to avoid new tracking fn being generated
23
+ // eslint-disable-next-line react-hooks/exhaustive-deps
24
+ [trackedFunction]);
19
25
  return {
20
26
  isUsed: isUsed,
21
27
  trackingFunction: trackingFunction
@@ -0,0 +1,61 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
+
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
6
+
7
+ import { TRACK_EVENT_TYPE } from '@atlaskit/analytics-gas-types';
8
+ import { FabricChannel } from '@atlaskit/analytics-listeners';
9
+ import { createAndFireEvent } from '@atlaskit/analytics-next';
10
+ import { name as packageName, version as packageVersion } from '../../version.json';
11
+ var createAndFireEventInElementsChannel = createAndFireEvent(FabricChannel.elements);
12
+
13
+ var createEvent = function createEvent(eventType, action, actionSubject) {
14
+ var attributes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
15
+ return {
16
+ eventType: eventType,
17
+ action: action,
18
+ actionSubject: actionSubject,
19
+ source: '@atlaskit/smart-hooks/use-user-recommendations',
20
+ attributes: _objectSpread({
21
+ packageName: packageName,
22
+ packageVersion: packageVersion
23
+ }, attributes)
24
+ };
25
+ };
26
+
27
+ export var findUserPosition = function findUserPosition(loadedUsers, userId) {
28
+ return loadedUsers.findIndex(function (val) {
29
+ return val.id === userId;
30
+ });
31
+ };
32
+ export var createDefaultAttributes = function createDefaultAttributes(props, renderId, sessionId, query) {
33
+ var fieldId = props.fieldId,
34
+ objectId = props.objectId,
35
+ containerId = props.containerId,
36
+ childObjectId = props.childObjectId,
37
+ preload = props.preload,
38
+ includeTeams = props.includeTeams,
39
+ productKey = props.productKey,
40
+ principalId = props.principalId,
41
+ tenantId = props.tenantId,
42
+ maxNumberOfResults = props.maxNumberOfResults;
43
+ return {
44
+ context: fieldId,
45
+ childObjectId: childObjectId,
46
+ containerId: containerId,
47
+ includeTeams: includeTeams,
48
+ maxNumberOfResults: maxNumberOfResults,
49
+ objectId: objectId,
50
+ preload: preload,
51
+ principalId: principalId,
52
+ productKey: productKey,
53
+ queryLength: (query || '').length,
54
+ renderId: renderId,
55
+ sessionId: sessionId,
56
+ tenantId: tenantId
57
+ };
58
+ };
59
+ export var fireUserSelectedEvent = function fireUserSelectedEvent(createAnalyticsEvent, payloadAttributes) {
60
+ return createAndFireEventInElementsChannel(createEvent(TRACK_EVENT_TYPE, 'selected', 'user', payloadAttributes))(createAnalyticsEvent);
61
+ };
@@ -7,10 +7,15 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
7
7
 
8
8
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
9
9
 
10
- import { useCallback, useEffect, useMemo, useState } from 'react';
10
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
11
  import debounce from 'lodash/debounce';
12
+ import memoizeOne from 'memoize-one';
13
+ import { v4 as uuid } from 'uuid';
14
+ import { useAnalyticsEvents } from '@atlaskit/analytics-next';
12
15
  import { EntityType, fetchUserRecommendations } from '@atlaskit/smart-common';
13
16
  import useFunctionUsageTracking from '../use-function-usage-tracking';
17
+ import { createDefaultAttributes, findUserPosition, fireUserSelectedEvent } from './analytics';
18
+ import { UsersFetchedUfoExperience } from './ufoExperiences';
14
19
  var MAX_NUMBER_RESULTS = 25;
15
20
  var DEFAULT_DEBOUNCE_TIME_MS = 150;
16
21
  var defaultProps = {
@@ -60,16 +65,56 @@ var useUserRecommendations = function useUserRecommendations(props) {
60
65
  error = _useState6[0],
61
66
  setError = _useState6[1];
62
67
 
68
+ var _useState7 = useState(function () {
69
+ return uuid();
70
+ }),
71
+ _useState8 = _slicedToArray(_useState7, 1),
72
+ renderId = _useState8[0];
73
+
74
+ var sessionId = useRef('');
75
+ var currentQuery = useRef('');
76
+ var lastAbortController = useRef();
77
+
78
+ var _useAnalyticsEvents = useAnalyticsEvents(),
79
+ createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
80
+
81
+ var getAnalyticsAttributes = useCallback(function () {
82
+ return _objectSpread({}, createDefaultAttributes({
83
+ fieldId: fieldId,
84
+ objectId: objectId,
85
+ containerId: containerId,
86
+ childObjectId: childObjectId,
87
+ preload: preload,
88
+ includeTeams: includeTeams,
89
+ productKey: productKey,
90
+ principalId: principalId,
91
+ tenantId: tenantId,
92
+ maxNumberOfResults: maxNumberOfResults
93
+ }, renderId, sessionId.current, currentQuery.current));
94
+ }, [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, renderId, tenantId]);
63
95
  var fetchRecommendations = useCallback( /*#__PURE__*/function () {
64
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(query, sessionId) {
65
- var recommendedUsers;
96
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(query) {
97
+ var _lastAbortController$, currentController, recommendedUsersResult;
98
+
66
99
  return _regeneratorRuntime.wrap(function _callee$(_context) {
67
100
  while (1) {
68
101
  switch (_context.prev = _context.next) {
69
102
  case 0:
70
- setIsLoading(true);
71
- _context.prev = 1;
72
- _context.next = 4;
103
+ setIsLoading(true); // restart session
104
+
105
+ sessionId.current = uuid();
106
+ UsersFetchedUfoExperience.getInstance(fieldId).start();
107
+ _context.prev = 3;
108
+
109
+ if (lastAbortController.current) {
110
+ (_lastAbortController$ = lastAbortController.current) === null || _lastAbortController$ === void 0 ? void 0 : _lastAbortController$.abort();
111
+ } // in case there are still IE users, check AbortController before init,
112
+ // IE has no timeout applied on fetch since AbortController isn't available
113
+
114
+
115
+ currentController = typeof AbortController !== 'undefined' ? new AbortController() : null;
116
+ lastAbortController.current = currentController;
117
+ _context.next = 9;
73
118
  return fetchUserRecommendations({
74
119
  baseUrl: baseUrl,
75
120
  context: {
@@ -81,7 +126,7 @@ var useUserRecommendations = function useUserRecommendations(props) {
81
126
  productKey: productKey,
82
127
  contextType: fieldId,
83
128
  siteId: tenantId,
84
- sessionId: sessionId
129
+ sessionId: sessionId.current
85
130
  },
86
131
  includeUsers: includeUsers,
87
132
  includeGroups: includeGroups,
@@ -89,61 +134,88 @@ var useUserRecommendations = function useUserRecommendations(props) {
89
134
  maxNumberOfResults: maxNumberOfResults,
90
135
  searchQuery: cpusSearchQuery,
91
136
  query: query
137
+ }, currentController === null || currentController === void 0 ? void 0 : currentController.signal);
138
+
139
+ case 9:
140
+ recommendedUsersResult = _context.sent;
141
+ currentQuery.current = query !== null && query !== void 0 ? query : '';
142
+ UsersFetchedUfoExperience.getInstance(fieldId).success({
143
+ metadata: _objectSpread(_objectSpread({}, getAnalyticsAttributes()), {}, {
144
+ loadedUsersSize: recommendedUsersResult.length
145
+ })
92
146
  });
93
-
94
- case 4:
95
- recommendedUsers = _context.sent;
96
- setRecommendations(recommendedUsers);
97
- _context.next = 11;
147
+ setRecommendations(recommendedUsersResult);
148
+ _context.next = 24;
98
149
  break;
99
150
 
100
- case 8:
101
- _context.prev = 8;
102
- _context.t0 = _context["catch"](1);
151
+ case 15:
152
+ _context.prev = 15;
153
+ _context.t0 = _context["catch"](3);
154
+
155
+ if (!(_context.t0 instanceof Error && _context.t0.name === 'AbortError')) {
156
+ _context.next = 22;
157
+ break;
158
+ }
159
+
160
+ // Request aborted client-side
161
+ UsersFetchedUfoExperience.getInstance(fieldId).abort(); // return early to prevent disabling isLoading
162
+
163
+ return _context.abrupt("return");
164
+
165
+ case 22:
166
+ UsersFetchedUfoExperience.getInstance(fieldId).failure({
167
+ metadata: getAnalyticsAttributes()
168
+ });
103
169
  setError(_context.t0);
104
170
 
105
- case 11:
106
- setIsLoading(false);
171
+ case 24:
172
+ setIsLoading(false); // clear abort controller
173
+
174
+ lastAbortController.current = undefined;
107
175
 
108
- case 12:
176
+ case 26:
109
177
  case "end":
110
178
  return _context.stop();
111
179
  }
112
180
  }
113
- }, _callee, null, [[1, 8]]);
181
+ }, _callee, null, [[3, 15]]);
114
182
  }));
115
183
 
116
- return function (_x, _x2) {
184
+ return function (_x) {
117
185
  return _ref.apply(this, arguments);
118
186
  };
119
- }(), [baseUrl, childObjectId, containerId, fieldId, includeGroups, includeTeams, includeUsers, maxNumberOfResults, objectId, principalId, productAttributes, productKey, cpusSearchQuery, tenantId]);
120
- var debouncedFetchRecommendations = useMemo(function () {
121
- return debounce(fetchRecommendations, debounceTimeMs);
187
+ }(), [baseUrl, childObjectId, containerId, objectId, principalId, productAttributes, productKey, fieldId, tenantId, includeUsers, includeGroups, includeTeams, maxNumberOfResults, cpusSearchQuery, getAnalyticsAttributes]);
188
+ var memoizedDebouncedFetchRecommendations = useMemo(function () {
189
+ return memoizeOne(debounce(fetchRecommendations, debounceTimeMs));
122
190
  }, [fetchRecommendations, debounceTimeMs]);
123
191
  useEffect(function () {
124
192
  if (preload) {
125
- debouncedFetchRecommendations('');
193
+ memoizedDebouncedFetchRecommendations('');
126
194
  }
127
- }, [preload, debouncedFetchRecommendations]); // TODO - analytics
128
-
129
- var onInputChange = useCallback(function (query, sessionId) {
130
- debouncedFetchRecommendations(query, sessionId);
131
- }, [debouncedFetchRecommendations]); // TODO - analytics
132
-
133
- var onChange = useCallback(function (value, action) {}, []);
195
+ }, [preload, memoizedDebouncedFetchRecommendations]);
196
+ var onInputChange = useCallback(function (query) {
197
+ memoizedDebouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
198
+ }, [memoizedDebouncedFetchRecommendations]);
199
+ var onUserSelect = useCallback(function (userId) {
200
+ fireUserSelectedEvent(createAnalyticsEvent, _objectSpread(_objectSpread({}, getAnalyticsAttributes()), {}, {
201
+ selectedUser: userId,
202
+ loadedUsersSize: recommendations.length,
203
+ position: findUserPosition(recommendations, userId)
204
+ }));
205
+ }, [createAnalyticsEvent, getAnalyticsAttributes, recommendations]);
134
206
 
135
207
  var _useFunctionUsageTrac = useFunctionUsageTracking(onInputChange),
136
208
  isOnInputChangeUsed = _useFunctionUsageTrac.isUsed,
137
209
  usageTrackedOnInputChange = _useFunctionUsageTrac.trackingFunction;
138
210
 
139
- var _useFunctionUsageTrac2 = useFunctionUsageTracking(onChange),
140
- isOnChangeUsed = _useFunctionUsageTrac2.isUsed,
141
- usageTrackedOnChange = _useFunctionUsageTrac2.trackingFunction;
211
+ var _useFunctionUsageTrac2 = useFunctionUsageTracking(onUserSelect),
212
+ isOnUserSelectUsed = _useFunctionUsageTrac2.isUsed,
213
+ usageTrackedOnUserSelect = _useFunctionUsageTrac2.trackingFunction;
142
214
 
143
215
  return {
144
- recommendations: isOnInputChangeUsed && isOnChangeUsed ? recommendations : instrumentFailureOption,
145
- onInputChange: usageTrackedOnInputChange,
146
- onChange: usageTrackedOnChange,
216
+ recommendations: isOnInputChangeUsed && isOnUserSelectUsed ? recommendations : instrumentFailureOption,
217
+ triggerSearchFactory: usageTrackedOnInputChange,
218
+ selectUserFactory: usageTrackedOnUserSelect,
147
219
  isLoading: isLoading,
148
220
  error: error
149
221
  };
@@ -0,0 +1,9 @@
1
+ import { ConcurrentExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atlaskit/ufo';
2
+ var COMPONENT_NAME = 'smart-hooks.use-user-recommendations';
3
+ export var UsersFetchedUfoExperience = new ConcurrentExperience('users-fetched', {
4
+ platform: {
5
+ component: COMPONENT_NAME
6
+ },
7
+ type: ExperienceTypes.Load,
8
+ performanceType: ExperiencePerformanceTypes.InlineResult
9
+ });
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.0.2",
3
+ "version": "0.1.2",
4
4
  "sideEffects": false
5
5
  }
@@ -1,5 +1,5 @@
1
1
  declare function useFunctionUsageTracking<InputFunctionType extends (...any: any) => any>(trackedFunction: InputFunctionType): {
2
2
  isUsed: boolean;
3
- trackingFunction: () => InputFunctionType;
3
+ trackingFunction: import("memoize-one").MemoizedFn<() => InputFunctionType>;
4
4
  };
5
5
  export default useFunctionUsageTracking;
@@ -0,0 +1,20 @@
1
+ import { AnalyticsEventPayload, CreateUIAnalyticsEvent } from '@atlaskit/analytics-next';
2
+ import { UserSearchItem } from '@atlaskit/smart-common';
3
+ import { UseUserRecommendationsProps } from '../../types';
4
+ export declare const findUserPosition: (loadedUsers: UserSearchItem[], userId: string) => number;
5
+ export declare const createDefaultAttributes: (props: UseUserRecommendationsProps, renderId: string, sessionId: string, query: string) => {
6
+ context: string;
7
+ childObjectId: string | undefined;
8
+ containerId: string | undefined;
9
+ includeTeams: boolean | undefined;
10
+ maxNumberOfResults: number | undefined;
11
+ objectId: string | undefined;
12
+ preload: boolean | undefined;
13
+ principalId: string | undefined;
14
+ productKey: string;
15
+ queryLength: number;
16
+ renderId: string;
17
+ sessionId: string;
18
+ tenantId: string;
19
+ };
20
+ export declare const fireUserSelectedEvent: (createAnalyticsEvent: CreateUIAnalyticsEvent, payloadAttributes: AnalyticsEventPayload) => import("@atlaskit/analytics-next").UIAnalyticsEvent;
@@ -1,5 +1,4 @@
1
1
  import { EntityType, UserSearchItem } from '@atlaskit/smart-common';
2
- import { ActionTypes, Value } from '@atlaskit/user-picker';
3
2
  import type { UseUserRecommendationsProps } from '../../types';
4
3
  export declare const instrumentFailureOption: {
5
4
  id: string;
@@ -8,14 +7,14 @@ export declare const instrumentFailureOption: {
8
7
  avatarUrl: string;
9
8
  }[];
10
9
  declare const useUserRecommendations: (props: UseUserRecommendationsProps) => {
11
- recommendations: {
10
+ recommendations: UserSearchItem[] | {
12
11
  id: string;
13
12
  name: string;
14
13
  entityType: EntityType;
15
14
  avatarUrl: string;
16
- }[] | UserSearchItem[];
17
- onInputChange: () => (query?: string | undefined, sessionId?: string | undefined) => void;
18
- onChange: () => (value: Value, action: ActionTypes) => void;
15
+ }[];
16
+ triggerSearchFactory: import("memoize-one").MemoizedFn<() => (query?: string | undefined) => void>;
17
+ selectUserFactory: import("memoize-one").MemoizedFn<() => (userId: string) => void>;
19
18
  isLoading: boolean;
20
19
  error: any;
21
20
  };
@@ -0,0 +1,2 @@
1
+ import { ConcurrentExperience } from '@atlaskit/ufo';
2
+ export declare const UsersFetchedUfoExperience: ConcurrentExperience;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.0.2",
3
+ "version": "0.1.2",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/"
6
6
  },
@@ -18,19 +18,22 @@
18
18
  "releaseModel": "continuous"
19
19
  },
20
20
  "dependencies": {
21
- "@atlaskit/smart-common": "^0.0.2",
22
- "@atlaskit/user-picker": "^8.3.0",
21
+ "@atlaskit/analytics-gas-types": "^5.0.5",
22
+ "@atlaskit/analytics-listeners": "^8.1.3",
23
+ "@atlaskit/analytics-next": "^8.0.0",
24
+ "@atlaskit/smart-common": "^0.1.0",
25
+ "@atlaskit/ufo": "^0.1.0",
26
+ "@atlaskit/user-picker": "^8.5.0",
23
27
  "@babel/runtime": "^7.0.0",
24
- "lodash": "^4.17.21"
28
+ "lodash": "^4.17.21",
29
+ "memoize-one": "^6.0.0",
30
+ "uuid": "^3.1.0"
25
31
  },
26
32
  "peerDependencies": {
27
33
  "react": "^16.8.0",
28
34
  "react-intl-next": "npm:react-intl@^5.18.1"
29
35
  },
30
36
  "devDependencies": {
31
- "@atlaskit/analytics-gas-types": "^5.0.0",
32
- "@atlaskit/analytics-listeners": "^8.0.0",
33
- "@atlaskit/analytics-next": "^8.2.0",
34
37
  "@atlaskit/analytics-viewer": "^0.4.5",
35
38
  "@atlaskit/button": "^16.0.0",
36
39
  "@atlaskit/docs": "*",
@@ -40,10 +43,12 @@
40
43
  "@atlaskit/visual-regression": "*",
41
44
  "@atlaskit/webdriver-runner": "*",
42
45
  "@atlassian/atlassian-frontend-prettier-config-1.0.1": "npm:@atlassian/atlassian-frontend-prettier-config@1.0.1",
46
+ "@atlassian/ufo": "^0.1.0",
43
47
  "@atlassiansox/analytics-web-client": "^4.2.0",
44
48
  "@storybook/addon-knobs": "^5.3.18",
45
49
  "@testing-library/react": "^8.0.1",
46
50
  "@testing-library/react-hooks": "^1.0.4",
51
+ "@welldone-software/why-did-you-render": "^6.2.0",
47
52
  "enzyme": "^3.10.0",
48
53
  "fetch-mock": "^8.0.0",
49
54
  "react-dom": "^16.8.0",