@atlaskit/link-datasource 1.17.13 → 1.18.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/analytics/constants.js +1 -1
  3. package/dist/cjs/hooks/useDatasourceTableState.js +15 -10
  4. package/dist/cjs/hooks/useErrorLogger.js +48 -0
  5. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +2 -2
  6. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/index.js +7 -7
  7. package/dist/cjs/ui/jira-issues-modal/basic-filters/utils/transformers.js +3 -1
  8. package/dist/cjs/ui/jira-issues-modal/jira-search-container/index.js +34 -8
  9. package/dist/es2019/analytics/constants.js +1 -1
  10. package/dist/es2019/hooks/useDatasourceTableState.js +8 -2
  11. package/dist/es2019/hooks/useErrorLogger.js +44 -0
  12. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +2 -2
  13. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/index.js +7 -5
  14. package/dist/es2019/ui/jira-issues-modal/basic-filters/utils/transformers.js +3 -1
  15. package/dist/es2019/ui/jira-issues-modal/jira-search-container/index.js +30 -9
  16. package/dist/esm/analytics/constants.js +1 -1
  17. package/dist/esm/hooks/useDatasourceTableState.js +15 -10
  18. package/dist/esm/hooks/useErrorLogger.js +42 -0
  19. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +2 -2
  20. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/index.js +7 -7
  21. package/dist/esm/ui/jira-issues-modal/basic-filters/utils/transformers.js +3 -1
  22. package/dist/esm/ui/jira-issues-modal/jira-search-container/index.js +34 -8
  23. package/dist/types/analytics/generated/analytics.types.d.ts +9 -1
  24. package/dist/types/hooks/useErrorLogger.d.ts +4 -0
  25. package/dist/types/ui/jira-issues-modal/basic-filters/hooks/useHydrateJqlQuery.d.ts +2 -4
  26. package/dist/types/ui/jira-issues-modal/basic-filters/types.d.ts +3 -0
  27. package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +1 -1
  28. package/dist/types/ui/jira-issues-modal/basic-filters/ui/index.d.ts +3 -1
  29. package/dist/types/ui/jira-issues-modal/basic-filters/utils/transformers.d.ts +2 -7
  30. package/dist/types/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +2 -4
  31. package/dist/types-ts4.5/analytics/generated/analytics.types.d.ts +9 -1
  32. package/dist/types-ts4.5/hooks/useErrorLogger.d.ts +4 -0
  33. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/hooks/useHydrateJqlQuery.d.ts +2 -4
  34. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/types.d.ts +3 -0
  35. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +1 -1
  36. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/index.d.ts +3 -1
  37. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/utils/transformers.d.ts +2 -7
  38. package/dist/types-ts4.5/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +2 -4
  39. package/package.json +6 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @atlaskit/link-datasource
2
2
 
3
+ ## 1.18.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#43497](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/43497) [`049969f8eb1`](https://bitbucket.org/atlassian/atlassian-frontend/commits/049969f8eb1) - Added error logging to the datasource try catches.
8
+ - Updated dependencies
9
+
10
+ ## 1.18.0
11
+
12
+ ### Minor Changes
13
+
14
+ - [#43374](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/43374) [`0d93cf12d25`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0d93cf12d25) - Selecting and unselecting filters causes search to occur and datasource table to refresh
15
+
16
+ ### Patch Changes
17
+
18
+ - [#43417](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/43417) [`3f3c17f0273`](https://bitbucket.org/atlassian/atlassian-frontend/commits/3f3c17f0273) - ED-20971 Upgrade adf-schema package to ^34.0.0
19
+
3
20
  ## 1.17.13
4
21
 
5
22
  ### Patch Changes
@@ -7,5 +7,5 @@ exports.packageMetaData = exports.EVENT_CHANNEL = void 0;
7
7
  var EVENT_CHANNEL = exports.EVENT_CHANNEL = 'media';
8
8
  var packageMetaData = exports.packageMetaData = {
9
9
  packageName: "@atlaskit/link-datasource",
10
- packageVersion: "1.17.13"
10
+ packageVersion: "1.18.1"
11
11
  };
@@ -13,6 +13,7 @@ var _react = require("react");
13
13
  var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
14
14
  var _linkClientExtension = require("@atlaskit/link-client-extension");
15
15
  var _analytics = require("../analytics");
16
+ var _useErrorLogger2 = _interopRequireDefault(require("./useErrorLogger"));
16
17
  var useDatasourceTableState = exports.useDatasourceTableState = function useDatasourceTableState(_ref) {
17
18
  var datasourceId = _ref.datasourceId,
18
19
  parameters = _ref.parameters,
@@ -20,6 +21,8 @@ var useDatasourceTableState = exports.useDatasourceTableState = function useData
20
21
  fieldKeys = _ref$fieldKeys === void 0 ? [] : _ref$fieldKeys;
21
22
  var _useDatasourceAnalyti = (0, _analytics.useDatasourceAnalyticsEvents)(),
22
23
  fireEvent = _useDatasourceAnalyti.fireEvent;
24
+ var _useErrorLogger = (0, _useErrorLogger2.default)(),
25
+ captureError = _useErrorLogger.captureError;
23
26
  var idFieldCount = 1;
24
27
  var keyFieldCount = 1;
25
28
  var _useState = (0, _react.useState)([]),
@@ -110,25 +113,26 @@ var useDatasourceTableState = exports.useDatasourceTableState = function useData
110
113
  allColumns = schema.properties;
111
114
  newColumns = allColumns.filter(isColumnNotPresentInCurrentColumnsList);
112
115
  newColumns.length > 0 && setColumns([].concat((0, _toConsumableArray2.default)(columns), (0, _toConsumableArray2.default)(newColumns)));
113
- _context.next = 23;
116
+ _context.next = 24;
114
117
  break;
115
118
  case 17:
116
119
  _context.prev = 17;
117
120
  _context.t0 = _context["catch"](2);
121
+ captureError('loadDatasourceDetails', _context.t0);
118
122
  if (!(_context.t0 instanceof Response && (_context.t0.status === 401 || _context.t0.status === 403))) {
119
- _context.next = 22;
123
+ _context.next = 23;
120
124
  break;
121
125
  }
122
126
  setStatus('unauthorized');
123
127
  return _context.abrupt("return");
124
- case 22:
125
- setStatus('rejected');
126
128
  case 23:
129
+ setStatus('rejected');
130
+ case 24:
127
131
  case "end":
128
132
  return _context.stop();
129
133
  }
130
134
  }, _callee, null, [[2, 17]]);
131
- })), [columns, datasourceId, getDatasourceDetails, parameters]);
135
+ })), [captureError, columns, datasourceId, getDatasourceDetails, parameters]);
132
136
  var applySchemaProperties = (0, _react.useCallback)(function (schema, fieldKeys) {
133
137
  var properties = schema.properties,
134
138
  _schema$defaultProper = schema.defaultProperties,
@@ -256,25 +260,26 @@ var useDatasourceTableState = exports.useDatasourceTableState = function useData
256
260
  });
257
261
  }
258
262
  setStatus('resolved');
259
- _context2.next = 42;
263
+ _context2.next = 43;
260
264
  break;
261
265
  case 36:
262
266
  _context2.prev = 36;
263
267
  _context2.t0 = _context2["catch"](7);
