@atlaskit/link-datasource 1.16.5 → 1.17.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 +19 -0
- package/dist/cjs/analytics/constants.js +1 -1
- package/dist/cjs/hooks/useAssetsClient.js +7 -4
- package/dist/cjs/hooks/useDatasourceTableState.js +83 -52
- package/dist/cjs/hooks/useValidateAqlText.js +5 -2
- package/dist/cjs/services/cmdbService.js +50 -35
- package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +58 -15
- package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.js +26 -3
- package/dist/cjs/ui/jira-issues-modal/basic-filters/ui/index.js +6 -3
- package/dist/es2019/analytics/constants.js +1 -1
- package/dist/es2019/hooks/useAssetsClient.js +8 -4
- package/dist/es2019/hooks/useDatasourceTableState.js +40 -12
- package/dist/es2019/hooks/useValidateAqlText.js +6 -2
- package/dist/es2019/services/cmdbService.js +27 -12
- package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +41 -16
- package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.js +23 -3
- package/dist/es2019/ui/jira-issues-modal/basic-filters/ui/index.js +5 -3
- package/dist/esm/analytics/constants.js +1 -1
- package/dist/esm/hooks/useAssetsClient.js +7 -4
- package/dist/esm/hooks/useDatasourceTableState.js +83 -52
- package/dist/esm/hooks/useValidateAqlText.js +5 -2
- package/dist/esm/services/cmdbService.js +50 -35
- package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/index.js +59 -16
- package/dist/esm/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.js +26 -3
- package/dist/esm/ui/jira-issues-modal/basic-filters/ui/index.js +7 -4
- package/dist/types/analytics/generated/analytics.types.d.ts +41 -1
- package/dist/types/services/cmdbService.d.ts +8 -4
- package/dist/types/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.d.ts +2 -1
- package/dist/types-ts4.5/analytics/generated/analytics.types.d.ts +41 -1
- package/dist/types-ts4.5/services/cmdbService.d.ts +8 -4
- package/dist/types-ts4.5/ui/jira-issues-modal/basic-filters/ui/async-popup-select/trigger.d.ts +2 -1
- package/package.json +5 -4
|
@@ -9,6 +9,7 @@ exports.default = exports.SEARCH_DEBOUNCE_MS = void 0;
|
|
|
9
9
|
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
10
10
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
11
11
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
12
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
12
13
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
13
14
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
14
15
|
var _react = _interopRequireWildcard(require("react"));
|
|
@@ -41,7 +42,6 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
|
|
|
41
42
|
isDisabled = _ref$isDisabled === void 0 ? false : _ref$isDisabled;
|
|
42
43
|
var _useIntl = (0, _reactIntlNext.useIntl)(),
|
|
43
44
|
formatMessage = _useIntl.formatMessage;
|
|
44
|
-
var pickerRef = (0, _react.useRef)(null);
|
|
45
45
|
var _useState = (0, _react.useState)(''),
|
|
46
46
|
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
47
47
|
searchTerm = _useState2[0],
|
|
@@ -50,6 +50,10 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
|
|
|
50
50
|
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
|
|
51
51
|
selectedOptions = _useState4[0],
|
|
52
52
|
setSelectedOptions = _useState4[1];
|
|
53
|
+
var _useState5 = (0, _react.useState)(selectedOptions),
|
|
54
|
+
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
|
|
55
|
+
sortedOptions = _useState6[0],
|
|
56
|
+
setSortedOptions = _useState6[1];
|
|
53
57
|
var _useFilterOptions = (0, _useFilterOptions2.useFilterOptions)({
|
|
54
58
|
filterType: filterType,
|
|
55
59
|
cloudId: cloudId
|
|
@@ -90,14 +94,46 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
|
|
|
90
94
|
setSelectedOptions(newValue);
|
|
91
95
|
onSelectionChange(newValue);
|
|
92
96
|
};
|
|
93
|
-
var
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
var sortOptionsOnPopupOpen = (0, _react.useCallback)(function () {
|
|
98
|
+
if (selectedOptions.length === 0) {
|
|
99
|
+
setSortedOptions(filterOptions);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
var nonSelectedOptions = filterOptions.filter(function (option) {
|
|
103
|
+
return !selectedOptions.find(function (selectedOption) {
|
|
104
|
+
return selectedOption.value === option.value;
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
var newOptions = [].concat((0, _toConsumableArray2.default)(selectedOptions), (0, _toConsumableArray2.default)(nonSelectedOptions));
|
|
108
|
+
setSortedOptions(newOptions);
|
|
109
|
+
}, [selectedOptions, filterOptions]);
|
|
110
|
+
var sortOptionsOnResolve = (0, _react.useCallback)(function () {
|
|
111
|
+
var newOptions = filterOptions.filter(function (option) {
|
|
112
|
+
return !sortedOptions.find(function (sortedOption) {
|
|
113
|
+
return sortedOption.value === option.value;
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
var shouldSetSortOptions = false;
|
|
117
|
+
if (sortedOptions.length !== filterOptions.length) {
|
|
118
|
+
shouldSetSortOptions = true;
|
|
119
|
+
} else {
|
|
120
|
+
sortedOptions.forEach(function (sortedOption) {
|
|
121
|
+
if (!filterOptions.some(function (filterOption) {
|
|
122
|
+
return filterOption.value === sortedOption.value;
|
|
123
|
+
})) {
|
|
124
|
+
shouldSetSortOptions = true;
|
|
125
|
+
}
|
|
98
126
|
});
|
|
99
127
|
}
|
|
100
|
-
|
|
128
|
+
if (shouldSetSortOptions) {
|
|
129
|
+
var sortedOptionsFiltered = sortedOptions.filter(function (sortedOption) {
|
|
130
|
+
return filterOptions.some(function (filterOption) {
|
|
131
|
+
return filterOption.value === sortedOption.value;
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
setSortedOptions([].concat((0, _toConsumableArray2.default)(sortedOptionsFiltered), (0, _toConsumableArray2.default)(newOptions)));
|
|
135
|
+
}
|
|
136
|
+
}, [filterOptions, sortedOptions]);
|
|
101
137
|
var handleShowMore = (0, _react.useCallback)(function () {
|
|
102
138
|
if (pageCursor) {
|
|
103
139
|
fetchFilterOptions({
|
|
@@ -106,28 +142,34 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
|
|
|
106
142
|
});
|
|
107
143
|
}
|
|
108
144
|
}, [fetchFilterOptions, pageCursor, searchTerm]);
|
|
145
|
+
var handleOpenPopup = (0, _react.useCallback)(function () {
|
|
146
|
+
if (status === 'empty' || status === 'rejected') {
|
|
147
|
+
// if user searches and gets status as rejected, we want the dropdown to try load the request with searchString when the user reopens the dropdown
|
|
148
|
+
fetchFilterOptions({
|
|
149
|
+
searchString: searchTerm
|
|
150
|
+
});
|
|
151
|
+
} else if (status === 'resolved') {
|
|
152
|
+
sortOptionsOnPopupOpen();
|
|
153
|
+
}
|
|
154
|
+
}, [fetchFilterOptions, searchTerm, sortOptionsOnPopupOpen, status]);
|
|
109
155
|
(0, _react.useEffect)(function () {
|
|
110
156
|
if (status === 'resolved') {
|
|
111
|
-
|
|
112
|
-
// necessary to refocus the search input after the loading state
|
|
113
|
-
pickerRef === null || pickerRef === void 0 || (_pickerRef$current = pickerRef.current) === null || _pickerRef$current === void 0 || (_pickerRef$current = _pickerRef$current.selectRef) === null || _pickerRef$current === void 0 || (_pickerRef$current = _pickerRef$current.inputRef) === null || _pickerRef$current === void 0 || _pickerRef$current.focus();
|
|
157
|
+
sortOptionsOnResolve();
|
|
114
158
|
}
|
|
115
|
-
}, [status]);
|
|
159
|
+
}, [sortOptionsOnResolve, status]);
|
|
116
160
|
var filterOptionsLength = filterOptions.length;
|
|
117
161
|
var isError = status === 'rejected';
|
|
118
162
|
var isLoading = status === 'loading' || status === 'empty';
|
|
119
163
|
var isLoadingMore = status === 'loadingMore';
|
|
120
164
|
var isEmpty = status === 'resolved' && filterOptionsLength === 0;
|
|
165
|
+
var popupSelectOptions = isLoading || isError ? [] : sortedOptions; // if not set to [], then on loading, no loading UI will be shown
|
|
121
166
|
var areAllResultsLoaded = filterOptions.length === totalCount;
|
|
122
167
|
var shouldShowFooter = (status === 'resolved' || isLoadingMore) && filterOptions.length > 0; // footer should not disappear when there is an inline spinner for loading more data
|
|
123
168
|
var shouldDisplayShowMoreButton = status === 'resolved' && !!pageCursor && !areAllResultsLoaded;
|
|
124
|
-
var options = isLoading || isError ? [] : filterOptions; // if not set to [], for eg: on loading, no loading UI will be shown
|
|
125
|
-
|
|
126
169
|
return /*#__PURE__*/_react.default.createElement(_select.PopupSelect, {
|
|
127
170
|
isMulti: true,
|
|
128
171
|
maxMenuWidth: 300,
|
|
129
172
|
minMenuWidth: 300,
|
|
130
|
-
ref: pickerRef,
|
|
131
173
|
testId: "jlol-basic-filter-popup-select",
|
|
132
174
|
inputId: "jlol-basic-filter-popup-select--input"
|
|
133
175
|
/*
|
|
@@ -163,7 +205,7 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
|
|
|
163
205
|
IndicatorSeparator: undefined // disables the | separator between search input and icon
|
|
164
206
|
},
|
|
165
207
|
|
|
166
|
-
options:
|
|
208
|
+
options: popupSelectOptions,
|
|
167
209
|
value: selectedOptions,
|
|
168
210
|
filterOption: noFilterOptions,
|
|
169
211
|
formatOptionLabel: _formatOptionLabel.default,
|
|
@@ -174,6 +216,7 @@ var AsyncPopupSelect = function AsyncPopupSelect(_ref) {
|
|
|
174
216
|
triggerProps = (0, _objectWithoutProperties2.default)(_ref3, _excluded);
|
|
175
217
|
return /*#__PURE__*/_react.default.createElement(_trigger.default, (0, _extends2.default)({}, triggerProps, {
|
|
176
218
|
filterType: filterType,
|
|
219
|
+
selectedOptions: selectedOptions,
|
|
177
220
|
isSelected: isOpen,
|
|
178
221
|
onClick: handleOpenPopup,
|
|
179
222
|
isDisabled: isDisabled
|
|
@@ -6,28 +6,51 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
8
|
exports.default = void 0;
|
|
9
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
10
|
var _react = _interopRequireWildcard(require("react"));
|
|
10
11
|
var _reactIntlNext = require("react-intl-next");
|
|
12
|
+
var _badge = _interopRequireDefault(require("@atlaskit/badge"));
|
|
11
13
|
var _standardButton = _interopRequireDefault(require("@atlaskit/button/standard-button"));
|
|
12
14
|
var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/glyph/chevron-down"));
|
|
15
|
+
var _primitives = require("@atlaskit/primitives");
|
|
13
16
|
var _messages = require("./messages");
|
|
14
17
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
15
18
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
19
|
+
var triggerButtonLabelStyles = (0, _primitives.xcss)({
|
|
20
|
+
textOverflow: 'ellipsis',
|
|
21
|
+
overflow: 'hidden',
|
|
22
|
+
maxWidth: '150px'
|
|
23
|
+
});
|
|
24
|
+
var badgeStyles = (0, _primitives.xcss)({
|
|
25
|
+
marginLeft: 'space.050'
|
|
26
|
+
});
|
|
16
27
|
var PopupTrigger = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
|
|
17
28
|
var filterType = _ref.filterType,
|
|
18
29
|
isSelected = _ref.isSelected,
|
|
19
30
|
isDisabled = _ref.isDisabled,
|
|
20
|
-
onClick = _ref.onClick
|
|
31
|
+
onClick = _ref.onClick,
|
|
32
|
+
selectedOptions = _ref.selectedOptions;
|
|
33
|
+
var _ref2 = selectedOptions || [],
|
|
34
|
+
_ref3 = (0, _slicedToArray2.default)(_ref2, 1),
|
|
35
|
+
firstOption = _ref3[0];
|
|
36
|
+
var hasOptions = selectedOptions && selectedOptions.length > 0;
|
|
21
37
|
return /*#__PURE__*/_react.default.createElement(_standardButton.default, {
|
|
22
38
|
ref: ref,
|
|
23
39
|
appearance: "default",
|
|
24
|
-
isSelected: isSelected,
|
|
40
|
+
isSelected: isSelected || hasOptions,
|
|
25
41
|
isDisabled: isDisabled,
|
|
26
42
|
onClick: onClick,
|
|
27
43
|
testId: "jlol-basic-filter-".concat(filterType, "-trigger"),
|
|
28
44
|
iconAfter: /*#__PURE__*/_react.default.createElement(_chevronDown.default, {
|
|
29
45
|
label: ""
|
|
30
46
|
})
|
|
31
|
-
}, /*#__PURE__*/_react.default.createElement(
|
|
47
|
+
}, /*#__PURE__*/_react.default.createElement(_primitives.Flex, null, /*#__PURE__*/_react.default.createElement(_primitives.Box, {
|
|
48
|
+
xcss: triggerButtonLabelStyles
|
|
49
|
+
}, /*#__PURE__*/_react.default.createElement(_reactIntlNext.FormattedMessage, _messages.asyncPopupSelectMessages["".concat(filterType, "Label")]), firstOption && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, ": ", firstOption.label)), selectedOptions && selectedOptions.length > 1 && /*#__PURE__*/_react.default.createElement(_primitives.Flex, {
|
|
50
|
+
xcss: badgeStyles,
|
|
51
|
+
alignItems: "center"
|
|
52
|
+
}, /*#__PURE__*/_react.default.createElement(_badge.default, {
|
|
53
|
+
appearance: "primary"
|
|
54
|
+
}, "+", selectedOptions.length - 1))));
|
|
32
55
|
});
|
|
33
56
|
var _default = exports.default = PopupTrigger;
|
|
@@ -21,14 +21,17 @@ var BasicFilterContainer = function BasicFilterContainer(_ref) {
|
|
|
21
21
|
var jql = _ref.jql,
|
|
22
22
|
cloudId = _ref.cloudId;
|
|
23
23
|
var _useState = (0, _react.useState)([]),
|
|
24
|
-
_useState2 = (0, _slicedToArray2.default)(_useState,
|
|
25
|
-
selection = _useState2[0]
|
|
24
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
25
|
+
selection = _useState2[0],
|
|
26
|
+
setSelection = _useState2[1];
|
|
26
27
|
(0, _react.useEffect)(function () {
|
|
27
28
|
if ((0, _utils.isValidJql)(jql)) {
|
|
28
29
|
// hydrate hook call goes in here
|
|
29
30
|
}
|
|
30
31
|
}, [jql]);
|
|
31
|
-
var handleSelectionChange = function
|
|
32
|
+
var handleSelectionChange = (0, _react.useCallback)(function (options) {
|
|
33
|
+
setSelection(options);
|
|
34
|
+
}, [setSelection]);
|
|
32
35
|
return /*#__PURE__*/_react.default.createElement(_primitives.Flex, {
|
|
33
36
|
xcss: basicFilterContainerStyles,
|
|
34
37
|
gap: "space.100",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useDatasourceAnalyticsEvents } from '../analytics';
|
|
2
3
|
import { fetchObjectSchema, fetchObjectSchemas, getWorkspaceId } from '../services/cmdbService';
|
|
3
4
|
const handleAssetsClientErrors = (errorSetter, error) => {
|
|
4
5
|
if (error instanceof Error) {
|
|
@@ -16,6 +17,9 @@ export const useAssetsClient = initialParameters => {
|
|
|
16
17
|
const [objectSchemas, setObjectSchemas] = useState();
|
|
17
18
|
const [totalObjectSchemas, setTotalObjectSchemas] = useState();
|
|
18
19
|
const [objectSchemasError, setObjectSchemasError] = useState();
|
|
20
|
+
const {
|
|
21
|
+
fireEvent
|
|
22
|
+
} = useDatasourceAnalyticsEvents();
|
|
19
23
|
|
|
20
24
|
/*
|
|
21
25
|
* We wrap this in nested try/catch blocks because we want to handle
|
|
@@ -27,19 +31,19 @@ export const useAssetsClient = initialParameters => {
|
|
|
27
31
|
setLoading(true);
|
|
28
32
|
setWorkspaceError(undefined);
|
|
29
33
|
try {
|
|
30
|
-
const workspaceId = await getWorkspaceId();
|
|
34
|
+
const workspaceId = await getWorkspaceId(fireEvent);
|
|
31
35
|
setWorkspaceId(workspaceId);
|
|
32
36
|
// Check schema from initial parameters still exists and fetch name/permissions for schema select
|
|
33
37
|
if (initialParameters !== null && initialParameters !== void 0 && initialParameters.schemaId) {
|
|
34
38
|
try {
|
|
35
|
-
const fetchedObjectSchema = await fetchObjectSchema(workspaceId, initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.schemaId);
|
|
39
|
+
const fetchedObjectSchema = await fetchObjectSchema(workspaceId, initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.schemaId, fireEvent);
|
|
36
40
|
setExistingObjectSchema(fetchedObjectSchema);
|
|
37
41
|
} catch (fetchObjectSchemaError) {
|
|
38
42
|
handleAssetsClientErrors(setExistingObjectSchemaError, fetchObjectSchemaError);
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
try {
|
|
42
|
-
const fetchedObjectSchemasResponse = await fetchObjectSchemas(workspaceId);
|
|
46
|
+
const fetchedObjectSchemasResponse = await fetchObjectSchemas(workspaceId, undefined, fireEvent);
|
|
43
47
|
setObjectSchemas(fetchedObjectSchemasResponse.values);
|
|
44
48
|
setTotalObjectSchemas(fetchedObjectSchemasResponse.total);
|
|
45
49
|
} catch (fetchObjectSchemasError) {
|
|
@@ -51,7 +55,7 @@ export const useAssetsClient = initialParameters => {
|
|
|
51
55
|
setLoading(false);
|
|
52
56
|
}
|
|
53
57
|
})();
|
|
54
|
-
}, [initialParameters]);
|
|
58
|
+
}, [initialParameters, fireEvent]);
|
|
55
59
|
return {
|
|
56
60
|
workspaceId,
|
|
57
61
|
workspaceError,
|
|
@@ -10,8 +10,13 @@ export const useDatasourceTableState = ({
|
|
|
10
10
|
const {
|
|
11
11
|
fireEvent
|
|
12
12
|
} = useDatasourceAnalyticsEvents();
|
|
13
|
+
const idFieldCount = 1;
|
|
14
|
+
const keyFieldCount = 1;
|
|
13
15
|
const [defaultVisibleColumnKeys, setDefaultVisibleColumnKeys] = useState([]);
|
|
14
16
|
const [lastRequestedFieldKeys, setLastRequestedFieldKeys] = useState([]);
|
|
17
|
+
const [fullSchema, setFullSchema] = useState({
|
|
18
|
+
properties: []
|
|
19
|
+
});
|
|
15
20
|
const [status, setStatus] = useState('empty');
|
|
16
21
|
const [responseItems, setResponseItems] = useState([]);
|
|
17
22
|
const [hasNextPage, setHasNextPage] = useState(true);
|
|
@@ -56,19 +61,38 @@ export const useDatasourceTableState = ({
|
|
|
56
61
|
setStatus('rejected');
|
|
57
62
|
}
|
|
58
63
|
}, [columns, datasourceId, getDatasourceDetails, parameters]);
|
|
59
|
-
const applySchemaProperties = useCallback(
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
const applySchemaProperties = useCallback((schema, fieldKeys) => {
|
|
65
|
+
let {
|
|
66
|
+
properties,
|
|
67
|
+
defaultProperties = []
|
|
68
|
+
} = schema;
|
|
69
|
+
let propertiesToBeUsed = properties;
|
|
70
|
+
const propertyKeysToBeUsed = Array.isArray(fieldKeys) && fieldKeys.length > 0 ? fieldKeys : defaultProperties;
|
|
71
|
+
if (fieldKeys.length > 0 || defaultProperties.length > 0) {
|
|
72
|
+
propertiesToBeUsed = properties.filter(property => {
|
|
73
|
+
return propertyKeysToBeUsed.includes(property.key);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/*Jira adds identifier fields like id and key to all data responses
|
|
78
|
+
Since defaultProperties already send back the keyField, we are accounting only
|
|
79
|
+
for the idField when we are using defaulProperties
|
|
80
|
+
*/
|
|
81
|
+
if (properties.length > fieldKeys.length + idFieldCount + keyFieldCount && properties.length > defaultProperties.length + idFieldCount) {
|
|
82
|
+
setFullSchema(schema);
|
|
83
|
+
}
|
|
84
|
+
if (!isEqual(columns, propertiesToBeUsed)) {
|
|
85
|
+
setColumns(propertiesToBeUsed);
|
|
62
86
|
}
|
|
63
|
-
const
|
|
87
|
+
const newProperties = propertiesToBeUsed.map(prop => prop.key);
|
|
64
88
|
|
|
65
89
|
// when loading for the first time, we will need to set default visible props as /data does not give you that info
|
|
66
90
|
// also, since we dont pass any fields, we will need to set this info as lastRequestedFieldKeys
|
|
67
|
-
if (!isEqual(defaultVisibleColumnKeys,
|
|
68
|
-
setDefaultVisibleColumnKeys(
|
|
91
|
+
if (!isEqual(defaultVisibleColumnKeys, newProperties)) {
|
|
92
|
+
setDefaultVisibleColumnKeys(newProperties);
|
|
69
93
|
}
|
|
70
|
-
if (!isEqual(lastRequestedFieldKeys,
|
|
71
|
-
setLastRequestedFieldKeys(
|
|
94
|
+
if (!isEqual(lastRequestedFieldKeys, newProperties)) {
|
|
95
|
+
setLastRequestedFieldKeys(newProperties);
|
|
72
96
|
}
|
|
73
97
|
}, [columns, defaultVisibleColumnKeys, lastRequestedFieldKeys]);
|
|
74
98
|
const onNextPage = useCallback(async (requestInfo = {}) => {
|
|
@@ -80,12 +104,13 @@ export const useDatasourceTableState = ({
|
|
|
80
104
|
shouldRequestFirstPage,
|
|
81
105
|
shouldForceRequest = false
|
|
82
106
|
} = requestInfo;
|
|
107
|
+
const isFullSchemaLoaded = fullSchema.properties.length > 0;
|
|
83
108
|
const datasourceDataRequest = {
|
|
84
109
|
parameters,
|
|
85
110
|
pageSize: DEFAULT_GET_DATASOURCE_DATA_PAGE_SIZE,
|
|
86
111
|
pageCursor: shouldRequestFirstPage ? undefined : nextCursor,
|
|
87
112
|
fields: fieldKeys,
|
|
88
|
-
includeSchema: isSchemaFromData
|
|
113
|
+
includeSchema: isFullSchemaLoaded ? false : isSchemaFromData
|
|
89
114
|
};
|
|
90
115
|
setStatus('loading');
|
|
91
116
|
try {
|
|
@@ -120,8 +145,8 @@ export const useDatasourceTableState = ({
|
|
|
120
145
|
if (fieldKeys.length > 0) {
|
|
121
146
|
setLastRequestedFieldKeys(fieldKeys);
|
|
122
147
|
}
|
|
123
|
-
if (isSchemaFromData && schema && items.length > 0) {
|
|
124
|
-
applySchemaProperties(schema
|
|
148
|
+
if ((isSchemaFromData && schema || fullSchema.properties.length > 0) && items.length > 0) {
|
|
149
|
+
applySchemaProperties(schema || fullSchema, fieldKeys);
|
|
125
150
|
}
|
|
126
151
|
const isUserLoadingNextPage = (responseItems === null || responseItems === void 0 ? void 0 : responseItems.length) !== 0 && !shouldRequestFirstPage;
|
|
127
152
|
if (isUserLoadingNextPage) {
|
|
@@ -141,7 +166,7 @@ export const useDatasourceTableState = ({
|
|
|
141
166
|
}
|
|
142
167
|
setStatus('rejected');
|
|
143
168
|
}
|
|
144
|
-
}, [parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent]);
|
|
169
|
+
}, [parameters, fieldKeys, nextCursor, getDatasourceData, datasourceId, responseItems === null || responseItems === void 0 ? void 0 : responseItems.length, applySchemaProperties, fireEvent, fullSchema]);
|
|
145
170
|
const reset = useCallback(options => {
|
|
146
171
|
setStatus('empty');
|
|
147
172
|
setResponseItems([]);
|
|
@@ -149,6 +174,9 @@ export const useDatasourceTableState = ({
|
|
|
149
174
|
setNextCursor(undefined);
|
|
150
175
|
setTotalCount(undefined);
|
|
151
176
|
setLastRequestedFieldKeys([]);
|
|
177
|
+
setFullSchema({
|
|
178
|
+
properties: []
|
|
179
|
+
});
|
|
152
180
|
setShouldForceRequest((options === null || options === void 0 ? void 0 : options.shouldForceRequest) || false);
|
|
153
181
|
if (options !== null && options !== void 0 && options.shouldResetColumns) {
|
|
154
182
|
setColumns([]);
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react';
|
|
2
|
+
import { useDatasourceAnalyticsEvents } from '../analytics';
|
|
2
3
|
import { validateAql } from '../services/cmdbService';
|
|
3
4
|
export const useValidateAqlText = workspaceId => {
|
|
4
5
|
const [loading, setLoading] = useState(false);
|
|
5
6
|
const [isValidAqlText, setIsValidAqlText] = useState(false);
|
|
6
7
|
const [error, setError] = useState();
|
|
8
|
+
const {
|
|
9
|
+
fireEvent
|
|
10
|
+
} = useDatasourceAnalyticsEvents();
|
|
7
11
|
const validateAqlText = useCallback(async aql => {
|
|
8
12
|
setLoading(true);
|
|
9
13
|
setError(undefined);
|
|
@@ -13,7 +17,7 @@ export const useValidateAqlText = workspaceId => {
|
|
|
13
17
|
var _validateAqlResponse$;
|
|
14
18
|
const validateAqlResponse = await validateAql(workspaceId, {
|
|
15
19
|
qlQuery: aql
|
|
16
|
-
});
|
|
20
|
+
}, fireEvent);
|
|
17
21
|
setIsValidAqlText(validateAqlResponse.isValid);
|
|
18
22
|
isValid = validateAqlResponse.isValid;
|
|
19
23
|
message = ((_validateAqlResponse$ = validateAqlResponse.errors) === null || _validateAqlResponse$ === void 0 ? void 0 : _validateAqlResponse$.iql) || null;
|
|
@@ -30,7 +34,7 @@ export const useValidateAqlText = workspaceId => {
|
|
|
30
34
|
isValid,
|
|
31
35
|
message
|
|
32
36
|
};
|
|
33
|
-
}, [workspaceId]);
|
|
37
|
+
}, [workspaceId, fireEvent]);
|
|
34
38
|
return {
|
|
35
39
|
isValidAqlText,
|
|
36
40
|
validateAqlText,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { request } from '@atlaskit/linking-common';
|
|
2
2
|
import { FetchError, getStatusCodeGroup, mapFetchErrors, PermissionError } from './cmdbService.utils';
|
|
3
|
-
export const getWorkspaceId = async
|
|
3
|
+
export const getWorkspaceId = async fireEvent => {
|
|
4
4
|
const url = '/rest/servicedesk/cmdb/latest/workspace';
|
|
5
5
|
try {
|
|
6
6
|
var _workspaceDetailsResp;
|
|
@@ -8,12 +8,15 @@ export const getWorkspaceId = async () => {
|
|
|
8
8
|
if (!((_workspaceDetailsResp = workspaceDetailsResponse.results) !== null && _workspaceDetailsResp !== void 0 && _workspaceDetailsResp.length)) {
|
|
9
9
|
throw new PermissionError('No workspace results found');
|
|
10
10
|
}
|
|
11
|
+
fireEvent && fireEvent('operational.getWorkspaceId.success', {});
|
|
11
12
|
return workspaceDetailsResponse.results[0].id;
|
|
12
13
|
} catch (err) {
|
|
13
14
|
let error = mapFetchErrors(err);
|
|
14
15
|
if (error instanceof FetchError) {
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
fireEvent && fireEvent('operational.getWorkspaceId.failed', {
|
|
17
|
+
statusCodeGroup: getStatusCodeGroup(error)
|
|
18
|
+
});
|
|
19
|
+
// Only 429 and5xx errors will be treated as FetchErrors otherwise PermissionError
|
|
17
20
|
if (getStatusCodeGroup(error) !== '5xx' && error.statusCode !== 429) {
|
|
18
21
|
error = new PermissionError('Failed to fetch workspace');
|
|
19
22
|
}
|
|
@@ -21,17 +24,21 @@ export const getWorkspaceId = async () => {
|
|
|
21
24
|
throw error;
|
|
22
25
|
}
|
|
23
26
|
};
|
|
24
|
-
export const validateAql = async (workspaceId, data) => {
|
|
27
|
+
export const validateAql = async (workspaceId, data, fireEvent) => {
|
|
25
28
|
const url = `/gateway/api/jsm/assets/workspace/${workspaceId}/v1/aql/validate`;
|
|
26
29
|
try {
|
|
27
|
-
|
|
30
|
+
const response = await request('post', url, {
|
|
28
31
|
qlQuery: data.qlQuery,
|
|
29
32
|
context: 'SMART_LINKS'
|
|
30
33
|
}, undefined, [200, 201, 202, 203, 204]);
|
|
34
|
+
fireEvent && fireEvent('operational.validateAql.success', {});
|
|
35
|
+
return response;
|
|
31
36
|
} catch (err) {
|
|
32
37
|
let error = mapFetchErrors(err);
|
|
33
38
|
if (error instanceof FetchError) {
|
|
34
|
-
|
|
39
|
+
fireEvent && fireEvent('operational.validateAql.failed', {
|
|
40
|
+
statusCodeGroup: getStatusCodeGroup(error)
|
|
41
|
+
});
|
|
35
42
|
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
36
43
|
error = new PermissionError('Failed to fetch object schemas');
|
|
37
44
|
}
|
|
@@ -39,14 +46,18 @@ export const validateAql = async (workspaceId, data) => {
|
|
|
39
46
|
throw error;
|
|
40
47
|
}
|
|
41
48
|
};
|
|
42
|
-
export const fetchObjectSchema = async (workspaceId, schemaId) => {
|
|
49
|
+
export const fetchObjectSchema = async (workspaceId, schemaId, fireEvent) => {
|
|
43
50
|
const url = `/gateway/api/jsm/assets/workspace/${workspaceId}/v1/objectschema/${schemaId}`;
|
|
44
51
|
try {
|
|
45
|
-
|
|
52
|
+
const response = await request('get', url, undefined, undefined, [200, 201, 202, 203, 204]);
|
|
53
|
+
fireEvent && fireEvent('operational.objectSchema.success', {});
|
|
54
|
+
return response;
|
|
46
55
|
} catch (err) {
|
|
47
56
|
let error = mapFetchErrors(err);
|
|
48
57
|
if (error instanceof FetchError) {
|
|
49
|
-
|
|
58
|
+
fireEvent && fireEvent('operational.objectSchema.failed', {
|
|
59
|
+
statusCodeGroup: getStatusCodeGroup(error)
|
|
60
|
+
});
|
|
50
61
|
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
51
62
|
error = new PermissionError('Failed to fetch object schemas');
|
|
52
63
|
}
|
|
@@ -54,18 +65,22 @@ export const fetchObjectSchema = async (workspaceId, schemaId) => {
|
|
|
54
65
|
throw error;
|
|
55
66
|
}
|
|
56
67
|
};
|
|
57
|
-
export const fetchObjectSchemas = async (workspaceId, query) => {
|
|
68
|
+
export const fetchObjectSchemas = async (workspaceId, query, fireEvent) => {
|
|
58
69
|
const queryParams = new URLSearchParams();
|
|
59
70
|
queryParams.set('maxResults', '20');
|
|
60
71
|
queryParams.set('includeCounts', 'false');
|
|
61
72
|
query && queryParams.set('query', query);
|
|
62
73
|
const url = `/gateway/api/jsm/assets/workspace/${workspaceId}/v1/objectschema/list?${queryParams}`;
|
|
63
74
|
try {
|
|
64
|
-
|
|
75
|
+
const response = await request('get', url, undefined, undefined, [200, 201, 202, 203, 204]);
|
|
76
|
+
fireEvent && fireEvent('operational.objectSchemas.success', {});
|
|
77
|
+
return response;
|
|
65
78
|
} catch (err) {
|
|
66
79
|
let error = mapFetchErrors(err);
|
|
67
80
|
if (error instanceof FetchError) {
|
|
68
|
-
|
|
81
|
+
fireEvent && fireEvent('operational.objectSchemas.failed', {
|
|
82
|
+
statusCodeGroup: getStatusCodeGroup(error)
|
|
83
|
+
});
|
|
69
84
|
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
70
85
|
error = new PermissionError('Failed to fetch object schemas');
|
|
71
86
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
import React, { useCallback, useEffect,
|
|
2
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
3
3
|
import { useIntl } from 'react-intl-next';
|
|
4
4
|
import { useDebouncedCallback } from 'use-debounce';
|
|
5
5
|
import { CheckboxOption, PopupSelect } from '@atlaskit/select';
|
|
@@ -24,9 +24,9 @@ const AsyncPopupSelect = ({
|
|
|
24
24
|
const {
|
|
25
25
|
formatMessage
|
|
26
26
|
} = useIntl();
|
|
27
|
-
const pickerRef = useRef(null);
|
|
28
27
|
const [searchTerm, setSearchTerm] = useState('');
|
|
29
28
|
const [selectedOptions, setSelectedOptions] = useState(selection);
|
|
29
|
+
const [sortedOptions, setSortedOptions] = useState(selectedOptions);
|
|
30
30
|
const {
|
|
31
31
|
filterOptions,
|
|
32
32
|
fetchFilterOptions,
|
|
@@ -53,14 +53,32 @@ const AsyncPopupSelect = ({
|
|
|
53
53
|
setSelectedOptions(newValue);
|
|
54
54
|
onSelectionChange(newValue);
|
|
55
55
|
};
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
const sortOptionsOnPopupOpen = useCallback(() => {
|
|
57
|
+
if (selectedOptions.length === 0) {
|
|
58
|
+
setSortedOptions(filterOptions);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const nonSelectedOptions = filterOptions.filter(option => !selectedOptions.find(selectedOption => selectedOption.value === option.value));
|
|
62
|
+
const newOptions = [...selectedOptions, ...nonSelectedOptions];
|
|
63
|
+
setSortedOptions(newOptions);
|
|
64
|
+
}, [selectedOptions, filterOptions]);
|
|
65
|
+
const sortOptionsOnResolve = useCallback(() => {
|
|
66
|
+
const newOptions = filterOptions.filter(option => !sortedOptions.find(sortedOption => sortedOption.value === option.value));
|
|
67
|
+
let shouldSetSortOptions = false;
|
|
68
|
+
if (sortedOptions.length !== filterOptions.length) {
|
|
69
|
+
shouldSetSortOptions = true;
|
|
70
|
+
} else {
|
|
71
|
+
sortedOptions.forEach(sortedOption => {
|
|
72
|
+
if (!filterOptions.some(filterOption => filterOption.value === sortedOption.value)) {
|
|
73
|
+
shouldSetSortOptions = true;
|
|
74
|
+
}
|
|
61
75
|
});
|
|
62
76
|
}
|
|
63
|
-
|
|
77
|
+
if (shouldSetSortOptions) {
|
|
78
|
+
const sortedOptionsFiltered = sortedOptions.filter(sortedOption => filterOptions.some(filterOption => filterOption.value === sortedOption.value));
|
|
79
|
+
setSortedOptions([...sortedOptionsFiltered, ...newOptions]);
|
|
80
|
+
}
|
|
81
|
+
}, [filterOptions, sortedOptions]);
|
|
64
82
|
const handleShowMore = useCallback(() => {
|
|
65
83
|
if (pageCursor) {
|
|
66
84
|
fetchFilterOptions({
|
|
@@ -69,28 +87,34 @@ const AsyncPopupSelect = ({
|
|
|
69
87
|
});
|
|
70
88
|
}
|
|
71
89
|
}, [fetchFilterOptions, pageCursor, searchTerm]);
|
|
90
|
+
const handleOpenPopup = useCallback(() => {
|
|
91
|
+
if (status === 'empty' || status === 'rejected') {
|
|
92
|
+
// if user searches and gets status as rejected, we want the dropdown to try load the request with searchString when the user reopens the dropdown
|
|
93
|
+
fetchFilterOptions({
|
|
94
|
+
searchString: searchTerm
|
|
95
|
+
});
|
|
96
|
+
} else if (status === 'resolved') {
|
|
97
|
+
sortOptionsOnPopupOpen();
|
|
98
|
+
}
|
|
99
|
+
}, [fetchFilterOptions, searchTerm, sortOptionsOnPopupOpen, status]);
|
|
72
100
|
useEffect(() => {
|
|
73
101
|
if (status === 'resolved') {
|
|
74
|
-
|
|
75
|
-
// necessary to refocus the search input after the loading state
|
|
76
|
-
pickerRef === null || pickerRef === void 0 ? void 0 : (_pickerRef$current = pickerRef.current) === null || _pickerRef$current === void 0 ? void 0 : (_pickerRef$current$se = _pickerRef$current.selectRef) === null || _pickerRef$current$se === void 0 ? void 0 : (_pickerRef$current$se2 = _pickerRef$current$se.inputRef) === null || _pickerRef$current$se2 === void 0 ? void 0 : _pickerRef$current$se2.focus();
|
|
102
|
+
sortOptionsOnResolve();
|
|
77
103
|
}
|
|
78
|
-
}, [status]);
|
|
104
|
+
}, [sortOptionsOnResolve, status]);
|
|
79
105
|
const filterOptionsLength = filterOptions.length;
|
|
80
106
|
const isError = status === 'rejected';
|
|
81
107
|
const isLoading = status === 'loading' || status === 'empty';
|
|
82
108
|
const isLoadingMore = status === 'loadingMore';
|
|
83
109
|
const isEmpty = status === 'resolved' && filterOptionsLength === 0;
|
|
110
|
+
const popupSelectOptions = isLoading || isError ? [] : sortedOptions; // if not set to [], then on loading, no loading UI will be shown
|
|
84
111
|
const areAllResultsLoaded = filterOptions.length === totalCount;
|
|
85
112
|
const shouldShowFooter = (status === 'resolved' || isLoadingMore) && filterOptions.length > 0; // footer should not disappear when there is an inline spinner for loading more data
|
|
86
113
|
const shouldDisplayShowMoreButton = status === 'resolved' && !!pageCursor && !areAllResultsLoaded;
|
|
87
|
-
const options = isLoading || isError ? [] : filterOptions; // if not set to [], for eg: on loading, no loading UI will be shown
|
|
88
|
-
|
|
89
114
|
return /*#__PURE__*/React.createElement(PopupSelect, {
|
|
90
115
|
isMulti: true,
|
|
91
116
|
maxMenuWidth: 300,
|
|
92
117
|
minMenuWidth: 300,
|
|
93
|
-
ref: pickerRef,
|
|
94
118
|
testId: "jlol-basic-filter-popup-select",
|
|
95
119
|
inputId: "jlol-basic-filter-popup-select--input"
|
|
96
120
|
/*
|
|
@@ -124,7 +148,7 @@ const AsyncPopupSelect = ({
|
|
|
124
148
|
IndicatorSeparator: undefined // disables the | separator between search input and icon
|
|
125
149
|
},
|
|
126
150
|
|
|
127
|
-
options:
|
|
151
|
+
options: popupSelectOptions,
|
|
128
152
|
value: selectedOptions,
|
|
129
153
|
filterOption: noFilterOptions,
|
|
130
154
|
formatOptionLabel: formatOptionLabel,
|
|
@@ -135,6 +159,7 @@ const AsyncPopupSelect = ({
|
|
|
135
159
|
...triggerProps
|
|
136
160
|
}) => /*#__PURE__*/React.createElement(PopupTrigger, _extends({}, triggerProps, {
|
|
137
161
|
filterType: filterType,
|
|
162
|
+
selectedOptions: selectedOptions,
|
|
138
163
|
isSelected: isOpen,
|
|
139
164
|
onClick: handleOpenPopup,
|
|
140
165
|
isDisabled: isDisabled
|