@atlaskit/jql-editor 5.0.7 → 5.1.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 +16 -0
- package/dist/cjs/analytics/util.js +1 -1
- package/dist/cjs/state/index.js +17 -2
- package/dist/cjs/ui/jql-editor-footer-content/jql-messages/errors/index.js +91 -1
- package/dist/cjs/ui/jql-editor-footer-content/jql-messages/format/index.js +28 -1
- package/dist/es2019/analytics/util.js +1 -1
- package/dist/es2019/state/index.js +17 -2
- package/dist/es2019/ui/jql-editor-footer-content/jql-messages/errors/index.js +88 -2
- package/dist/es2019/ui/jql-editor-footer-content/jql-messages/format/index.js +23 -0
- package/dist/esm/analytics/util.js +1 -1
- package/dist/esm/state/index.js +17 -2
- package/dist/esm/ui/jql-editor-footer-content/jql-messages/errors/index.js +92 -2
- package/dist/esm/ui/jql-editor-footer-content/jql-messages/format/index.js +27 -0
- package/dist/types/state/types.d.ts +5 -0
- package/dist/types/ui/jql-editor-footer-content/jql-messages/format/index.d.ts +7 -0
- package/dist/types-ts4.5/state/types.d.ts +5 -0
- package/dist/types-ts4.5/ui/jql-editor-footer-content/jql-messages/format/index.d.ts +7 -0
- package/package.json +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atlaskit/jql-editor
|
|
2
2
|
|
|
3
|
+
## 5.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#129443](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/129443)
|
|
8
|
+
[`cea97763ee228`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/cea97763ee228) -
|
|
9
|
+
Pass down validation error messages and extra IDs for a11y [GRAVITYAI-2553]
|
|
10
|
+
|
|
11
|
+
## 5.0.8
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#129314](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/129314)
|
|
16
|
+
[`439b876d25b73`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/439b876d25b73) -
|
|
17
|
+
Improved error logging for editor transactions.
|
|
18
|
+
|
|
3
19
|
## 5.0.7
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -6,5 +6,5 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.useJqlEditorAnalytics = void 0;
|
|
7
7
|
var _jqlEditorCommon = require("@atlaskit/jql-editor-common");
|
|
8
8
|
var useJqlEditorAnalytics = exports.useJqlEditorAnalytics = function useJqlEditorAnalytics(analyticsSource) {
|
|
9
|
-
return (0, _jqlEditorCommon.useJqlPackageAnalytics)(analyticsSource, "@atlaskit/jql-editor", "5.0
|
|
9
|
+
return (0, _jqlEditorCommon.useJqlPackageAnalytics)(analyticsSource, "@atlaskit/jql-editor", "5.1.0", _jqlEditorCommon.ANALYTICS_CHANNEL);
|
|
10
10
|
};
|
package/dist/cjs/state/index.js
CHANGED
|
@@ -452,10 +452,25 @@ var actions = exports.actions = {
|
|
|
452
452
|
query = _getState7.query,
|
|
453
453
|
editorState = _getState7.editorState,
|
|
454
454
|
editorView = _getState7.editorView,
|
|
455
|
-
enableRichInlineNodes = _getState7.enableRichInlineNodes
|
|
455
|
+
enableRichInlineNodes = _getState7.enableRichInlineNodes,
|
|
456
|
+
onDebugUnsafeMessage = _getState7.onDebugUnsafeMessage;
|
|
456
457
|
var oldSelection = editorState.selection;
|
|
457
458
|
var updatedQuery = (0, _documentText.getNodeText)(transaction.doc, 0, transaction.doc.content.size);
|
|
458
|
-
var updatedEditorState
|
|
459
|
+
var updatedEditorState;
|
|
460
|
+
try {
|
|
461
|
+
updatedEditorState = editorState.apply(transaction);
|
|
462
|
+
} catch (error) {
|
|
463
|
+
// We've observed several errors in Splunk from this step but we're unsure how to reproduce it. It seems to be some type of
|
|
464
|
+
// race condition where the transaction is applied to the editor state but the editor state is being updated in another transaction.
|
|
465
|
+
if (error instanceof RangeError && editorView) {
|
|
466
|
+
var message = "Error occurred trying to update editor state with the message: ".concat(error.message);
|
|
467
|
+
(0, _util.sendDebugMessage)(message, editorView, editorState, onDebugUnsafeMessage, {
|
|
468
|
+
stack: error.stack,
|
|
469
|
+
transaction: JSON.stringify(transaction)
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
throw error;
|
|
473
|
+
}
|
|
459
474
|
|
|
460
475
|
// Update state in our editor view
|
|
461
476
|
if (editorView) {
|
|
@@ -61,6 +61,65 @@ var useFormattedErrorMessage = function useFormattedErrorMessage() {
|
|
|
61
61
|
}
|
|
62
62
|
return null;
|
|
63
63
|
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* This function maps client side validation errors and external messages into a unified format
|
|
67
|
+
* This is so that the output of this function can then be processed in a unified manner by different renderers
|
|
68
|
+
*
|
|
69
|
+
* ------ REMOVE THE FOLLOWING COMMENTS WITH THE FG CLEANUP OF gravityai-2553-fix-jql-debugger-flicker -----
|
|
70
|
+
* Cloned from useFormattedErrorMessage. Differences are:
|
|
71
|
+
* - return type is ExternalMessage[] instead of ReactNode
|
|
72
|
+
* - Stripped rendering logic away (i.e. FormatMessages) to make the implementation modular
|
|
73
|
+
*/
|
|
74
|
+
var useErrorMessages = function useErrorMessages() {
|
|
75
|
+
var _useIntl3 = (0, _state.useIntl)(),
|
|
76
|
+
_useIntl4 = (0, _slicedToArray2.default)(_useIntl3, 1),
|
|
77
|
+
formatMessage = _useIntl4[0].formatMessage;
|
|
78
|
+
var _useJqlError3 = (0, _state.useJqlError)(),
|
|
79
|
+
_useJqlError4 = (0, _slicedToArray2.default)(_useJqlError3, 1),
|
|
80
|
+
jqlError = _useJqlError4[0];
|
|
81
|
+
var _useExternalMessages3 = (0, _state.useExternalMessages)(),
|
|
82
|
+
_useExternalMessages4 = (0, _slicedToArray2.default)(_useExternalMessages3, 1),
|
|
83
|
+
externalErrors = _useExternalMessages4[0].errors;
|
|
84
|
+
var _useStoreActions3 = (0, _state.useStoreActions)(),
|
|
85
|
+
_useStoreActions4 = (0, _slicedToArray2.default)(_useStoreActions3, 2),
|
|
86
|
+
externalErrorMessageViewed = _useStoreActions4[1].externalErrorMessageViewed;
|
|
87
|
+
var editorViewIsInvalid = (0, _useEditorViewIsInvalid.useEditorViewIsInvalid)();
|
|
88
|
+
(0, _react.useEffect)(function () {
|
|
89
|
+
// Emit a UI event whenever external errors has changed
|
|
90
|
+
externalErrorMessageViewed();
|
|
91
|
+
}, [externalErrorMessageViewed, externalErrors]);
|
|
92
|
+
if (!editorViewIsInvalid) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Transform a string message to take the form of an ExternalMessage,
|
|
98
|
+
* so that we can reduce a bunch of conditionals when processing the output of useErrorMessages
|
|
99
|
+
*/
|
|
100
|
+
var toExternalMessageShape = function toExternalMessageShape(message) {
|
|
101
|
+
return [{
|
|
102
|
+
type: 'error',
|
|
103
|
+
message: message
|
|
104
|
+
}];
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Prioritise client errors over external errors
|
|
108
|
+
if (jqlError instanceof _jqlAst.JQLSyntaxError) {
|
|
109
|
+
return toExternalMessageShape("".concat(jqlError.message, " ").concat(formatMessage(_messages2.messages.jqlErrorPosition, {
|
|
110
|
+
lineNumber: jqlError.line,
|
|
111
|
+
charPosition: jqlError.charPositionInLine + 1
|
|
112
|
+
})));
|
|
113
|
+
}
|
|
114
|
+
if (externalErrors.length > 0) {
|
|
115
|
+
return externalErrors;
|
|
116
|
+
}
|
|
117
|
+
if (jqlError !== null) {
|
|
118
|
+
return toExternalMessageShape(formatMessage(_messages.commonMessages.unknownError));
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
};
|
|
122
|
+
|
|
64
123
|
/**
|
|
65
124
|
* This is a decorator component to include the editorTheme prop to the already passed list of props
|
|
66
125
|
*/
|
|
@@ -86,10 +145,41 @@ var ErrorMessages = exports.ErrorMessages = function ErrorMessages() {
|
|
|
86
145
|
var _useScopedId3 = (0, _state.useScopedId)(_constants.JQL_EDITOR_VALIDATION_ID),
|
|
87
146
|
_useScopedId4 = (0, _slicedToArray2.default)(_useScopedId3, 1),
|
|
88
147
|
validationId = _useScopedId4[0];
|
|
89
|
-
|
|
148
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
149
|
+
var errorMessages = (0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker') ? useErrorMessages() : null;
|
|
150
|
+
var errorMessage = !(0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker') ?
|
|
151
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
152
|
+
useFormattedErrorMessage() : null;
|
|
90
153
|
var _useCustomErrorCompon = (0, _state.useCustomErrorComponent)(),
|
|
91
154
|
_useCustomErrorCompon2 = (0, _slicedToArray2.default)(_useCustomErrorCompon, 1),
|
|
92
155
|
CustomErrorComponent = _useCustomErrorCompon2[0];
|
|
156
|
+
if ((0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker')) {
|
|
157
|
+
var _childrenToRender = errorMessages != null ? /*#__PURE__*/_react.default.createElement(_format.MessageContainer, null, /*#__PURE__*/_react.default.createElement(_form.ErrorMessage, {
|
|
158
|
+
testId: _constants.JQL_EDITOR_VALIDATION_ID
|
|
159
|
+
}, (0, _platformFeatureFlags.fg)('jql_editor_a11y') ? /*#__PURE__*/_react.default.createElement("span", {
|
|
160
|
+
role: "alert",
|
|
161
|
+
id: validationId
|
|
162
|
+
}, /*#__PURE__*/_react.default.createElement(_format.FormatMessages, {
|
|
163
|
+
messages: errorMessages
|
|
164
|
+
})) : /*#__PURE__*/_react.default.createElement("span", {
|
|
165
|
+
role: "alert",
|
|
166
|
+
"aria-describedby": editorId
|
|
167
|
+
}, /*#__PURE__*/_react.default.createElement(_format.FormatMessages, {
|
|
168
|
+
messages: errorMessages
|
|
169
|
+
})))) : null;
|
|
170
|
+
|
|
171
|
+
// Only render CustomErrorComponent if there is an errorMessage
|
|
172
|
+
if (errorMessages != null && CustomErrorComponent) {
|
|
173
|
+
return /*#__PURE__*/_react.default.createElement(CustomComponentDecoratedWithEditorTheme, {
|
|
174
|
+
testId: _constants.JQL_EDITOR_VALIDATION_ID,
|
|
175
|
+
editorId: editorId,
|
|
176
|
+
validationId: validationId,
|
|
177
|
+
Component: CustomErrorComponent,
|
|
178
|
+
errorMessages: (0, _format.extractMessageNodes)(errorMessages)
|
|
179
|
+
}, _childrenToRender);
|
|
180
|
+
}
|
|
181
|
+
return _childrenToRender;
|
|
182
|
+
}
|
|
93
183
|
var childrenToRender = errorMessage != null ? /*#__PURE__*/_react.default.createElement(_format.MessageContainer, null, /*#__PURE__*/_react.default.createElement(_form.ErrorMessage, {
|
|
94
184
|
testId: _constants.JQL_EDITOR_VALIDATION_ID
|
|
95
185
|
}, (0, _platformFeatureFlags.fg)('jql_editor_a11y') ? /*#__PURE__*/_react.default.createElement("span", {
|
|
@@ -4,8 +4,9 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.MessageContainer = exports.FormatMessages = void 0;
|
|
7
|
+
exports.extractMessageNodes = exports.MessageContainer = exports.FormatMessages = void 0;
|
|
8
8
|
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
9
10
|
var _useEditorTheme = require("../../../../hooks/use-editor-theme");
|
|
10
11
|
var _styled = require("./styled");
|
|
11
12
|
// Max number messages we want to show
|
|
@@ -20,6 +21,20 @@ var MessageContainer = exports.MessageContainer = function MessageContainer(_ref
|
|
|
20
21
|
};
|
|
21
22
|
var FormatMessages = exports.FormatMessages = function FormatMessages(_ref2) {
|
|
22
23
|
var messages = _ref2.messages;
|
|
24
|
+
if ((0, _platformFeatureFlags.fg)('gravityai-2553-fix-jql-debugger-flicker')) {
|
|
25
|
+
var messageNodes = extractMessageNodes(messages);
|
|
26
|
+
if (messageNodes.length === 0) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (messageNodes.length === 1) {
|
|
30
|
+
return /*#__PURE__*/_react.default.createElement("span", null, messageNodes[0]);
|
|
31
|
+
}
|
|
32
|
+
return /*#__PURE__*/_react.default.createElement(_styled.MessageList, null, messageNodes.map(function (m, i) {
|
|
33
|
+
return /*#__PURE__*/_react.default.createElement("li", {
|
|
34
|
+
key: i
|
|
35
|
+
}, m);
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
23
38
|
if (messages.length === 0) {
|
|
24
39
|
return null;
|
|
25
40
|
}
|
|
@@ -31,4 +46,16 @@ var FormatMessages = exports.FormatMessages = function FormatMessages(_ref2) {
|
|
|
31
46
|
key: i
|
|
32
47
|
}, m.message);
|
|
33
48
|
}));
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
|
|
53
|
+
* This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
|
|
54
|
+
*
|
|
55
|
+
* Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
|
|
56
|
+
*/
|
|
57
|
+
var extractMessageNodes = exports.extractMessageNodes = function extractMessageNodes(messages) {
|
|
58
|
+
return messages.slice(0, MAX_MESSAGES).map(function (m) {
|
|
59
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, m.message);
|
|
60
|
+
});
|
|
34
61
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ANALYTICS_CHANNEL, useJqlPackageAnalytics } from '@atlaskit/jql-editor-common';
|
|
2
2
|
export const useJqlEditorAnalytics = analyticsSource => {
|
|
3
|
-
return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.0
|
|
3
|
+
return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.1.0", ANALYTICS_CHANNEL);
|
|
4
4
|
};
|
|
@@ -463,11 +463,26 @@ export const actions = {
|
|
|
463
463
|
query,
|
|
464
464
|
editorState,
|
|
465
465
|
editorView,
|
|
466
|
-
enableRichInlineNodes
|
|
466
|
+
enableRichInlineNodes,
|
|
467
|
+
onDebugUnsafeMessage
|
|
467
468
|
} = getState();
|
|
468
469
|
const oldSelection = editorState.selection;
|
|
469
470
|
const updatedQuery = getNodeText(transaction.doc, 0, transaction.doc.content.size);
|
|
470
|
-
|
|
471
|
+
let updatedEditorState;
|
|
472
|
+
try {
|
|
473
|
+
updatedEditorState = editorState.apply(transaction);
|
|
474
|
+
} catch (error) {
|
|
475
|
+
// We've observed several errors in Splunk from this step but we're unsure how to reproduce it. It seems to be some type of
|
|
476
|
+
// race condition where the transaction is applied to the editor state but the editor state is being updated in another transaction.
|
|
477
|
+
if (error instanceof RangeError && editorView) {
|
|
478
|
+
const message = `Error occurred trying to update editor state with the message: ${error.message}`;
|
|
479
|
+
sendDebugMessage(message, editorView, editorState, onDebugUnsafeMessage, {
|
|
480
|
+
stack: error.stack,
|
|
481
|
+
transaction: JSON.stringify(transaction)
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
throw error;
|
|
485
|
+
}
|
|
471
486
|
|
|
472
487
|
// Update state in our editor view
|
|
473
488
|
if (editorView) {
|
|
@@ -9,7 +9,7 @@ import { commonMessages } from '../../../../common/messages';
|
|
|
9
9
|
import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
|
|
10
10
|
import { useEditorViewIsInvalid } from '../../../../hooks/use-editor-view-is-invalid';
|
|
11
11
|
import { useCustomErrorComponent, useExternalMessages, useIntl, useJqlError, useScopedId, useStoreActions } from '../../../../state';
|
|
12
|
-
import { FormatMessages, MessageContainer } from '../format';
|
|
12
|
+
import { extractMessageNodes, FormatMessages, MessageContainer } from '../format';
|
|
13
13
|
import { messages } from './messages';
|
|
14
14
|
const useFormattedErrorMessage = () => {
|
|
15
15
|
const [{
|
|
@@ -46,6 +46,61 @@ const useFormattedErrorMessage = () => {
|
|
|
46
46
|
}
|
|
47
47
|
return null;
|
|
48
48
|
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* This function maps client side validation errors and external messages into a unified format
|
|
52
|
+
* This is so that the output of this function can then be processed in a unified manner by different renderers
|
|
53
|
+
*
|
|
54
|
+
* ------ REMOVE THE FOLLOWING COMMENTS WITH THE FG CLEANUP OF gravityai-2553-fix-jql-debugger-flicker -----
|
|
55
|
+
* Cloned from useFormattedErrorMessage. Differences are:
|
|
56
|
+
* - return type is ExternalMessage[] instead of ReactNode
|
|
57
|
+
* - Stripped rendering logic away (i.e. FormatMessages) to make the implementation modular
|
|
58
|
+
*/
|
|
59
|
+
const useErrorMessages = () => {
|
|
60
|
+
const [{
|
|
61
|
+
formatMessage
|
|
62
|
+
}] = useIntl();
|
|
63
|
+
const [jqlError] = useJqlError();
|
|
64
|
+
const [{
|
|
65
|
+
errors: externalErrors
|
|
66
|
+
}] = useExternalMessages();
|
|
67
|
+
const [, {
|
|
68
|
+
externalErrorMessageViewed
|
|
69
|
+
}] = useStoreActions();
|
|
70
|
+
const editorViewIsInvalid = useEditorViewIsInvalid();
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
// Emit a UI event whenever external errors has changed
|
|
73
|
+
externalErrorMessageViewed();
|
|
74
|
+
}, [externalErrorMessageViewed, externalErrors]);
|
|
75
|
+
if (!editorViewIsInvalid) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Transform a string message to take the form of an ExternalMessage,
|
|
81
|
+
* so that we can reduce a bunch of conditionals when processing the output of useErrorMessages
|
|
82
|
+
*/
|
|
83
|
+
const toExternalMessageShape = message => [{
|
|
84
|
+
type: 'error',
|
|
85
|
+
message
|
|
86
|
+
}];
|
|
87
|
+
|
|
88
|
+
// Prioritise client errors over external errors
|
|
89
|
+
if (jqlError instanceof JQLSyntaxError) {
|
|
90
|
+
return toExternalMessageShape(`${jqlError.message} ${formatMessage(messages.jqlErrorPosition, {
|
|
91
|
+
lineNumber: jqlError.line,
|
|
92
|
+
charPosition: jqlError.charPositionInLine + 1
|
|
93
|
+
})}`);
|
|
94
|
+
}
|
|
95
|
+
if (externalErrors.length > 0) {
|
|
96
|
+
return externalErrors;
|
|
97
|
+
}
|
|
98
|
+
if (jqlError !== null) {
|
|
99
|
+
return toExternalMessageShape(formatMessage(commonMessages.unknownError));
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
103
|
+
|
|
49
104
|
/**
|
|
50
105
|
* This is a decorator component to include the editorTheme prop to the already passed list of props
|
|
51
106
|
*/
|
|
@@ -69,8 +124,39 @@ const CustomComponentDecoratedWithEditorTheme = props => {
|
|
|
69
124
|
export const ErrorMessages = () => {
|
|
70
125
|
const [editorId] = useScopedId(JQL_EDITOR_INPUT_ID);
|
|
71
126
|
const [validationId] = useScopedId(JQL_EDITOR_VALIDATION_ID);
|
|
72
|
-
|
|
127
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
128
|
+
const errorMessages = fg('gravityai-2553-fix-jql-debugger-flicker') ? useErrorMessages() : null;
|
|
129
|
+
const errorMessage = !fg('gravityai-2553-fix-jql-debugger-flicker') ?
|
|
130
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
131
|
+
useFormattedErrorMessage() : null;
|
|
73
132
|
const [CustomErrorComponent] = useCustomErrorComponent();
|
|
133
|
+
if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
|
|
134
|
+
const childrenToRender = errorMessages != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
|
|
135
|
+
testId: JQL_EDITOR_VALIDATION_ID
|
|
136
|
+
}, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
|
|
137
|
+
role: "alert",
|
|
138
|
+
id: validationId
|
|
139
|
+
}, /*#__PURE__*/React.createElement(FormatMessages, {
|
|
140
|
+
messages: errorMessages
|
|
141
|
+
})) : /*#__PURE__*/React.createElement("span", {
|
|
142
|
+
role: "alert",
|
|
143
|
+
"aria-describedby": editorId
|
|
144
|
+
}, /*#__PURE__*/React.createElement(FormatMessages, {
|
|
145
|
+
messages: errorMessages
|
|
146
|
+
})))) : null;
|
|
147
|
+
|
|
148
|
+
// Only render CustomErrorComponent if there is an errorMessage
|
|
149
|
+
if (errorMessages != null && CustomErrorComponent) {
|
|
150
|
+
return /*#__PURE__*/React.createElement(CustomComponentDecoratedWithEditorTheme, {
|
|
151
|
+
testId: JQL_EDITOR_VALIDATION_ID,
|
|
152
|
+
editorId: editorId,
|
|
153
|
+
validationId: validationId,
|
|
154
|
+
Component: CustomErrorComponent,
|
|
155
|
+
errorMessages: extractMessageNodes(errorMessages)
|
|
156
|
+
}, childrenToRender);
|
|
157
|
+
}
|
|
158
|
+
return childrenToRender;
|
|
159
|
+
}
|
|
74
160
|
const childrenToRender = errorMessage != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
|
|
75
161
|
testId: JQL_EDITOR_VALIDATION_ID
|
|
76
162
|
}, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
2
3
|
import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
|
|
3
4
|
import { MessageContainer as MessageContainerStyled, MessageList } from './styled';
|
|
4
5
|
|
|
@@ -17,6 +18,18 @@ export const MessageContainer = ({
|
|
|
17
18
|
export const FormatMessages = ({
|
|
18
19
|
messages
|
|
19
20
|
}) => {
|
|
21
|
+
if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
|
|
22
|
+
const messageNodes = extractMessageNodes(messages);
|
|
23
|
+
if (messageNodes.length === 0) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (messageNodes.length === 1) {
|
|
27
|
+
return /*#__PURE__*/React.createElement("span", null, messageNodes[0]);
|
|
28
|
+
}
|
|
29
|
+
return /*#__PURE__*/React.createElement(MessageList, null, messageNodes.map((m, i) => /*#__PURE__*/React.createElement("li", {
|
|
30
|
+
key: i
|
|
31
|
+
}, m)));
|
|
32
|
+
}
|
|
20
33
|
if (messages.length === 0) {
|
|
21
34
|
return null;
|
|
22
35
|
}
|
|
@@ -26,4 +39,14 @@ export const FormatMessages = ({
|
|
|
26
39
|
return /*#__PURE__*/React.createElement(MessageList, null, messages.slice(0, MAX_MESSAGES).map((m, i) => /*#__PURE__*/React.createElement("li", {
|
|
27
40
|
key: i
|
|
28
41
|
}, m.message)));
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
|
|
46
|
+
* This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
|
|
47
|
+
*
|
|
48
|
+
* Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
|
|
49
|
+
*/
|
|
50
|
+
export const extractMessageNodes = messages => {
|
|
51
|
+
return messages.slice(0, MAX_MESSAGES).map(m => /*#__PURE__*/React.createElement(React.Fragment, null, m.message));
|
|
29
52
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ANALYTICS_CHANNEL, useJqlPackageAnalytics } from '@atlaskit/jql-editor-common';
|
|
2
2
|
export var useJqlEditorAnalytics = function useJqlEditorAnalytics(analyticsSource) {
|
|
3
|
-
return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.0
|
|
3
|
+
return useJqlPackageAnalytics(analyticsSource, "@atlaskit/jql-editor", "5.1.0", ANALYTICS_CHANNEL);
|
|
4
4
|
};
|
package/dist/esm/state/index.js
CHANGED
|
@@ -445,10 +445,25 @@ export var actions = {
|
|
|
445
445
|
query = _getState7.query,
|
|
446
446
|
editorState = _getState7.editorState,
|
|
447
447
|
editorView = _getState7.editorView,
|
|
448
|
-
enableRichInlineNodes = _getState7.enableRichInlineNodes
|
|
448
|
+
enableRichInlineNodes = _getState7.enableRichInlineNodes,
|
|
449
|
+
onDebugUnsafeMessage = _getState7.onDebugUnsafeMessage;
|
|
449
450
|
var oldSelection = editorState.selection;
|
|
450
451
|
var updatedQuery = getNodeText(transaction.doc, 0, transaction.doc.content.size);
|
|
451
|
-
var updatedEditorState
|
|
452
|
+
var updatedEditorState;
|
|
453
|
+
try {
|
|
454
|
+
updatedEditorState = editorState.apply(transaction);
|
|
455
|
+
} catch (error) {
|
|
456
|
+
// We've observed several errors in Splunk from this step but we're unsure how to reproduce it. It seems to be some type of
|
|
457
|
+
// race condition where the transaction is applied to the editor state but the editor state is being updated in another transaction.
|
|
458
|
+
if (error instanceof RangeError && editorView) {
|
|
459
|
+
var message = "Error occurred trying to update editor state with the message: ".concat(error.message);
|
|
460
|
+
sendDebugMessage(message, editorView, editorState, onDebugUnsafeMessage, {
|
|
461
|
+
stack: error.stack,
|
|
462
|
+
transaction: JSON.stringify(transaction)
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
throw error;
|
|
466
|
+
}
|
|
452
467
|
|
|
453
468
|
// Update state in our editor view
|
|
454
469
|
if (editorView) {
|
|
@@ -12,7 +12,7 @@ import { commonMessages } from '../../../../common/messages';
|
|
|
12
12
|
import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
|
|
13
13
|
import { useEditorViewIsInvalid } from '../../../../hooks/use-editor-view-is-invalid';
|
|
14
14
|
import { useCustomErrorComponent, useExternalMessages, useIntl, useJqlError, useScopedId, useStoreActions } from '../../../../state';
|
|
15
|
-
import { FormatMessages, MessageContainer } from '../format';
|
|
15
|
+
import { extractMessageNodes, FormatMessages, MessageContainer } from '../format';
|
|
16
16
|
import { messages } from './messages';
|
|
17
17
|
var useFormattedErrorMessage = function useFormattedErrorMessage() {
|
|
18
18
|
var _useIntl = useIntl(),
|
|
@@ -51,6 +51,65 @@ var useFormattedErrorMessage = function useFormattedErrorMessage() {
|
|
|
51
51
|
}
|
|
52
52
|
return null;
|
|
53
53
|
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* This function maps client side validation errors and external messages into a unified format
|
|
57
|
+
* This is so that the output of this function can then be processed in a unified manner by different renderers
|
|
58
|
+
*
|
|
59
|
+
* ------ REMOVE THE FOLLOWING COMMENTS WITH THE FG CLEANUP OF gravityai-2553-fix-jql-debugger-flicker -----
|
|
60
|
+
* Cloned from useFormattedErrorMessage. Differences are:
|
|
61
|
+
* - return type is ExternalMessage[] instead of ReactNode
|
|
62
|
+
* - Stripped rendering logic away (i.e. FormatMessages) to make the implementation modular
|
|
63
|
+
*/
|
|
64
|
+
var useErrorMessages = function useErrorMessages() {
|
|
65
|
+
var _useIntl3 = useIntl(),
|
|
66
|
+
_useIntl4 = _slicedToArray(_useIntl3, 1),
|
|
67
|
+
formatMessage = _useIntl4[0].formatMessage;
|
|
68
|
+
var _useJqlError3 = useJqlError(),
|
|
69
|
+
_useJqlError4 = _slicedToArray(_useJqlError3, 1),
|
|
70
|
+
jqlError = _useJqlError4[0];
|
|
71
|
+
var _useExternalMessages3 = useExternalMessages(),
|
|
72
|
+
_useExternalMessages4 = _slicedToArray(_useExternalMessages3, 1),
|
|
73
|
+
externalErrors = _useExternalMessages4[0].errors;
|
|
74
|
+
var _useStoreActions3 = useStoreActions(),
|
|
75
|
+
_useStoreActions4 = _slicedToArray(_useStoreActions3, 2),
|
|
76
|
+
externalErrorMessageViewed = _useStoreActions4[1].externalErrorMessageViewed;
|
|
77
|
+
var editorViewIsInvalid = useEditorViewIsInvalid();
|
|
78
|
+
useEffect(function () {
|
|
79
|
+
// Emit a UI event whenever external errors has changed
|
|
80
|
+
externalErrorMessageViewed();
|
|
81
|
+
}, [externalErrorMessageViewed, externalErrors]);
|
|
82
|
+
if (!editorViewIsInvalid) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Transform a string message to take the form of an ExternalMessage,
|
|
88
|
+
* so that we can reduce a bunch of conditionals when processing the output of useErrorMessages
|
|
89
|
+
*/
|
|
90
|
+
var toExternalMessageShape = function toExternalMessageShape(message) {
|
|
91
|
+
return [{
|
|
92
|
+
type: 'error',
|
|
93
|
+
message: message
|
|
94
|
+
}];
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Prioritise client errors over external errors
|
|
98
|
+
if (jqlError instanceof JQLSyntaxError) {
|
|
99
|
+
return toExternalMessageShape("".concat(jqlError.message, " ").concat(formatMessage(messages.jqlErrorPosition, {
|
|
100
|
+
lineNumber: jqlError.line,
|
|
101
|
+
charPosition: jqlError.charPositionInLine + 1
|
|
102
|
+
})));
|
|
103
|
+
}
|
|
104
|
+
if (externalErrors.length > 0) {
|
|
105
|
+
return externalErrors;
|
|
106
|
+
}
|
|
107
|
+
if (jqlError !== null) {
|
|
108
|
+
return toExternalMessageShape(formatMessage(commonMessages.unknownError));
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
};
|
|
112
|
+
|
|
54
113
|
/**
|
|
55
114
|
* This is a decorator component to include the editorTheme prop to the already passed list of props
|
|
56
115
|
*/
|
|
@@ -76,10 +135,41 @@ export var ErrorMessages = function ErrorMessages() {
|
|
|
76
135
|
var _useScopedId3 = useScopedId(JQL_EDITOR_VALIDATION_ID),
|
|
77
136
|
_useScopedId4 = _slicedToArray(_useScopedId3, 1),
|
|
78
137
|
validationId = _useScopedId4[0];
|
|
79
|
-
|
|
138
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
139
|
+
var errorMessages = fg('gravityai-2553-fix-jql-debugger-flicker') ? useErrorMessages() : null;
|
|
140
|
+
var errorMessage = !fg('gravityai-2553-fix-jql-debugger-flicker') ?
|
|
141
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
142
|
+
useFormattedErrorMessage() : null;
|
|
80
143
|
var _useCustomErrorCompon = useCustomErrorComponent(),
|
|
81
144
|
_useCustomErrorCompon2 = _slicedToArray(_useCustomErrorCompon, 1),
|
|
82
145
|
CustomErrorComponent = _useCustomErrorCompon2[0];
|
|
146
|
+
if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
|
|
147
|
+
var _childrenToRender = errorMessages != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
|
|
148
|
+
testId: JQL_EDITOR_VALIDATION_ID
|
|
149
|
+
}, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
|
|
150
|
+
role: "alert",
|
|
151
|
+
id: validationId
|
|
152
|
+
}, /*#__PURE__*/React.createElement(FormatMessages, {
|
|
153
|
+
messages: errorMessages
|
|
154
|
+
})) : /*#__PURE__*/React.createElement("span", {
|
|
155
|
+
role: "alert",
|
|
156
|
+
"aria-describedby": editorId
|
|
157
|
+
}, /*#__PURE__*/React.createElement(FormatMessages, {
|
|
158
|
+
messages: errorMessages
|
|
159
|
+
})))) : null;
|
|
160
|
+
|
|
161
|
+
// Only render CustomErrorComponent if there is an errorMessage
|
|
162
|
+
if (errorMessages != null && CustomErrorComponent) {
|
|
163
|
+
return /*#__PURE__*/React.createElement(CustomComponentDecoratedWithEditorTheme, {
|
|
164
|
+
testId: JQL_EDITOR_VALIDATION_ID,
|
|
165
|
+
editorId: editorId,
|
|
166
|
+
validationId: validationId,
|
|
167
|
+
Component: CustomErrorComponent,
|
|
168
|
+
errorMessages: extractMessageNodes(errorMessages)
|
|
169
|
+
}, _childrenToRender);
|
|
170
|
+
}
|
|
171
|
+
return _childrenToRender;
|
|
172
|
+
}
|
|
83
173
|
var childrenToRender = errorMessage != null ? /*#__PURE__*/React.createElement(MessageContainer, null, /*#__PURE__*/React.createElement(ErrorMessage, {
|
|
84
174
|
testId: JQL_EDITOR_VALIDATION_ID
|
|
85
175
|
}, fg('jql_editor_a11y') ? /*#__PURE__*/React.createElement("span", {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
2
3
|
import { useEditorThemeContext } from '../../../../hooks/use-editor-theme';
|
|
3
4
|
import { MessageContainer as MessageContainerStyled, MessageList } from './styled';
|
|
4
5
|
|
|
@@ -14,6 +15,20 @@ export var MessageContainer = function MessageContainer(_ref) {
|
|
|
14
15
|
};
|
|
15
16
|
export var FormatMessages = function FormatMessages(_ref2) {
|
|
16
17
|
var messages = _ref2.messages;
|
|
18
|
+
if (fg('gravityai-2553-fix-jql-debugger-flicker')) {
|
|
19
|
+
var messageNodes = extractMessageNodes(messages);
|
|
20
|
+
if (messageNodes.length === 0) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (messageNodes.length === 1) {
|
|
24
|
+
return /*#__PURE__*/React.createElement("span", null, messageNodes[0]);
|
|
25
|
+
}
|
|
26
|
+
return /*#__PURE__*/React.createElement(MessageList, null, messageNodes.map(function (m, i) {
|
|
27
|
+
return /*#__PURE__*/React.createElement("li", {
|
|
28
|
+
key: i
|
|
29
|
+
}, m);
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
17
32
|
if (messages.length === 0) {
|
|
18
33
|
return null;
|
|
19
34
|
}
|
|
@@ -25,4 +40,16 @@ export var FormatMessages = function FormatMessages(_ref2) {
|
|
|
25
40
|
key: i
|
|
26
41
|
}, m.message);
|
|
27
42
|
}));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
|
|
47
|
+
* This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
|
|
48
|
+
*
|
|
49
|
+
* Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
|
|
50
|
+
*/
|
|
51
|
+
export var extractMessageNodes = function extractMessageNodes(messages) {
|
|
52
|
+
return messages.slice(0, MAX_MESSAGES).map(function (m) {
|
|
53
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, m.message);
|
|
54
|
+
});
|
|
28
55
|
};
|
|
@@ -69,7 +69,12 @@ export type CustomErrorComponent = React.ComponentType<PropsWithChildren<{
|
|
|
69
69
|
testId: string;
|
|
70
70
|
editorTheme: EditorTheme;
|
|
71
71
|
editorId: string;
|
|
72
|
+
errorMessages?: React.ReactElement[];
|
|
73
|
+
validationId?: string;
|
|
72
74
|
}>>;
|
|
75
|
+
export type CustomErrorMessageProps = Omit<React.ComponentProps<CustomErrorComponent>, 'editorTheme'> & {
|
|
76
|
+
Component: CustomErrorComponent;
|
|
77
|
+
};
|
|
73
78
|
export type CustomComponents = {
|
|
74
79
|
ErrorMessage?: CustomErrorComponent;
|
|
75
80
|
};
|
|
@@ -6,3 +6,10 @@ export declare const MessageContainer: ({ children }: {
|
|
|
6
6
|
export declare const FormatMessages: ({ messages }: {
|
|
7
7
|
messages: ExternalMessage[];
|
|
8
8
|
}) => React.JSX.Element | null;
|
|
9
|
+
/**
|
|
10
|
+
* This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
|
|
11
|
+
* This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
|
|
12
|
+
*
|
|
13
|
+
* Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
|
|
14
|
+
*/
|
|
15
|
+
export declare const extractMessageNodes: (messages: ExternalMessage[]) => React.ReactElement[];
|
|
@@ -69,7 +69,12 @@ export type CustomErrorComponent = React.ComponentType<PropsWithChildren<{
|
|
|
69
69
|
testId: string;
|
|
70
70
|
editorTheme: EditorTheme;
|
|
71
71
|
editorId: string;
|
|
72
|
+
errorMessages?: React.ReactElement[];
|
|
73
|
+
validationId?: string;
|
|
72
74
|
}>>;
|
|
75
|
+
export type CustomErrorMessageProps = Omit<React.ComponentProps<CustomErrorComponent>, 'editorTheme'> & {
|
|
76
|
+
Component: CustomErrorComponent;
|
|
77
|
+
};
|
|
73
78
|
export type CustomComponents = {
|
|
74
79
|
ErrorMessage?: CustomErrorComponent;
|
|
75
80
|
};
|
|
@@ -6,3 +6,10 @@ export declare const MessageContainer: ({ children }: {
|
|
|
6
6
|
export declare const FormatMessages: ({ messages }: {
|
|
7
7
|
messages: ExternalMessage[];
|
|
8
8
|
}) => React.JSX.Element | null;
|
|
9
|
+
/**
|
|
10
|
+
* This function was extracted from FormatMessages, so that the rendering is decoupled from the logic
|
|
11
|
+
* This is so that the extractMessageNodes can used elsewhere where rendering is delegated to a different renderer
|
|
12
|
+
*
|
|
13
|
+
* Simply put, this function only handles getting m.message, and limiting to MAX_MESSAGES
|
|
14
|
+
*/
|
|
15
|
+
export declare const extractMessageNodes: (messages: ExternalMessage[]) => React.ReactElement[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/jql-editor",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "This package allows consumers to render an advanced JQL editor component to enable autocomplete-assisted authoring and validation of JQL queries.",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"@atlaskit/jql-parser": "^2.0.0",
|
|
51
51
|
"@atlaskit/legacy-custom-icons": "^0.22.0",
|
|
52
52
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
53
|
-
"@atlaskit/primitives": "^14.
|
|
53
|
+
"@atlaskit/primitives": "^14.2.0",
|
|
54
54
|
"@atlaskit/spinner": "^18.0.0",
|
|
55
55
|
"@atlaskit/theme": "^18.0.0",
|
|
56
|
-
"@atlaskit/tokens": "^4.
|
|
56
|
+
"@atlaskit/tokens": "^4.5.0",
|
|
57
57
|
"@atlaskit/tooltip": "^20.0.0",
|
|
58
58
|
"@babel/runtime": "^7.0.0",
|
|
59
59
|
"@emotion/react": "^11.7.1",
|
|
@@ -136,6 +136,9 @@
|
|
|
136
136
|
},
|
|
137
137
|
"jql_editor_a11y": {
|
|
138
138
|
"type": "boolean"
|
|
139
|
+
},
|
|
140
|
+
"gravityai-2553-fix-jql-debugger-flicker": {
|
|
141
|
+
"type": "boolean"
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
144
|
}
|