268
+ captureError('onNextPage', _context2.t0);
264
269
  if (!(_context2.t0 instanceof Response && (_context2.t0.status === 401 || _context2.t0.status === 403))) {
265
- _context2.next = 41;
270
+ _context2.next = 42;
266
271
  break;
267
272
  }
268
273
  setStatus('unauthorized');
269
274
  return _context2.abrupt("return");
270
- case 41:
271
- setStatus('rejected');
272
275
  case 42:
276
+ setStatus('rejected');
277
+ case 43:
273
278
  case "end":
274
279
  return _context2.stop();
275
280
  }
276
281
  }, _callee2, null, [[7, 36]]);
277
- })), [parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent, fullSchema]);
282
+ })), [captureError, parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent, fullSchema]);
278
283
  var reset = (0, _react.useCallback)(function (options) {
279
284
  setStatus('empty');
280
285
  setResponseItems([]);
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = require("react");
8
+ var _sentry = require("@atlaskit/linking-common/sentry");
9
+ var _utils = require("@atlaskit/linking-common/utils");
10
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
+ var _analytics = require("../analytics");
12
+ var getNetworkFields = function getNetworkFields(error) {
13
+ return error instanceof Response ? {
14
+ traceId: (0, _utils.getTraceId)(error),
15
+ status: error.status
16
+ } : {
17
+ traceId: null,
18
+ status: null
19
+ };
20
+ };
21
+ var useErrorLogger = function useErrorLogger() {
22
+ var _useDatasourceAnalyti = (0, _analytics.useDatasourceAnalyticsEvents)(),
23
+ fireEvent = _useDatasourceAnalyti.fireEvent;
24
+
25
+ /**
26
+ * Sentry is good because it can retrieve name, message, stacktrace of an Error. That's why we will send to Sentry only
27
+ * if an error is instance of `Error`. Sentry is also capable of some PII scrubbing of these risky fields.
28
+ *
29
+ * We will send to Splunk every single time, though, but we won't send PII risky fields.
30
+ */
31
+ var captureError = (0, _react.useCallback)(function (errorLocation, error) {
32
+ var _getNetworkFields = getNetworkFields(error),
33
+ traceId = _getNetworkFields.traceId,
34
+ status = _getNetworkFields.status;
35
+ fireEvent('operational.datasource.operationFailed', {
36
+ errorLocation: errorLocation,
37
+ traceId: traceId,
38
+ status: status
39
+ });
40
+ if ((0, _platformFeatureFlags.getBooleanFF)('platform.linking-platform.datasources.enable-sentry-client') && error instanceof Error) {
41
+ (0, _sentry.captureException)(error, 'link-datasource');
42
+ }
43
+ }, [fireEvent]);
44
+ return {
45
+ captureError: captureError
46
+ };
47
+ };
48
+ var _default = exports.default = useErrorLogger;
@@ -101,8 +101,8 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
101
101
  };
102
102
  }(), [handleDebouncedFetchFilterOptions, searchTerm]);
