Skip to content

Commit 6beb382

Browse files
authored
Drilldown demo 2 (#64300)
* chore: πŸ€– add example of Discover drilldown to sample plugin * fix: πŸ› show drilldowns with higher "order" first * feat: 🎸 add createStartServicesGetter() to /public kibana_util * feat: 🎸 load index patterns in Discover drilldown * feat: 🎸 add toggle for index pattern selection * feat: 🎸 add spacer to separate unrelated config fields * fix: πŸ› correctly configre setup core * feat: 🎸 navigate to correct index pattern * chore: πŸ€– fix type check errors * fix: πŸ› make index pattern select full width * fix: πŸ› add getHref support * feat: 🎸 add example plugin ability to X-Pack * refactor: πŸ’‘ move Discover drilldown example to X-Pack * feat: 🎸 add dashboard-to-url drilldown example * feat: 🎸 add new tab support for URL drilldown * feat: 🎸 add "hello world" drilldown example * docs: ✏️ add README * feat: 🎸 add getHref support * chore: πŸ€– cleanup after moving examples to X-Pack * docs: ✏️ add to README.md info on how to find drilldowns
1 parent ad1b02a commit 6beb382

File tree

24 files changed

+582
-17
lines changed

24 files changed

+582
-17
lines changed

β€Ž.i18nrc.jsonβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"data": "src/plugins/data",
99
"embeddableApi": "src/plugins/embeddable",
1010
"embeddableExamples": "examples/embeddable_examples",
11+
"uiActionsExamples": "examples/ui_action_examples",
1112
"share": "src/plugins/share",
1213
"home": "src/plugins/home",
1314
"charts": "src/plugins/charts",

β€Žexamples/ui_action_examples/public/index.tsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@
1818
*/
1919

2020
import { UiActionExamplesPlugin } from './plugin';
21-
import { PluginInitializer } from '../../../src/core/public';
2221

23-
export const plugin: PluginInitializer<void, void> = () => new UiActionExamplesPlugin();
22+
export const plugin = () => new UiActionExamplesPlugin();
2423

2524
export { HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger';
2625
export { ACTION_HELLO_WORLD } from './hello_world_action';

β€Žexamples/ui_action_examples/public/plugin.tsβ€Ž

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@
1717
* under the License.
1818
*/
1919

20-
import { Plugin, CoreSetup } from '../../../src/core/public';
21-
import { UiActionsSetup } from '../../../src/plugins/ui_actions/public';
20+
import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public';
21+
import { UiActionsSetup, UiActionsStart } from '../../../src/plugins/ui_actions/public';
2222
import { createHelloWorldAction, ACTION_HELLO_WORLD } from './hello_world_action';
2323
import { helloWorldTrigger, HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger';
2424

25-
interface UiActionExamplesSetupDependencies {
25+
export interface UiActionExamplesSetupDependencies {
2626
uiActions: UiActionsSetup;
2727
}
2828

29+
export interface UiActionExamplesStartDependencies {
30+
uiActions: UiActionsStart;
31+
}
32+
2933
declare module '../../../src/plugins/ui_actions/public' {
3034
export interface TriggerContextMapping {
3135
[HELLO_WORLD_TRIGGER_ID]: {};
@@ -37,8 +41,12 @@ declare module '../../../src/plugins/ui_actions/public' {
3741
}
3842

3943
export class UiActionExamplesPlugin
40-
implements Plugin<void, void, UiActionExamplesSetupDependencies> {
41-
public setup(core: CoreSetup, { uiActions }: UiActionExamplesSetupDependencies) {
44+
implements
45+
Plugin<void, void, UiActionExamplesSetupDependencies, UiActionExamplesStartDependencies> {
46+
public setup(
47+
core: CoreSetup<UiActionExamplesStartDependencies>,
48+
{ uiActions }: UiActionExamplesSetupDependencies
49+
) {
4250
uiActions.registerTrigger(helloWorldTrigger);
4351

4452
const helloWorldAction = createHelloWorldAction(async () => ({
@@ -49,6 +57,7 @@ export class UiActionExamplesPlugin
4957
uiActions.addTriggerAction(helloWorldTrigger.id, helloWorldAction);
5058
}
5159

52-
public start() {}
60+
public start(core: CoreStart, plugins: UiActionExamplesStartDependencies) {}
61+
5362
public stop() {}
5463
}

β€Žsrc/plugins/data/public/index_patterns/index_patterns/index_patterns.tsβ€Ž

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,14 @@ const indexPatternCache = createIndexPatternCache();
3737

3838
type IndexPatternCachedFieldType = 'id' | 'title';
3939

40+
export interface IndexPatternSavedObjectAttrs {
41+
title: string;
42+
}
43+
4044
export class IndexPatternsService {
4145
private config: IUiSettingsClient;
4246
private savedObjectsClient: SavedObjectsClientContract;
43-
private savedObjectsCache?: Array<SimpleSavedObject<Record<string, any>>> | null;
47+
private savedObjectsCache?: Array<SimpleSavedObject<IndexPatternSavedObjectAttrs>> | null;
4448
private apiClient: IndexPatternsApiClient;
4549
ensureDefaultIndexPattern: EnsureDefaultIndexPattern;
4650

@@ -53,7 +57,7 @@ export class IndexPatternsService {
5357

5458
private async refreshSavedObjectsCache() {
5559
this.savedObjectsCache = (
56-
await this.savedObjectsClient.find<Record<string, any>>({
60+
await this.savedObjectsClient.find<IndexPatternSavedObjectAttrs>({
5761
type: 'index-pattern',
5862
fields: ['title'],
5963
perPage: 10000,

β€Žx-pack/.i18nrc.jsonβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"paths": {
44
"xpack.actions": "plugins/actions",
55
"xpack.advancedUiActions": "plugins/advanced_ui_actions",
6+
"xpack.uiActionsEnhanced": "examples/ui_actions_enhanced_examples",
67
"xpack.alerting": "plugins/alerting",
78
"xpack.alertingBuiltins": "plugins/alerting_builtins",
89
"xpack.apm": ["legacy/plugins/apm", "plugins/apm"],
Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1-
## Ui actions enhanced examples
1+
# Ui actions enhanced examples
22

3-
To run this example, use the command `yarn start --run-examples`.
3+
To run this example plugin, use the command `yarn start --run-examples`.
4+
5+
6+
## Drilldown examples
7+
8+
This plugin holds few examples on how to add drilldown types to dashboard.
9+
10+
To play with drilldowns, open any dashboard, click "Edit" to put it in *edit mode*.
11+
Now when opening context menu of dashboard panels you should see "Create drilldown" option.
12+
13+
![image](https://user-images.githubusercontent.com/9773803/80460907-c2ef7880-8934-11ea-8400-533bb9d57e36.png)
14+
15+
Once you click "Create drilldown" you should be able to see drilldowns added by
16+
this sample plugin.
17+
18+
![image](https://user-images.githubusercontent.com/9773803/80460408-131a0b00-8934-11ea-81e4-137e9e33f34b.png)
19+
20+
21+
### `dashboard_hello_world_drilldown`
22+
23+
`dashboard_hello_world_drilldown` is the most basic "hello world" example showing
24+
how a drilldown can be built, all in one file.
25+
26+
### `dashboard_to_url_drilldown`
27+
28+
`dashboard_to_url_drilldown` is a good starting point for build a drilldown
29+
that navigates somewhere externally.
30+
31+
One can see how middle-click or Ctrl + click behavior could be supported using
32+
`getHref` field.
33+
34+
### `dashboard_to_discover_drilldown`
35+
36+
`dashboard_to_discover_drilldown` shows how a real-world drilldown could look like.

β€Žx-pack/examples/ui_actions_enhanced_examples/kibana.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
"configPath": ["ui_actions_enhanced_examples"],
66
"server": false,
77
"ui": true,
8-
"requiredPlugins": ["uiActions", "data"],
8+
"requiredPlugins": ["uiActions", "drilldowns", "data"],
99
"optionalPlugins": []
1010
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This folder contains a one-file example of the most basic drilldown implementation.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React from 'react';
8+
import { EuiFormRow, EuiFieldText } from '@elastic/eui';
9+
import { reactToUiComponent } from '../../../../../src/plugins/kibana_react/public';
10+
import { DrilldownDefinition as Drilldown } from '../../../../plugins/drilldowns/public';
11+
import {
12+
EmbeddableContext,
13+
RangeSelectTriggerContext,
14+
ValueClickTriggerContext,
15+
} from '../../../../../src/plugins/embeddable/public';
16+
import { UiActionsCollectConfigProps } from '../../../../../src/plugins/ui_actions/public';
17+
18+
export type ActionContext = RangeSelectTriggerContext | ValueClickTriggerContext;
19+
20+
export interface Config {
21+
name: string;
22+
}
23+
24+
const SAMPLE_DASHBOARD_HELLO_WORLD_DRILLDOWN = 'SAMPLE_DASHBOARD_HELLO_WORLD_DRILLDOWN';
25+
26+
export class DashboardHelloWorldDrilldown
27+
implements Drilldown<Config, EmbeddableContext, ActionContext> {
28+
public readonly id = SAMPLE_DASHBOARD_HELLO_WORLD_DRILLDOWN;
29+
30+
public readonly order = 6;
31+
32+
public readonly getDisplayName = () => 'Say hello drilldown';
33+
34+
public readonly euiIcon = 'cheer';
35+
36+
private readonly ReactCollectConfig: React.FC<UiActionsCollectConfigProps<Config>> = ({
37+
config,
38+
onConfig,
39+
}) => (
40+
<EuiFormRow label="Enter your name" fullWidth>
41+
<EuiFieldText
42+
fullWidth
43+
value={config.name}
44+
onChange={event => onConfig({ ...config, name: event.target.value })}
45+
/>
46+
</EuiFormRow>
47+
);
48+
49+
public readonly CollectConfig = reactToUiComponent(this.ReactCollectConfig);
50+
51+
public readonly createConfig = () => ({
52+
name: '',
53+
});
54+
55+
public readonly isConfigValid = (config: Config): config is Config => {
56+
return !!config.name;
57+
};
58+
59+
public readonly execute = async (config: Config, context: ActionContext) => {
60+
alert(`Hello, ${config.name}`);
61+
};
62+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React, { useState, useEffect } from 'react';
8+
import useMountedState from 'react-use/lib/useMountedState';
9+
import { CollectConfigProps } from './types';
10+
import { DiscoverDrilldownConfig, IndexPatternItem } from './components/discover_drilldown_config';
11+
import { Params } from './drilldown';
12+
13+
export interface CollectConfigContainerProps extends CollectConfigProps {
14+
params: Params;
15+
}
16+
17+
export const CollectConfigContainer: React.FC<CollectConfigContainerProps> = ({
18+
config,
19+
onConfig,
20+
params: { start },
21+
}) => {
22+
const isMounted = useMountedState();
23+
const [indexPatterns, setIndexPatterns] = useState<IndexPatternItem[]>([]);
24+
25+
useEffect(() => {
26+
(async () => {
27+
const indexPatternSavedObjects = await start().plugins.data.indexPatterns.getCache();
28+
if (!isMounted()) return;
29+
setIndexPatterns(
30+
indexPatternSavedObjects
31+
? indexPatternSavedObjects.map(indexPattern => ({
32+
id: indexPattern.id,
33+
title: indexPattern.attributes.title,
34+
}))
35+
: []
36+
);
37+
})();
38+
}, [isMounted, start]);
39+
40+
return (
41+
<DiscoverDrilldownConfig
42+
activeIndexPatternId={config.indexPatternId}
43+
indexPatterns={indexPatterns}
44+
onIndexPatternSelect={indexPatternId => {
45+
onConfig({ ...config, indexPatternId });
46+
}}
47+
customIndexPattern={config.customIndexPattern}
48+
onCustomIndexPatternToggle={() =>
49+
onConfig({
50+
...config,
51+
customIndexPattern: !config.customIndexPattern,
52+
indexPatternId: undefined,
53+
})
54+
}
55+
carryFiltersAndQuery={config.carryFiltersAndQuery}
56+
onCarryFiltersAndQueryToggle={() =>
57+
onConfig({
58+
...config,
59+
carryFiltersAndQuery: !config.carryFiltersAndQuery,
60+
})
61+
}
62+
carryTimeRange={config.carryTimeRange}
63+
onCarryTimeRangeToggle={() =>
64+
onConfig({
65+
...config,
66+
carryTimeRange: !config.carryTimeRange,
67+
})
68+
}
69+
/>
70+
);
71+
};

0 commit comments

Comments
Β (0)