-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Lens] Visualization validation and better error messages #81439
Changes from 45 commits
1bed7c0
bb93701
0aea6c5
d389d85
4c48b23
91a700a
b1d71dd
be2312d
c64603a
8e77401
64a22ef
7089b2f
86cc058
4e0c179
6672302
ee80a6b
f1127f4
95f9daf
ce7f857
d88d55d
694757b
0277aa5
822a23e
957bd98
7bfabd1
2fd7a90
4464285
e039c4f
a84fad2
d06f099
135c40d
b12a320
9f5d951
f984d5d
5e265ae
4b3c36a
c7fdd61
d0bce6b
cb0214e
d3fabc2
6c27723
9437162
4ac3bd8
6798112
8d31435
97dc1ae
33b71fa
0a0f5d3
37dca5a
fa32b19
1a440a9
cdb7054
11caf4a
8ccd1d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,41 +61,48 @@ const PreviewRenderer = ({ | |
withLabel, | ||
ExpressionRendererComponent, | ||
expression, | ||
hasError, | ||
}: { | ||
withLabel: boolean; | ||
expression: string; | ||
expression: string | null | undefined; | ||
ExpressionRendererComponent: ReactExpressionRendererType; | ||
hasError: boolean; | ||
}) => { | ||
const onErrorMessage = ( | ||
<div className="lnsSuggestionPanel__suggestionIcon"> | ||
<EuiIconTip | ||
size="xl" | ||
color="danger" | ||
type="alert" | ||
aria-label={i18n.translate('xpack.lens.editorFrame.previewErrorLabel', { | ||
defaultMessage: 'Preview rendering failed', | ||
})} | ||
content={i18n.translate('xpack.lens.editorFrame.previewErrorLabel', { | ||
defaultMessage: 'Preview rendering failed', | ||
})} | ||
/> | ||
</div> | ||
); | ||
return ( | ||
<div | ||
className={classNames('lnsSuggestionPanel__chartWrapper', { | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
'lnsSuggestionPanel__chartWrapper--withLabel': withLabel, | ||
})} | ||
> | ||
<ExpressionRendererComponent | ||
className="lnsSuggestionPanel__expressionRenderer" | ||
padding="s" | ||
expression={expression} | ||
debounce={2000} | ||
renderError={() => { | ||
return ( | ||
<div className="lnsSuggestionPanel__suggestionIcon"> | ||
<EuiIconTip | ||
size="xl" | ||
color="danger" | ||
type="alert" | ||
aria-label={i18n.translate('xpack.lens.editorFrame.previewErrorLabel', { | ||
defaultMessage: 'Preview rendering failed', | ||
})} | ||
content={i18n.translate('xpack.lens.editorFrame.previewErrorLabel', { | ||
defaultMessage: 'Preview rendering failed', | ||
})} | ||
/> | ||
</div> | ||
); | ||
}} | ||
/> | ||
{!expression || hasError ? ( | ||
onErrorMessage | ||
) : ( | ||
<ExpressionRendererComponent | ||
className="lnsSuggestionPanel__expressionRenderer" | ||
padding="s" | ||
expression={expression} | ||
debounce={2000} | ||
renderError={() => { | ||
return onErrorMessage; | ||
}} | ||
/> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
@@ -112,6 +119,7 @@ const SuggestionPreview = ({ | |
expression?: Ast | null; | ||
icon: IconType; | ||
title: string; | ||
error?: boolean; | ||
}; | ||
ExpressionRenderer: ReactExpressionRendererType; | ||
selected: boolean; | ||
|
@@ -129,11 +137,12 @@ const SuggestionPreview = ({ | |
data-test-subj="lnsSuggestion" | ||
onClick={onSelect} | ||
> | ||
{preview.expression ? ( | ||
{preview.expression || preview.error ? ( | ||
<PreviewRenderer | ||
ExpressionRendererComponent={ExpressionRendererComponent} | ||
expression={toExpression(preview.expression)} | ||
expression={preview.expression && toExpression(preview.expression)} | ||
withLabel={Boolean(showTitleAsLabel)} | ||
hasError={Boolean(preview.error)} | ||
/> | ||
) : ( | ||
<span className="lnsSuggestionPanel__suggestionIcon"> | ||
|
@@ -170,14 +179,21 @@ export function SuggestionPanel({ | |
? stagedPreview.visualization.activeId | ||
: activeVisualizationId; | ||
|
||
const { suggestions, currentStateExpression } = useMemo(() => { | ||
const { suggestions, currentStateExpression, currentStateError } = useMemo(() => { | ||
const newSuggestions = getSuggestions({ | ||
datasourceMap, | ||
datasourceStates: currentDatasourceStates, | ||
visualizationMap, | ||
activeVisualizationId: currentVisualizationId, | ||
visualizationState: currentVisualizationState, | ||
}) | ||
.filter(({ visualizationId, visualizationState: suggestionVisualizationState }) => { | ||
const suggestionVisualization = visualizationMap[visualizationId]; | ||
// filter out visualizations with errors | ||
return ( | ||
suggestionVisualization.getErrorMessages(suggestionVisualizationState, frame) == null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not checking whether the datasource contains errors - we should use the same logic here as for the workspace panel. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The check is below the new suggestion creation. |
||
); | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still looking for an easy way to reproduce, but I was able to get this error message after switching charts when the starting state was invalid:
it's probably a race condition There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I managed to reproduce this in the It is probably an issue that requires to be addressed in a separate PR. I'll open an issue about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created issue #82253 |
||
.map((suggestion) => ({ | ||
...suggestion, | ||
previewExpression: preparePreviewExpression( | ||
|
@@ -191,8 +207,22 @@ export function SuggestionPanel({ | |
.filter((suggestion) => !suggestion.hide) | ||
.slice(0, MAX_SUGGESTIONS_DISPLAYED); | ||
|
||
const activeDatasource = activeDatasourceId ? datasourceMap[activeDatasourceId] : null; | ||
const datasourceValidationErrors = activeDatasourceId | ||
? activeDatasource?.getErrorMessages(currentDatasourceStates[activeDatasourceId]?.state) | ||
: undefined; | ||
|
||
const visualizationValidationErrors = currentVisualizationId | ||
? visualizationMap[currentVisualizationId]?.getErrorMessages(currentVisualizationState, frame) | ||
: undefined; | ||
|
||
const validationErrors = | ||
datasourceValidationErrors || visualizationValidationErrors | ||
? [...(datasourceValidationErrors || []), ...(visualizationValidationErrors || [])] | ||
: undefined; | ||
|
||
const newStateExpression = | ||
currentVisualizationState && currentVisualizationId | ||
currentVisualizationState && currentVisualizationId && !validationErrors | ||
? preparePreviewExpression( | ||
{ visualizationState: currentVisualizationState }, | ||
visualizationMap[currentVisualizationId], | ||
|
@@ -202,14 +232,19 @@ export function SuggestionPanel({ | |
) | ||
: undefined; | ||
|
||
return { suggestions: newSuggestions, currentStateExpression: newStateExpression }; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was kept on purpose - otherwise the suggestions are recalculated too often because the frame object gets recreated on each render. This hook should not depend on the frame object. Maybe this is causing the issue with |
||
return { | ||
suggestions: newSuggestions, | ||
currentStateExpression: newStateExpression, | ||
currentStateError: validationErrors, | ||
}; | ||
}, [ | ||
currentDatasourceStates, | ||
currentVisualizationState, | ||
currentVisualizationId, | ||
activeDatasourceId, | ||
datasourceMap, | ||
visualizationMap, | ||
frame, | ||
]); | ||
|
||
const context: ExecutionContextSearch = useMemo( | ||
|
@@ -305,6 +340,7 @@ export function SuggestionPanel({ | |
{currentVisualizationId && ( | ||
<SuggestionPreview | ||
preview={{ | ||
error: currentStateError != null, | ||
expression: currentStateExpression, | ||
icon: | ||
visualizationMap[currentVisualizationId].getDescription(currentVisualizationState) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New order: