@atlaskit/link-datasource 1.19.8 → 1.19.9

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 (27) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/analytics/constants.js +1 -1
  3. package/dist/cjs/ui/jira-issues-modal/basic-filters/hooks/messages.js +14 -0
  4. package/dist/cjs/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.js +34 -10
  5. package/dist/cjs/ui/jira-issues-modal/basic-filters/hooks/useHydrateJqlQuery.js +24 -9
  6. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/messages.js +3 -2
  7. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/menu-list/messages.js +3 -2
  8. package/dist/cjs/ui/jira-issues-modal/basic-filters/utils/extractValuesFromNonComplexJQL.js +11 -3
  9. package/dist/es2019/analytics/constants.js +1 -1
  10. package/dist/es2019/ui/jira-issues-modal/basic-filters/hooks/messages.js +8 -0
  11. package/dist/es2019/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.js +25 -4
  12. package/dist/es2019/ui/jira-issues-modal/basic-filters/hooks/useHydrateJqlQuery.js +21 -3
  13. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/messages.js +3 -2
  14. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/menu-list/messages.js +3 -2
  15. package/dist/es2019/ui/jira-issues-modal/basic-filters/utils/extractValuesFromNonComplexJQL.js +11 -1
  16. package/dist/esm/analytics/constants.js +1 -1
  17. package/dist/esm/ui/jira-issues-modal/basic-filters/hooks/messages.js +8 -0
  18. package/dist/esm/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.js +33 -9
  19. package/dist/esm/ui/jira-issues-modal/basic-filters/hooks/useHydrateJqlQuery.js +24 -9
  20. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/messages.js +3 -2
  21. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/menu-list/messages.js +3 -2
  22. package/dist/esm/ui/jira-issues-modal/basic-filters/utils/extractValuesFromNonComplexJQL.js +11 -3
  23. package/dist/types/ui/jira-issues-modal/basic-filters/hooks/messages.d.ts +7 -0
  24. package/dist/types/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.d.ts +3 -1
  25. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/hooks/messages.d.ts +7 -0
  26. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.d.ts +3 -1
  27. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @atlaskit/link-datasource
2
2
 
3
+ ## 1.19.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#56564](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/56564) [`b26cc1ff959d`](https://bitbucket.org/atlassian/atlassian-frontend/commits/b26cc1ff959d) - Add `Unassigned` option for Assignee filter dropdown.
8
+
3
9
  ## 1.19.8
4
10
 
5
11
  ### 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.19.8"
10
+ packageVersion: "1.19.9"
11
11
  };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.filterOptionMessages = void 0;
7
+ var _reactIntlNext = require("react-intl-next");
8
+ var filterOptionMessages = exports.filterOptionMessages = (0, _reactIntlNext.defineMessages)({
9
+ assigneeUnassignedFilterOption: {
10
+ id: 'linkDataSource.basic-filter.dropdown.select.assignee.unassigned',
11
+ description: 'Text to display for Unassigned assignee filter option.',
12
+ defaultMessage: 'Unassigned'
13
+ }
14
+ });
@@ -4,17 +4,28 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.useFilterOptions = void 0;
7
+ exports.useFilterOptions = exports.getAssigneeUnassignedFilterOption = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
9
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10
10
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
11
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
12
12
  var _react = require("react");
13
+ var _reactIntlNext = require("react-intl-next");
13
14
  var _useBasicFilterAGG2 = require("../../../../services/useBasicFilterAGG");
14
15
  var _transformers = require("../utils/transformers");