103
103
  var handleOptionSelection = (0, _react.useCallback)(function (newValue) {
104
- onSelectionChange(newValue);
105
- }, [onSelectionChange]);
104
+ onSelectionChange(filterType, newValue);
105
+ }, [filterType, onSelectionChange]);
106
106
  var sortOptionsOnPopupOpen = (0, _react.useCallback)(function () {
107
107
  if (selectedOptions.length === 0) {
108
108
  return setSortedOptions(filterOptions);
@@ -22,7 +22,8 @@ var basicFilterContainerStyles = (0, _primitives.xcss)({
22
22
  });
23
23
  var BasicFilterContainer = function BasicFilterContainer(_ref) {
24
24
  var jql = _ref.jql,
25
- cloudId = _ref.cloudId;
25
+ cloudId = _ref.cloudId,
26
+ onChange = _ref.onChange;
26
27
  var _useState = (0, _react.useState)({}),
27
28
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
28
29
  selection = _useState2[0],
@@ -32,10 +33,11 @@ var BasicFilterContainer = function BasicFilterContainer(_ref) {
32
33
  // hydrate hook call goes in here
33
34
  }
34
35
  }, [jql]);
35
- var handleSelectionChange = (0, _react.useCallback)(function (options, filter) {
36
- var updatedSelection = _objectSpread(_objectSpread({}, selection), {}, (0, _defineProperty2.default)({}, filter, options));
36
+ var handleSelectionChange = (0, _react.useCallback)(function (filterType, options) {
37
+ var updatedSelection = _objectSpread(_objectSpread({}, selection), {}, (0, _defineProperty2.default)({}, filterType, options));
37
38
  setSelection(updatedSelection);
38
- }, [selection]);
39
+ onChange(updatedSelection);
40
+ }, [onChange, selection]);
39
41
  var handleReset = (0, _react.useCallback)(function () {
40
42
  if (Object.keys(selection).length > 0) {
41
43
  setSelection({});
@@ -52,9 +54,7 @@ var BasicFilterContainer = function BasicFilterContainer(_ref) {
52
54
  key: filter,
53
55
  selection: selection[filter] || [],
54
56
  isDisabled: !cloudId,
55
- onSelectionChange: function onSelectionChange(options) {
56
- return handleSelectionChange(options, filter);
57
- },
57
+ onSelectionChange: handleSelectionChange,
58
58
  onReset: handleReset
59
59
  });
60
60
  }));
@@ -34,7 +34,9 @@ function mapNodeToOption(_ref) {
34
34
  try {
35
35
  var baseProps = {
36
36
  label: displayName,
37
- value: jqlTerm
37
+ // this ensures that the returned value is not wrapped in single and double quotes
38
+ // e.g. '"value"' -> 'value'
39
+ value: decodeURIComponent(jqlTerm).replace(/^"|"$/g, '')
38
40
  };
39
41
  if (user) {
40
42
  return _objectSpread(_objectSpread({}, baseProps), {}, {
@@ -10,10 +10,12 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
10
10
  var _react = _interopRequireWildcard(require("react"));
11
11
  var _react2 = require("@emotion/react");
12
12
  var _reactIntlNext = require("react-intl-next");
13
+ var _useDebounce = require("use-debounce");
13
14
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
14
15
  var _primitives = require("@atlaskit/primitives");
15
16
  var _analytics = require("../../../analytics");
16
17
  var _basicFilters = require("../basic-filters");
18
+ var _asyncPopupSelect = require("../basic-filters/ui/async-popup-select");
17
19
  var _isQueryTooComplex = require("../basic-filters/utils/isQueryTooComplex");
18
20
  var _basicSearchInput = require("../basic-search-input");
19
21
  var _jqlEditor = require("../jql-editor");
@@ -46,6 +48,8 @@ var JiraSearchContainer = exports.JiraSearchContainer = function JiraSearchConta
46
48
  initialJql = _ref.jql;
47
49
  var _useIntl = (0, _reactIntlNext.useIntl)(),
48
50
  formatMessage = _useIntl.formatMessage;
51
+ var _useDatasourceAnalyti = (0, _analytics.useDatasourceAnalyticsEvents)(),
52
+ fireEvent = _useDatasourceAnalyti.fireEvent;
49
53
  var _useState = (0, _react.useState)(''),
50
54
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
51
55
  basicSearchTerm = _useState2[0],
@@ -70,8 +74,10 @@ var JiraSearchContainer = exports.JiraSearchContainer = function JiraSearchConta
70
74
  _useState12 = (0, _slicedToArray2.default)(_useState11, 2),
71
75
  orderDirection = _useState12[0],
72
76
  setOrderDirection = _useState12[1];
73
- var _useDatasourceAnalyti = (0, _analytics.useDatasourceAnalyticsEvents)(),
74
- fireEvent = _useDatasourceAnalyti.fireEvent;
77
+ var _useState13 = (0, _react.useState)({}),
78
+ _useState14 = (0, _slicedToArray2.default)(_useState13, 2),
79
+ filters = _useState14[0],
80
+ setFilters = _useState14[1];
75
81
  var onSearchMethodChange = (0, _react.useCallback)(function (searchMethod) {
76
82
  onSearchMethodChangeCallback(searchMethod);
77
83
  setCurrentSearchMethod(searchMethod);
@@ -81,10 +87,11 @@ var JiraSearchContainer = exports.JiraSearchContainer = function JiraSearchConta
81
87
  setBasicSearchTerm(rawSearch);
82
88
  setJql((0, _buildJQL.buildJQL)({
83
89
  rawSearch: rawSearch,
90
+ filterValues: filters,
84
91
  orderDirection: orderDirection,
85
92
  orderKey: orderKey
86
93
  }));
87
- }, [orderDirection, orderKey]);
94
+ }, [filters, orderDirection, orderKey]);
88
95
  var onQueryChange = (0, _react.useCallback)(function (query) {
89
96
  var _query$split$map$filt, _fragments$at, _fragments$at2, _fragments$at3;
90
97
  // determine if order keys have been set so they can be saved and persisted when changes occur in basic search
@@ -113,16 +120,34 @@ var JiraSearchContainer = exports.JiraSearchContainer = function JiraSearchConta
113
120
  fireEvent('ui.jqlEditor.searched', {});
114
121
  }
115
122
  }, [currentSearchMethod, fireEvent, jql, onSearch]);
123
+ var _useDebouncedCallback = (0, _useDebounce.useDebouncedCallback)(function (filterValues) {
124
+ var jqlWithFilterValues = (0, _buildJQL.buildJQL)({
125
+ rawSearch: basicSearchTerm,
126
+ filterValues: filterValues,
127
+ orderDirection: orderDirection,
128
+ orderKey: orderKey
129
+ });
130
+ setJql(jqlWithFilterValues);
131
+ onSearch({
132
+ jql: jqlWithFilterValues
133
+ }, currentSearchMethod);
134
+ }, _asyncPopupSelect.SEARCH_DEBOUNCE_MS),
135
+ _useDebouncedCallback2 = (0, _slicedToArray2.default)(_useDebouncedCallback, 1),
136
+ debouncedBasicFilterSelectionChange = _useDebouncedCallback2[0];
137
+ var handleBasicFilterSelectionChange = (0, _react.useCallback)(function (filterValues) {
138
+ setFilters(filterValues);
139
+ debouncedBasicFilterSelectionChange(filterValues);
140
+ }, [debouncedBasicFilterSelectionChange]);
141
+ (0, _react.useEffect)(function () {
142
+ setIsComplexQuery((0, _isQueryTooComplex.isQueryTooComplex)(jql));
143
+ // eslint-disable-next-line react-hooks/exhaustive-deps
144
+ }, []);
116
145
  var showBasicFilters = (0, _react.useMemo)(function () {
117
146
  if ((0, _platformFeatureFlags.getBooleanFF)('platform.linking-platform.datasource.show-jlol-basic-filters')) {
118
147
  return true;
119
148
  }
120
149
  return false;
121
150
  }, []);
122
- (0, _react.useEffect)(function () {
123
- setIsComplexQuery((0, _isQueryTooComplex.isQueryTooComplex)(jql));
124
- // eslint-disable-next-line react-hooks/exhaustive-deps
125
- }, []);
126
151
  return (0, _react2.jsx)("div", {
127
152
  css: inputContainerStyles
128
153
  }, currentSearchMethod === 'basic' && (0, _react2.jsx)(_primitives.Flex, {
@@ -135,7 +160,8 @@ var JiraSearchContainer = exports.JiraSearchContainer = function JiraSearchConta
135
160
  searchTerm: basicSearchTerm
136
161
  }), showBasicFilters && (0, _react2.jsx)(_basicFilters.BasicFilters, {
137
162
  jql: jql,
138
- cloudId: cloudId || ''
163
+ cloudId: cloudId || '',
164
+ onChange: handleBasicFilterSelectionChange
139
165
  })), currentSearchMethod === 'jql' && (0, _react2.jsx)(_jqlEditor.JiraJQLEditor, {
140
166
  cloudId: cloudId || '',
141
167
  isSearching: isSearching,
@@ -1,5 +1,5 @@
1
1
  export const EVENT_CHANNEL = 'media';
2
2
  export const packageMetaData = {
3
3
  packageName: "@atlaskit/link-datasource",
4
- packageVersion: "1.17.13"
4
+ packageVersion: "1.18.1"
5
5
  };
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useState } from 'react';
2
2
  import isEqual from 'lodash/isEqual';
3
3
  import { DEFAULT_GET_DATASOURCE_DATA_PAGE_SIZE, useDatasourceClientExtension } from '@atlaskit/link-client-extension';
4
4
  import { useDatasourceAnalyticsEvents } from '../analytics';
5
+ import useErrorLogger from './useErrorLogger';
5
6
  export const useDatasourceTableState = ({
6
7
  datasourceId,
7
8
  parameters,
@@ -10,6 +11,9 @@ export const useDatasourceTableState = ({
10
11
  const {
11
12
  fireEvent
12
13
  } = useDatasourceAnalyticsEvents();
14
+ const {
15
+ captureError
16
+ } = useErrorLogger();
13
17
  const idFieldCount = 1;
14
18
  const keyFieldCount = 1;
15
19
  const [defaultVisibleColumnKeys, setDefaultVisibleColumnKeys] = useState([]);
@@ -54,13 +58,14 @@ export const useDatasourceTableState = ({
54
58
  const newColumns = allColumns.filter(isColumnNotPresentInCurrentColumnsList);
55
59
  newColumns.length > 0 && setColumns([...columns, ...newColumns]);
56
60
  } catch (e) {
61
+ captureError('loadDatasourceDetails', e);
57
62
  if (e instanceof Response && (e.status === 401 || e.status === 403)) {
58
63
  setStatus('unauthorized');
59
64
  return;
60
65
  }
61
66
  setStatus('rejected');
62
67
  }
63
- }, [columns, datasourceId, getDatasourceDetails, parameters]);
68
+ }, [captureError, columns, datasourceId, getDatasourceDetails, parameters]);
64
69
  const applySchemaProperties = useCallback((schema, fieldKeys) => {
65
70
  let {
66
71
  properties,
@@ -160,13 +165,14 @@ export const useDatasourceTableState = ({
160
165
  }
161
166
  setStatus('resolved');
162
167
  } catch (e) {
168
+ captureError('onNextPage', e);
163
169
  if (e instanceof Response && (e.status === 401 || e.status === 403)) {
164
170
  setStatus('unauthorized');
165
171
  return;
166
172
  }
167
173
  setStatus('rejected');
168
174
  }
169
- }, [parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent, fullSchema]);
175
+ }, [captureError, parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent, fullSchema]);
170
176
  const reset = useCallback(options => {
171
177
  setStatus('empty');
172
178
  setResponseItems([]);
@@ -0,0 +1,44 @@
1
+ import { useCallback } from 'react';
2
+ import { captureException } from '@atlaskit/linking-common/sentry';
3
+ import { getTraceId } from '@atlaskit/linking-common/utils';
4
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
5
+ import { useDatasourceAnalyticsEvents } from '../analytics';
6
+ const getNetworkFields = error => {
7
+ return error instanceof Response ? {
8
+ traceId: getTraceId(error),
9
+ status: error.status
10
+ } : {
11
+ traceId: null,
12
+ status: null
13
+ };
14
+ };
15
+ const useErrorLogger = () => {
16
+ const {
17
+ fireEvent
18
+ } = useDatasourceAnalyticsEvents();
19
+
20
+ /**
21
+ * Sentry is good because it can retrieve name, message, stacktrace of an Error. That's why we will send to Sentry only
22
+ * if an error is instance of `Error`. Sentry is also capable of some PII scrubbing of these risky fields.
23
+ *
24
+ * We will send to Splunk every single time, though, but we won't send PII risky fields.
25
+ */
26
+ const captureError = useCallback((errorLocation, error) => {
27
+ const {
28
+ traceId,
29
+ status
30
+ } = getNetworkFields(error);
31
+ fireEvent('operational.datasource.operationFailed', {
32
+ errorLocation,
33
+ traceId,
34
+ status
35
+ });
36
+ if (getBooleanFF('platform.linking-platform.datasources.enable-sentry-client') && error instanceof Error) {
37
+ captureException(error, 'link-datasource');
38
+ }
39
+ }, [fireEvent]);
40
+ return {
41
+ captureError
42
+ };
43
+ };
44
+ export default useErrorLogger;
@@ -60,8 +60,8 @@ const AsyncPopupSelect = ({
60
60
  }
61
61
  }, [handleDebouncedFetchFilterOptions, searchTerm]);
62
62
  const handleOptionSelection = useCallback(newValue => {
63
- onSelectionChange(newValue);
64
- }, [onSelectionChange]);
63
+ onSelectionChange(filterType, newValue);
64
+ }, [filterType, onSelectionChange]);
65
65
  const sortOptionsOnPopupOpen = useCallback(() => {
66
66
  if (selectedOptions.length === 0) {
67
67
  return setSortedOptions(filterOptions);
@@ -8,7 +8,8 @@ const basicFilterContainerStyles = xcss({
8
8
  });
9
9
  const BasicFilterContainer = ({
10
10
  jql,
11
- cloudId
11
+ cloudId,
12
+ onChange
12
13
  }) => {
13
14
  const [selection, setSelection] = useState({});
14
15
  useEffect(() => {
@@ -16,13 +17,14 @@ const BasicFilterContainer = ({
16
17
  // hydrate hook call goes in here
17
18
  }
18
19
  }, [jql]);
19
- const handleSelectionChange = useCallback((options, filter) => {
20
+ const handleSelectionChange = useCallback((filterType, options) => {
20
21
  const updatedSelection = {
21
22
  ...selection,
22
- [filter]: options
23
+ [filterType]: options
23
24
  };
24
25
  setSelection(updatedSelection);
25
- }, [selection]);
26
+ onChange(updatedSelection);
27
+ }, [onChange, selection]);
26
28
  const handleReset = useCallback(() => {
27
29
  if (Object.keys(selection).length > 0) {
28
30
  setSelection({});
@@ -38,7 +40,7 @@ const BasicFilterContainer = ({
38
40
  key: filter,
39
41
  selection: selection[filter] || [],
40
42
  isDisabled: !cloudId,
41
- onSelectionChange: options => handleSelectionChange(options, filter),
43
+ onSelectionChange: handleSelectionChange,
42
44
  onReset: handleReset
43
45
  })));
44
46
  };
@@ -22,7 +22,9 @@ function mapNodeToOption({
22
22
  try {
23
23
  const baseProps = {
24
24
  label: displayName,
25
- value: jqlTerm
25
+ // this ensures that the returned value is not wrapped in single and double quotes
26
+ // e.g. '"value"' -> 'value'
27
+ value: decodeURIComponent(jqlTerm).replace(/^"|"$/g, '')
26
28
  };
27
29
  if (user) {
28
30
  return {
@@ -2,10 +2,12 @@
2
2
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
3
3
  import { css, jsx } from '@emotion/react';
4
4
  import { useIntl } from 'react-intl-next';
5
+ import { useDebouncedCallback } from 'use-debounce';
5
6
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
6
7
  import { Flex, xcss } from '@atlaskit/primitives';
7
8
  import { useDatasourceAnalyticsEvents } from '../../../analytics';
8
9
  import { BasicFilters } from '../basic-filters';
10
+ import { SEARCH_DEBOUNCE_MS } from '../basic-filters/ui/async-popup-select';
9
11
  import { isQueryTooComplex } from '../basic-filters/utils/isQueryTooComplex';
10
12
  import { BasicSearchInput } from '../basic-search-input';
11
13
  import { JiraJQLEditor } from '../jql-editor';
@@ -38,15 +40,16 @@ export const JiraSearchContainer = props => {
38
40
  const {
39
41
  formatMessage
40
42
  } = useIntl();
43
+ const {
44
+ fireEvent
45
+ } = useDatasourceAnalyticsEvents();
41
46
  const [basicSearchTerm, setBasicSearchTerm] = useState('');
42
47
  const [currentSearchMethod, setCurrentSearchMethod] = useState(initialSearchMethod);
43
48
  const [jql, setJql] = useState(initialJql || DEFAULT_JQL_QUERY);
44
49
  const [isComplexQuery, setIsComplexQuery] = useState(false);
45
50
  const [orderKey, setOrderKey] = useState();
46
51
  const [orderDirection, setOrderDirection] = useState();
47
- const {
48
- fireEvent
49
- } = useDatasourceAnalyticsEvents();
52
+ const [filters, setFilters] = useState({});
50
53
  const onSearchMethodChange = useCallback(searchMethod => {
51
54
  onSearchMethodChangeCallback(searchMethod);
52
55
  setCurrentSearchMethod(searchMethod);
@@ -56,10 +59,11 @@ export const JiraSearchContainer = props => {
56
59
  setBasicSearchTerm(rawSearch);
57
60
  setJql(buildJQL({
58
61
  rawSearch,
62
+ filterValues: filters,
59
63
  orderDirection,
60
64
  orderKey
61
65
  }));
62
- }, [orderDirection, orderKey]);
66
+ }, [filters, orderDirection, orderKey]);
63
67
  const onQueryChange = useCallback(query => {
64
68
  var _query$split$map$filt, _fragments$at, _fragments$at2, _fragments$at3;
65
69
  // determine if order keys have been set so they can be saved and persisted when changes occur in basic search
@@ -86,16 +90,32 @@ export const JiraSearchContainer = props => {
86
90
  fireEvent('ui.jqlEditor.searched', {});
87
91
  }
88
92
  }, [currentSearchMethod, fireEvent, jql, onSearch]);
93
+ const [debouncedBasicFilterSelectionChange] = useDebouncedCallback(filterValues => {
94
+ const jqlWithFilterValues = buildJQL({
95
+ rawSearch: basicSearchTerm,
96
+ filterValues,
97
+ orderDirection,
98
+ orderKey
99
+ });
100
+ setJql(jqlWithFilterValues);
101
+ onSearch({
102
+ jql: jqlWithFilterValues
103
+ }, currentSearchMethod);
104
+ }, SEARCH_DEBOUNCE_MS);
105
+ const handleBasicFilterSelectionChange = useCallback(filterValues => {
106
+ setFilters(filterValues);
107
+ debouncedBasicFilterSelectionChange(filterValues);
108
+ }, [debouncedBasicFilterSelectionChange]);
109
+ useEffect(() => {
110
+ setIsComplexQuery(isQueryTooComplex(jql));
111
+ // eslint-disable-next-line react-hooks/exhaustive-deps
112
+ }, []);
89
113
  const showBasicFilters = useMemo(() => {
90
114
  if (getBooleanFF('platform.linking-platform.datasource.show-jlol-basic-filters')) {
91
115
  return true;
92
116
  }
93
117
  return false;
94
118
  }, []);
95
- useEffect(() => {
96
- setIsComplexQuery(isQueryTooComplex(jql));
97
- // eslint-disable-next-line react-hooks/exhaustive-deps
98
- }, []);
99
119
  return jsx("div", {
100
120
  css: inputContainerStyles
101
121
  }, currentSearchMethod === 'basic' && jsx(Flex, {
@@ -108,7 +128,8 @@ export const JiraSearchContainer = props => {
108
128
  searchTerm: basicSearchTerm
109
129
  }), showBasicFilters && jsx(BasicFilters, {
110
130
  jql: jql,
111
- cloudId: cloudId || ''
131
+ cloudId: cloudId || '',
132
+ onChange: handleBasicFilterSelectionChange
112
133
  })), currentSearchMethod === 'jql' && jsx(JiraJQLEditor, {
113
134
  cloudId: cloudId || '',
114
135
  isSearching: isSearching,
@@ -1,5 +1,5 @@
1
1
  export var EVENT_CHANNEL = 'media';
2
2
  export var packageMetaData = {
3
3
  packageName: "@atlaskit/link-datasource",
4
- packageVersion: "1.17.13"
4
+ packageVersion: "1.18.1"
5
5
  };
@@ -6,6 +6,7 @@ import { useCallback, useEffect, useState } from 'react';
6
6
  import isEqual from 'lodash/isEqual';
7
7
  import { DEFAULT_GET_DATASOURCE_DATA_PAGE_SIZE, useDatasourceClientExtension } from '@atlaskit/link-client-extension';
8
8
  import { useDatasourceAnalyticsEvents } from '../analytics';
9
+ import useErrorLogger from './useErrorLogger';
9
10
  export var useDatasourceTableState = function useDatasourceTableState(_ref) {
10
11
  var datasourceId = _ref.datasourceId,
11
12
  parameters = _ref.parameters,
@@ -13,6 +14,8 @@ export var useDatasourceTableState = function useDatasourceTableState(_ref) {
13
14
  fieldKeys = _ref$fieldKeys === void 0 ? [] : _ref$fieldKeys;
14
15
  var _useDatasourceAnalyti = useDatasourceAnalyticsEvents(),
15
16
  fireEvent = _useDatasourceAnalyti.fireEvent;
17
+ var _useErrorLogger = useErrorLogger(),
18
+ captureError = _useErrorLogger.captureError;
16
19
  var idFieldCount = 1;
17
20
  var keyFieldCount = 1;
18
21
  var _useState = useState([]),
@@ -103,25 +106,26 @@ export var useDatasourceTableState = function useDatasourceTableState(_ref) {
103
106
  allColumns = schema.properties;
104
107
  newColumns = allColumns.filter(isColumnNotPresentInCurrentColumnsList);
105
108
  newColumns.length > 0 && setColumns([].concat(_toConsumableArray(columns), _toConsumableArray(newColumns)));
106
- _context.next = 23;
109
+ _context.next = 24;
107
110
  break;
108
111
  case 17:
109
112
  _context.prev = 17;
110
113
  _context.t0 = _context["catch"](2);
114
+ captureError('loadDatasourceDetails', _context.t0);
111
115
  if (!(_context.t0 instanceof Response && (_context.t0.status === 401 || _context.t0.status === 403))) {
112
- _context.next = 22;
116
+ _context.next = 23;
113
117
  break;
114
118
  }
115
119
  setStatus('unauthorized');
116
120
  return _context.abrupt("return");
117
- case 22:
118
- setStatus('rejected');
119
121
  case 23:
122
+ setStatus('rejected');
123
+ case 24:
120
124
  case "end":
121
125
  return _context.stop();
122
126
  }
123
127
  }, _callee, null, [[2, 17]]);
124
- })), [columns, datasourceId, getDatasourceDetails, parameters]);
128
+ })), [captureError, columns, datasourceId, getDatasourceDetails, parameters]);
125
129
  var applySchemaProperties = useCallback(function (schema, fieldKeys) {
126
130
  var properties = schema.properties,
127
131
  _schema$defaultProper = schema.defaultProperties,
@@ -249,25 +253,26 @@ export var useDatasourceTableState = function useDatasourceTableState(_ref) {
249
253
  });
250
254
  }
251
255
  setStatus('resolved');
252
- _context2.next = 42;
256
+ _context2.next = 43;
253
257
  break;
254
258
  case 36:
255
259
  _context2.prev = 36;
256
260
  _context2.t0 = _context2["catch"](7);
261
+ captureError('onNextPage', _context2.t0);
257
262
  if (!(_context2.t0 instanceof Response && (_context2.t0.status === 401 || _context2.t0.status === 403))) {
258
- _context2.next = 41;
263
+ _context2.next = 42;
259
264
  break;
260
265
  }
261
266
  setStatus('unauthorized');
262
267
  return _context2.abrupt("return");
263
- case 41:
264
- setStatus('rejected');
265
268
  case 42:
269
+ setStatus('rejected');
270
+ case 43:
266
271
  case "end":
267
272
  return _context2.stop();
268
273
  }
269
274
  }, _callee2, null, [[7, 36]]);
270
- })), [parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent, fullSchema]);
275
+ })), [captureError, parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent, fullSchema]);
271
276
  var reset = useCallback(function (options) {
272
277
  setStatus('empty');
273
278
  setResponseItems([]);
@@ -0,0 +1,42 @@
1
+ import { useCallback } from 'react';
2
+ import { captureException } from '@atlaskit/linking-common/sentry';
3
+ import { getTraceId } from '@atlaskit/linking-common/utils';
4
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
5
+ import { useDatasourceAnalyticsEvents } from '../analytics';
6
+ var getNetworkFields = function getNetworkFields(error) {
7
+ return error instanceof Response ? {
8
+ traceId: getTraceId(error),
9
+ status: error.status
10
+ } : {
11
+ traceId: null,
12
+ status: null
13
+ };
14
+ };
15
+ var useErrorLogger = function useErrorLogger() {
16
+ var _useDatasourceAnalyti = useDatasourceAnalyticsEvents(),
17
+ fireEvent = _useDatasourceAnalyti.fireEvent;
18
+
19
+ /**
20
+ * Sentry is good because it can retrieve name, message, stacktrace of an Error. That's why we will send to Sentry only
21
+ * if an error is instance of `Error`. Sentry is also capable of some PII scrubbing of these risky fields.
22
+ *
23
+ * We will send to Splunk every single time, though, but we won't send PII risky fields.
24
+ */
25
+ var captureError = useCallback(function (errorLocation, error) {
26
+ var _getNetworkFields = getNetworkFields(error),
27
+ traceId = _getNetworkFields.traceId,
28
+ status = _getNetworkFields.status;
29
+ fireEvent('operational.datasource.operationFailed', {
30
+ errorLocation: errorLocation,
31
+ traceId: traceId,
32
+ status: status
33
+ });
34
+ if (getBooleanFF('platform.linking-platform.datasources.enable-sentry-client') && error instanceof Error) {
35
+ captureException(error, 'link-datasource');
36
+ }
37
+ }, [fireEvent]);
38
+ return {
39
+ captureError: captureError
40
+ };
41
+ };
42
+ export default useErrorLogger;
@@ -91,8 +91,8 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
91
91
  };
92
92
  }(), [handleDebouncedFetchFilterOptions, searchTerm]);
