@atlaskit/link-datasource 3.12.0 → 3.13.0
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 +24 -0
- package/dist/cjs/hooks/useLoadOptions.js +100 -0
- package/dist/cjs/ui/issue-like-table/edit-type/icon/index.js +16 -106
- package/dist/cjs/ui/issue-like-table/edit-type/index.js +26 -9
- package/dist/cjs/ui/issue-like-table/edit-type/status/index.js +10 -112
- package/dist/cjs/ui/issue-like-table/edit-type/text/index.js +4 -6
- package/dist/cjs/ui/issue-like-table/edit-type/user/index.js +97 -0
- package/dist/cjs/ui/issue-like-table/index.js +28 -26
- package/dist/cjs/ui/issue-like-table/table-cell-content/inline-edit.js +5 -2
- package/dist/es2019/hooks/useLoadOptions.js +63 -0
- package/dist/es2019/ui/issue-like-table/edit-type/icon/index.js +13 -74
- package/dist/es2019/ui/issue-like-table/edit-type/index.js +24 -5
- package/dist/es2019/ui/issue-like-table/edit-type/status/index.js +8 -76
- package/dist/es2019/ui/issue-like-table/edit-type/text/index.js +5 -5
- package/dist/es2019/ui/issue-like-table/edit-type/user/index.js +74 -0
- package/dist/es2019/ui/issue-like-table/index.js +29 -27
- package/dist/es2019/ui/issue-like-table/table-cell-content/inline-edit.js +5 -2
- package/dist/esm/hooks/useLoadOptions.js +93 -0
- package/dist/esm/ui/issue-like-table/edit-type/icon/index.js +18 -107
- package/dist/esm/ui/issue-like-table/edit-type/index.js +25 -5
- package/dist/esm/ui/issue-like-table/edit-type/status/index.js +11 -113
- package/dist/esm/ui/issue-like-table/edit-type/text/index.js +3 -5
- package/dist/esm/ui/issue-like-table/edit-type/user/index.js +87 -0
- package/dist/esm/ui/issue-like-table/index.js +28 -26
- package/dist/esm/ui/issue-like-table/table-cell-content/inline-edit.js +5 -2
- package/dist/types/hooks/useLoadOptions.d.ts +11 -0
- package/dist/types/ui/issue-like-table/edit-type/icon/index.d.ts +2 -2
- package/dist/types/ui/issue-like-table/edit-type/index.d.ts +1 -0
- package/dist/types/ui/issue-like-table/edit-type/status/index.d.ts +4 -4
- package/dist/types/ui/issue-like-table/edit-type/text/index.d.ts +2 -3
- package/dist/types/ui/issue-like-table/edit-type/user/index.d.ts +11 -0
- package/dist/types/ui/issue-like-table/types.d.ts +3 -0
- package/dist/types-ts4.5/hooks/useLoadOptions.d.ts +11 -0
- package/dist/types-ts4.5/ui/issue-like-table/edit-type/icon/index.d.ts +2 -2
- package/dist/types-ts4.5/ui/issue-like-table/edit-type/index.d.ts +1 -0
- package/dist/types-ts4.5/ui/issue-like-table/edit-type/status/index.d.ts +4 -4
- package/dist/types-ts4.5/ui/issue-like-table/edit-type/text/index.d.ts +2 -3
- package/dist/types-ts4.5/ui/issue-like-table/edit-type/user/index.d.ts +11 -0
- package/dist/types-ts4.5/ui/issue-like-table/types.d.ts +3 -0
- package/package.json +8 -5
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
10
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
12
|
+
var _useDebounce = require("use-debounce");
|
|
13
|
+
var _avatar = _interopRequireWildcard(require("@atlaskit/avatar"));
|
|
14
|
+
var _select = _interopRequireDefault(require("@atlaskit/select"));
|
|
15
|
+
var _ufoExperiences = require("../../../../analytics/ufoExperiences");
|
|
16
|
+
var _datasourceExperienceId = require("../../../../contexts/datasource-experience-id");
|
|
17
|
+
var _useLoadOptions2 = require("../../../../hooks/useLoadOptions");
|
|
18
|
+
var _constants = require("../../../common/modal/popup-select/constants");
|
|
19
|
+
var _user = require("../../render-type/user");
|
|
20
|
+
var _inlineEdit = require("../../table-cell-content/inline-edit");
|
|
21
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
22
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
23
|
+
var UserEditType = function UserEditType(props) {
|
|
24
|
+
var _currentValue$values;
|
|
25
|
+
var currentValue = props.currentValue,
|
|
26
|
+
executeFetch = props.executeFetch;
|
|
27
|
+
var _useState = (0, _react.useState)({
|
|
28
|
+
query: ''
|
|
29
|
+
}),
|
|
30
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
31
|
+
fetchInputs = _useState2[0],
|
|
32
|
+
setFetchInputs = _useState2[1];
|
|
33
|
+
var _useDebouncedCallback = (0, _useDebounce.useDebouncedCallback)(function (query) {
|
|
34
|
+
return setFetchInputs({
|
|
35
|
+
query: query
|
|
36
|
+
});
|
|
37
|
+
}, _constants.SEARCH_DEBOUNCE_MS),
|
|
38
|
+
_useDebouncedCallback2 = (0, _slicedToArray2.default)(_useDebouncedCallback, 1),
|
|
39
|
+
handleUserInputDebounced = _useDebouncedCallback2[0];
|
|
40
|
+
var _useLoadOptions = (0, _useLoadOptions2.useLoadOptions)({
|
|
41
|
+
executeFetch: executeFetch,
|
|
42
|
+
fetchInputs: fetchInputs
|
|
43
|
+
}),
|
|
44
|
+
options = _useLoadOptions.options,
|
|
45
|
+
isLoading = _useLoadOptions.isLoading,
|
|
46
|
+
hasFailed = _useLoadOptions.hasFailed;
|
|
47
|
+
var experienceId = (0, _datasourceExperienceId.useDatasourceExperienceId)();
|
|
48
|
+
(0, _react.useEffect)(function () {
|
|
49
|
+
if (!experienceId) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (hasFailed) {
|
|
53
|
+
(0, _ufoExperiences.failUfoExperience)({
|
|
54
|
+
name: _inlineEdit.InlineEditUFOExperience
|
|
55
|
+
}, experienceId);
|
|
56
|
+
} else if (!isLoading) {
|
|
57
|
+
(0, _ufoExperiences.succeedUfoExperience)({
|
|
58
|
+
name: _inlineEdit.InlineEditUFOExperience
|
|
59
|
+
}, experienceId);
|
|
60
|
+
}
|
|
61
|
+
}, [experienceId, isLoading, hasFailed]);
|
|
62
|
+
return /*#__PURE__*/_react.default.createElement(_select.default, (0, _extends2.default)({}, props, {
|
|
63
|
+
autoFocus: true,
|
|
64
|
+
defaultMenuIsOpen: true,
|
|
65
|
+
blurInputOnSelect: true,
|
|
66
|
+
options: options,
|
|
67
|
+
isLoading: isLoading,
|
|
68
|
+
testId: "inline-edit-user",
|
|
69
|
+
filterOption: function filterOption() {
|
|
70
|
+
return true;
|
|
71
|
+
} // necessary, otherwise by default all options will be filtered out on user input
|
|
72
|
+
,
|
|
73
|
+
onInputChange: handleUserInputDebounced,
|
|
74
|
+
defaultValue: currentValue === null || currentValue === void 0 || (_currentValue$values = currentValue.values) === null || _currentValue$values === void 0 ? void 0 : _currentValue$values[0],
|
|
75
|
+
getOptionValue: function getOptionValue(option) {
|
|
76
|
+
return option.atlassianUserId;
|
|
77
|
+
},
|
|
78
|
+
formatOptionLabel: function formatOptionLabel(option) {
|
|
79
|
+
return /*#__PURE__*/_react.default.createElement(_avatar.AvatarItem, {
|
|
80
|
+
avatar: /*#__PURE__*/_react.default.createElement(_avatar.default, {
|
|
81
|
+
appearance: "circle",
|
|
82
|
+
size: 'small',
|
|
83
|
+
src: option.avatarSource,
|
|
84
|
+
testId: "".concat(_user.USER_TYPE_TEST_ID, "--avatar--").concat(option.atlassianUserId)
|
|
85
|
+
}),
|
|
86
|
+
primaryText: option.displayName
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
onChange: function onChange(e) {
|
|
90
|
+
return props.setEditValues({
|
|
91
|
+
type: 'user',
|
|
92
|
+
values: e ? [e] : []
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}));
|
|
96
|
+
};
|
|
97
|
+
var _default = exports.default = UserEditType;
|
|
@@ -719,35 +719,37 @@ var IssueLikeDataTableView = exports.IssueLikeDataTableView = function IssueLike
|
|
|
719
719
|
shouldUseWidth: shouldUseWidth,
|
|
720
720
|
width: width
|
|
721
721
|
});
|
|
722
|
-
|
|
723
722
|
// eslint-disable-next-line @atlaskit/platform/ensure-feature-flag-prefix
|
|
724
|
-
if ((0, _platformFeatureFlags.fg)('
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
if (key !== null && key !== void 0 && key.includes('loading')) {
|
|
737
|
-
loadingRowStyle = _objectSpread(_objectSpread({}, loadingRowStyle), {}, {
|
|
738
|
-
paddingBlock: "var(--ds-space-100, 8px)"
|
|
739
|
-
});
|
|
723
|
+
if ((0, _platformFeatureFlags.fg)('enable_datasource_react_sweet_state')) {
|
|
724
|
+
// eslint-disable-next-line @atlaskit/platform/ensure-feature-flag-prefix
|
|
725
|
+
if ((0, _platformFeatureFlags.fg)('platform-datasources-enable-two-way-sync')) {
|
|
726
|
+
return (0, _react2.jsx)(_styled2.InlineEditableTableCell, {
|
|
727
|
+
key: cellKey,
|
|
728
|
+
"data-testid": testId && "".concat(testId, "--cell-").concat(cellIndex),
|
|
729
|
+
colSpan: isEditable && isLastCell ? 2 : undefined
|
|
730
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
|
|
731
|
+
,
|
|
732
|
+
style: loadingRowStyle,
|
|
733
|
+
css: [wrappedColumnKeys !== null && wrappedColumnKeys !== void 0 && wrappedColumnKeys.includes(cellKey) ? null : truncateStyles]
|
|
734
|
+
}, content);
|
|
740
735
|
}
|
|
741
|
-
return (0, _react2.jsx)(_styled2.TableCell, {
|
|
742
|
-
key: cellKey,
|
|
743
|
-
"data-testid": testId && "".concat(testId, "--cell-").concat(cellIndex),
|
|
744
|
-
colSpan: isEditable && isLastCell ? 2 : undefined
|
|
745
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
|
|
746
|
-
,
|
|
747
|
-
style: loadingRowStyle,
|
|
748
|
-
css: [wrappedColumnKeys !== null && wrappedColumnKeys !== void 0 && wrappedColumnKeys.includes(cellKey) ? null : truncateStyles]
|
|
749
|
-
}, content);
|
|
750
736
|
}
|
|
737
|
+
|
|
738
|
+
// extra padding is required around skeleton loader to avoid vertical jumps when data loads
|
|
739
|
+
if (key !== null && key !== void 0 && key.includes('loading')) {
|
|
740
|
+
loadingRowStyle = _objectSpread(_objectSpread({}, loadingRowStyle), {}, {
|
|
741
|
+
paddingBlock: "var(--ds-space-100, 8px)"
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
return (0, _react2.jsx)(_styled2.TableCell, {
|
|
745
|
+
key: cellKey,
|
|
746
|
+
"data-testid": testId && "".concat(testId, "--cell-").concat(cellIndex),
|
|
747
|
+
colSpan: isEditable && isLastCell ? 2 : undefined
|
|
748
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
|
|
749
|
+
,
|
|
750
|
+
style: loadingRowStyle,
|
|
751
|
+
css: [wrappedColumnKeys !== null && wrappedColumnKeys !== void 0 && wrappedColumnKeys.includes(cellKey) ? null : truncateStyles]
|
|
752
|
+
}, content);
|
|
751
753
|
}));
|
|
752
754
|
}))));
|
|
753
755
|
return (0, _platformFeatureFlags.fg)('platform-datasources-enable-two-way-sync') ? (0, _react2.jsx)(_flag.FlagsProvider, null, view) : view;
|
|
@@ -29,14 +29,16 @@ var editContainerStyles = (0, _primitives.xcss)({
|
|
|
29
29
|
marginBlockStart: 'space.negative.100'
|
|
30
30
|
});
|
|
31
31
|
var getBackendUpdateValue = function getBackendUpdateValue(typedNewValue) {
|
|
32
|
-
var _typedNewValue$values, _typedNewValue$values2;
|
|
32
|
+
var _typedNewValue$values, _typedNewValue$values2, _typedNewValue$values3;
|
|
33
33
|
switch (typedNewValue.type) {
|
|
34
34
|
case 'string':
|
|
35
35
|
return typedNewValue.values[0] || '';
|
|
36
36
|
case 'status':
|
|
37
37
|
return ((_typedNewValue$values = typedNewValue.values[0]) === null || _typedNewValue$values === void 0 ? void 0 : _typedNewValue$values.transitionId) || '';
|
|
38
|
+
case 'user':
|
|
39
|
+
return ((_typedNewValue$values2 = typedNewValue.values[0]) === null || _typedNewValue$values2 === void 0 ? void 0 : _typedNewValue$values2.atlassianUserId) || '';
|
|
38
40
|
case 'icon':
|
|
39
|
-
return ((_typedNewValue$
|
|
41
|
+
return ((_typedNewValue$values3 = typedNewValue.values[0]) === null || _typedNewValue$values3 === void 0 ? void 0 : _typedNewValue$values3.id) || '';
|
|
40
42
|
}
|
|
41
43
|
throw new Error("Datasource 2 way sync Backend update value not implemented for type ".concat(typedNewValue.type));
|
|
42
44
|
};
|
|
@@ -47,6 +49,7 @@ var mapUpdatedItem = function mapUpdatedItem(existingItem, columnKey, newValue)
|
|
|
47
49
|
data: newValue.values[0] || ''
|
|
48
50
|
}));
|
|
49
51
|
case 'status':
|
|
52
|
+
case 'user':
|
|
50
53
|
case 'icon':
|
|
51
54
|
return newValue.values[0] ? _objectSpread(_objectSpread({}, existingItem), {}, (0, _defineProperty2.default)({}, columnKey, {
|
|
52
55
|
data: newValue.values[0]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { ActionOperationStatus } from '@atlaskit/linking-types';
|
|
3
|
+
import { useDatasourceTableFlag } from './useDatasourceTableFlag';
|
|
4
|
+
const loadOptions = async (fetchInputs = {}, executeFetch) => {
|
|
5
|
+
if (!executeFetch) {
|
|
6
|
+
return [];
|
|
7
|
+
}
|
|
8
|
+
const result = await executeFetch(fetchInputs);
|
|
9
|
+
const {
|
|
10
|
+
operationStatus,
|
|
11
|
+
entities
|
|
12
|
+
} = result;
|
|
13
|
+
if (operationStatus === ActionOperationStatus.FAILURE) {
|
|
14
|
+
throw new Error('Failed to fetch status options');
|
|
15
|
+
}
|
|
16
|
+
return entities !== null && entities !== void 0 ? entities : [];
|
|
17
|
+
};
|
|
18
|
+
export const useLoadOptions = ({
|
|
19
|
+
fetchInputs,
|
|
20
|
+
executeFetch
|
|
21
|
+
}) => {
|
|
22
|
+
const [{
|
|
23
|
+
options,
|
|
24
|
+
isLoading,
|
|
25
|
+
hasFailed
|
|
26
|
+
}, setOptions] = useState({
|
|
27
|
+
isLoading: true,
|
|
28
|
+
options: [],
|
|
29
|
+
hasFailed: false
|
|
30
|
+
});
|
|
31
|
+
const {
|
|
32
|
+
showErrorFlag
|
|
33
|
+
} = useDatasourceTableFlag({
|
|
34
|
+
isFetchAction: true
|
|
35
|
+
});
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
let isMounted = true;
|
|
38
|
+
loadOptions(fetchInputs, executeFetch).then(options => {
|
|
39
|
+
if (isMounted) {
|
|
40
|
+
setOptions({
|
|
41
|
+
isLoading: false,
|
|
42
|
+
options,
|
|
43
|
+
hasFailed: false
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}).catch(err => {
|
|
47
|
+
showErrorFlag();
|
|
48
|
+
setOptions({
|
|
49
|
+
isLoading: false,
|
|
50
|
+
options: [],
|
|
51
|
+
hasFailed: true
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return () => {
|
|
55
|
+
isMounted = false;
|
|
56
|
+
};
|
|
57
|
+
}, [fetchInputs, executeFetch, showErrorFlag]);
|
|
58
|
+
return {
|
|
59
|
+
options,
|
|
60
|
+
isLoading,
|
|
61
|
+
hasFailed
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
import React, { useEffect
|
|
3
|
-
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
3
|
+
|
|
4
4
|
// FilterOptionOption is used in the filterOption function which is part of the public API, but the type itself is not exported
|
|
5
5
|
// eslint-disable-next-line import/no-extraneous-dependencies,no-restricted-imports
|
|
6
6
|
|
|
7
7
|
import Select from '@atlaskit/select';
|
|
8
8
|
import { failUfoExperience, succeedUfoExperience } from '../../../../analytics/ufoExperiences';
|
|
9
9
|
import { useDatasourceExperienceId } from '../../../../contexts/datasource-experience-id';
|
|
10
|
-
import {
|
|
10
|
+
import { useLoadOptions } from '../../../../hooks/useLoadOptions';
|
|
11
11
|
import { SharedIconComponent } from '../../shared-components/icon';
|
|
12
12
|
import { InlineEditUFOExperience } from '../../table-cell-content/inline-edit';
|
|
13
13
|
/**
|
|
@@ -23,7 +23,9 @@ const IconEditType = props => {
|
|
|
23
23
|
options,
|
|
24
24
|
isLoading,
|
|
25
25
|
hasFailed
|
|
26
|
-
} =
|
|
26
|
+
} = useLoadOptions({
|
|
27
|
+
executeFetch
|
|
28
|
+
});
|
|
27
29
|
const experienceId = useDatasourceExperienceId();
|
|
28
30
|
useEffect(() => {
|
|
29
31
|
if (!experienceId) {
|
|
@@ -39,16 +41,17 @@ const IconEditType = props => {
|
|
|
39
41
|
}, experienceId);
|
|
40
42
|
}
|
|
41
43
|
}, [experienceId, isLoading, hasFailed]);
|
|
42
|
-
return /*#__PURE__*/React.createElement(
|
|
43
|
-
testId: "inline-edit-priority",
|
|
44
|
+
return /*#__PURE__*/React.createElement(Select, _extends({}, props, {
|
|
44
45
|
autoFocus: true,
|
|
45
|
-
defaultMenuIsOpen: true,
|
|
46
46
|
blurInputOnSelect: true,
|
|
47
|
-
|
|
47
|
+
defaultMenuIsOpen: true,
|
|
48
48
|
options: options,
|
|
49
|
+
menuPlacement: "auto",
|
|
49
50
|
isLoading: isLoading,
|
|
50
|
-
defaultValue: currentValue === null || currentValue === void 0 ? void 0 : (_currentValue$values = currentValue.values) === null || _currentValue$values === void 0 ? void 0 : _currentValue$values[0],
|
|
51
51
|
filterOption: filterOption,
|
|
52
|
+
testId: "inline-edit-priority",
|
|
53
|
+
defaultValue: currentValue === null || currentValue === void 0 ? void 0 : (_currentValue$values = currentValue.values) === null || _currentValue$values === void 0 ? void 0 : _currentValue$values[0],
|
|
54
|
+
getOptionValue: option => option.text || '',
|
|
52
55
|
formatOptionLabel: ({
|
|
53
56
|
source,
|
|
54
57
|
label,
|
|
@@ -63,71 +66,7 @@ const IconEditType = props => {
|
|
|
63
66
|
type: 'icon',
|
|
64
67
|
values: e ? [e] : []
|
|
65
68
|
})
|
|
66
|
-
}))
|
|
69
|
+
}));
|
|
67
70
|
};
|
|
68
71
|
const filterOption = (option, inputValue) => option.label.toLowerCase().includes(inputValue.toLowerCase());
|
|
69
|
-
const usePriorityOptions = (currentValue, executeFetch) => {
|
|
70
|
-
const [{
|
|
71
|
-
options,
|
|
72
|
-
isLoading,
|
|
73
|
-
hasFailed
|
|
74
|
-
}, setOptions] = useState({
|
|
75
|
-
isLoading: true,
|
|
76
|
-
options: [],
|
|
77
|
-
hasFailed: false
|
|
78
|
-
});
|
|
79
|
-
const {
|
|
80
|
-
showErrorFlag
|
|
81
|
-
} = useDatasourceTableFlag({
|
|
82
|
-
isFetchAction: true
|
|
83
|
-
});
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
let isMounted = true;
|
|
86
|
-
loadOptions(currentValue, executeFetch).then(options => {
|
|
87
|
-
if (isMounted) {
|
|
88
|
-
setOptions({
|
|
89
|
-
isLoading: false,
|
|
90
|
-
options,
|
|
91
|
-
hasFailed: false
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}).catch(err => {
|
|
95
|
-
showErrorFlag();
|
|
96
|
-
setOptions({
|
|
97
|
-
isLoading: false,
|
|
98
|
-
options: [],
|
|
99
|
-
hasFailed: true
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
return () => {
|
|
103
|
-
isMounted = false;
|
|
104
|
-
};
|
|
105
|
-
}, [currentValue, executeFetch, showErrorFlag]);
|
|
106
|
-
return {
|
|
107
|
-
options,
|
|
108
|
-
isLoading,
|
|
109
|
-
hasFailed
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Load options for the select
|
|
115
|
-
*/
|
|
116
|
-
const loadOptions = async (_currentValue, executeFetch) => {
|
|
117
|
-
if (!executeFetch) {
|
|
118
|
-
return [];
|
|
119
|
-
}
|
|
120
|
-
const {
|
|
121
|
-
operationStatus,
|
|
122
|
-
entities
|
|
123
|
-
} = await executeFetch({});
|
|
124
|
-
if (operationStatus === ActionOperationStatus.FAILURE) {
|
|
125
|
-
throw new Error('Failed to fetch icon options');
|
|
126
|
-
}
|
|
127
|
-
if (operationStatus === ActionOperationStatus.SUCCESS && entities) {
|
|
128
|
-
// Map entities here if the backend type is different from the type required by the select
|
|
129
|
-
return entities;
|
|
130
|
-
}
|
|
131
|
-
return [];
|
|
132
|
-
};
|
|
133
72
|
export default IconEditType;
|
|
@@ -3,7 +3,8 @@ import React from 'react';
|
|
|
3
3
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
4
|
import IconEditType from './icon';
|
|
5
5
|
import StatusEditType from './status';
|
|
6
|
-
import TextEditType
|
|
6
|
+
import TextEditType from './text';
|
|
7
|
+
import UserEditType from './user';
|
|
7
8
|
|
|
8
9
|
// This is used in editor-card-plugin to identify if any type of inline edit is active.
|
|
9
10
|
const ACTIVE_INLINE_EDIT_ID = 'sllv-active-inline-edit';
|
|
@@ -13,10 +14,11 @@ export const editType = ({
|
|
|
13
14
|
setEditValues,
|
|
14
15
|
executeFetch
|
|
15
16
|
}) => {
|
|
17
|
+
var _toValueType, _value$atlassianUserI;
|
|
16
18
|
switch (defaultValue.type) {
|
|
17
19
|
case 'string':
|
|
18
20
|
return {
|
|
19
|
-
defaultValue:
|
|
21
|
+
defaultValue: (_toValueType = toValueType(defaultValue)) !== null && _toValueType !== void 0 ? _toValueType : '',
|
|
20
22
|
editView: ({
|
|
21
23
|
...fieldProps
|
|
22
24
|
}) => /*#__PURE__*/React.createElement(TextEditType, _extends({}, fieldProps, {
|
|
@@ -27,7 +29,7 @@ export const editType = ({
|
|
|
27
29
|
};
|
|
28
30
|
case 'icon':
|
|
29
31
|
return {
|
|
30
|
-
defaultValue:
|
|
32
|
+
defaultValue: toValueType(defaultValue),
|
|
31
33
|
editView: ({
|
|
32
34
|
value,
|
|
33
35
|
...fieldProps
|
|
@@ -40,7 +42,7 @@ export const editType = ({
|
|
|
40
42
|
};
|
|
41
43
|
case 'status':
|
|
42
44
|
return {
|
|
43
|
-
defaultValue:
|
|
45
|
+
defaultValue: toValueType(defaultValue),
|
|
44
46
|
editView: ({
|
|
45
47
|
...fieldProps
|
|
46
48
|
}) => /*#__PURE__*/React.createElement(StatusEditType, _extends({}, fieldProps, {
|
|
@@ -50,6 +52,19 @@ export const editType = ({
|
|
|
50
52
|
executeFetch: executeFetch
|
|
51
53
|
}))
|
|
52
54
|
};
|
|
55
|
+
case 'user':
|
|
56
|
+
const value = toValueType(defaultValue);
|
|
57
|
+
return {
|
|
58
|
+
defaultValue: (_value$atlassianUserI = value === null || value === void 0 ? void 0 : value.atlassianUserId) !== null && _value$atlassianUserI !== void 0 ? _value$atlassianUserI : '',
|
|
59
|
+
editView: ({
|
|
60
|
+
...fieldProps
|
|
61
|
+
}) => /*#__PURE__*/React.createElement(UserEditType, _extends({}, fieldProps, {
|
|
62
|
+
currentValue: currentValue,
|
|
63
|
+
setEditValues: setEditValues,
|
|
64
|
+
id: ACTIVE_INLINE_EDIT_ID,
|
|
65
|
+
executeFetch: executeFetch
|
|
66
|
+
}))
|
|
67
|
+
};
|
|
53
68
|
}
|
|
54
69
|
return {
|
|
55
70
|
defaultValue: '',
|
|
@@ -57,10 +72,14 @@ export const editType = ({
|
|
|
57
72
|
};
|
|
58
73
|
};
|
|
59
74
|
export const isEditTypeSupported = type => {
|
|
60
|
-
const supportedEditType = ['string', ...(fg('platform-datasources-enable-two-way-sync-statuses') ? ['status'] : []), ...(fg('platform-datasources-enable-two-way-sync-priority') ? ['icon'] : [])];
|
|
75
|
+
const supportedEditType = ['string', ...(fg('platform-datasources-enable-two-way-sync-statuses') ? ['status'] : []), ...(fg('platform-datasources-enable-two-way-sync-priority') ? ['icon'] : []), ...(fg('platform-datasources-enable-two-way-sync-assignee') ? ['user'] : [])];
|
|
61
76
|
return supportedEditType.includes(type);
|
|
62
77
|
};
|
|
63
78
|
export const isEditTypeSelectable = type => {
|
|
64
79
|
const selectEditTypes = ['status', 'icon', 'user'];
|
|
65
80
|
return selectEditTypes.includes(type);
|
|
81
|
+
};
|
|
82
|
+
export const toValueType = typeWithValues => {
|
|
83
|
+
var _typeWithValues$value;
|
|
84
|
+
return (_typeWithValues$value = typeWithValues.values) === null || _typeWithValues$value === void 0 ? void 0 : _typeWithValues$value[0];
|
|
66
85
|
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
import React, { useEffect
|
|
3
|
-
import { ActionOperationStatus } from '@atlaskit/linking-types';
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
4
3
|
import Lozenge from '@atlaskit/lozenge';
|
|
5
4
|
import Select from '@atlaskit/select';
|
|
6
5
|
import { failUfoExperience, succeedUfoExperience } from '../../../../analytics/ufoExperiences';
|
|
7
6
|
import { useDatasourceExperienceId } from '../../../../contexts/datasource-experience-id';
|
|
8
|
-
import {
|
|
7
|
+
import { useLoadOptions } from '../../../../hooks/useLoadOptions';
|
|
9
8
|
import { InlineEditUFOExperience } from '../../table-cell-content/inline-edit';
|
|
10
9
|
const StatusEditType = props => {
|
|
11
10
|
var _currentValue$values;
|
|
@@ -17,7 +16,7 @@ const StatusEditType = props => {
|
|
|
17
16
|
options,
|
|
18
17
|
isLoading,
|
|
19
18
|
hasFailed
|
|
20
|
-
} =
|
|
19
|
+
} = useLoadOptions({
|
|
21
20
|
executeFetch
|
|
22
21
|
});
|
|
23
22
|
const experienceId = useDatasourceExperienceId();
|
|
@@ -36,16 +35,16 @@ const StatusEditType = props => {
|
|
|
36
35
|
}
|
|
37
36
|
}, [experienceId, isLoading, hasFailed]);
|
|
38
37
|
return /*#__PURE__*/React.createElement(Select, _extends({}, props, {
|
|
39
|
-
testId: "inline-edit-status",
|
|
40
38
|
autoFocus: true,
|
|
39
|
+
options: options,
|
|
41
40
|
defaultMenuIsOpen: true,
|
|
42
41
|
blurInputOnSelect: true,
|
|
43
|
-
|
|
44
|
-
options: options,
|
|
42
|
+
menuPlacement: "auto",
|
|
45
43
|
isLoading: isLoading,
|
|
46
|
-
defaultValue: currentValue === null || currentValue === void 0 ? void 0 : (_currentValue$values = currentValue.values) === null || _currentValue$values === void 0 ? void 0 : _currentValue$values[0],
|
|
47
44
|
filterOption: filterOption,
|
|
48
|
-
|
|
45
|
+
testId: "inline-edit-status",
|
|
46
|
+
getOptionValue: option => option.text,
|
|
47
|
+
defaultValue: currentValue === null || currentValue === void 0 ? void 0 : (_currentValue$values = currentValue.values) === null || _currentValue$values === void 0 ? void 0 : _currentValue$values[0],
|
|
49
48
|
formatOptionLabel: option => /*#__PURE__*/React.createElement(Lozenge, _extends({
|
|
50
49
|
testId: `inline-edit-status-option-${option.text}`
|
|
51
50
|
}, option.style), option.text),
|
|
@@ -56,71 +55,4 @@ const StatusEditType = props => {
|
|
|
56
55
|
}));
|
|
57
56
|
};
|
|
58
57
|
const filterOption = (option, inputValue) => option.data.text.toLowerCase().includes(inputValue.toLowerCase());
|
|
59
|
-
const useStatusOptions = ({
|
|
60
|
-
fetchInputs,
|
|
61
|
-
executeFetch
|
|
62
|
-
}) => {
|
|
63
|
-
const [{
|
|
64
|
-
options,
|
|
65
|
-
isLoading,
|
|
66
|
-
hasFailed
|
|
67
|
-
}, setOptions] = useState({
|
|
68
|
-
isLoading: true,
|
|
69
|
-
options: [],
|
|
70
|
-
hasFailed: false
|
|
71
|
-
});
|
|
72
|
-
const {
|
|
73
|
-
showErrorFlag
|
|
74
|
-
} = useDatasourceTableFlag({
|
|
75
|
-
isFetchAction: true
|
|
76
|
-
});
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
let isMounted = true;
|
|
79
|
-
loadOptions(fetchInputs, executeFetch).then(options => {
|
|
80
|
-
if (isMounted) {
|
|
81
|
-
setOptions({
|
|
82
|
-
isLoading: false,
|
|
83
|
-
options,
|
|
84
|
-
hasFailed: false
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}).catch(err => {
|
|
88
|
-
showErrorFlag();
|
|
89
|
-
setOptions({
|
|
90
|
-
isLoading: false,
|
|
91
|
-
options: [],
|
|
92
|
-
hasFailed: true
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
return () => {
|
|
96
|
-
isMounted = false;
|
|
97
|
-
};
|
|
98
|
-
}, [fetchInputs, executeFetch, showErrorFlag]);
|
|
99
|
-
return {
|
|
100
|
-
options,
|
|
101
|
-
isLoading,
|
|
102
|
-
hasFailed
|
|
103
|
-
};
|
|
104
|
-
};
|
|
105
|
-
const loadOptions = async (fetchInputs = {}, executeFetch) => {
|
|
106
|
-
if (executeFetch) {
|
|
107
|
-
const result = await executeFetch(fetchInputs);
|
|
108
|
-
const {
|
|
109
|
-
operationStatus,
|
|
110
|
-
entities
|
|
111
|
-
} = result;
|
|
112
|
-
if (operationStatus === ActionOperationStatus.FAILURE) {
|
|
113
|
-
throw new Error('Failed to fetch status options');
|
|
114
|
-
}
|
|
115
|
-
if (entities) {
|
|
116
|
-
return entities.map(entity => ({
|
|
117
|
-
id: entity.id,
|
|
118
|
-
text: entity.text,
|
|
119
|
-
style: entity.style,
|
|
120
|
-
transitionId: entity.transitionId
|
|
121
|
-
}));
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return [];
|
|
125
|
-
};
|
|
126
58
|
export default StatusEditType;
|
|
@@ -4,12 +4,12 @@ import { Layering } from '@atlaskit/layering';
|
|
|
4
4
|
import Textfield from '@atlaskit/textfield';
|
|
5
5
|
import { succeedUfoExperience } from '../../../../analytics/ufoExperiences';
|
|
6
6
|
import { useDatasourceExperienceId } from '../../../../contexts/datasource-experience-id';
|
|
7
|
-
export const toTextValue = typeWithValues => {
|
|
8
|
-
var _ref, _typeWithValues$value;
|
|
9
|
-
return (_ref = (_typeWithValues$value = typeWithValues.values) === null || _typeWithValues$value === void 0 ? void 0 : _typeWithValues$value[0]) !== null && _ref !== void 0 ? _ref : '';
|
|
10
|
-
};
|
|
11
7
|
const TextEditType = props => {
|
|
8
|
+
var _currentValue$values$, _currentValue$values;
|
|
12
9
|
const experienceId = useDatasourceExperienceId();
|
|
10
|
+
const {
|
|
11
|
+
currentValue
|
|
12
|
+
} = props;
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
if (experienceId) {
|
|
15
15
|
succeedUfoExperience({
|
|
@@ -27,7 +27,7 @@ const TextEditType = props => {
|
|
|
27
27
|
// We need 8px left padding to match read only version, but there is already 1px of border
|
|
28
28
|
padding: `${"var(--ds-space-100, 8px)"} calc(${"var(--ds-space-100, 8px)"} - 1px)`
|
|
29
29
|
},
|
|
30
|
-
value:
|
|
30
|
+
value: (_currentValue$values$ = currentValue === null || currentValue === void 0 ? void 0 : (_currentValue$values = currentValue.values) === null || _currentValue$values === void 0 ? void 0 : _currentValue$values[0]) !== null && _currentValue$values$ !== void 0 ? _currentValue$values$ : '',
|
|
31
31
|
onChange: e => props.setEditValues({
|
|
32
32
|
type: 'string',
|
|
33
33
|
values: [e.currentTarget.value]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import React, { useEffect, useState } from 'react';
|
|
3
|
+
import { useDebouncedCallback } from 'use-debounce';
|
|
4
|
+
import Avatar, { AvatarItem } from '@atlaskit/avatar';
|
|
5
|
+
import Select from '@atlaskit/select';
|
|
6
|
+
import { failUfoExperience, succeedUfoExperience } from '../../../../analytics/ufoExperiences';
|
|
7
|
+
import { useDatasourceExperienceId } from '../../../../contexts/datasource-experience-id';
|
|
8
|
+
import { useLoadOptions } from '../../../../hooks/useLoadOptions';
|
|
9
|
+
import { SEARCH_DEBOUNCE_MS } from '../../../common/modal/popup-select/constants';
|
|
10
|
+
import { USER_TYPE_TEST_ID } from '../../render-type/user';
|
|
11
|
+
import { InlineEditUFOExperience } from '../../table-cell-content/inline-edit';
|
|
12
|
+
const UserEditType = props => {
|
|
13
|
+
var _currentValue$values;
|
|
14
|
+
const {
|
|
15
|
+
currentValue,
|
|
16
|
+
executeFetch
|
|
17
|
+
} = props;
|
|
18
|
+
const [fetchInputs, setFetchInputs] = useState({
|
|
19
|
+
query: ''
|
|
20
|
+
});
|
|
21
|
+
const [handleUserInputDebounced] = useDebouncedCallback(query => setFetchInputs({
|
|
22
|
+
query
|
|
23
|
+
}), SEARCH_DEBOUNCE_MS);
|
|
24
|
+
const {
|
|
25
|
+
options,
|
|
26
|
+
isLoading,
|
|
27
|
+
hasFailed
|
|
28
|
+
} = useLoadOptions({
|
|
29
|
+
executeFetch,
|
|
30
|
+
fetchInputs
|
|
31
|
+
});
|
|
32
|
+
const experienceId = useDatasourceExperienceId();
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!experienceId) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (hasFailed) {
|
|
38
|
+
failUfoExperience({
|
|
39
|
+
name: InlineEditUFOExperience
|
|
40
|
+
}, experienceId);
|
|
41
|
+
} else if (!isLoading) {
|
|
42
|
+
succeedUfoExperience({
|
|
43
|
+
name: InlineEditUFOExperience
|
|
44
|
+
}, experienceId);
|
|
45
|
+
}
|
|
46
|
+
}, [experienceId, isLoading, hasFailed]);
|
|
47
|
+
return /*#__PURE__*/React.createElement(Select, _extends({}, props, {
|
|
48
|
+
autoFocus: true,
|
|
49
|
+
defaultMenuIsOpen: true,
|
|
50
|
+
blurInputOnSelect: true,
|
|
51
|
+
options: options,
|
|
52
|
+
isLoading: isLoading,
|
|
53
|
+
testId: "inline-edit-user",
|
|
54
|
+
filterOption: () => true // necessary, otherwise by default all options will be filtered out on user input
|
|
55
|
+
,
|
|
56
|
+
onInputChange: handleUserInputDebounced,
|
|
57
|
+
defaultValue: currentValue === null || currentValue === void 0 ? void 0 : (_currentValue$values = currentValue.values) === null || _currentValue$values === void 0 ? void 0 : _currentValue$values[0],
|
|
58
|
+
getOptionValue: option => option.atlassianUserId,
|
|
59
|
+
formatOptionLabel: option => /*#__PURE__*/React.createElement(AvatarItem, {
|
|
60
|
+
avatar: /*#__PURE__*/React.createElement(Avatar, {
|
|
61
|
+
appearance: "circle",
|
|
62
|
+
size: 'small',
|
|
63
|
+
src: option.avatarSource,
|
|
64
|
+
testId: `${USER_TYPE_TEST_ID}--avatar--${option.atlassianUserId}`
|
|
65
|
+
}),
|
|
66
|
+
primaryText: option.displayName
|
|
67
|
+
}),
|
|
68
|
+
onChange: e => props.setEditValues({
|
|
69
|
+
type: 'user',
|
|
70
|
+
values: e ? [e] : []
|
|
71
|
+
})
|
|
72
|
+
}));
|
|
73
|
+
};
|
|
74
|
+
export default UserEditType;
|