mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Lens] Hide fix action when in embeddable (#213414)
## Summary
Related to #177932
Inline editing introduced a blurred boundary for the editing experience
in Lens, while the full editor relies on a Redux state manager to
dispatch state changes the inline editor has an hybrid approach.
Specifically the `fixAction` feature in the user messages system needs
access to the redux store which is not available within the embeddable
environment as for now.
So with this PR I've currently limited the scope provided for those
message with a `fixAction` and won't render the button any more.
For instance while investigating #177932 I've noticed that now the
embeddable doesn't crash any more, but rather shows the error message
with the `fixAction` button:
<img width="1496" alt="Screenshot 2025-03-06 at 16 07 35"
src="https://github.com/user-attachments/assets/1b2a5d73-56d9-4010-8a6f-82528efcb2ce"
/>
Note that clicking on the `Use filters` nothing will happen as
d2412a5f98/x-pack/platform/plugins/shared/lens/public/react_embeddable/user_messages/api.ts (L195)
is a mock. A simple `updateAttributes` call here won't suffice as it
requires the logic behind `updateDatasourceState` slice to harmonize the
datasource changes with the visualisation counter part.
With this PR the message will hide the button and render as follow:
<img width="1498" alt="Screenshot 2025-03-06 at 16 18 55"
src="https://github.com/user-attachments/assets/01d55f6c-7563-4e07-a18e-35d1062a8d79"
/>
It is a temporary fix but at least it won't feel broken.
### Checklist
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
parent
b731d759e8
commit
3c3038b855
8 changed files with 95 additions and 62 deletions
|
@ -934,7 +934,7 @@ function blankLayer(indexPatternId: string, linkToLayers?: string[]): FormBasedL
|
|||
function getLayerErrorMessages(
|
||||
state: FormBasedPrivateState,
|
||||
framePublicAPI: FramePublicAPI,
|
||||
setState: StateSetter<FormBasedPrivateState, unknown>,
|
||||
setState: StateSetter<FormBasedPrivateState, unknown> | undefined,
|
||||
core: CoreStart,
|
||||
data: DataPublicPluginStart
|
||||
): UserMessage[] {
|
||||
|
@ -962,7 +962,7 @@ function getLayerErrorMessages(
|
|||
) : (
|
||||
<>
|
||||
{error.message}
|
||||
{error.fixAction && (
|
||||
{error.fixAction && setState && (
|
||||
<EuiButton
|
||||
data-test-subj="errorFixAction"
|
||||
onClick={async () => {
|
||||
|
|
|
@ -150,12 +150,12 @@ export function getDisallowedTermsMessage(
|
|||
currentColumn.sourceField,
|
||||
...(currentColumn.params?.secondaryFields ?? []),
|
||||
];
|
||||
const table = frame.activeData?.[layerId] || frame.activeData?.default;
|
||||
const activeDataFieldNameMatch =
|
||||
frame.activeData?.[layerId].columns.find(({ id }) => id === columnId)?.meta.field ===
|
||||
fieldNames[0];
|
||||
table?.columns.find(({ id }) => id === columnId)?.meta.field === fieldNames[0];
|
||||
|
||||
let currentTerms = uniq(
|
||||
frame.activeData?.[layerId].rows
|
||||
table?.rows
|
||||
.map((row) => row[columnId] as string | MultiFieldKeyFormat)
|
||||
.filter((term) =>
|
||||
fieldNames.length > 1
|
||||
|
|
|
@ -10,6 +10,7 @@ import { CoreStart } from '@kbn/core/public';
|
|||
import type { Query } from '@kbn/es-query';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import { DataPublicPluginStart, UI_SETTINGS } from '@kbn/data-plugin/public';
|
||||
import { nonNullable } from '../../../utils';
|
||||
import type { DateRange } from '../../../../common/types';
|
||||
import type {
|
||||
DatasourceFixAction,
|
||||
|
@ -1567,7 +1568,7 @@ export function getErrorMessages(
|
|||
const skippedColumns = visibleManagedReferences.flatMap(([columnId]) =>
|
||||
getManagedColumnsFrom(columnId, layer.columns).map(([id]) => id)
|
||||
);
|
||||
const errors = columns
|
||||
const errors: LayerErrorMessage[] = columns
|
||||
.flatMap(([columnId, column]) => {
|
||||
if (skippedColumns.includes(columnId)) {
|
||||
return;
|
||||
|
@ -1606,7 +1607,7 @@ export function getErrorMessages(
|
|||
};
|
||||
})
|
||||
// remove the undefined values
|
||||
.filter((v) => v != null) as LayerErrorMessage[];
|
||||
.filter(nonNullable) as LayerErrorMessage[];
|
||||
|
||||
return errors.length ? errors : undefined;
|
||||
}
|
||||
|
|
|
@ -134,6 +134,22 @@ describe('indexpattern_datasource utils', () => {
|
|||
expect(setStateMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should not render a fix link if no setState is provided', () => {
|
||||
framePublicAPI.activeData!.id.columns[0].meta.sourceParams!.hasPrecisionError = true;
|
||||
const warningMessages = getPrecisionErrorWarningMessages(
|
||||
datatableUtilitites,
|
||||
state,
|
||||
framePublicAPI,
|
||||
docLinks
|
||||
);
|
||||
|
||||
render(<I18nProvider>{getLongMessage(warningMessages[0])}</I18nProvider>);
|
||||
screen.debug();
|
||||
// Make sure the message is there before checking the absence of the link/button
|
||||
expect(screen.getByText(/might be an approximation./)).toBeInTheDocument();
|
||||
expect(screen.queryByText('Enable accuracy mode')).toBe(null);
|
||||
});
|
||||
|
||||
test('should other suggestions if accuracy mode already enabled', async () => {
|
||||
framePublicAPI.activeData!.id.columns[0].meta.sourceParams!.hasPrecisionError = true;
|
||||
(state.layers.id.columns.col1 as TermsIndexPatternColumn).params.accuracyMode = true;
|
||||
|
|
|
@ -182,7 +182,7 @@ export function fieldIsInvalid(
|
|||
const accuracyModeDisabledWarning = (
|
||||
columnName: string,
|
||||
columnId: string,
|
||||
enableAccuracyMode: () => void
|
||||
enableAccuracyMode?: () => void
|
||||
): UserMessage => ({
|
||||
uniqueId: PRECISION_ERROR_ACCURACY_MODE_DISABLED,
|
||||
severity: 'warning',
|
||||
|
@ -204,12 +204,16 @@ const accuracyModeDisabledWarning = (
|
|||
name: <strong>{columnName}</strong>,
|
||||
}}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiLink data-test-subj="lnsPrecisionWarningEnableAccuracy" onClick={enableAccuracyMode}>
|
||||
{i18n.translate('xpack.lens.indexPattern.enableAccuracyMode', {
|
||||
defaultMessage: 'Enable accuracy mode',
|
||||
})}
|
||||
</EuiLink>
|
||||
{enableAccuracyMode ? (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiLink data-test-subj="lnsPrecisionWarningEnableAccuracy" onClick={enableAccuracyMode}>
|
||||
{i18n.translate('xpack.lens.indexPattern.enableAccuracyMode', {
|
||||
defaultMessage: 'Enable accuracy mode',
|
||||
})}
|
||||
</EuiLink>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
});
|
||||
|
@ -442,7 +446,7 @@ export function getPrecisionErrorWarningMessages(
|
|||
state: FormBasedPrivateState,
|
||||
{ activeData, dataViews }: FramePublicAPI,
|
||||
docLinks: DocLinksStart,
|
||||
setState: StateSetter<FormBasedPrivateState>
|
||||
setState?: StateSetter<FormBasedPrivateState>
|
||||
) {
|
||||
const warningMessages: UserMessage[] = [];
|
||||
|
||||
|
@ -491,23 +495,29 @@ export function getPrecisionErrorWarningMessages(
|
|||
column.id,
|
||||
docLinks.links.aggs.terms_doc_count_error
|
||||
)
|
||||
: accuracyModeDisabledWarning(column.name, column.id, () => {
|
||||
setState((prevState) =>
|
||||
mergeLayer({
|
||||
state: prevState,
|
||||
layerId,
|
||||
newLayer: updateDefaultLabels(
|
||||
updateColumnParam({
|
||||
layer: currentLayer,
|
||||
columnId: column.id,
|
||||
paramName: 'accuracyMode',
|
||||
value: true,
|
||||
}),
|
||||
indexPattern
|
||||
),
|
||||
})
|
||||
);
|
||||
})
|
||||
: accuracyModeDisabledWarning(
|
||||
column.name,
|
||||
column.id,
|
||||
setState
|
||||
? () => {
|
||||
setState((prevState) =>
|
||||
mergeLayer({
|
||||
state: prevState,
|
||||
layerId,
|
||||
newLayer: updateDefaultLabels(
|
||||
updateColumnParam({
|
||||
layer: currentLayer,
|
||||
columnId: column.id,
|
||||
paramName: 'accuracyMode',
|
||||
value: true,
|
||||
}),
|
||||
indexPattern
|
||||
),
|
||||
})
|
||||
);
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
);
|
||||
} else {
|
||||
warningMessages.push({
|
||||
|
@ -545,33 +555,37 @@ export function getPrecisionErrorWarningMessages(
|
|||
),
|
||||
}}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiLink
|
||||
onClick={() => {
|
||||
setState((prevState) =>
|
||||
mergeLayer({
|
||||
state: prevState,
|
||||
layerId,
|
||||
newLayer: updateDefaultLabels(
|
||||
updateColumnParam({
|
||||
layer: currentLayer,
|
||||
columnId: column.id,
|
||||
paramName: 'orderBy',
|
||||
value: {
|
||||
type: 'rare',
|
||||
maxDocCount: DEFAULT_MAX_DOC_COUNT,
|
||||
},
|
||||
}),
|
||||
indexPattern
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
{i18n.translate('xpack.lens.indexPattern.switchToRare', {
|
||||
defaultMessage: 'Rank by rarity',
|
||||
})}
|
||||
</EuiLink>
|
||||
{setState ? (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiLink
|
||||
onClick={() => {
|
||||
setState((prevState) =>
|
||||
mergeLayer({
|
||||
state: prevState,
|
||||
layerId,
|
||||
newLayer: updateDefaultLabels(
|
||||
updateColumnParam({
|
||||
layer: currentLayer,
|
||||
columnId: column.id,
|
||||
paramName: 'orderBy',
|
||||
value: {
|
||||
type: 'rare',
|
||||
maxDocCount: DEFAULT_MAX_DOC_COUNT,
|
||||
},
|
||||
}),
|
||||
indexPattern
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
{i18n.translate('xpack.lens.indexPattern.switchToRare', {
|
||||
defaultMessage: 'Rank by rarity',
|
||||
})}
|
||||
</EuiLink>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
fixableInEditor: true,
|
||||
|
|
|
@ -192,7 +192,8 @@ export function buildUserMessagesHelpers(
|
|||
|
||||
userMessages.push(
|
||||
...(activeDatasource?.getUserMessages(activeDatasourceState, {
|
||||
setState: () => {},
|
||||
// limit the fixAction within the embeddable for now
|
||||
setState: undefined,
|
||||
frame: framePublicAPI,
|
||||
visualizationInfo: activeVisualization?.getVisualizationInfo?.(
|
||||
activeVisualizationState,
|
||||
|
|
|
@ -480,7 +480,7 @@ export interface Datasource<T = unknown, P = unknown, Q = Query | AggregateQuery
|
|||
state: T,
|
||||
deps: {
|
||||
frame: FramePublicAPI;
|
||||
setState: StateSetter<T>;
|
||||
setState?: StateSetter<T>;
|
||||
visualizationInfo?: VisualizationInfo;
|
||||
}
|
||||
) => UserMessage[];
|
||||
|
@ -532,6 +532,7 @@ export interface Datasource<T = unknown, P = unknown, Q = Query | AggregateQuery
|
|||
|
||||
export interface DatasourceFixAction<T> {
|
||||
label: string;
|
||||
isCompatible?: (frame: FramePublicAPI) => boolean;
|
||||
newState: (frame: FramePublicAPI) => Promise<T>;
|
||||
}
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await lens.assertFocusedField('clientip');
|
||||
});
|
||||
it('should duplicate an element in a group', async () => {
|
||||
await lens.dimensionKeyboardDragDrop('lnsXY_yDimensionPanel', 0, 1);
|
||||
await lens.dimensionKeyboardDragDrop('lnsXY_yDimensionPanel', 0, 2);
|
||||
expect(await lens.getDimensionTriggersTexts('lnsXY_yDimensionPanel')).to.eql([
|
||||
'Count of records',
|
||||
'Median of bytes',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue