@atlaskit/link-datasource 1.12.4 → 1.13.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 (61) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/analytics/constants.js +1 -1
  3. package/dist/cjs/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.js +34 -12
  4. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/dropdownIndicator.js +39 -0
  5. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +51 -20
  6. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.js +2 -0
  7. package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/index.js +1 -0
  8. package/dist/cjs/ui/jira-issues-modal/basic-filters/utils/isClauseTooComplex.js +93 -0
  9. package/dist/cjs/ui/jira-issues-modal/basic-filters/utils/isQueryTooComplex.js +146 -0
  10. package/dist/cjs/ui/jira-issues-modal/jira-search-container/buildJQL.js +3 -2
  11. package/dist/cjs/ui/jira-issues-modal/jira-search-container/index.js +21 -8
  12. package/dist/cjs/ui/jira-issues-modal/jira-search-container/messages.js +5 -0
  13. package/dist/cjs/ui/jira-issues-modal/mode-switcher/index.js +28 -16
  14. package/dist/es2019/analytics/constants.js +1 -1
  15. package/dist/es2019/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.js +14 -2
  16. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/dropdownIndicator.js +34 -0
  17. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +25 -10
  18. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.js +2 -0
  19. package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/index.js +1 -0
  20. package/dist/es2019/ui/jira-issues-modal/basic-filters/utils/isClauseTooComplex.js +77 -0
  21. package/dist/es2019/ui/jira-issues-modal/basic-filters/utils/isQueryTooComplex.js +105 -0
  22. package/dist/es2019/ui/jira-issues-modal/jira-search-container/buildJQL.js +2 -1
  23. package/dist/es2019/ui/jira-issues-modal/jira-search-container/index.js +13 -3
  24. package/dist/es2019/ui/jira-issues-modal/jira-search-container/messages.js +5 -0
  25. package/dist/es2019/ui/jira-issues-modal/mode-switcher/index.js +19 -9
  26. package/dist/esm/analytics/constants.js +1 -1
  27. package/dist/esm/ui/jira-issues-modal/basic-filters/hooks/useFilterOptions.js +35 -13
  28. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/dropdownIndicator.js +32 -0
  29. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +52 -21
  30. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.js +2 -0
  31. package/dist/esm/ui/jira-issues-modal/basic-filters/ui/index.js +1 -0
  32. package/dist/esm/ui/jira-issues-modal/basic-filters/utils/isClauseTooComplex.js +86 -0
  33. package/dist/esm/ui/jira-issues-modal/basic-filters/utils/isQueryTooComplex.js +140 -0
  34. package/dist/esm/ui/jira-issues-modal/jira-search-container/buildJQL.js +2 -1
  35. package/dist/esm/ui/jira-issues-modal/jira-search-container/index.js +21 -8
  36. package/dist/esm/ui/jira-issues-modal/jira-search-container/messages.js +5 -0
  37. package/dist/esm/ui/jira-issues-modal/mode-switcher/index.js +29 -17
  38. package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/dropdownIndicator.d.ts +5 -0
  39. package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +2 -1
  40. package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.d.ts +1 -0
  41. package/dist/types/ui/jira-issues-modal/basic-filters/utils/isClauseTooComplex.d.ts +2 -0
  42. package/dist/types/ui/jira-issues-modal/basic-filters/utils/isQueryTooComplex.d.ts +1 -0
  43. package/dist/types/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +1 -0
  44. package/dist/types/ui/jira-issues-modal/jira-search-container/index.d.ts +1 -0
  45. package/dist/types/ui/jira-issues-modal/jira-search-container/messages.d.ts +5 -0
  46. package/dist/types/ui/jira-issues-modal/mode-switcher/index.d.ts +2 -0
  47. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/dropdownIndicator.d.ts +5 -0
  48. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +2 -1
  49. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.d.ts +1 -0
  50. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/utils/isClauseTooComplex.d.ts +2 -0
  51. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/utils/isQueryTooComplex.d.ts +1 -0
  52. package/dist/types-ts4.5/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +1 -0
  53. package/dist/types-ts4.5/ui/jira-issues-modal/jira-search-container/index.d.ts +1 -0
  54. package/dist/types-ts4.5/ui/jira-issues-modal/jira-search-container/messages.d.ts +5 -0
  55. package/dist/types-ts4.5/ui/jira-issues-modal/mode-switcher/index.d.ts +2 -0
  56. package/package.json +1 -2
  57. package/dist/cjs/ui/jira-issues-modal/basic-filters/hooks/useIsComplexQuery.js +0 -12
  58. package/dist/es2019/ui/jira-issues-modal/basic-filters/hooks/useIsComplexQuery.js +0 -6
  59. package/dist/esm/ui/jira-issues-modal/basic-filters/hooks/useIsComplexQuery.js +0 -6
  60. package/dist/types/ui/jira-issues-modal/basic-filters/hooks/useIsComplexQuery.d.ts +0 -3
  61. package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/hooks/useIsComplexQuery.d.ts +0 -3