16
+ var _messages = require("./messages");
17
+ var getAssigneeUnassignedFilterOption = exports.getAssigneeUnassignedFilterOption = function getAssigneeUnassignedFilterOption(formatMessage) {
18
+ return {
19
+ label: formatMessage(_messages.filterOptionMessages.assigneeUnassignedFilterOption),
20
+ optionType: 'avatarLabel',
21
+ value: 'empty'
22
+ };
23
+ };
15
24
  var useFilterOptions = exports.useFilterOptions = function useFilterOptions(_ref) {
16
25
  var filterType = _ref.filterType,
17
26
  cloudId = _ref.cloudId;
27
+ var _useIntl = (0, _reactIntlNext.useIntl)(),
28
+ formatMessage = _useIntl.formatMessage;
18
29
  var _useState = (0, _react.useState)([]),
19
30
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
20
31
  filterOptions = _useState2[0],
@@ -46,6 +57,8 @@ var useFilterOptions = exports.useFilterOptions = function useFilterOptions(_ref
46
57
  isRequestLikeInitialSearch,
47
58
  initialResponseData,
48
59
  response,
60
+ mappedResponse,
61
+ mappedTotalCount,
49
62
  _args = arguments;
50
63
  return _regenerator.default.wrap(function _callee$(_context) {
51
64
  while (1) switch (_context.prev = _context.next) {
@@ -84,34 +97,45 @@ var useFilterOptions = exports.useFilterOptions = function useFilterOptions(_ref
84
97
  setErrors(response.errors);
85
98
  return _context.abrupt("return");
86
99
  case 18:
100
+ mappedResponse = (0, _transformers.mapFieldValuesToFilterOptions)(response);
101
+ mappedTotalCount = (0, _transformers.mapFieldValuesToTotalCount)(response);
87
102
  if (isNewSearch) {
88
- setFilterOptions((0, _transformers.mapFieldValuesToFilterOptions)(response));
89
103
  if (isRequestLikeInitialSearch) {
90
104
  /**
91
105
  * The initial dataset is used in couple of paths, eg: when a user searches and clears the search text.
92
106
  * During these times, we dont want to fetch data again and again, hence a mini cache setup to store and provide the initial dataset
93
107
  */
94
108
  initialData.current = response;
109
+
110
+ /**
111
+ * For assignee filter option, we want `Unassigned` as an option.
112
+ * Since `Unassigned/EMPTY` is not returned by the API, we add it manually, but only for the initial list
113
+ */
114
+ if (filterType === 'assignee') {
115
+ mappedResponse.unshift(getAssigneeUnassignedFilterOption(formatMessage));
116
+ mappedTotalCount += 1;
117
+ }
95
118
  }
119
+ setFilterOptions(mappedResponse);
96
120
  } else {
97
- setFilterOptions([].concat((0, _toConsumableArray2.default)(filterOptions), (0, _toConsumableArray2.default)((0, _transformers.mapFieldValuesToFilterOptions)(response))));
121
+ setFilterOptions([].concat((0, _toConsumableArray2.default)(filterOptions), (0, _toConsumableArray2.default)(mappedResponse)));
98
122
  }
99
- setTotalCount((0, _transformers.mapFieldValuesToTotalCount)(response));
123
+ setTotalCount(mappedTotalCount);
100
124
  setNextPageCursor((0, _transformers.mapFieldValuesToPageCursor)(response));
101
125
  setStatus('resolved');
102
- _context.next = 28;
126
+ _context.next = 30;
103
127
  break;
104
- case 24:
105
- _context.prev = 24;
128
+ case 26:
129
+ _context.prev = 26;
106
130
  _context.t1 = _context["catch"](5);
107
131
  setStatus('rejected');
108
132
  setErrors([_context.t1]);
109
- case 28:
133
+ case 30:
110
134
  case "end":
111
135
  return _context.stop();
112
136
  }
113
- }, _callee, null, [[5, 24]]);
114
- })), [cloudId, filterOptions, filterType, getFieldValues]);
137
+ }, _callee, null, [[5, 26]]);
138
+ })), [cloudId, filterOptions, filterType, formatMessage, getFieldValues]);
115
139
  (0, _react.useEffect)(function () {
116
140
  if (status !== 'rejected' && errors.length !== 0) {
117
141
  setErrors([]);
@@ -6,14 +6,20 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.useHydrateJqlQuery = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
10
12
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
13
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
12
14
  var _react = require("react");
15
+ var _reactIntlNext = require("react-intl-next");
16
+ var _jqlAst = require("@atlaskit/jql-ast");
13
17
  var _useBasicFilterAGG2 = require("../../../../services/useBasicFilterAGG");
14
18
  var _extractValuesFromNonComplexJQL = require("../utils/extractValuesFromNonComplexJQL");
15
19
  var _isClauseTooComplex = require("../utils/isClauseTooComplex");
16
20
  var _transformers = require("../utils/transformers");
21
+ var _useFilterOptions = require("./useFilterOptions");
22
+ var _excluded = ["assignee"];
17
23
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
18
24
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
19
25
  var useHydrateJqlQuery = exports.useHydrateJqlQuery = function useHydrateJqlQuery(cloudId, jql) {
@@ -21,6 +27,8 @@ var useHydrateJqlQuery = exports.useHydrateJqlQuery = function useHydrateJqlQuer
21
27
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
22
28
  hydratedOptions = _useState2[0],
23
29
  setHydratedOptions = _useState2[1];
30
+ var _useIntl = (0, _reactIntlNext.useIntl)(),
31
+ formatMessage = _useIntl.formatMessage;
24
32
  var _useState3 = (0, _react.useState)('empty'),
25
33
  _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
26
34
  status = _useState4[0],
@@ -32,7 +40,7 @@ var useHydrateJqlQuery = exports.useHydrateJqlQuery = function useHydrateJqlQuer
32
40
  var _useBasicFilterAGG = (0, _useBasicFilterAGG2.useBasicFilterAGG)(),
33
41
  getHydratedJQL = _useBasicFilterAGG.getHydratedJQL;
34
42
  var fetchHydratedJqlOptions = (0, _react.useCallback)( /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
35
- var response, _extractValuesFromNon, text, summary, key, _ref2, _ref3, textFieldValue, mappedValues;
43
+ var response, _mapHydrateResponseDa, mappedHydratedAssigneeValue, restOfMappedHydratedResponse, _extractValuesFromNon, text, summary, key, extractedAssigneeValue, _ref2, _ref3, textFieldValue, mappedValues;
36
44
  return _regenerator.default.wrap(function _callee$(_context) {
37
45
  while (1) switch (_context.prev = _context.next) {
38
46
  case 0:
@@ -50,29 +58,36 @@ var useHydrateJqlQuery = exports.useHydrateJqlQuery = function useHydrateJqlQuer
50
58
  setErrors(response.errors);
51
59
  return _context.abrupt("return");
52
60
  case 9:
61
+ _mapHydrateResponseDa = (0, _transformers.mapHydrateResponseData)(response), mappedHydratedAssigneeValue = _mapHydrateResponseDa.assignee, restOfMappedHydratedResponse = (0, _objectWithoutProperties2.default)(_mapHydrateResponseDa, _excluded);
53
62
  /**
54
63
  * Hydrate logic does not return text field, hence we parse and extract value from jql
55
64
  */
56
- _extractValuesFromNon = (0, _extractValuesFromNonComplexJQL.extractValuesFromNonComplexJQL)(jql), text = _extractValuesFromNon.text, summary = _extractValuesFromNon.summary, key = _extractValuesFromNon.key;
65
+ _extractValuesFromNon = (0, _extractValuesFromNonComplexJQL.extractValuesFromNonComplexJQL)(jql), text = _extractValuesFromNon.text, summary = _extractValuesFromNon.summary, key = _extractValuesFromNon.key, extractedAssigneeValue = _extractValuesFromNon.assignee;
57
66
  _ref2 = text || summary || key || [], _ref3 = (0, _slicedToArray2.default)(_ref2, 1), textFieldValue = _ref3[0];
58
- mappedValues = _objectSpread(_objectSpread({}, (0, _transformers.mapHydrateResponseData)(response)), textFieldValue ? {
67
+ mappedValues = _objectSpread(_objectSpread({}, restOfMappedHydratedResponse), {}, {
68
+ /**
69
+ * Special handling for assignee as we need to inject Unassigned value if JQL contains EMPTY keyword for assignee
70
+ */
71
+ assignee: [].concat((0, _toConsumableArray2.default)(mappedHydratedAssigneeValue || []), (0, _toConsumableArray2.default)(extractedAssigneeValue !== null && extractedAssigneeValue !== void 0 && extractedAssigneeValue.includes(_jqlAst.OPERAND_EMPTY) // checks and adds EMPTY filter option if extracted assignee values from jql contains EMPTY
72
+ ? [(0, _useFilterOptions.getAssigneeUnassignedFilterOption)(formatMessage)] : []))
73
+ }, textFieldValue ? {
59
74
  basicInputTextValue: (0, _isClauseTooComplex.removeFuzzyCharacter)(textFieldValue)
60
75
  } : {});
61
76
  setHydratedOptions(mappedValues);
62
77
  setStatus('resolved');
63
- _context.next = 20;
78
+ _context.next = 21;
64
79
  break;
65
- case 16:
66
- _context.prev = 16;
80
+ case 17:
81
+ _context.prev = 17;
67
82
  _context.t0 = _context["catch"](0);
68
83
  setErrors([_context.t0]);
69
84
  setStatus('rejected');
70
- case 20:
85
+ case 21:
71
86
  case "end":
72
87
  return _context.stop();
73
88
  }
74
- }, _callee, null, [[0, 16]]);
75
- })), [cloudId, getHydratedJQL, jql]);
89
+ }, _callee, null, [[0, 17]]);
90
+ })), [cloudId, formatMessage, getHydratedJQL, jql]);
76
91
  (0, _react.useEffect)(function () {
77
92
  if (status !== 'rejected' && errors.length !== 0) {
78
93
  setErrors([]);
@@ -4,7 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.asyncPopupSelectMessages = void 0;
7
- var asyncPopupSelectMessages = exports.asyncPopupSelectMessages = {
7
+ var _reactIntlNext = require("react-intl-next");
8
+ var asyncPopupSelectMessages = exports.asyncPopupSelectMessages = (0, _reactIntlNext.defineMessages)({
8
9
  selectPlaceholder: {
9
10
  id: 'linkDataSource.basic-filter.dropdown.select.placeholder',
10
11
  description: 'Placeholder text to be displayed for the search input box.',
@@ -40,4 +41,4 @@ var asyncPopupSelectMessages = exports.asyncPopupSelectMessages = {
40
41
  defaultMessage: 'Show more',
41
42
  description: 'The text to show more options in dropdown'
42
43
  }
43
- };
44
+ });
@@ -4,7 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.asyncPopupSelectMessages = void 0;
7
- var asyncPopupSelectMessages = exports.asyncPopupSelectMessages = {
7
+ var _reactIntlNext = require("react-intl-next");
8
+ var asyncPopupSelectMessages = exports.asyncPopupSelectMessages = (0, _reactIntlNext.defineMessages)({
8
9
  loadingMessage: {
9
10
  id: 'linkDataSource.basic-filter.loading-message',
10
11
  defaultMessage: 'Loading...',
@@ -20,4 +21,4 @@ var asyncPopupSelectMessages = exports.asyncPopupSelectMessages = {
20
21
  defaultMessage: 'Something went wrong',
21
22
  description: 'The text for when an error occurs when loading options'
22
23
  }
23
- };
24
+ });
@@ -20,11 +20,19 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
20
20
  // Map of field keys to their respective clauses in the Jast
21
21
 
22
22
  var getFieldValues = function getFieldValues(operand) {
23
+ var mapValuesFromList = function mapValuesFromList(value) {
24
+ if (value.operandType === _jqlAst.OPERAND_TYPE_VALUE) {
25
+ return value.value;
26
+ }
27
+ // we only support EMPTY keyword atm, hence making sure if operandType is a KEYWORD, then its an EMPTY keyword
28
+ if (value.operandType === _jqlAst.OPERAND_TYPE_KEYWORD && value.value === _jqlAst.OPERAND_EMPTY) {
29
+ return value.value;
30
+ }
31
+ return undefined;
32
+ };
23
33
  switch (operand.operandType) {
24
34
  case _jqlAst.OPERAND_TYPE_LIST:
25
- return operand.values.map(function (value) {
26
- return value.operandType === _jqlAst.OPERAND_TYPE_VALUE && value.value || undefined;
27
- }).filter(function (value) {
35
+ return operand.values.map(mapValuesFromList).filter(function (value) {
28
36
  return !!value;
29
37
  });
30
38
  case _jqlAst.OPERAND_TYPE_VALUE:
@@ -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.19.8"
4
+ packageVersion: "1.19.9"
5
5
  };
@@ -0,0 +1,8 @@
1
+ import { defineMessages } from 'react-intl-next';
2
+ export const filterOptionMessages = defineMessages({
3
+ assigneeUnassignedFilterOption: {
4
+ id: 'linkDataSource.basic-filter.dropdown.select.assignee.unassigned',
5
+ description: 'Text to display for Unassigned assignee filter option.',
6
+ defaultMessage: 'Unassigned'
7
+ }
8
+ });
@@ -1,10 +1,20 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { useIntl } from 'react-intl-next';
2
3
  import { useBasicFilterAGG } from '../../../../services/useBasicFilterAGG';
3
4
  import { mapFieldValuesToFilterOptions, mapFieldValuesToPageCursor, mapFieldValuesToTotalCount } from '../utils/transformers';
5
+ import { filterOptionMessages } from './messages';
6
+ export const getAssigneeUnassignedFilterOption = formatMessage => ({
7
+ label: formatMessage(filterOptionMessages.assigneeUnassignedFilterOption),
8
+ optionType: 'avatarLabel',
9
+ value: 'empty'
10
+ });
4
11
  export const useFilterOptions = ({
5
12
  filterType,
6
13
  cloudId
7
14
  }) => {
15
+ const {
16
+ formatMessage
17
+ } = useIntl();
8
18
  const [filterOptions, setFilterOptions] = useState([]);
9
19
  const [totalCount, setTotalCount] = useState(0);
10
20
  const [status, setStatus] = useState('empty');
@@ -37,26 +47,37 @@ export const useFilterOptions = ({
37
47
  setErrors(response.errors);
38
48
  return;
39
49
  }
50
+ const mappedResponse = mapFieldValuesToFilterOptions(response);
51
+ let mappedTotalCount = mapFieldValuesToTotalCount(response);
40
52
  if (isNewSearch) {
41
- setFilterOptions(mapFieldValuesToFilterOptions(response));
42
53
  if (isRequestLikeInitialSearch) {
43
54
  /**
44
55
  * The initial dataset is used in couple of paths, eg: when a user searches and clears the search text.
45
56
  * During these times, we dont want to fetch data again and again, hence a mini cache setup to store and provide the initial dataset
46
57
  */
47
58
  initialData.current = response;
59
+
60
+ /**
61
+ * For assignee filter option, we want `Unassigned` as an option.
62
+ * Since `Unassigned/EMPTY` is not returned by the API, we add it manually, but only for the initial list
63
+ */
64
+ if (filterType === 'assignee') {
65
+ mappedResponse.unshift(getAssigneeUnassignedFilterOption(formatMessage));
66
+ mappedTotalCount += 1;
67
+ }
48
68
  }
69
+ setFilterOptions(mappedResponse);
49
70
  } else {
50
- setFilterOptions([...filterOptions, ...mapFieldValuesToFilterOptions(response)]);
71
+ setFilterOptions([...filterOptions, ...mappedResponse]);
51
72
  }
52
- setTotalCount(mapFieldValuesToTotalCount(response));
73
+ setTotalCount(mappedTotalCount);
53
74
  setNextPageCursor(mapFieldValuesToPageCursor(response));
54
75
  setStatus('resolved');
55
76
  } catch (error) {
56
77
  setStatus('rejected');
57
78
  setErrors([error]);
58
79
  }
59
- }, [cloudId, filterOptions, filterType, getFieldValues]);
80
+ }, [cloudId, filterOptions, filterType, formatMessage, getFieldValues]);
60
81
  useEffect(() => {
61
82
  if (status !== 'rejected' && errors.length !== 0) {
62
83
  setErrors([]);
@@ -1,10 +1,16 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
+ import { useIntl } from 'react-intl-next';
3
+ import { OPERAND_EMPTY } from '@atlaskit/jql-ast';
2
4
  import { useBasicFilterAGG } from '../../../../services/useBasicFilterAGG';
3
5
  import { extractValuesFromNonComplexJQL } from '../utils/extractValuesFromNonComplexJQL';
4
6
  import { removeFuzzyCharacter } from '../utils/isClauseTooComplex';
5
7
  import { mapHydrateResponseData } from '../utils/transformers';
8
+ import { getAssigneeUnassignedFilterOption } from './useFilterOptions';
6
9
  export const useHydrateJqlQuery = (cloudId, jql) => {
7
10
  const [hydratedOptions, setHydratedOptions] = useState({});
11
+ const {
12
+ formatMessage
13
+ } = useIntl();
8
14
  const [status, setStatus] = useState('empty');
9
15
  const [errors, setErrors] = useState([]);
10
16
  const {
@@ -19,6 +25,10 @@ export const useHydrateJqlQuery = (cloudId, jql) => {
19
25
  setErrors(response.errors);
20
26
  return;
21
27
  }
28
+ const {
29
+ assignee: mappedHydratedAssigneeValue,
30
+ ...restOfMappedHydratedResponse
31
+ } = mapHydrateResponseData(response);
22
32
 
23
33
  /**
24
34
  * Hydrate logic does not return text field, hence we parse and extract value from jql
@@ -26,11 +36,19 @@ export const useHydrateJqlQuery = (cloudId, jql) => {
26
36
  const {
27
37
  text,
28
38
  summary,
29
- key
39
+ key,
40
+ assignee: extractedAssigneeValue
30
41
  } = extractValuesFromNonComplexJQL(jql);
31
42
  const [textFieldValue] = text || summary || key || [];
32
43
  const mappedValues = {
33
- ...mapHydrateResponseData(response),
44
+ ...restOfMappedHydratedResponse,
45
+ /**
46
+ * Special handling for assignee as we need to inject Unassigned value if JQL contains EMPTY keyword for assignee
47
+ */
48
+ assignee: [...(mappedHydratedAssigneeValue || []),
49
+ // all values provided by the hydrate API for assignee
50
+ ...(extractedAssigneeValue !== null && extractedAssigneeValue !== void 0 && extractedAssigneeValue.includes(OPERAND_EMPTY) // checks and adds EMPTY filter option if extracted assignee values from jql contains EMPTY
51
+ ? [getAssigneeUnassignedFilterOption(formatMessage)] : [])],
34
52
  ...(textFieldValue ? {
35
53
  basicInputTextValue: removeFuzzyCharacter(textFieldValue)
36
54
  } : {})
@@ -41,7 +59,7 @@ export const useHydrateJqlQuery = (cloudId, jql) => {
41
59
  setErrors([error]);
42
60
  setStatus('rejected');
43
61
  }
44
- }, [cloudId, getHydratedJQL, jql]);
62
+ }, [cloudId, formatMessage, getHydratedJQL, jql]);
45
63
  useEffect(() => {
46
64
  if (status !== 'rejected' && errors.length !== 0) {
47
65
  setErrors([]);
@@ -1,4 +1,5 @@
1
- export const asyncPopupSelectMessages = {
1
+ import { defineMessages } from 'react-intl-next';
2
+ export const asyncPopupSelectMessages = defineMessages({
2
3
  selectPlaceholder: {
3
4
  id: 'linkDataSource.basic-filter.dropdown.select.placeholder',
4
5
  description: 'Placeholder text to be displayed for the search input box.',
@@ -34,4 +35,4 @@ export const asyncPopupSelectMessages = {
34
35
  defaultMessage: 'Show more',
35
36
  description: 'The text to show more options in dropdown'
36
37
  }
37
- };
38
+ });
@@ -1,4 +1,5 @@
1
- export const asyncPopupSelectMessages = {
1
+ import { defineMessages } from 'react-intl-next';
2
+ export const asyncPopupSelectMessages = defineMessages({
2
3
  loadingMessage: {
3
4
  id: 'linkDataSource.basic-filter.loading-message',
4
5
  defaultMessage: 'Loading...',
@@ -14,4 +15,4 @@ export const asyncPopupSelectMessages = {
14
15
  defaultMessage: 'Something went wrong',
15
16
  description: 'The text for when an error occurs when loading options'
16
17
  }
17
- };
18
+ });
@@ -6,9 +6,19 @@ import { isQueryTooComplex } from './isQueryTooComplex';
6
6
  // Map of field keys to their respective clauses in the Jast
7
7
 
8
8
  const getFieldValues = operand => {
9
+ const mapValuesFromList = value => {
10
+ if (value.operandType === OPERAND_TYPE_VALUE) {
11
+ return value.value;
12
+ }
13
+ // we only support EMPTY keyword atm, hence making sure if operandType is a KEYWORD, then its an EMPTY keyword
14
+ if (value.operandType === OPERAND_TYPE_KEYWORD && value.value === OPERAND_EMPTY) {
15
+ return value.value;
16
+ }
17
+ return undefined;
18
+ };
9
19
  switch (operand.operandType) {
10
20
  case OPERAND_TYPE_LIST:
11
- return operand.values.map(value => value.operandType === OPERAND_TYPE_VALUE && value.value || undefined).filter(value => !!value);
21
+ return operand.values.map(mapValuesFromList).filter(value => !!value);
12
22
  case OPERAND_TYPE_VALUE:
13
23
  return operand.value ? [operand.value] : [];
14
24
  case OPERAND_TYPE_KEYWORD:
@@ -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.19.8"
4
+ packageVersion: "1.19.9"
5
5
  };
@@ -0,0 +1,8 @@
1
+ import { defineMessages } from 'react-intl-next';
2
+ export var filterOptionMessages = defineMessages({
3
+ assigneeUnassignedFilterOption: {
4
+ id: 'linkDataSource.basic-filter.dropdown.select.assignee.unassigned',
5
+ description: 'Text to display for Unassigned assignee filter option.',
6
+ defaultMessage: 'Unassigned'
7
+ }
8
+ });
@@ -3,11 +3,22 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
3
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
4
  import _regeneratorRuntime from "@babel/runtime/regenerator";
5
5
  import { useCallback, useEffect, useRef, useState } from 'react';
6
+ import { useIntl } from 'react-intl-next';
6
7
  import { useBasicFilterAGG } from '../../../../services/useBasicFilterAGG';
7
8
  import { mapFieldValuesToFilterOptions, mapFieldValuesToPageCursor, mapFieldValuesToTotalCount } from '../utils/transformers';
9
+ import { filterOptionMessages } from './messages';
10
+ export var getAssigneeUnassignedFilterOption = function getAssigneeUnassignedFilterOption(formatMessage) {
11
+ return {
12
+ label: formatMessage(filterOptionMessages.assigneeUnassignedFilterOption),
13
+ optionType: 'avatarLabel',
14
+ value: 'empty'
15
+ };
16
+ };
8
17
  export var useFilterOptions = function useFilterOptions(_ref) {
9
18
  var filterType = _ref.filterType,
10
19
  cloudId = _ref.cloudId;
20
+ var _useIntl = useIntl(),
21
+ formatMessage = _useIntl.formatMessage;
11
22
  var _useState = useState([]),
12
23
  _useState2 = _slicedToArray(_useState, 2),
13
24
  filterOptions = _useState2[0],
@@ -39,6 +50,8 @@ export var useFilterOptions = function useFilterOptions(_ref) {
39
50
  isRequestLikeInitialSearch,
40
51
  initialResponseData,
41
52
  response,
53
+ mappedResponse,
54
+ mappedTotalCount,
42
55
  _args = arguments;
43
56
  return _regeneratorRuntime.wrap(function _callee$(_context) {
44
57
  while (1) switch (_context.prev = _context.next) {
@@ -77,34 +90,45 @@ export var useFilterOptions = function useFilterOptions(_ref) {
77
90
  setErrors(response.errors);
78
91
  return _context.abrupt("return");
79
92
  case 18:
93
+ mappedResponse = mapFieldValuesToFilterOptions(response);
94
+ mappedTotalCount = mapFieldValuesToTotalCount(response);
80
95
  if (isNewSearch) {
81
- setFilterOptions(mapFieldValuesToFilterOptions(response));
82
96
  if (isRequestLikeInitialSearch) {
83
97
  /**
84
98
  * The initial dataset is used in couple of paths, eg: when a user searches and clears the search text.
85
99
  * During these times, we dont want to fetch data again and again, hence a mini cache setup to store and provide the initial dataset
86
100
  */
87
101
  initialData.current = response;
102
+
103
+ /**
104
+ * For assignee filter option, we want `Unassigned` as an option.
105
+ * Since `Unassigned/EMPTY` is not returned by the API, we add it manually, but only for the initial list
106
+ */
107
+ if (filterType === 'assignee') {
108
+ mappedResponse.unshift(getAssigneeUnassignedFilterOption(formatMessage));
109
+ mappedTotalCount += 1;
110
+ }
88
111
  }
112
+ setFilterOptions(mappedResponse);
89
113
  } else {
90
- setFilterOptions([].concat(_toConsumableArray(filterOptions), _toConsumableArray(mapFieldValuesToFilterOptions(response))));
114
+ setFilterOptions([].concat(_toConsumableArray(filterOptions), _toConsumableArray(mappedResponse)));
91
115
  }
92
- setTotalCount(mapFieldValuesToTotalCount(response));
116
+ setTotalCount(mappedTotalCount);
93
117
  setNextPageCursor(mapFieldValuesToPageCursor(response));
94
118
  setStatus('resolved');
95
- _context.next = 28;
119
+ _context.next = 30;
96
120
  break;
97
- case 24:
98
- _context.prev = 24;
121
+ case 26:
122
+ _context.prev = 26;
99
123
  _context.t1 = _context["catch"](5);
100
124
  setStatus('rejected');
101
125
  setErrors([_context.t1]);
102
- case 28:
126
+ case 30:
103
127
  case "end":
104
128
  return _context.stop();
105
129
  }
106
- }, _callee, null, [[5, 24]]);
107
- })), [cloudId, filterOptions, filterType, getFieldValues]);
130
+ }, _callee, null, [[5, 26]]);
131
+ })), [cloudId, filterOptions, filterType, formatMessage, getFieldValues]);
108
132
  useEffect(function () {
109
133
  if (status !== 'rejected' && errors.length !== 0) {
110
134
  setErrors([]);
@@ -1,19 +1,27 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
2
4
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
3
5
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
6
+ var _excluded = ["assignee"];
4
7
  import _regeneratorRuntime from "@babel/runtime/regenerator";
5
8
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
6
9
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
7
10
  import { useCallback, useEffect, useState } from 'react';
11
+ import { useIntl } from 'react-intl-next';
12
+ import { OPERAND_EMPTY } from '@atlaskit/jql-ast';
8
13
  import { useBasicFilterAGG } from '../../../../services/useBasicFilterAGG';
9
14
  import { extractValuesFromNonComplexJQL } from '../utils/extractValuesFromNonComplexJQL';
10
15
  import { removeFuzzyCharacter } from '../utils/isClauseTooComplex';
11
16
  import { mapHydrateResponseData } from '../utils/transformers';
17
+ import { getAssigneeUnassignedFilterOption } from './useFilterOptions';
12
18
  export var useHydrateJqlQuery = function useHydrateJqlQuery(cloudId, jql) {
13
19
  var _useState = useState({}),
14
20
  _useState2 = _slicedToArray(_useState, 2),
15
21
  hydratedOptions = _useState2[0],
16
22
  setHydratedOptions = _useState2[1];
23
+ var _useIntl = useIntl(),
24
+ formatMessage = _useIntl.formatMessage;
17
25
  var _useState3 = useState('empty'),
18
26
  _useState4 = _slicedToArray(_useState3, 2),
19
27
  status = _useState4[0],
@@ -25,7 +33,7 @@ export var useHydrateJqlQuery = function useHydrateJqlQuery(cloudId, jql) {
25
33
  var _useBasicFilterAGG = useBasicFilterAGG(),
26
34
  getHydratedJQL = _useBasicFilterAGG.getHydratedJQL;
27
35
  var fetchHydratedJqlOptions = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
28
- var response, _extractValuesFromNon, text, summary, key, _ref2, _ref3, textFieldValue, mappedValues;
36
+ var response, _mapHydrateResponseDa, mappedHydratedAssigneeValue, restOfMappedHydratedResponse, _extractValuesFromNon, text, summary, key, extractedAssigneeValue, _ref2, _ref3, textFieldValue, mappedValues;
29
37
  return _regeneratorRuntime.wrap(function _callee$(_context) {
30
38
  while (1) switch (_context.prev = _context.next) {
31
39
  case 0:
@@ -43,29 +51,36 @@ export var useHydrateJqlQuery = function useHydrateJqlQuery(cloudId, jql) {
43
51
  setErrors(response.errors);
44
52
  return _context.abrupt("return");
45
53
  case 9:
54
+ _mapHydrateResponseDa = mapHydrateResponseData(response), mappedHydratedAssigneeValue = _mapHydrateResponseDa.assignee, restOfMappedHydratedResponse = _objectWithoutProperties(_mapHydrateResponseDa, _excluded);
46
55
  /**
47
56
  * Hydrate logic does not return text field, hence we parse and extract value from jql
48
57
  */
49
- _extractValuesFromNon = extractValuesFromNonComplexJQL(jql), text = _extractValuesFromNon.text, summary = _extractValuesFromNon.summary, key = _extractValuesFromNon.key;
58
+ _extractValuesFromNon = extractValuesFromNonComplexJQL(jql), text = _extractValuesFromNon.text, summary = _extractValuesFromNon.summary, key = _extractValuesFromNon.key, extractedAssigneeValue = _extractValuesFromNon.assignee;
50
59
  _ref2 = text || summary || key || [], _ref3 = _slicedToArray(_ref2, 1), textFieldValue = _ref3[0];
51
- mappedValues = _objectSpread(_objectSpread({}, mapHydrateResponseData(response)), textFieldValue ? {
60
+ mappedValues = _objectSpread(_objectSpread({}, restOfMappedHydratedResponse), {}, {
61
+ /**
62
+ * Special handling for assignee as we need to inject Unassigned value if JQL contains EMPTY keyword for assignee
63
+ */
64
+ assignee: [].concat(_toConsumableArray(mappedHydratedAssigneeValue || []), _toConsumableArray(extractedAssigneeValue !== null && extractedAssigneeValue !== void 0 && extractedAssigneeValue.includes(OPERAND_EMPTY) // checks and adds EMPTY filter option if extracted assignee values from jql contains EMPTY
65
+ ? [getAssigneeUnassignedFilterOption(formatMessage)] : []))
66
+ }, textFieldValue ? {
52
67
  basicInputTextValue: removeFuzzyCharacter(textFieldValue)
53
68
  } : {});
54
69
  setHydratedOptions(mappedValues);
55
70
  setStatus('resolved');
56
- _context.next = 20;
71
+ _context.next = 21;
57
72
  break;
58
- case 16:
59
- _context.prev = 16;
73
+ case 17:
74
+ _context.prev = 17;
60
75
  _context.t0 = _context["catch"](0);
61
76
  setErrors([_context.t0]);
62
77
  setStatus('rejected');
63
- case 20:
78
+ case 21:
64
79
  case "end":
65
80
  return _context.stop();
66
81
  }
67
- }, _callee, null, [[0, 16]]);
68
- })), [cloudId, getHydratedJQL, jql]);
82
+ }, _callee, null, [[0, 17]]);
83
+ })), [cloudId, formatMessage, getHydratedJQL, jql]);
69
84
  useEffect(function () {
70
85
  if (status !== 'rejected' && errors.length !== 0) {
71
86
  setErrors([]);
@@ -1,4 +1,5 @@
1
- export var asyncPopupSelectMessages = {
1
+ import { defineMessages } from 'react-intl-next';
2
+ export var asyncPopupSelectMessages = defineMessages({
2
3
  selectPlaceholder: {
3
4
  id: 'linkDataSource.basic-filter.dropdown.select.placeholder',
4
5
  description: 'Placeholder text to be displayed for the search input box.',
@@ -34,4 +35,4 @@ export var asyncPopupSelectMessages = {
34
35
  defaultMessage: 'Show more',
35
36
  description: 'The text to show more options in dropdown'
36
37
  }
37
- };
38
+ });
@@ -1,4 +1,5 @@
1
- export var asyncPopupSelectMessages = {
1
+ import { defineMessages } from 'react-intl-next';
2
+ export var asyncPopupSelectMessages = defineMessages({
2
3
  loadingMessage: {
3
4
  id: 'linkDataSource.basic-filter.loading-message',
4
5
  defaultMessage: 'Loading...',
@@ -14,4 +15,4 @@ export var asyncPopupSelectMessages = {
14
15
  defaultMessage: 'Something went wrong',
15
16
  description: 'The text for when an error occurs when loading options'
16
17
  }
17
- };
18
+ });
@@ -14,11 +14,19 @@ import { isQueryTooComplex } from './isQueryTooComplex';
14
14
  // Map of field keys to their respective clauses in the Jast
15
15
 
16
16
  var getFieldValues = function getFieldValues(operand) {
17
+ var mapValuesFromList = function mapValuesFromList(value) {
18
+ if (value.operandType === OPERAND_TYPE_VALUE) {
19
+ return value.value;
20
+ }
21
+ // we only support EMPTY keyword atm, hence making sure if operandType is a KEYWORD, then its an EMPTY keyword
22
+ if (value.operandType === OPERAND_TYPE_KEYWORD && value.value === OPERAND_EMPTY) {
23
+ return value.value;
24
+ }
25
+ return undefined;
26
+ };
17
27
  switch (operand.operandType) {
18
28
  case OPERAND_TYPE_LIST:
19
- return operand.values.map(function (value) {
20
- return value.operandType === OPERAND_TYPE_VALUE && value.value || undefined;
21
- }).filter(function (value) {
29
+ return operand.values.map(mapValuesFromList).filter(function (value) {
22
30
  return !!value;
23
31
  });
24
32
  case OPERAND_TYPE_VALUE:
@@ -0,0 +1,7 @@
1
+ export declare const filterOptionMessages: {
2
+ assigneeUnassignedFilterOption: {
3
+ id: string;
4
+ description: string;
5
+ defaultMessage: string;
6
+ };
7
+ };
@@ -1,4 +1,5 @@
1
- import { BasicFilterFieldType, SelectOption } from '../types';
1
+ import { IntlShape } from 'react-intl-next';
2
+ import { AvatarLabelOption, BasicFilterFieldType, SelectOption } from '../types';
2
3
  interface FilterOptionsProps {
3
4
  filterType: BasicFilterFieldType;
4
5
  cloudId: string;
@@ -16,5 +17,6 @@ export interface FilterOptionsState {
16
17
  status: 'empty' | 'loading' | 'resolved' | 'rejected' | 'loadingMore';
17
18
  errors: unknown[];
18
19
  }
20
+ export declare const getAssigneeUnassignedFilterOption: (formatMessage: IntlShape['formatMessage']) => AvatarLabelOption;
19
21
  export declare const useFilterOptions: ({ filterType, cloudId, }: FilterOptionsProps) => FilterOptionsState;
20
22
  export {};
@@ -0,0 +1,7 @@
1
+ export declare const filterOptionMessages: {
2
+ assigneeUnassignedFilterOption: {
3
+ id: string;
4
+ description: string;
5
+ defaultMessage: string;
6
+ };
7
+ };
@@ -1,4 +1,5 @@
1
- import { BasicFilterFieldType, SelectOption } from '../types';
1
+ import { IntlShape } from 'react-intl-next';
2
+ import { AvatarLabelOption, BasicFilterFieldType, SelectOption } from '../types';
2
3
  interface FilterOptionsProps {
3
4
  filterType: BasicFilterFieldType;
4
5
  cloudId: string;
@@ -16,5 +17,6 @@ export interface FilterOptionsState {
16
17
  status: 'empty' | 'loading' | 'resolved' | 'rejected' | 'loadingMore';
17
18
  errors: unknown[];
18
19
  }
20
+ export declare const getAssigneeUnassignedFilterOption: (formatMessage: IntlShape['formatMessage']) => AvatarLabelOption;
19
21
  export declare const useFilterOptions: ({ filterType, cloudId, }: FilterOptionsProps) => FilterOptionsState;
20
22
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/link-datasource",
3
- "version": "1.19.8",
3
+ "version": "1.19.9",
4
4
  "description": "UI Components to support linking platform dataset feature",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"