@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.
- package/CHANGELOG.md +17 -0
- package/dist/cjs/analytics/constants.js +1 -1
- package/dist/cjs/hooks/useDatasourceTableState.js +15 -10
- package/dist/cjs/hooks/useErrorLogger.js +48 -0
- package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +2 -2
- package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/index.js +7 -7
- package/dist/cjs/ui/jira-issues-modal/basic-filters/utils/transformers.js +3 -1
- package/dist/cjs/ui/jira-issues-modal/jira-search-container/index.js +34 -8
- package/dist/es2019/analytics/constants.js +1 -1
- package/dist/es2019/hooks/useDatasourceTableState.js +8 -2
- package/dist/es2019/hooks/useErrorLogger.js +44 -0
- package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +2 -2
- package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/index.js +7 -5
- package/dist/es2019/ui/jira-issues-modal/basic-filters/utils/transformers.js +3 -1
- package/dist/es2019/ui/jira-issues-modal/jira-search-container/index.js +30 -9
- package/dist/esm/analytics/constants.js +1 -1
- package/dist/esm/hooks/useDatasourceTableState.js +15 -10
- package/dist/esm/hooks/useErrorLogger.js +42 -0
- package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +2 -2
- package/dist/esm/ui/jira-issues-modal/basic-filters/ui/index.js +7 -7
- package/dist/esm/ui/jira-issues-modal/basic-filters/utils/transformers.js +3 -1
- package/dist/esm/ui/jira-issues-modal/jira-search-container/index.js +34 -8
- package/dist/types/analytics/generated/analytics.types.d.ts +9 -1
- package/dist/types/hooks/useErrorLogger.d.ts +4 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/hooks/useHydrateJqlQuery.d.ts +2 -4
- package/dist/types/ui/jira-issues-modal/basic-filters/types.d.ts +3 -0
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +1 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/index.d.ts +3 -1
- package/dist/types/ui/jira-issues-modal/basic-filters/utils/transformers.d.ts +2 -7
- package/dist/types/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +2 -4
- package/dist/types-ts4.5/analytics/generated/analytics.types.d.ts +9 -1
- package/dist/types-ts4.5/hooks/useErrorLogger.d.ts +4 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/hooks/useHydrateJqlQuery.d.ts +2 -4
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/types.d.ts +3 -0
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts +1 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/index.d.ts +3 -1
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/utils/transformers.d.ts +2 -7
- package/dist/types-ts4.5/ui/jira-issues-modal/jira-search-container/buildJQL.d.ts +2 -4
- 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.
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 (
|
|
36
|
-
var updatedSelection = _objectSpread(_objectSpread({}, selection), {}, (0, _defineProperty2.default)({},
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
|
74
|
-
|
|
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,
|
|
@@ -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((
|
|
20
|
+
const handleSelectionChange = useCallback((filterType, options) => {
|
|
20
21
|
const updatedSelection = {
|
|
21
22
|
...selection,
|
|
22
|
-
[
|
|
23
|
+
[filterType]: options
|
|
23
24
|
};
|
|
24
25
|
setSelection(updatedSelection);
|
|
25
|
-
|
|
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:
|
|
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
|
|
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,
|
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 (
|
|
26
|
-
var updatedSelection = _objectSpread(_objectSpread({}, selection), {}, _defineProperty({},
|
|
26
|
+
var handleSelectionChange = useCallback(function (filterType, options) {
|
|
27
|
+
var updatedSelection = _objectSpread(_objectSpread({}, selection), {}, _defineProperty({}, filterType, options));
|
|
27
28
|
setSelection(updatedSelection);
|
|
28
|
-
|
|
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:
|
|
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
|
|
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
|
|
63
|
-
|
|
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::
|
|
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;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
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?: (
|
|
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 {
|
|
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::
|
|
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;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
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";
|
package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface AsyncPopupSelectProps {
|
|
|
4
4
|
filterType: BasicFilterFieldType;
|
|
5
5
|
cloudId: string;
|
|
6
6
|
selection: SelectOption[];
|
|
7
|
-
onSelectionChange?: (
|
|
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 {
|
|
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.
|
|
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
|
+
"@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.
|
|
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
|
}
|