@@ -1,7 +1,9 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
1
2
  /** @jsx jsx */
2
3
  import React from 'react';
3
4
  import { css, jsx } from '@emotion/react';
4
- import { N0, N20, N30A, N700 } from '@atlaskit/theme/colors';
5
+ import { N0, N20, N30A, N60, N700 } from '@atlaskit/theme/colors';
6
+ import Tooltip from '@atlaskit/tooltip';
5
7
  const modeSwitcherStyles = css({
6
8
  alignItems: 'center',
7
9
  background: `var(--ds-background-neutral, ${N20})`,
@@ -44,8 +46,12 @@ const modeSwitcherLabelSelectedStyles = css({
44
46
  }
45
47
  });
46
48
  const modeSwitcherLabelDisabledStyles = css({
49
+ color: `var(--ds-text-disabled, ${N60})`
50
+ });
51
+ const modeSwitcherDisabledStyles = css({
47
52
  ':hover': {
48
- cursor: 'not-allowed'
53
+ cursor: 'not-allowed',
54
+ background: 'transparent'
49
55
  }
50
56
  });
51
57
  const compactModeSwitcherLabelStyles = css({
@@ -69,22 +75,26 @@ export const ModeSwitcher = props => {
69
75
  disabled: isDisabled
70
76
  }, options.map(({
71
77
  value,
72
- label
78
+ label,
79
+ disabled: isOptionDisabled,
80
+ tooltipText
73
81
  }) => {
74
82
  const isSelected = value === selectedOptionValue;
75
- return jsx("label", {
83
+ return jsx(Tooltip, {
84
+ content: tooltipText
85
+ }, tooltipProps => jsx("label", _extends({}, tooltipProps, {
76
86
  key: value,
77
- css: [modeSwitcherLabelStyles, isCompact && compactModeSwitcherLabelStyles, isSelected && modeSwitcherLabelSelectedStyles, isDisabled && modeSwitcherLabelDisabledStyles],
87
+ css: [modeSwitcherLabelStyles, isCompact && compactModeSwitcherLabelStyles, isSelected && modeSwitcherLabelSelectedStyles, isDisabled && modeSwitcherDisabledStyles, isOptionDisabled && [modeSwitcherLabelDisabledStyles, modeSwitcherDisabledStyles]],
78
88
  "data-testid": `mode-toggle-${value}`
79
- }, label, jsx("input", {
89
+ }), label, jsx("input", {
80
90
  "aria-checked": isSelected,
81
- "aria-disabled": isDisabled,
91
+ "aria-disabled": isOptionDisabled,
82
92
  checked: isSelected,
83
93
  css: modeInputStyles,
84
- disabled: isDisabled,
94
+ disabled: isOptionDisabled,
85
95
  onChange: handleModeChange,
86
96
  type: "radio",
87
97
  value: value
88
- }));
98
+ })));
89
99
  })) : null;
90
100
  };
@@ -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.12.4"
4
+ packageVersion: "1.13.1"
5
5
  };
@@ -2,7 +2,7 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  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
- import { useCallback, useState } from 'react';
5
+ import { useCallback, useRef, useState } from 'react';
6
6
  import { useBasicFilterAGG } from '../../../../services/useBasicFilterAGG';
7
7
  import { mapFieldValuesToFilterOptions, mapFieldValuesToPageCursor, mapFieldValuesToTotalCount } from '../utils/transformers';
