@atlaskit/smart-hooks 0.1.0 → 0.1.1

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,12 @@
1
1
  # @atlaskit/smart-hooks
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`c7cd471ace6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/c7cd471ace6) - [ux] add abortcontrollers, replace ufo experience identifier, memoization for search query
8
+ - Updated dependencies
9
+
3
10
  ## 0.1.0
4
11
 
5
12
  ### Minor Changes
@@ -19,6 +19,8 @@ var _react = require("react");
19
19
 
20
20
  var _debounce = _interopRequireDefault(require("lodash/debounce"));
21
21
 
22
+ var _memoizeOne = _interopRequireDefault(require("memoize-one"));
23
+
22
24
  var _uuid = require("uuid");
23
25
 
24
26
  var _analyticsNext = require("@atlaskit/analytics-next");
@@ -85,9 +87,15 @@ var useUserRecommendations = function useUserRecommendations(props) {
85
87
  error = _useState6[0],
86
88
  setError = _useState6[1];
87
89
 
88
- var renderId = (0, _react.useRef)('');
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
+
89
96
  var sessionId = (0, _react.useRef)('');
90
97
  var currentQuery = (0, _react.useRef)('');
98
+ var lastAbortController = (0, _react.useRef)();
91
99
 
92
100
  var _useAnalyticsEvents = (0, _analyticsNext.useAnalyticsEvents)(),
93
101
  createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
@@ -104,11 +112,12 @@ var useUserRecommendations = function useUserRecommendations(props) {
104
112
  principalId: principalId,
105
113
  tenantId: tenantId,
106
114
  maxNumberOfResults: maxNumberOfResults
107
- }, renderId.current, sessionId.current, currentQuery.current));
108
- }, [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, tenantId]);
115
+ }, renderId, sessionId.current, currentQuery.current));
116
+ }, [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, renderId, tenantId]);
109
117
  var fetchRecommendations = (0, _react.useCallback)( /*#__PURE__*/function () {
110
118
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(query) {
111
- var recommendedUsersResult;
119
+ var _lastAbortController$, currentController, recommendedUsersResult;
120
+
112
121
  return _regenerator.default.wrap(function _callee$(_context) {
113
122
  while (1) {
114
123
  switch (_context.prev = _context.next) {
@@ -120,7 +129,16 @@ var useUserRecommendations = function useUserRecommendations(props) {
120
129
  _ufoExperiences.UsersFetchedUfoExperience.getInstance(fieldId).start();
121
130
 
122
131
  _context.prev = 3;
123
- _context.next = 6;
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;
124
142
  return (0, _smartCommon.fetchUserRecommendations)({
125
143
  baseUrl: baseUrl,
126
144
  context: {
@@ -140,9 +158,9 @@ var useUserRecommendations = function useUserRecommendations(props) {
140
158
  maxNumberOfResults: maxNumberOfResults,
141
159
  searchQuery: cpusSearchQuery,
142
160
  query: query
143
- });
161
+ }, currentController === null || currentController === void 0 ? void 0 : currentController.signal);
144
162
 
145
- case 6:
163
+ case 9:
146
164
  recommendedUsersResult = _context.sent;
147
165
  currentQuery.current = query !== null && query !== void 0 ? query : '';
148
166
 
@@ -153,45 +171,59 @@ var useUserRecommendations = function useUserRecommendations(props) {
153
171
  });
154
172
 
155
173
  setRecommendations(recommendedUsersResult);
156
- _context.next = 16;
174
+ _context.next = 24;
157
175
  break;
158
176
 
159
- case 12:
160
- _context.prev = 12;
177
+ case 15:
178
+ _context.prev = 15;
161
179
  _context.t0 = _context["catch"](3);
162
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:
163
193
  _ufoExperiences.UsersFetchedUfoExperience.getInstance(fieldId).failure({
164
194
  metadata: getAnalyticsAttributes()
165
195
  });
166
196
 
167
197
  setError(_context.t0);
168
198
 
169
- case 16:
170
- setIsLoading(false);
199
+ case 24:
200
+ setIsLoading(false); // clear abort controller
201
+
202
+ lastAbortController.current = undefined;
171
203
 
172
- case 17:
204
+ case 26:
173
205
  case "end":
174
206
  return _context.stop();
175
207
  }
176
208
  }
177
- }, _callee, null, [[3, 12]]);
209
+ }, _callee, null, [[3, 15]]);
178
210
  }));
179
211
 
180
212
  return function (_x) {
181
213
  return _ref.apply(this, arguments);
182
214
  };
183
215
  }(), [baseUrl, childObjectId, containerId, objectId, principalId, productAttributes, productKey, fieldId, tenantId, includeUsers, includeGroups, includeTeams, maxNumberOfResults, cpusSearchQuery, getAnalyticsAttributes]);
184
- var debouncedFetchRecommendations = (0, _react.useMemo)(function () {
185
- return (0, _debounce.default)(fetchRecommendations, debounceTimeMs);
216
+ var memoizedDebouncedFetchRecommendations = (0, _react.useMemo)(function () {
217
+ return (0, _memoizeOne.default)((0, _debounce.default)(fetchRecommendations, debounceTimeMs));
186
218
  }, [fetchRecommendations, debounceTimeMs]);
187
219
  (0, _react.useEffect)(function () {
188
220
  if (preload) {
189
- debouncedFetchRecommendations('');
221
+ memoizedDebouncedFetchRecommendations('');
190
222
  }
191
- }, [preload, debouncedFetchRecommendations]);
223
+ }, [preload, memoizedDebouncedFetchRecommendations]);
192
224
  var onInputChange = (0, _react.useCallback)(function (query) {
193
- debouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
194
- }, [debouncedFetchRecommendations]);
225
+ memoizedDebouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
226
+ }, [memoizedDebouncedFetchRecommendations]);
195
227
  var onUserSelect = (0, _react.useCallback)(function (userId) {
196
228
  (0, _analytics.fireUserSelectedEvent)(createAnalyticsEvent, _objectSpread(_objectSpread({}, getAnalyticsAttributes()), {}, {
197
229
  selectedUser: userId,
@@ -208,9 +240,6 @@ var useUserRecommendations = function useUserRecommendations(props) {
208
240
  isOnUserSelectUsed = _useFunctionUsageTrac2.isUsed,
209
241
  usageTrackedOnUserSelect = _useFunctionUsageTrac2.trackingFunction;
210
242
 
211
- (0, _react.useEffect)(function () {
212
- renderId.current = (0, _uuid.v4)();
213
- }, []);
214
243
  return {
215
244
  recommendations: isOnInputChangeUsed && isOnUserSelectUsed ? recommendations : instrumentFailureOption,
216
245
  triggerSearchFactory: usageTrackedOnInputChange,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "sideEffects": false
5
5
  }
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import debounce from 'lodash/debounce';
3
+ import memoizeOne from 'memoize-one';
3
4
  import { v4 as uuid } from 'uuid';
4
5
  import { useAnalyticsEvents } from '@atlaskit/analytics-next';
5
6
  import { EntityType, fetchUserRecommendations } from '@atlaskit/smart-common';
@@ -45,9 +46,10 @@ const useUserRecommendations = props => {
45
46
  const [recommendations, setRecommendations] = useState([]);
46
47
  const [isLoading, setIsLoading] = useState(false);
47
48
  const [error, setError] = useState();
48
- const renderId = useRef('');
49
+ const [renderId] = useState(() => uuid());
49
50
  const sessionId = useRef('');
50
51
  const currentQuery = useRef('');
52
+ const lastAbortController = useRef();
51
53
  const {
52
54
  createAnalyticsEvent
53
55
  } = useAnalyticsEvents();
@@ -62,8 +64,8 @@ const useUserRecommendations = props => {
62
64
  principalId,
63
65
  tenantId,
64
66
  maxNumberOfResults
65
- }, renderId.current, sessionId.current, currentQuery.current)
66
- }), [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, tenantId]);
67
+ }, renderId, sessionId.current, currentQuery.current)
68
+ }), [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, renderId, tenantId]);
67
69
  const fetchRecommendations = useCallback(async query => {
68
70
  setIsLoading(true); // restart session
69
71
 
@@ -71,6 +73,16 @@ const useUserRecommendations = props => {
71
73
  UsersFetchedUfoExperience.getInstance(fieldId).start();
72
74
 
73
75
  try {
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;
74
86
  const recommendedUsersResult = await fetchUserRecommendations({
75
87
  baseUrl,
76
88
  context: {
@@ -90,7 +102,7 @@ const useUserRecommendations = props => {
90
102
  maxNumberOfResults,
91
103
  searchQuery: cpusSearchQuery,
92
104
  query
93
- });
105
+ }, currentController === null || currentController === void 0 ? void 0 : currentController.signal);
94
106
  currentQuery.current = query !== null && query !== void 0 ? query : '';
95
107
  UsersFetchedUfoExperience.getInstance(fieldId).success({
96
108
  metadata: { ...getAnalyticsAttributes(),
@@ -99,23 +111,32 @@ const useUserRecommendations = props => {
99
111
  });
100
112
  setRecommendations(recommendedUsersResult);
101
113
  } catch (error) {
102
- UsersFetchedUfoExperience.getInstance(fieldId).failure({
103
- metadata: getAnalyticsAttributes()
104
- });
105
- 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
+ }
106
125
  }
107
126
 
108
- setIsLoading(false);
127
+ setIsLoading(false); // clear abort controller
128
+
129
+ lastAbortController.current = undefined;
109
130
  }, [baseUrl, childObjectId, containerId, objectId, principalId, productAttributes, productKey, fieldId, tenantId, includeUsers, includeGroups, includeTeams, maxNumberOfResults, cpusSearchQuery, getAnalyticsAttributes]);
110
- const debouncedFetchRecommendations = useMemo(() => debounce(fetchRecommendations, debounceTimeMs), [fetchRecommendations, debounceTimeMs]);
131
+ const memoizedDebouncedFetchRecommendations = useMemo(() => memoizeOne(debounce(fetchRecommendations, debounceTimeMs)), [fetchRecommendations, debounceTimeMs]);
111
132
  useEffect(() => {
112
133
  if (preload) {
113
- debouncedFetchRecommendations('');
134
+ memoizedDebouncedFetchRecommendations('');
114
135
  }
115
- }, [preload, debouncedFetchRecommendations]);
136
+ }, [preload, memoizedDebouncedFetchRecommendations]);
116
137
  const onInputChange = useCallback(query => {
117
- debouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
118
- }, [debouncedFetchRecommendations]);
138
+ memoizedDebouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
139
+ }, [memoizedDebouncedFetchRecommendations]);
119
140
  const onUserSelect = useCallback(userId => {
120
141
  fireUserSelectedEvent(createAnalyticsEvent, { ...getAnalyticsAttributes(),
121
142
  selectedUser: userId,
@@ -131,9 +152,6 @@ const useUserRecommendations = props => {
131
152
  isUsed: isOnUserSelectUsed,
132
153
  trackingFunction: usageTrackedOnUserSelect
133
154
  } = useFunctionUsageTracking(onUserSelect);
134
- useEffect(() => {
135
- renderId.current = uuid();
136
- }, []);
137
155
  return {
138
156
  recommendations: isOnInputChangeUsed && isOnUserSelectUsed ? recommendations : instrumentFailureOption,
139
157
  triggerSearchFactory: usageTrackedOnInputChange,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "sideEffects": false
5
5
  }
@@ -9,6 +9,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
9
9
 
10
10
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
11
  import debounce from 'lodash/debounce';
12
+ import memoizeOne from 'memoize-one';
12
13
  import { v4 as uuid } from 'uuid';
13
14
  import { useAnalyticsEvents } from '@atlaskit/analytics-next';
14
15
  import { EntityType, fetchUserRecommendations } from '@atlaskit/smart-common';
@@ -64,9 +65,15 @@ var useUserRecommendations = function useUserRecommendations(props) {
64
65
  error = _useState6[0],
65
66
  setError = _useState6[1];
66
67
 
67
- var renderId = useRef('');
68
+ var _useState7 = useState(function () {
69
+ return uuid();
70
+ }),
71
+ _useState8 = _slicedToArray(_useState7, 1),
72
+ renderId = _useState8[0];
73
+
68
74
  var sessionId = useRef('');
69
75
  var currentQuery = useRef('');
76
+ var lastAbortController = useRef();
70
77
 
71
78
  var _useAnalyticsEvents = useAnalyticsEvents(),
72
79
  createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
@@ -83,11 +90,12 @@ var useUserRecommendations = function useUserRecommendations(props) {
83
90
  principalId: principalId,
84
91
  tenantId: tenantId,
85
92
  maxNumberOfResults: maxNumberOfResults
86
- }, renderId.current, sessionId.current, currentQuery.current));
87
- }, [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, tenantId]);
93
+ }, renderId, sessionId.current, currentQuery.current));
94
+ }, [childObjectId, containerId, fieldId, includeTeams, maxNumberOfResults, objectId, preload, principalId, productKey, renderId, tenantId]);
88
95
  var fetchRecommendations = useCallback( /*#__PURE__*/function () {
89
96
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(query) {
90
- var recommendedUsersResult;
97
+ var _lastAbortController$, currentController, recommendedUsersResult;
98
+
91
99
  return _regeneratorRuntime.wrap(function _callee$(_context) {
92
100
  while (1) {
93
101
  switch (_context.prev = _context.next) {
@@ -97,7 +105,16 @@ var useUserRecommendations = function useUserRecommendations(props) {
97
105
  sessionId.current = uuid();
98
106
  UsersFetchedUfoExperience.getInstance(fieldId).start();
99
107
  _context.prev = 3;
100
- _context.next = 6;
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;
101
118
  return fetchUserRecommendations({
102
119
  baseUrl: baseUrl,
103
120
  context: {
@@ -117,9 +134,9 @@ var useUserRecommendations = function useUserRecommendations(props) {
117
134
  maxNumberOfResults: maxNumberOfResults,
118
135
  searchQuery: cpusSearchQuery,
119
136
  query: query
120
- });
137
+ }, currentController === null || currentController === void 0 ? void 0 : currentController.signal);
121
138
 
122
- case 6:
139
+ case 9:
123
140
  recommendedUsersResult = _context.sent;
124
141
  currentQuery.current = query !== null && query !== void 0 ? query : '';
125
142
  UsersFetchedUfoExperience.getInstance(fieldId).success({
@@ -128,43 +145,57 @@ var useUserRecommendations = function useUserRecommendations(props) {
128
145
  })
129
146
  });
130
147
  setRecommendations(recommendedUsersResult);
131
- _context.next = 16;
148
+ _context.next = 24;
132
149
  break;
133
150
 
134
- case 12:
135
- _context.prev = 12;
151
+ case 15:
152
+ _context.prev = 15;
136
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:
137
166
  UsersFetchedUfoExperience.getInstance(fieldId).failure({
138
167
  metadata: getAnalyticsAttributes()
139
168
  });
140
169
  setError(_context.t0);
141
170
 
142
- case 16:
143
- setIsLoading(false);
171
+ case 24:
172
+ setIsLoading(false); // clear abort controller
173
+
174
+ lastAbortController.current = undefined;
144
175
 
145
- case 17:
176
+ case 26:
146
177
  case "end":
147
178
  return _context.stop();
148
179
  }
149
180
  }
150
- }, _callee, null, [[3, 12]]);
181
+ }, _callee, null, [[3, 15]]);
151
182
  }));
152
183
 
153
184
  return function (_x) {
154
185
  return _ref.apply(this, arguments);
155
186
  };
156
187
  }(), [baseUrl, childObjectId, containerId, objectId, principalId, productAttributes, productKey, fieldId, tenantId, includeUsers, includeGroups, includeTeams, maxNumberOfResults, cpusSearchQuery, getAnalyticsAttributes]);
157
- var debouncedFetchRecommendations = useMemo(function () {
158
- return debounce(fetchRecommendations, debounceTimeMs);
188
+ var memoizedDebouncedFetchRecommendations = useMemo(function () {
189
+ return memoizeOne(debounce(fetchRecommendations, debounceTimeMs));
159
190
  }, [fetchRecommendations, debounceTimeMs]);
160
191
  useEffect(function () {
161
192
  if (preload) {
162
- debouncedFetchRecommendations('');
193
+ memoizedDebouncedFetchRecommendations('');
163
194
  }
164
- }, [preload, debouncedFetchRecommendations]);
195
+ }, [preload, memoizedDebouncedFetchRecommendations]);
165
196
  var onInputChange = useCallback(function (query) {
166
- debouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
167
- }, [debouncedFetchRecommendations]);
197
+ memoizedDebouncedFetchRecommendations(query !== null && query !== void 0 ? query : '');
198
+ }, [memoizedDebouncedFetchRecommendations]);
168
199
  var onUserSelect = useCallback(function (userId) {
169
200
  fireUserSelectedEvent(createAnalyticsEvent, _objectSpread(_objectSpread({}, getAnalyticsAttributes()), {}, {
170
201
  selectedUser: userId,
@@ -181,9 +212,6 @@ var useUserRecommendations = function useUserRecommendations(props) {
181
212
  isOnUserSelectUsed = _useFunctionUsageTrac2.isUsed,
182
213
  usageTrackedOnUserSelect = _useFunctionUsageTrac2.trackingFunction;
183
214
 
184
- useEffect(function () {
185
- renderId.current = uuid();
186
- }, []);
187
215
  return {
188
216
  recommendations: isOnInputChangeUsed && isOnUserSelectUsed ? recommendations : instrumentFailureOption,
189
217
  triggerSearchFactory: usageTrackedOnInputChange,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "sideEffects": false
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-hooks",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/"
6
6
  },
@@ -21,9 +21,9 @@
21
21
  "@atlaskit/analytics-gas-types": "^5.0.5",
22
22
  "@atlaskit/analytics-listeners": "^8.1.3",
23
23
  "@atlaskit/analytics-next": "^8.0.0",
24
- "@atlaskit/smart-common": "^0.0.3",
24
+ "@atlaskit/smart-common": "^0.1.0",
25
25
  "@atlaskit/ufo": "^0.0.6",
26
- "@atlaskit/user-picker": "^8.4.0",
26
+ "@atlaskit/user-picker": "^8.5.0",
27
27
  "@babel/runtime": "^7.0.0",
28
28
  "lodash": "^4.17.21",
29
29
  "memoize-one": "^6.0.0",