Skip to content

Commit

Permalink
Drilldown demo 2 (#64300)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
streamich authored Apr 28, 2020
1 parent ad1b02a commit 6beb382
Show file tree
Hide file tree
Showing 24 changed files with 582 additions and 17 deletions.
1 change: 1 addition & 0 deletions .i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"data": "src/plugins/data",
"embeddableApi": "src/plugins/embeddable",
"embeddableExamples": "examples/embeddable_examples",
"uiActionsExamples": "examples/ui_action_examples",
"share": "src/plugins/share",
"home": "src/plugins/home",
"charts": "src/plugins/charts",
Expand Down
3 changes: 1 addition & 2 deletions examples/ui_action_examples/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
*/

import { UiActionExamplesPlugin } from './plugin';
import { PluginInitializer } from '../../../src/core/public';

export const plugin: PluginInitializer<void, void> = () => new UiActionExamplesPlugin();
export const plugin = () => new UiActionExamplesPlugin();

export { HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger';
export { ACTION_HELLO_WORLD } from './hello_world_action';
21 changes: 15 additions & 6 deletions examples/ui_action_examples/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@
* under the License.
*/

import { Plugin, CoreSetup } from '../../../src/core/public';
import { UiActionsSetup } from '../../../src/plugins/ui_actions/public';
import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public';
import { UiActionsSetup, UiActionsStart } from '../../../src/plugins/ui_actions/public';
import { createHelloWorldAction, ACTION_HELLO_WORLD } from './hello_world_action';
import { helloWorldTrigger, HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger';

interface UiActionExamplesSetupDependencies {
export interface UiActionExamplesSetupDependencies {
uiActions: UiActionsSetup;
}

export interface UiActionExamplesStartDependencies {
uiActions: UiActionsStart;
}

declare module '../../../src/plugins/ui_actions/public' {
export interface TriggerContextMapping {
[HELLO_WORLD_TRIGGER_ID]: {};
Expand All @@ -37,8 +41,12 @@ declare module '../../../src/plugins/ui_actions/public' {
}

export class UiActionExamplesPlugin
implements Plugin<void, void, UiActionExamplesSetupDependencies> {
public setup(core: CoreSetup, { uiActions }: UiActionExamplesSetupDependencies) {
implements
Plugin<void, void, UiActionExamplesSetupDependencies, UiActionExamplesStartDependencies> {
public setup(
core: CoreSetup<UiActionExamplesStartDependencies>,
{ uiActions }: UiActionExamplesSetupDependencies
) {
uiActions.registerTrigger(helloWorldTrigger);

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

public start() {}
public start(core: CoreStart, plugins: UiActionExamplesStartDependencies) {}

public stop() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ const indexPatternCache = createIndexPatternCache();

type IndexPatternCachedFieldType = 'id' | 'title';

export interface IndexPatternSavedObjectAttrs {
title: string;
}

export class IndexPatternsService {
private config: IUiSettingsClient;
private savedObjectsClient: SavedObjectsClientContract;
private savedObjectsCache?: Array<SimpleSavedObject<Record<string, any>>> | null;
private savedObjectsCache?: Array<SimpleSavedObject<IndexPatternSavedObjectAttrs>> | null;
private apiClient: IndexPatternsApiClient;
ensureDefaultIndexPattern: EnsureDefaultIndexPattern;

Expand All @@ -53,7 +57,7 @@ export class IndexPatternsService {

private async refreshSavedObjectsCache() {
this.savedObjectsCache = (
await this.savedObjectsClient.find<Record<string, any>>({
await this.savedObjectsClient.find<IndexPatternSavedObjectAttrs>({
type: 'index-pattern',
fields: ['title'],
perPage: 10000,
Expand Down
1 change: 1 addition & 0 deletions x-pack/.i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"paths": {
"xpack.actions": "plugins/actions",
"xpack.advancedUiActions": "plugins/advanced_ui_actions",
"xpack.uiActionsEnhanced": "examples/ui_actions_enhanced_examples",
"xpack.alerting": "plugins/alerting",
"xpack.alertingBuiltins": "plugins/alerting_builtins",
"xpack.apm": ["legacy/plugins/apm", "plugins/apm"],
Expand Down
37 changes: 35 additions & 2 deletions x-pack/examples/ui_actions_enhanced_examples/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
## Ui actions enhanced examples
# Ui actions enhanced examples

To run this example, use the command `yarn start --run-examples`.
To run this example plugin, use the command `yarn start --run-examples`.


## Drilldown examples

This plugin holds few examples on how to add drilldown types to dashboard.

To play with drilldowns, open any dashboard, click "Edit" to put it in *edit mode*.
Now when opening context menu of dashboard panels you should see "Create drilldown" option.

![image](https://user-images.githubusercontent.com/9773803/80460907-c2ef7880-8934-11ea-8400-533bb9d57e36.png)

Once you click "Create drilldown" you should be able to see drilldowns added by
this sample plugin.

![image](https://user-images.githubusercontent.com/9773803/80460408-131a0b00-8934-11ea-81e4-137e9e33f34b.png)


### `dashboard_hello_world_drilldown`

`dashboard_hello_world_drilldown` is the most basic "hello world" example showing
how a drilldown can be built, all in one file.

### `dashboard_to_url_drilldown`

`dashboard_to_url_drilldown` is a good starting point for build a drilldown
that navigates somewhere externally.

One can see how middle-click or Ctrl + click behavior could be supported using
`getHref` field.

### `dashboard_to_discover_drilldown`

`dashboard_to_discover_drilldown` shows how a real-world drilldown could look like.
2 changes: 1 addition & 1 deletion x-pack/examples/ui_actions_enhanced_examples/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"configPath": ["ui_actions_enhanced_examples"],
"server": false,
"ui": true,
"requiredPlugins": ["uiActions", "data"],
"requiredPlugins": ["uiActions", "drilldowns", "data"],
"optionalPlugins": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This folder contains a one-file example of the most basic drilldown implementation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { EuiFormRow, EuiFieldText } from '@elastic/eui';
import { reactToUiComponent } from '../../../../../src/plugins/kibana_react/public';
import { DrilldownDefinition as Drilldown } from '../../../../plugins/drilldowns/public';
import {
EmbeddableContext,
RangeSelectTriggerContext,
ValueClickTriggerContext,
} from '../../../../../src/plugins/embeddable/public';
import { UiActionsCollectConfigProps } from '../../../../../src/plugins/ui_actions/public';

export type ActionContext = RangeSelectTriggerContext | ValueClickTriggerContext;

export interface Config {
name: string;
}

const SAMPLE_DASHBOARD_HELLO_WORLD_DRILLDOWN = 'SAMPLE_DASHBOARD_HELLO_WORLD_DRILLDOWN';

export class DashboardHelloWorldDrilldown
implements Drilldown<Config, EmbeddableContext, ActionContext> {
public readonly id = SAMPLE_DASHBOARD_HELLO_WORLD_DRILLDOWN;

public readonly order = 6;

public readonly getDisplayName = () => 'Say hello drilldown';

public readonly euiIcon = 'cheer';

private readonly ReactCollectConfig: React.FC<UiActionsCollectConfigProps<Config>> = ({
config,
onConfig,
}) => (
<EuiFormRow label="Enter your name" fullWidth>
<EuiFieldText
fullWidth
value={config.name}
onChange={event => onConfig({ ...config, name: event.target.value })}
/>
</EuiFormRow>
);

public readonly CollectConfig = reactToUiComponent(this.ReactCollectConfig);

public readonly createConfig = () => ({
name: '',
});

public readonly isConfigValid = (config: Config): config is Config => {
return !!config.name;
};

public readonly execute = async (config: Config, context: ActionContext) => {
alert(`Hello, ${config.name}`);
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState, useEffect } from 'react';
import useMountedState from 'react-use/lib/useMountedState';
import { CollectConfigProps } from './types';
import { DiscoverDrilldownConfig, IndexPatternItem } from './components/discover_drilldown_config';
import { Params } from './drilldown';

export interface CollectConfigContainerProps extends CollectConfigProps {
params: Params;
}

export const CollectConfigContainer: React.FC<CollectConfigContainerProps> = ({
config,
onConfig,
params: { start },
}) => {
const isMounted = useMountedState();
const [indexPatterns, setIndexPatterns] = useState<IndexPatternItem[]>([]);

useEffect(() => {
(async () => {
const indexPatternSavedObjects = await start().plugins.data.indexPatterns.getCache();
if (!isMounted()) return;
setIndexPatterns(
indexPatternSavedObjects
? indexPatternSavedObjects.map(indexPattern => ({
id: indexPattern.id,
title: indexPattern.attributes.title,
}))
: []
);
})();
}, [isMounted, start]);

return (
<DiscoverDrilldownConfig
activeIndexPatternId={config.indexPatternId}
indexPatterns={indexPatterns}
onIndexPatternSelect={indexPatternId => {
onConfig({ ...config, indexPatternId });
}}
customIndexPattern={config.customIndexPattern}
onCustomIndexPatternToggle={() =>
onConfig({
...config,
customIndexPattern: !config.customIndexPattern,
indexPatternId: undefined,
})
}
carryFiltersAndQuery={config.carryFiltersAndQuery}
onCarryFiltersAndQueryToggle={() =>
onConfig({
...config,
carryFiltersAndQuery: !config.carryFiltersAndQuery,
})
}
carryTimeRange={config.carryTimeRange}
onCarryTimeRangeToggle={() =>
onConfig({
...config,
carryTimeRange: !config.carryTimeRange,
})
}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { EuiFormRow, EuiSelect, EuiSwitch, EuiSpacer } from '@elastic/eui';
import { txtChooseDestinationIndexPattern } from './i18n';

export interface IndexPatternItem {
id: string;
title: string;
}

export interface DiscoverDrilldownConfigProps {
activeIndexPatternId?: string;
indexPatterns: IndexPatternItem[];
onIndexPatternSelect: (indexPatternId: string) => void;
customIndexPattern?: boolean;
onCustomIndexPatternToggle?: () => void;
carryFiltersAndQuery?: boolean;
onCarryFiltersAndQueryToggle?: () => void;
carryTimeRange?: boolean;
onCarryTimeRangeToggle?: () => void;
}

export const DiscoverDrilldownConfig: React.FC<DiscoverDrilldownConfigProps> = ({
activeIndexPatternId,
indexPatterns,
onIndexPatternSelect,
customIndexPattern,
onCustomIndexPatternToggle,
carryFiltersAndQuery,
onCarryFiltersAndQueryToggle,
carryTimeRange,
onCarryTimeRangeToggle,
}) => {
return (
<>
{!!onCustomIndexPatternToggle && (
<>
<EuiFormRow hasChildLabel={false}>
<EuiSwitch
name="customIndexPattern"
label="Use custom index pattern"
checked={!!customIndexPattern}
onChange={onCustomIndexPatternToggle}
/>
</EuiFormRow>
{!!customIndexPattern && (
<EuiFormRow fullWidth label={txtChooseDestinationIndexPattern}>
<EuiSelect
name="selectDashboard"
hasNoInitialSelection={true}
fullWidth
options={[
{ id: '', text: 'Pick one...' },
...indexPatterns.map(({ id, title }) => ({ value: id, text: title })),
]}
value={activeIndexPatternId || ''}
onChange={e => onIndexPatternSelect(e.target.value)}
/>
</EuiFormRow>
)}
<EuiSpacer size="xl" />
</>
)}

{!!onCarryFiltersAndQueryToggle && (
<EuiFormRow hasChildLabel={false}>
<EuiSwitch
name="carryFiltersAndQuery"
label="Carry over filters and query"
checked={!!carryFiltersAndQuery}
onChange={onCarryFiltersAndQueryToggle}
/>
</EuiFormRow>
)}
{!!onCarryTimeRangeToggle && (
<EuiFormRow hasChildLabel={false}>
<EuiSwitch
name="carryTimeRange"
label="Carry over time range"
checked={!!carryTimeRange}
onChange={onCarryTimeRangeToggle}
/>
</EuiFormRow>
)}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { i18n } from '@kbn/i18n';

export const txtChooseDestinationIndexPattern = i18n.translate(
'xpack.uiActionsEnhanced.components.DiscoverDrilldownConfig.chooseIndexPattern',
{
defaultMessage: 'Choose destination index pattern',
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export * from './discover_drilldown_config';
Loading

0 comments on commit 6beb382

Please sign in to comment.