8
8
  export var useFilterOptions = function useFilterOptions(_ref) {
@@ -24,12 +24,15 @@ export var useFilterOptions = function useFilterOptions(_ref) {
24
24
  _useState8 = _slicedToArray(_useState7, 2),
25
25
  nextPageCursor = _useState8[0],
26
26
  setNextPageCursor = _useState8[1];
27
+ var initialData = useRef();
27
28
  var _useBasicFilterAGG = useBasicFilterAGG(),
28
29
  getFieldValues = _useBasicFilterAGG.getFieldValues;
29
30
  var fetchFilterOptions = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
30
31
  var _ref3,
31
32
  pageCursor,
32
33
  searchString,
34
+ isRequestLikeInitialSearch,
35
+ initialResponseData,
33
36
  response,
34
37
  isNewSearch,
35
38
  _args = arguments;
@@ -38,8 +41,18 @@ export var useFilterOptions = function useFilterOptions(_ref) {
38
41
  case 0:
39
42
  _ref3 = _args.length > 0 && _args[0] !== undefined ? _args[0] : {}, pageCursor = _ref3.pageCursor, searchString = _ref3.searchString;
40
43
  setStatus('loading');
41
- _context.prev = 2;
42
- _context.next = 5;
44
+ isRequestLikeInitialSearch = !pageCursor && !searchString;
45
+ initialResponseData = initialData.current;
46
+ _context.prev = 4;
47
+ if (!(isRequestLikeInitialSearch && initialResponseData)) {
48
+ _context.next = 9;
49
+ break;
50
+ }
51
+ _context.t0 = initialResponseData;
52
+ _context.next = 12;
53
+ break;
54
+ case 9:
55
+ _context.next = 11;
43
56
  return getFieldValues({
44
57
  cloudId: cloudId,
45
58
  jql: '',
@@ -47,35 +60,44 @@ export var useFilterOptions = function useFilterOptions(_ref) {
47
60
  searchString: searchString,
48
61
  pageCursor: pageCursor
49
62
  });
50
- case 5:
51
- response = _context.sent;
63
+ case 11:
64
+ _context.t0 = _context.sent;
65
+ case 12:
66
+ response = _context.t0;
52
67
  if (!(response.errors && response.errors.length > 0)) {
53
- _context.next = 9;
68
+ _context.next = 16;
54
69
  break;
55
70
  }
56
71
  setStatus('rejected');
57
72
  return _context.abrupt("return");
58
- case 9:
73
+ case 16:
59
74
  isNewSearch = !pageCursor;
60
75
  if (isNewSearch) {
61
76
  setFilterOptions(mapFieldValuesToFilterOptions(response));
77
+ if (isRequestLikeInitialSearch) {
78
+ /**
79
+ * The initial dataset is used in couple of paths, eg: when a user searches and clears the search text.
80
+ * During these times, we dont want to fetch data again and again, hence a mini cache setup to store and provide the initial dataset
81
+ */
82
+ initialData.current = response;
83
+ }
62
84
  } else {
63
85
  setFilterOptions([].concat(_toConsumableArray(filterOptions), _toConsumableArray(mapFieldValuesToFilterOptions(response))));
64
86
  }
65
87
  setTotalCount(mapFieldValuesToTotalCount(response));
66
88
  setNextPageCursor(mapFieldValuesToPageCursor(response));
67
89
  setStatus('resolved');
68
- _context.next = 19;
90
+ _context.next = 26;
69
91
  break;
70
- case 16:
71
- _context.prev = 16;
72
- _context.t0 = _context["catch"](2);
92
+ case 23:
93
+ _context.prev = 23;
94
+ _context.t1 = _context["catch"](4);
73
95
  setStatus('rejected');
74
- case 19:
96
+ case 26:
75
97
  case "end":
76
98
  return _context.stop();
77
99
  }
78
- }, _callee, null, [[2, 16]]);
100
+ }, _callee, null, [[4, 23]]);
79
101
  })), [cloudId, filterOptions, filterType, getFieldValues]);