93
93
  var handleOptionSelection = useCallback(function (newValue) {
94
- onSelectionChange(newValue);
95
- }, [onSelectionChange]);
94
+ onSelectionChange(filterType, newValue);
95
+ }, [filterType, onSelectionChange]);
96
96
  var sortOptionsOnPopupOpen = useCallback(function () {
97
97
  if (selectedOptions.length === 0) {
98
98
  return setSortedOptions(filterOptions);
@@ -12,7 +12,8 @@ var basicFilterContainerStyles = xcss({
12
12
  });
13
13
  var BasicFilterContainer = function BasicFilterContainer(_ref) {
14
14
  var jql = _ref.jql,
15
- cloudId = _ref.cloudId;
15
+ cloudId = _ref.cloudId,
16
+ onChange = _ref.onChange;
16
17
  var _useState = useState({}),
17
18
  _useState2 = _slicedToArray(_useState, 2),
18
19
  selection = _useState2[0],
@@ -22,10 +23,11 @@ var BasicFilterContainer = function BasicFilterContainer(_ref) {
22
23
  // hydrate hook call goes in here
23
24
  }
24
25
  }, [jql]);
25
- var handleSelectionChange = useCallback(function (options, filter) {
26
- var updatedSelection = _objectSpread(_objectSpread({}, selection), {}, _defineProperty({}, filter, options));
26
+ var handleSelectionChange = useCallback(function (filterType, options) {
27
+ var updatedSelection = _objectSpread(_objectSpread({}, selection), {}, _defineProperty({}, filterType, options));
27
28
  setSelection(updatedSelection);
28
- }, [selection]);
29
+ onChange(updatedSelection);
30
+ }, [onChange, selection]);
29
31
  var handleReset = useCallback(function () {
30
32
  if (Object.keys(selection).length > 0) {
31
33
  setSelection({});
@@ -42,9 +44,7 @@ var BasicFilterContainer = function BasicFilterContainer(_ref) {
42
44
  key: filter,
43
45
  selection: selection[filter] || [],
44
46
  isDisabled: !cloudId,
45
- onSelectionChange: function onSelectionChange(options) {
46
- return handleSelectionChange(options, filter);
47
- },
47
+ onSelectionChange: handleSelectionChange,
48
48
  onReset: handleReset
49
49
  });
50
50
  }));
@@ -24,7 +24,9 @@ function mapNodeToOption(_ref) {
24
24
  try {
25
25
  var baseProps = {
26
26
  label: displayName,
27
- value: jqlTerm
27
+ // this ensures that the returned value is not wrapped in single and double quotes
28
+ // e.g. '"value"' -> 'value'
29
+ value: decodeURIComponent(jqlTerm).replace(/^"|"$/g, '')
28
30
  };
29
31
  if (user) {
30
32
  return _objectSpread(_objectSpread({}, baseProps), {}, {
@@ -3,10 +3,12 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
3
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
4
  import { css, jsx } from '@emotion/react';
5
5
  import { useIntl } from 'react-intl-next';
6
+ import { useDebouncedCallback } from 'use-debounce';
6
7
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
7
8
  import { Flex, xcss } from '@atlaskit/primitives';
8
9
  import { useDatasourceAnalyticsEvents } from '../../../analytics';
9
10
  import { BasicFilters } from '../basic-filters';
11
+ import { SEARCH_DEBOUNCE_MS } from '../basic-filters/ui/async-popup-select';
10
12
  import { isQueryTooComplex } from '../basic-filters/utils/isQueryTooComplex';
11
13
  import { BasicSearchInput } from '../basic-search-input';
12
14
  import { JiraJQLEditor } from '../jql-editor';
@@ -35,6 +37,8 @@ export var JiraSearchContainer = function JiraSearchContainer(props) {
35
37
  initialJql = _ref.jql;
36
38
  var _useIntl = useIntl(),
37
39
  formatMessage = _useIntl.formatMessage;
40
+ var _useDatasourceAnalyti = useDatasourceAnalyticsEvents(),
41
+ fireEvent = _useDatasourceAnalyti.fireEvent;
38
42
  var _useState = useState(''),
39
43
  _useState2 = _slicedToArray(_useState, 2),
40
44
  basicSearchTerm = _useState2[0],
@@ -59,8 +63,10 @@ export var JiraSearchContainer = function JiraSearchContainer(props) {
59
63
  _useState12 = _slicedToArray(_useState11, 2),
60
64
  orderDirection = _useState12[0],
61
65
  setOrderDirection = _useState12[1];
62
- var _useDatasourceAnalyti = useDatasourceAnalyticsEvents(),
63
- fireEvent = _useDatasourceAnalyti.fireEvent;
66
+ var _useState13 = useState({}),
67
+ _useState14 = _slicedToArray(_useState13, 2),
68
+ filters = _useState14[0],
69
+ setFilters = _useState14[1];
64
70
  var onSearchMethodChange = useCallback(function (searchMethod) {
65
71
  onSearchMethodChangeCallback(searchMethod);
66
72
  setCurrentSearchMethod(searchMethod);
@@ -70,10 +76,11 @@ export var JiraSearchContainer = function JiraSearchContainer(props) {
70
76
  setBasicSearchTerm(rawSearch);
71
77
  setJql(buildJQL({
72
78
  rawSearch: rawSearch,
79
+ filterValues: filters,
73
80
  orderDirection: orderDirection,
74
81
  orderKey: orderKey
75
82
  }));
76
- }, [orderDirection, orderKey]);
83
+ }, [filters, orderDirection, orderKey]);
77
84
  var onQueryChange = useCallback(function (query) {
78
85
  var _query$split$map$filt, _fragments$at, _fragments$at2, _fragments$at3;
79
86
  // determine if order keys have been set so they can be saved and persisted when changes occur in basic search
@@ -102,16 +109,34 @@ export var JiraSearchContainer = function JiraSearchContainer(props) {
102
109
  fireEvent('ui.jqlEditor.searched', {});
103
110
  }
104
111
  }, [currentSearchMethod, fireEvent, jql, onSearch]);
112
+ var _useDebouncedCallback = useDebouncedCallback(function (filterValues) {
113
+ var jqlWithFilterValues = buildJQL({
114
+ rawSearch: basicSearchTerm,
115
+ filterValues: filterValues,
116
+ orderDirection: orderDirection,
117
+ orderKey: orderKey
118
+ });
119
+ setJql(jqlWithFilterValues);
120
+ onSearch({
121
+ jql: jqlWithFilterValues
122
+ }, currentSearchMethod);
123
+ }, SEARCH_DEBOUNCE_MS),
124
+ _useDebouncedCallback2 = _slicedToArray(_useDebouncedCallback, 1),
125
+ debouncedBasicFilterSelectionChange = _useDebouncedCallback2[0];
126
+ var handleBasicFilterSelectionChange = useCallback(function (filterValues) {
127
+ setFilters(filterValues);
128
+ debouncedBasicFilterSelectionChange(filterValues);
129
+ }, [debouncedBasicFilterSelectionChange]);
130
+ useEffect(function () {
131
+ setIsComplexQuery(isQueryTooComplex(jql));
132
+ // eslint-disable-next-line react-hooks/exhaustive-deps
133
+ }, []);
105
134
  var showBasicFilters = useMemo(function () {
106
135
  if (getBooleanFF('platform.linking-platform.datasource.show-jlol-basic-filters')) {
107
136
  return true;
108
137
  }
109
138
  return false;
110
139
  }, []);
111
- useEffect(function () {
112
- setIsComplexQuery(isQueryTooComplex(jql));
113
- // eslint-disable-next-line react-hooks/exhaustive-deps
114
- }, []);
115
140
  return jsx("div", {
116
141
  css: inputContainerStyles
117
142
  }, currentSearchMethod === 'basic' && jsx(Flex, {
@@ -124,7 +149,8 @@ export var JiraSearchContainer = function JiraSearchContainer(props) {
124
149
  searchTerm: basicSearchTerm
125
150
  }), showBasicFilters && jsx(BasicFilters, {
126
151
  jql: jql,
127
- cloudId: cloudId || ''
152
+ cloudId: cloudId || '',
153
+ onChange: handleBasicFilterSelectionChange
128
154
  })), currentSearchMethod === 'jql' && jsx(JiraJQLEditor, {
129
155
  cloudId: cloudId || '',
130
156
  isSearching: isSearching,
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Generates Typescript types for analytics events from analytics.spec.yaml
5
5
  *
6
- * @codegen <<SignedSource::ccda345ed2d15f3bbe167f871f676090>>
6
+ * @codegen <<SignedSource::4e6414d2c19c29a67f20beee73d4b788>>
7
7
  * @codegenCommand yarn workspace @atlassian/analytics-tooling run analytics:codegen link-datasource
8
8
  */
9
9
  export type PackageMetaDataType = {
@@ -59,6 +59,11 @@ export type DatasourceRenderSuccessAttributesType = {
59
59
  display: 'table';
60
60
  };
61
61
  export type DatasourceRenderFailureAttributesType = {};
62
+ export type DatasourceOperationFailedAttributesType = {
63
+ errorLocation: string | null;
64
+ traceId: string | null;
65
+ status: number | null;
66
+ };
62
67
  export type NextItemLoadedAttributesType = {
63
68
  destinationObjectTypes: unknown[];
64
69
  extensionKey: string | null;
@@ -155,6 +160,9 @@ export type AnalyticsEventAttributes = {
155
160
  /**
156
161
  * Fired when an inserted datasource fails to render */
157
162
  'operational.datasource.renderFailure': DatasourceRenderFailureAttributesType;
163
+ /**
164
+ * Fired when a generic operation failed */
165
+ 'operational.datasource.operationFailed': DatasourceOperationFailedAttributesType;
158
166
  /**
159
167
  * Fired when user scrolls to the next page/list of the objects */
160
168
  'track.nextItem.loaded': NextItemLoadedAttributesType;
@@ -0,0 +1,4 @@
1
+ declare const useErrorLogger: () => {
2
+ captureError: (errorLocation: string, error: unknown) => void;
3
+ };
4
+ export default useErrorLogger;
@@ -1,8 +1,6 @@
1
- import { BasicFilterFieldType, SelectOption } from '../types';
1
+ import { SelectedOptionsMap } from '../types';
2
2
  export interface HydrateJqlState {
3
- hydratedOptions: {
4
- [key in BasicFilterFieldType]?: SelectOption[];
5
- };
3
+ hydratedOptions: SelectedOptionsMap;
6
4
  fetchHydratedJqlOptions: () => Promise<void>;
7
5
  status: 'empty' | 'loading' | 'resolved' | 'rejected';
8
6
  errors: unknown[];
@@ -20,6 +20,9 @@ export type AvatarLabelOption = OptionBase & {
20
20
  isGroup?: boolean;
21
21
  };
22
22
  export type SelectOption = IconLabelOption | LozengeLabelOption | AvatarLabelOption;
23
+ export type SelectedOptionsMap = {
24
+ [key in BasicFilterFieldType]?: SelectOption[];
25
+ };
23
26
  export type FormatOptionLabel = (option: SelectOption) => ReactElement;
24
27
  export declare const appearanceMap: {
25
28
  readonly BLUE_GRAY: "default";
@@ -4,7 +4,7 @@ export interface AsyncPopupSelectProps {
4
4
  filterType: BasicFilterFieldType;
5
5
  cloudId: string;
6
6
  selection: SelectOption[];
7
- onSelectionChange?: (selection: SelectOption[]) => void;
7
+ onSelectionChange?: (filterType: BasicFilterFieldType, options: SelectOption[]) => void;
8
8
  onReset?: () => void;
9
9
  isDisabled?: boolean;
10
10
  }
@@ -1,7 +1,9 @@
1
1
  /// <reference types="react" />
2
+ import type { SelectedOptionsMap } from '../types';
2
3
  export interface BasicFilterContainerProps {
3
4
  jql: string;
4
5
  cloudId: string;
6
+ onChange: (selection: SelectedOptionsMap) => void;
5
7
  }
6
- declare const BasicFilterContainer: ({ jql, cloudId }: BasicFilterContainerProps) => JSX.Element;
8
+ declare const BasicFilterContainer: ({ jql, cloudId, onChange, }: BasicFilterContainerProps) => JSX.Element;
7
9
  export default BasicFilterContainer;
@@ -1,10 +1,5 @@
1
- import { FieldValuesResponse, HydrateResponse, SelectOption } from '../types';
2
- export declare function mapHydrateResponseData({ data }: HydrateResponse): {
3
- project?: SelectOption[] | undefined;
4
- assignee?: SelectOption[] | undefined;
5
- issuetype?: SelectOption[] | undefined;
6
- status?: SelectOption[] | undefined;
7
- };
1
+ import { FieldValuesResponse, HydrateResponse, SelectedOptionsMap, SelectOption } from '../types';
2
+ export declare function mapHydrateResponseData({ data }: HydrateResponse): SelectedOptionsMap;
8
3
  export declare function mapFieldValuesToFilterOptions({ data, }: FieldValuesResponse): SelectOption[];
9
4
  export declare function mapFieldValuesToTotalCount({ data, }: FieldValuesResponse): number;
10
5
  export declare function mapFieldValuesToPageCursor({ data, }: FieldValuesResponse): string | undefined;
@@ -1,11 +1,9 @@
1
- import { BasicFilterFieldType, SelectOption } from '../basic-filters/types';
1
+ import { SelectedOptionsMap } from '../basic-filters/types';
2
2
  type BuildJQLInput = {
3
3
  rawSearch: string;
4
4
  orderDirection?: string;
5
5
  orderKey?: string;
6
- filterValues?: {
7
- [key in BasicFilterFieldType]?: SelectOption[];
8
- };
6
+ filterValues?: SelectedOptionsMap;
9
7
  };
10
8
  export declare const fuzzyCharacter = "*";
11
9
  export declare const buildJQL: (input: BuildJQLInput) => string;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Generates Typescript types for analytics events from analytics.spec.yaml
5
5
  *
6
- * @codegen <<SignedSource::ccda345ed2d15f3bbe167f871f676090>>
6
+ * @codegen <<SignedSource::4e6414d2c19c29a67f20beee73d4b788>>
7
7
  * @codegenCommand yarn workspace @atlassian/analytics-tooling run analytics:codegen link-datasource
8
8
  */
9
9
  export type PackageMetaDataType = {
@@ -59,6 +59,11 @@ export type DatasourceRenderSuccessAttributesType = {
59
59
  display: 'table';
60
60
  };
61
61
  export type DatasourceRenderFailureAttributesType = {};
62
+ export type DatasourceOperationFailedAttributesType = {
63
+ errorLocation: string | null;
64
+ traceId: string | null;
65
+ status: number | null;
66
+ };
62
67
  export type NextItemLoadedAttributesType = {
63
68
  destinationObjectTypes: unknown[];
64
69
  extensionKey: string | null;
@@ -155,6 +160,9 @@ export type AnalyticsEventAttributes = {
155
160
  /**
156
161
  * Fired when an inserted datasource fails to render */
157
162
  'operational.datasource.renderFailure': DatasourceRenderFailureAttributesType;
163
+ /**
164
+ * Fired when a generic operation failed */
165
+ 'operational.datasource.operationFailed': DatasourceOperationFailedAttributesType;
158
166
  /**
159
167
  * Fired when user scrolls to the next page/list of the objects */
160
168
  'track.nextItem.loaded': NextItemLoadedAttributesType;
@@ -0,0 +1,4 @@
1
+ declare const useErrorLogger: () => {
2
+ captureError: (errorLocation: string, error: unknown) => void;
3
+ };
4
+ export default useErrorLogger;
@@ -1,8 +1,6 @@
1
- import { BasicFilterFieldType, SelectOption } from '../types';
1
+ import { SelectedOptionsMap } from '../types';
2
2
  export interface HydrateJqlState {
3
- hydratedOptions: {
4
- [key in BasicFilterFieldType]?: SelectOption[];
5
- };
3
+ hydratedOptions: SelectedOptionsMap;
6
4
  fetchHydratedJqlOptions: () => Promise<void>;
7
5
  status: 'empty' | 'loading' | 'resolved' | 'rejected';
8
6
  errors: unknown[];
@@ -20,6 +20,9 @@ export type AvatarLabelOption = OptionBase & {
20
20
  isGroup?: boolean;
21
21
  };
22
22
  export type SelectOption = IconLabelOption | LozengeLabelOption | AvatarLabelOption;
23
+ export type SelectedOptionsMap = {
24
+ [key in BasicFilterFieldType]?: SelectOption[];
25
+ };
23
26
  export type FormatOptionLabel = (option: SelectOption) => ReactElement;
24
27
  export declare const appearanceMap: {
25
28
  readonly BLUE_GRAY: "default";
@@ -4,7 +4,7 @@ export interface AsyncPopupSelectProps {
4
4
  filterType: BasicFilterFieldType;
5
5
  cloudId: string;
6
6
  selection: SelectOption[];
7
- onSelectionChange?: (selection: SelectOption[]) => void;
7
+ onSelectionChange?: (filterType: BasicFilterFieldType, options: SelectOption[]) => void;
8
8
  onReset?: () => void;
9
9
  isDisabled?: boolean;
10
10
  }
@@ -1,7 +1,9 @@
1
1
  /// <reference types="react" />
2
+ import type { SelectedOptionsMap } from '../types';
2
3
  export interface BasicFilterContainerProps {
3
4
  jql: string;
4
5
  cloudId: string;
6
+ onChange: (selection: SelectedOptionsMap) => void;
5
7
  }
6
- declare const BasicFilterContainer: ({ jql, cloudId }: BasicFilterContainerProps) => JSX.Element;
8
+ declare const BasicFilterContainer: ({ jql, cloudId, onChange, }: BasicFilterContainerProps) => JSX.Element;
7
9
  export default BasicFilterContainer;
@@ -1,10 +1,5 @@
1
- import { FieldValuesResponse, HydrateResponse, SelectOption } from '../types';
2
- export declare function mapHydrateResponseData({ data }: HydrateResponse): {
3
- project?: SelectOption[] | undefined;
4
- assignee?: SelectOption[] | undefined;
5
- issuetype?: SelectOption[] | undefined;
6
- status?: SelectOption[] | undefined;
7
- };
1
+ import { FieldValuesResponse, HydrateResponse, SelectedOptionsMap, SelectOption } from '../types';
2
+ export declare function mapHydrateResponseData({ data }: HydrateResponse): SelectedOptionsMap;
8
3
  export declare function mapFieldValuesToFilterOptions({ data, }: FieldValuesResponse): SelectOption[];
9
4
  export declare function mapFieldValuesToTotalCount({ data, }: FieldValuesResponse): number;
10
5
  export declare function mapFieldValuesToPageCursor({ data, }: FieldValuesResponse): string | undefined;
@@ -1,11 +1,9 @@
1
- import { BasicFilterFieldType, SelectOption } from '../basic-filters/types';
1
+ import { SelectedOptionsMap } from '../basic-filters/types';
2
2
  type BuildJQLInput = {
3
3
  rawSearch: string;
4
4
  orderDirection?: string;
5
5
  orderKey?: string;
6
- filterValues?: {
7
- [key in BasicFilterFieldType]?: SelectOption[];
8
- };
6
+ filterValues?: SelectedOptionsMap;
9
7
  };
10
8
  export declare const fuzzyCharacter = "*";
11
9
  export declare const buildJQL: (input: BuildJQLInput) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/link-datasource",
3
- "version": "1.17.13",
3
+ "version": "1.18.1",
4
4
  "description": "UI Components to support linking platform dataset feature",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -30,7 +30,7 @@
30
30
  "analytics:codegen": "yarn workspace @atlassian/analytics-tooling run analytics:codegen link-datasource --output ./src/analytics/generated"
31
31
  },
32
32
  "dependencies": {
33
- "@atlaskit/adf-schema": "^33.2.3",
33
+ "@atlaskit/adf-schema": "^34.0.0",
34
34
  "@atlaskit/analytics-next": "^9.1.3",
35
35
  "@atlaskit/avatar": "^21.4.0",
36
36
  "@atlaskit/badge": "^15.1.16",
@@ -46,7 +46,7 @@
46
46
  "@atlaskit/jql-ast": "^3.0.0",
47
47
  "@atlaskit/jql-editor-autocomplete-rest": "^2.0.0",
48
48
  "@atlaskit/link-client-extension": "^1.8.0",
49
- "@atlaskit/linking-common": "^4.18.0",
49
+ "@atlaskit/linking-common": "^4.19.0",
50
50
  "@atlaskit/linking-types": "^8.5.0",
51
51
  "@atlaskit/lozenge": "^11.4.0",
52
52
  "@atlaskit/modal-dialog": "^12.8.0",
@@ -138,6 +138,9 @@
138
138
  "platform-feature-flags": {
139
139
  "platform.linking-platform.datasource.show-jlol-basic-filters": {
140
140
  "type": "boolean"
141
+ },
142
+ "platform.linking-platform.datasources.enable-sentry-client": {
143
+ "type": "boolean"
141
144
  }
142
145
  }
143
146
  }