Skip to content

[Lens] Create filters on click with bar, line, area charts#57261

Merged
mbondyra merged 37 commits intoelastic:masterfrom
wylieconlon:lens/click-actions
Mar 24, 2020
Merged

[Lens] Create filters on click with bar, line, area charts#57261
mbondyra merged 37 commits intoelastic:masterfrom
wylieconlon:lens/click-actions

Conversation

@wylieconlon
Copy link
Copy Markdown
Contributor

@wylieconlon wylieconlon commented Feb 10, 2020

Release note

Lens now supports filtering in dashboards and the Lens editor for the bar, line and area visualizations.

Closes #52806

Checklist

Delete any items that are not applicable to this PR.

@wylieconlon wylieconlon added release_note:enhancement Team:Visualizations Team label for Lens, elastic-charts, Graph, legacy editors (TSVB, Visualize, Timelion) t// v8.0.0 Feature:Lens v7.7.0 labels Feb 10, 2020
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-app (Team:KibanaApp)

import { EuiIcon, EuiText, IconType, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { npStart } from 'ui/new_platform';
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely need to remove this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: I cleaned up the shimmed plugin structure in #56976

handlers,
}: XYChartRenderProps & {
handlers: IInterpreterRenderHandlers;
}) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppisljar I can't tell if it's better to do handlers.event(...) vs npStart.plugins.uiActions.executeTriggerActions('VALUE_CLICK_TRIGGER',, can you clarify the expected use?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handlers.event is better because it avoids direct, legacy access of npStart.plugins.uiActions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stacey-gammon could you clarify what API on handlers can be used to executeTriggerActions? I am not finding any API that could used to get access to uiActions via handlers?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the plan was to expose uiActions on handles, either from work Peter was doing, or Wylie. Afaik it is not exposed on handler on master, but I haven't kept up with the status.

column: table.columns.findIndex(col => col.id === layer.splitAccessor),
value: pointValue,
});
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@markov00 This logic is the logic I was expecting to have included in the chart library itself

@cqliu1 cqliu1 mentioned this pull request Mar 4, 2020
4 tasks
@mbondyra
Copy link
Copy Markdown
Contributor

@elasticmachine merge upstream

@elasticmachine
Copy link
Copy Markdown
Contributor

merge conflict between base and head

@streamich streamich mentioned this pull request Mar 16, 2020
5 tasks
# Conflicts:
#	src/legacy/core_plugins/data/public/actions/value_click_action.ts
@mbondyra mbondyra force-pushed the lens/click-actions branch from 231801d to 916f9dd Compare March 17, 2020 13:42
@mbondyra mbondyra force-pushed the lens/click-actions branch from 6f21737 to 5cd1af8 Compare March 18, 2020 13:10
Copy link
Copy Markdown
Contributor Author

@wylieconlon wylieconlon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I could approve my own PR, I would!

data,
editorFrame: editorFrameSetupInterface,
formatFactory,
executeTriggerActions: npStart.plugins.uiActions.executeTriggerActions,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically tech debt already, but I don't see an alternative that exists.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use npStart here, pass your dependencies into setup method.
once you are in new platform the second parameter to setup() wil lbe all the plugin contracts.
currently you already get the expressions, data and embeddable there ... add uiActions (between line 86 and 87) there as well

@wylieconlon wylieconlon changed the title [Lens] Apply filters from click in Lens visualizations [Lens] Create filters on click with bar, line, area charts Mar 23, 2020
Copy link
Copy Markdown
Contributor

@ppisljar ppisljar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code LGTM, apart from the comment above