80
102
  return {
81
103
  filterOptions: filterOptions,
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import CloseIcon from '@atlaskit/icon/glyph/cross-circle';
3
+ import SearchIcon from '@atlaskit/icon/glyph/search';
4
+ import { Box, xcss } from '@atlaskit/primitives';
5
+ import { components } from '@atlaskit/select';
6
+ var customDropdownIndicatorStyles = xcss({
7
+ display: 'flex',
8
+ cursor: 'pointer',
9
+ justifyContent: 'center',
10
+ width: "var(--ds-space-400, 32px)"
11
+ });
12
+ var CustomDropdownIndicator = function CustomDropdownIndicator(props) {
13
+ var selectProps = props.selectProps;
14
+ return /*#__PURE__*/React.createElement(components.DropdownIndicator, props, /*#__PURE__*/React.createElement(Box, {
15
+ xcss: customDropdownIndicatorStyles,
16
+ onClick: function onClick() {
17
+ if (selectProps.inputValue) {
18
+ selectProps.onInputChange && selectProps.onInputChange('', {
19
+ action: 'input-change',
20
+ prevInputValue: selectProps.inputValue
21
+ });
22
+ }
23
+ }
24
+ }, selectProps.inputValue ? /*#__PURE__*/React.createElement(CloseIcon, {
25
+ size: "small",
26
+ label: ""
27
+ }) : /*#__PURE__*/React.createElement(SearchIcon, {
28
+ size: "small",
29
+ label: ""
30
+ })));
31
+ };
32
+ export default CustomDropdownIndicator;
@@ -4,11 +4,13 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
4
4
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
5
5
  var _excluded = ["isOpen"];
6
6
  import _regeneratorRuntime from "@babel/runtime/regenerator";
7
- import React, { useCallback, useEffect, useRef, useState } from 'react';
7
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
8
+ import debounce from 'lodash/debounce';
8
9
  import { useIntl } from 'react-intl-next';
9
10
  import { CheckboxOption, PopupSelect } from '@atlaskit/select';
10
11
  import { useFilterOptions } from '../../hooks/useFilterOptions';
11
12
  import CustomControl from './control';
13
+ import CustomDropdownIndicator from './dropdownIndicator';
12
14
  import PopupFooter from './footer';
13
15
  import formatOptionLabel from './formatOptionLabel';
14
16
  import { asyncPopupSelectMessages } from './messages';
@@ -17,12 +19,15 @@ import PopupTrigger from './trigger';
17
19
  var noFilterOptions = function noFilterOptions() {
18
20
  return true;
19
21
  };
22
+ var SEARCH_DEBOUNCE_MS = 350;
20
23
  var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
21
24
  var filterType = _ref.filterType,
22
25
  cloudId = _ref.cloudId,
23
26
  selection = _ref.selection,
24
27
  _ref$onSelectionChang = _ref.onSelectionChange,
25
- onSelectionChange = _ref$onSelectionChang === void 0 ? function () {} : _ref$onSelectionChang;
28
+ onSelectionChange = _ref$onSelectionChang === void 0 ? function () {} : _ref$onSelectionChang,
29
+ _ref$isDisabled = _ref.isDisabled,
30
+ isDisabled = _ref$isDisabled === void 0 ? false : _ref$isDisabled;
26
31
  var _useIntl = useIntl(),
27
32
  formatMessage = _useIntl.formatMessage;
28
33
  var pickerRef = useRef(null);
@@ -42,30 +47,49 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
42
47
  fetchFilterOptions = _useFilterOptions.fetchFilterOptions,
43
48
  totalCount = _useFilterOptions.totalCount,
44
49
  status = _useFilterOptions.status;
45
- var handleInputChange = useCallback(function (searchString, actionMeta) {
46
- if (actionMeta.action === 'input-change' && searchString !== searchTerm) {
47
- setSearchTerm(searchString);
48
- }
49
- }, [searchTerm]);
50
+ var handleDebouncedFetchFilterOptions = useMemo(function () {
51
+ return debounce(fetchFilterOptions, SEARCH_DEBOUNCE_MS);
52
+ }, [fetchFilterOptions]);
53
+ var handleInputChange = useCallback( /*#__PURE__*/function () {
54
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(newSearchTerm, actionMeta) {
55
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
56
+ while (1) switch (_context.prev = _context.next) {
57
+ case 0:
58
+ if (actionMeta.action === 'input-change' && newSearchTerm !== searchTerm) {
59
+ setSearchTerm(newSearchTerm);
60
+ handleDebouncedFetchFilterOptions({
61
+ searchString: newSearchTerm
62
+ });
63
+ }
64
+ case 1:
65
+ case "end":
66
+ return _context.stop();
67
+ }
68
+ }, _callee);
69
+ }));
70
+ return function (_x, _x2) {
71
+ return _ref2.apply(this, arguments);
72
+ };
73
+ }(), [handleDebouncedFetchFilterOptions, searchTerm]);
50
74
  var handleOptionSelection = function handleOptionSelection(newValue) {
51
75
  setSelectedOptions(newValue);
52
76
  onSelectionChange(newValue);
53
77
  };
54
- var handleOpenPopup = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
55
- return _regeneratorRuntime.wrap(function _callee$(_context) {
56
- while (1) switch (_context.prev = _context.next) {
78
+ var handleOpenPopup = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
79
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
80
+ while (1) switch (_context2.prev = _context2.next) {
57
81
  case 0:
58
82
  if (!(status === 'empty')) {
59
- _context.next = 3;
83
+ _context2.next = 3;
60
84
  break;
61
85
  }
62
- _context.next = 3;
86
+ _context2.next = 3;
63
87
  return fetchFilterOptions();
64
88
  case 3:
65
89
  case "end":
66
- return _context.stop();
90
+ return _context2.stop();
67
91
  }
68
- }, _callee);
92
+ }, _callee2);
69
93
  })), [fetchFilterOptions, status]);
70
94
  useEffect(function () {
71
95
  if (status === 'resolved') {
@@ -75,6 +99,9 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
75
99
  }
76
100
  }, [status]);
77
101
  var isLoading = status === 'loading' || status === 'empty';
102
+ var shouldShowFooter = status === 'resolved' && filterOptions.length > 0;
103
+ var options = isLoading ? [] : filterOptions; // if not set to [], then on loading, no loading UI will be shown
104
+
78
105
  return /*#__PURE__*/React.createElement(PopupSelect, {
79
106
  isMulti: true,
80
107
  maxMenuWidth: 300,
@@ -96,24 +123,28 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
96
123
  components: {
97
124
  /* @ts-expect-error - This component has stricter OptionType, hence a temp setup untill its made generic */
98
125
  Option: CheckboxOption,
99
- Control: CustomControl
126
+ Control: CustomControl,
127
+ LoadingIndicator: undefined,
128
+ // disables the three ... indicator in the searchbox when picker is loading
129
+ DropdownIndicator: CustomDropdownIndicator
100
130
  },
101
- options: filterOptions,
131
+ options: options,
102
132
  value: selectedOptions,
103
133
  filterOption: noFilterOptions,
104
134
  formatOptionLabel: formatOptionLabel,
105
135
  onChange: handleOptionSelection,
106
136
  onInputChange: handleInputChange,
107
- target: function target(_ref3) {
108
- var isOpen = _ref3.isOpen,
109
- triggerProps = _objectWithoutProperties(_ref3, _excluded);
137
+ target: function target(_ref4) {
138
+ var isOpen = _ref4.isOpen,
139
+ triggerProps = _objectWithoutProperties(_ref4, _excluded);
110
140
  return /*#__PURE__*/React.createElement(PopupTrigger, _extends({}, triggerProps, {
111
141
  filterType: filterType,
112
142
  isSelected: isOpen,
113
- onClick: handleOpenPopup
143
+ onClick: handleOpenPopup,
144
+ isDisabled: isDisabled
114
145
  }));
115
146
  },
116
- footer: /*#__PURE__*/React.createElement(PopupFooter, {
147
+ footer: shouldShowFooter && /*#__PURE__*/React.createElement(PopupFooter, {
117
148
  currentDisplayCount: filterOptions.length,
118
149
  totalCount: totalCount
119
150
  })
@@ -6,11 +6,13 @@ import { asyncPopupSelectMessages } from './messages';
6
6
  var PopupTrigger = /*#__PURE__*/forwardRef(function (_ref, ref) {
7
7
  var filterType = _ref.filterType,
8
8
  isSelected = _ref.isSelected,
9
+ isDisabled = _ref.isDisabled,
9
10
  onClick = _ref.onClick;
10
11
  return /*#__PURE__*/React.createElement(Button, {
11
12
  ref: ref,
12
13
  appearance: "default",
13
14
  isSelected: isSelected,
15
+ isDisabled: isDisabled,
14
16
  onClick: onClick,
15
17
  testId: "jlol-basic-filter-".concat(filterType, "-trigger"),
16
18
  iconAfter: /*#__PURE__*/React.createElement(ChevronDownIcon, {
@@ -25,6 +25,7 @@ var BasicFilterContainer = function BasicFilterContainer(_ref) {
25
25
  filterType: filter,
26
26
  key: filter,
27
27
  selection: selection,
28
+ isDisabled: !cloudId,
28
29
  onSelectionChange: handleSelectionChange
29
30
  });
30
31
  }));
@@ -0,0 +1,86 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { CLAUSE_TYPE_COMPOUND, CLAUSE_TYPE_TERMINAL, OPERAND_TYPE_VALUE } from '@atlaskit/jql-ast';
3
+ import { fuzzyCharacter } from '../../jira-search-container/buildJQL';
4
+ var removeFuzzyCharacter = function removeFuzzyCharacter(value) {
5
+ if (value !== null && value !== void 0 && value.endsWith(fuzzyCharacter)) {
6
+ return value.slice(0, -1);
7
+ }
8
+ return value;
9
+ };
10
+ var getValueFromTerminalClause = function getValueFromTerminalClause(clause) {
11
+ var operand = clause.operand;
12
+ return operand !== undefined && operand.operandType === OPERAND_TYPE_VALUE && removeFuzzyCharacter(operand.value) || undefined;
13
+ };
14
+ var areClauseFieldValuesEqual = function areClauseFieldValuesEqual(clauseA, clauseB, clauseC) {
15
+ var valueA = clauseA && getValueFromTerminalClause(clauseA);
16
+ var valueB = clauseB && getValueFromTerminalClause(clauseB);
17
+ var valueC = clauseC && getValueFromTerminalClause(clauseC);
18
+ var values = [valueA, valueB, valueC].filter(Boolean);
19
+
20
+ // checks if valid fields, text, summary and key have the same value, if not, its a complex query and cannnot be recreated in basic mode
21
+ return values.length > 1 && values.every(function (value) {
22
+ return value === values[0];
23
+ });
24
+ };
25
+ var areClauseFieldKeysAllowed = function areClauseFieldKeysAllowed(clauseA, clauseB, clauseC) {
26
+ var fieldA = clauseA.field.value;
27
+ var fieldB = clauseB.field.value;
28
+ var fieldC = clauseC === null || clauseC === void 0 ? void 0 : clauseC.field.value; // clauseC only if jql with 3 OR clauses, 'text ~ "EDM-6023*" or summary ~ "EDM-6023*" or key = EDM-6023 ORDER BY created DESC',
29
+
30
+ return [fieldA, fieldB, fieldC].filter(Boolean).every(function (field) {
31
+ return ['summary', 'text', 'key'].includes(field);
32
+ });
33
+ };
34
+ var doesCompoundClauseContainAllTerminalClauses = function doesCompoundClauseContainAllTerminalClauses(clauses) {
35
+ return clauses.every(function (clauses) {
36
+ return clauses.clauseType === CLAUSE_TYPE_TERMINAL;
37
+ });
38
+ };
39
+ export var isClauseTooComplex = function isClauseTooComplex(clauses, key) {
40
+ if (key === 'text') {
41
+ var _clauses = _slicedToArray(clauses, 1),
42
+ clause = _clauses[0];
43
+ if (clause.clauseType === CLAUSE_TYPE_COMPOUND) {
44
+ var textClauses = clause.clauses;
45
+
46
+ /**
47
+ * valid: text ~ "test*" or summary ~ "test*" ORDER BY created DESC
48
+ * valid: text ~ "EDM-6023*" or summary ~ "EDM-6023*" or key = EDM-6023 ORDER BY created DESC
49
+ * invalid: assignee = "me" or text ~ "EDM-6023*" or summary ~ "EDM-6023*" or key = EDM-6023 ORDER BY created DESC
50
+ */
51
+ if (textClauses.length !== 2 && textClauses.length !== 3) {
52
+ return true;
53
+ }
54
+
55
+ /**
56
+ * valid: text ~ "test*" or summary ~ "test*"
57
+ * invalid: text ~ "test" or (summary ~ "test" or key = "test")
58
+ */
59
+ if (!doesCompoundClauseContainAllTerminalClauses(textClauses)) {
60
+ return true;
61
+ }
62
+ var _textClauses = _slicedToArray(textClauses, 3),
63
+ clauseA = _textClauses[0],
64
+ clauseB = _textClauses[1],
65
+ clauseC = _textClauses[2];
66
+
67
+ /**
68
+ * valid: text ~ "EDM-6023*" or summary ~ "EDM-6023*" or key = EDM-6023 ORDER BY created DESC
69
+ * invalid: text ~ "EDM-6023*" or summary ~ "anotherValue" ORDER BY created DESC
70
+ * invalid: text ~ "EDM-6023*" or text ~ "anotherValue" ORDER BY created DESC
71
+ */
72
+ if (!areClauseFieldValuesEqual(clauseA, clauseB, clauseC)) {
73
+ return true;
74
+ }
75
+
76
+ /**
77
+ * valid: text ~ "EDM-6023*" ORDER BY created DESC
78
+ * invalid: resolution = 40134 ORDER BY created DESC
79
+ */
80
+ if (!areClauseFieldKeysAllowed(clauseA, clauseB, clauseC)) {
81
+ return true;
82
+ }
83
+ }
84
+ }
85
+ return clauses.length > 1;
86
+ };
@@ -0,0 +1,140 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ import _createClass from "@babel/runtime/helpers/createClass";
5
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
6
+ import _inherits from "@babel/runtime/helpers/inherits";
7
+ import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
8
+ import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
9
+ import _wrapNativeSuper from "@babel/runtime/helpers/wrapNativeSuper";
10
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
11
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
12
+ import mergeWith from 'lodash/mergeWith';
13
+ import { AbstractJastVisitor, COMPOUND_OPERATOR_AND, COMPOUND_OPERATOR_OR, JastBuilder, OPERATOR_EQUALS, OPERATOR_GT_EQUALS, OPERATOR_IN, OPERATOR_LIKE } from '@atlaskit/jql-ast';
14
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
15
+ import { ALLOWED_ORDER_BY_KEYS } from '../../jira-search-container';
16
+ import { isClauseTooComplex } from './isClauseTooComplex';
17
+ import { isValidJql } from './index';
18
+
19
+ // Map of field keys to their respective clauses in the Jast
20
+
21
+ var allowedFields = [
22
+ // basic filter fields
23
+ 'assignee', 'issuetype', 'project', 'status',
24
+ // search input fields
25
+ 'text', 'summary', 'key',
26
+ // orderby field
27
+ 'created'];
28
+ var fallbackOperators = [OPERATOR_IN];
29
+ var fieldSpecificOperators = {
30
+ text: [OPERATOR_LIKE, OPERATOR_EQUALS],
31
+ summary: [OPERATOR_LIKE, OPERATOR_EQUALS],
32
+ key: [OPERATOR_EQUALS],
33
+ created: [OPERATOR_GT_EQUALS],
34
+ project: [OPERATOR_IN, OPERATOR_EQUALS],
35
+ issuetype: [OPERATOR_IN, OPERATOR_EQUALS],
36
+ status: [OPERATOR_IN, OPERATOR_EQUALS],
37
+ assignee: [OPERATOR_IN, OPERATOR_EQUALS]
38
+ };
39
+ var JqlClauseCollectingVisitorError = /*#__PURE__*/function (_Error) {
40
+ _inherits(JqlClauseCollectingVisitorError, _Error);
41
+ var _super = _createSuper(JqlClauseCollectingVisitorError);
42
+ function JqlClauseCollectingVisitorError() {
43
+ _classCallCheck(this, JqlClauseCollectingVisitorError);
44
+ return _super.apply(this, arguments);
45
+ }
46
+ return _createClass(JqlClauseCollectingVisitorError);
47
+ }( /*#__PURE__*/_wrapNativeSuper(Error));
48
+ /**
49
+ * Rather than having to navigate the entire tree structure ourself, we extend AbstractJastVisitor
50
+ * class and implement visitor functions for node types that we wish to process.
51
+ * A list of available visitor can be viewed in packages/jql/jql-ast/src/types/api/jast-visitor.ts
52
+ * more info - https://atlaskit.atlassian.com/packages/jql/jql-ast/docs/traversing-the-ast
53
+ * */
54
+ var JqlClauseCollectingVisitor = /*#__PURE__*/function (_AbstractJastVisitor) {
55
+ _inherits(JqlClauseCollectingVisitor, _AbstractJastVisitor);
56
+ var _super2 = _createSuper(JqlClauseCollectingVisitor);
57
+ function JqlClauseCollectingVisitor() {
58
+ var _this;
59
+ _classCallCheck(this, JqlClauseCollectingVisitor);
60
+ _this = _super2.call(this);
61
+ _defineProperty(_assertThisInitialized(_this), "visitNotClause", function () {
62
+ throw new JqlClauseCollectingVisitorError('Visited an unsupported node while traversing the AST');
63
+ });
64
+ _defineProperty(_assertThisInitialized(_this), "visitOrderByField", function (orderByField) {
65
+ var _orderByField$field$v;
66
+ var fieldValue = (_orderByField$field$v = orderByField.field.value) === null || _orderByField$field$v === void 0 ? void 0 : _orderByField$field$v.toLowerCase();
67
+ if (fieldValue && !ALLOWED_ORDER_BY_KEYS.includes(fieldValue)) {
68
+ throw new JqlClauseCollectingVisitorError("query with order by field '".concat(fieldValue, "' is not supported"));
69
+ }
70
+ return {};
71
+ });
72
+ _defineProperty(_assertThisInitialized(_this), "visitCompoundClause", function (compoundClause) {
73
+ var clauseMap = {};
74
+ var operator = compoundClause.operator.value;
75
+ if (operator === COMPOUND_OPERATOR_AND) {
76
+ return compoundClause.clauses.reduce(function (result, clause) {
77
+ return _this.aggregateResult(clause.accept(_assertThisInitialized(_this)), result);
78
+ }, clauseMap);
79
+ }
80
+ if (operator === COMPOUND_OPERATOR_OR) {
81
+ // this is delt with in isClauseTooComplex
82
+ return _this.aggregateResult({
83
+ text: [compoundClause]
84
+ }, clauseMap);
85
+ }
86
+ throw new JqlClauseCollectingVisitorError("Compound clauses using the operator '".concat(operator, "' is not supported"));
87
+ });
88
+ _defineProperty(_assertThisInitialized(_this), "visitTerminalClause", function (terminalClause) {
89
+ var _terminalClause$opera;
90
+ var fieldName = terminalClause.field.value.toLowerCase();
91
+ if (!allowedFields.includes(fieldName)) {
92
+ throw new JqlClauseCollectingVisitorError("Field with name '".concat(fieldName, "' of type ").concat(terminalClause.clauseType, " is not supported"));
93
+ }
94
+ var operator = (_terminalClause$opera = terminalClause.operator) === null || _terminalClause$opera === void 0 ? void 0 : _terminalClause$opera.value;
95
+ var allowedOperators = fieldSpecificOperators[fieldName] || fallbackOperators;
96
+ if (operator && !allowedOperators.includes(operator.toLowerCase())) {
97
+ throw new JqlClauseCollectingVisitorError("Field with name '".concat(fieldName, "' using operator ").concat(operator, " is not supported"));
98
+ }
99
+ return _defineProperty({}, terminalClause.field.value.toLowerCase(), [terminalClause]);
100
+ });
101
+ return _this;
102
+ }
103
+ _createClass(JqlClauseCollectingVisitor, [{
104
+ key: "aggregateResult",
105
+ value: function aggregateResult(aggregate, nextResult) {
106
+ return mergeWith(aggregate, nextResult, function (destValue, srcValue) {
107
+ return srcValue.concat(destValue !== null && destValue !== void 0 ? destValue : []);
108
+ });
109
+ }
110
+ }, {
111
+ key: "defaultResult",
112
+ value: function defaultResult() {
113
+ return {};
114
+ }
115
+ }]);
116
+ return JqlClauseCollectingVisitor;
117
+ }(AbstractJastVisitor);
118
+ export var isQueryTooComplex = function isQueryTooComplex(jql) {
119
+ if (!getBooleanFF('platform.linking-platform.datasource.show-jlol-basic-filters') || !jql) {
120
+ return false;
121
+ }
122
+ if (!isValidJql(jql)) {
123
+ return true;
124
+ }
125
+ var jast = new JastBuilder().build(jql);
126
+ try {
127
+ var jqlClauseCollectingVisitor = new JqlClauseCollectingVisitor();
128
+ var clauseMap = jast.query ? jast.query.accept(jqlClauseCollectingVisitor) : {}; // jast.query is defined as void | Query, hence the fallback
129
+
130
+ var hasAnyKeyWithComplexClause = Object.entries(clauseMap).some(function (_ref2) {
131
+ var _ref3 = _slicedToArray(_ref2, 2),
132
+ key = _ref3[0],
133
+ clauses = _ref3[1];
134
+ return isClauseTooComplex(clauses, key);
135
+ });
136
+ return hasAnyKeyWithComplexClause;
137
+ } catch (error) {
138
+ return true;
139
+ }
140
+ };
@@ -2,6 +2,7 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
2
  import { COMPOUND_OPERATOR_AND, COMPOUND_OPERATOR_OR, creators, JastBuilder, OPERATOR_EQUALS, OPERATOR_GT_EQUALS, OPERATOR_IN, OPERATOR_LIKE, ORDER_BY_DIRECTION_ASC, ORDER_BY_DIRECTION_DESC, print } from '@atlaskit/jql-ast';
3
3
  var fuzzySearchRegExp = /^"(.+)"$/;
4
4
  var jiraIssueKeyRegExp = /[A-Z]+-\d+/;
5
+ export var fuzzyCharacter = '*';
5
6
  var constructTerminalClause = function constructTerminalClause(field, operator, value) {
6
7
  return creators.terminalClause(creators.field(field), creators.operator(operator), creators.valueOperand(value));
7
8
  };
@@ -23,7 +24,7 @@ export var buildJQL = function buildJQL(input) {
23
24
  return '';
24
25
  }
25
26
  if (trimmedRawSearch) {
26
- var fuzzy = !trimmedRawSearch.match(fuzzySearchRegExp) ? '*' : '';
27
+ var fuzzy = !trimmedRawSearch.match(fuzzySearchRegExp) ? fuzzyCharacter : '';
27
28
  var basicSearch = trimmedRawSearch.replace(/['"?*]+/g, '');
28
29
  var text = constructTerminalClause('text', OPERATOR_LIKE, "".concat(basicSearch).concat(fuzzy));
29
30
  var summary = constructTerminalClause('summary', OPERATOR_LIKE, "".concat(basicSearch).concat(fuzzy));