const pluginInstance = plugin();
pluginInstance.setup(npSetup.core, {
...npSetup.plugins,
uiActions: npStart.plugins.uiActions,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not look correct. We cannot (technically in legacy platform we can, but it would break as soon as we move to Kibana platform) inject a start dependency into the setup phase of the plugin (that runs before the start phase).

If we get access to the uiActions only via the start contract, we need to pass it down from the start method of our plugin instead. We can use the createGetterSetter utils in kibana_utils to store a reference of it in start and use it later when clicking.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, thats right ... general problem, what to do when you need to register something to a registry (needs to happen in setup phase) but the thing you are registering has a start dependencies.

what we usually do is

  • create services.ts file and create uiActions getter and setter (check visualizations plugin, data plugin, expression plugin, ...)
  • wherever you need the uiActions use the getter
  • in your plugins start lifecycle method use the setter to set the reference
  • make sure you don't expose anything using the getter as a static export

Copy link
Copy Markdown
Contributor

@flash1293 flash1293 Mar 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have the same problem with “formatFactory” (currently importer via legacy imports, but actually exposed in the start phase. In a separate Pr I solved this problem by passing down a promise of the contract and resolve if needed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I've been solving this @flash1293's way, which I think is the correct way, it follows the pattern of coreSetup.getStartServices. So what would get passed down to handlers I think is async getUiActionsService() and that can be something like:

const getUiActionsService: async () =>  await coreSetup.getStartServices()[1].uiActions;

Expression fns are async so I think this should work fine. I think we should prefer that pattern over the getter/setter.

cc @joshdover

import { LensMultiTable } from '../types';
import React from 'react';
import { shallow } from 'enzyme';
import { mount, shallow, ReactWrapper } from 'enzyme';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use import { mountWithIntl } from 'test_utils/enzyme_helpers' instead, since that takes care about our i18n framework. Even if we don't have any call in it right now, this will prevent us from needing to change all calls later, in case we would ever introduce any messages within this component.

const table = data.tables[layerId];
const rows = table.rows.filter(
row =>
!(splitAccessor && !row[splitAccessor] && accessors.every(accessor => !row[accessor]))

This comment was marked as outdated.

row => layer.xAccessor && row[layer.xAccessor] === xyGeometry.x
),
column: table.columns.findIndex(col => col.id === layer.xAccessor),
value: (xyGeometry as GeometryValue).x,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
value: (xyGeometry as GeometryValue).x,
value: xyGeometry.x,

We already cast above.

Comment on lines +228 to +229
const xySeries = series as XYChartSeriesIdentifier;
const xyGeometry = geometry as GeometryValue;

This comment was marked as outdated.

Comment on lines +44 to +48
export interface XYChartSeriesIdentifier {
yAccessor: string | number;
splitAccessors: Map<string | number, string | number>; // does the map have a size vs making it optional
seriesKeys: Array<string | number>;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this type is now exposed by the chart library itself and we don't need to put this here manually.

Comment on lines +265 to +266
const timeFieldName =
xDomain && xAxisFieldName ? { timeFieldName: xAxisFieldName } : null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 Code Style suggestion:

const timeFieldName = xDomain && xAxisFieldName;
// ...
const context = {
  timeFieldName, // no weird spread needed.
}

Don't see why we would want to wrap it in an object to spread it further down immediately again?

});
}

const xAxisFieldName = table.columns.find(col => col.id === layer.xAccessor)?.meta
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best example of why unknown should always be preferred over any. Since meta is any we suddenly start spreading any here, and everything accessing xAxisFieldName will suddenly become any too.

Let's type here explicitly to prevent that: const xAxisFieldName: string | undefined = ....

import { EditorFrameSetup } from '../types';

import { UiActionsStart } from '../../../../../../src/plugins/ui_actions/public';
import { setExecuteTriggerActions } from './services';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 Could we please insert an empty line after the imports.


editorFrame.registerVisualization(xyVisualization);
}
start(core: CoreStart, { uiActions }: XyVisualizationPluginStartPlugins) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 ... and an empty line before new methods in a class

Copy link
Copy Markdown
Contributor

@timroes timroes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left two last code style comments. Besides that this looks good for me. Tested on Chrome Linux, in the editor and on dashboards. Seems to create filters correctly for several different chart configurations (we know there are some weird behaviors around multiple layers with mixed primary/non-primary time fields). LGTM

@kibanamachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature:Lens release_note:enhancement Team:Visualizations Team label for Lens, elastic-charts, Graph, legacy editors (TSVB, Visualize, Timelion) t// v7.7.0 v8.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Lens] Trigger a filter action on click in embedded visualizations for xychart

8 participants