Skip to content

Commit

Permalink
Drilldowns in examples (#75640)
Browse files Browse the repository at this point in the history
* feat: 🎸 add telemetry for in-chart "Explore underlying data"

* feat: 🎸 add telemetry for in-chart "Explore underlying data"

* refactor: 💡 move all drilldowns into a sub-folder

* feat: 🎸 setup example app section for ui_actions_enhanced

* feat: 🎸 set up Drilldown Manager section

* feat: 🎸 open drilldown manager from example plugin

* refactor: 💡 rename supportedTriggers -> triggers prop

* feat: 🎸 show dev warning if triggers prop is empty

* refactor: 💡 rename "supportedTriggers" -> "triggers" props

* feat: 🎸 open and close drilldown manager from example plugin

* feat: 🎸 add sample ML job trigger

* feat: 🎸 add sample ML URL drilldown

* refactor: 💡 move KibanaURL to share plugin

* refactor: 💡 add index file to ml drilldown

* feat: 🎸 add AbstractDashboardDrilldown

* refactor: 💡 make dashboard drilldown use abstract drilldown

* refactor: 💡 rename dashboard drilldown to embeddable drilldown

* feat: 🎸 add Dashboard drilldown to sample plugin

* feat: 🎸 open dashboard drilldown in list view

* feat: 🎸 add drilldown execute button

* refactor: 💡 move drilldown React hooks into /hooks folder

* test: 💍 fix tests after renaming triggers

* chore: 🤖 populate "requireBundles"

* fix: 🐛 fix TypeScript errors

* fix: 🐛 fix Kibana plugin dependency

* chore: 🤖 remoe unused import

* feat: 🎸 persist drilldown manager state across app navigations

* refactor: 💡 move no-embeddable example into a seprate file

* feat: 🎸 set up example with embeddable

* feat: 🎸 improve embeddable example

* refactor: 💡 rename without embeddable example

* feat: 🎸 set up no-embeddable single click example

* feat: 🎸 add dashboard drilldown to single button example

* fix: 🐛 remove unused margin

* fix: 🐛 make "Get more actions" translation static

* chore: 🤖 remove old dashboard drilldown definition

* refactor: 💡 rename samples to generic names

* refactor: 💡 make app 1 example drilldown "hello world"

* chore: 🤖 remove unused required bundle

* chore: 🤖 add dashboardEnhanced back

* [kbn/optimizer] only build xpack examples when building xpack plugins

* move alerting_example into x-pack/examples

* remove filter for alertingExample plugin in oss plugins CI step

* revert unrelated change

* fix: 🐛 use correct prop name

* test: 💍 fix embeddable-to-dashboard drilldown mock

* test: 💍 fix a test after refactor

* chore: 🤖 remove unused import

* chore: 🤖 add dashboard_enahcned to example plugin

* chore: 🤖 address review comments

* feat: 🎸 add description to UI Actions Enhanced examples

* docs: ✏️ improve docs of example plugin

Co-authored-by: spalger <spalger@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
4 people authored Oct 5, 2020
1 parent 13a737e commit 59e4e06
Show file tree
Hide file tree
Showing 92 changed files with 1,687 additions and 493 deletions.
7 changes: 6 additions & 1 deletion src/plugins/dashboard/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ export {
} from './application';
export { DashboardConstants, createDashboardEditUrl } from './dashboard_constants';

export { DashboardStart, DashboardUrlGenerator, DashboardFeatureFlagConfig } from './plugin';
export {
DashboardSetup,
DashboardStart,
DashboardUrlGenerator,
DashboardFeatureFlagConfig,
} from './plugin';
export {
DASHBOARD_APP_URL_GENERATOR,
createDashboardUrlGenerator,
Expand Down
17 changes: 4 additions & 13 deletions src/plugins/dashboard/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ interface StartDependencies {
savedObjects: SavedObjectsStart;
}

export type Setup = void;
export type DashboardSetup = void;

export interface DashboardStart {
getSavedDashboardLoader: () => SavedObjectLoader;
Expand Down Expand Up @@ -180,7 +180,7 @@ declare module '../../../plugins/ui_actions/public' {
}

export class DashboardPlugin
implements Plugin<Setup, DashboardStart, SetupDependencies, StartDependencies> {
implements Plugin<DashboardSetup, DashboardStart, SetupDependencies, StartDependencies> {
constructor(private initializerContext: PluginInitializerContext) {}

private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
Expand All @@ -193,17 +193,8 @@ export class DashboardPlugin

public setup(
core: CoreSetup<StartDependencies, DashboardStart>,
{
share,
uiActions,
embeddable,
home,
kibanaLegacy,
urlForwarding,
data,
usageCollection,
}: SetupDependencies
): Setup {
{ share, uiActions, embeddable, home, urlForwarding, data, usageCollection }: SetupDependencies
): DashboardSetup {
this.dashboardFeatureFlagConfig = this.initializerContext.config.get<
DashboardFeatureFlagConfig
>();
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/share/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ export {

import { SharePlugin } from './plugin';

export { KibanaURL } from './kibana_url';

export const plugin = () => new SharePlugin();
44 changes: 44 additions & 0 deletions src/plugins/share/public/kibana_url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

// TODO: Replace this logic with KibanaURL once it is available.
// https://github.com/elastic/kibana/issues/64497
export class KibanaURL {
public readonly path: string;
public readonly appName: string;
public readonly appPath: string;

constructor(path: string) {
const match = path.match(/^.*\/app\/([^\/#]+)(.+)$/);

if (!match) {
throw new Error('Unexpected URL path.');
}

const [, appName, appPath] = match;

if (!appName || !appPath) {
throw new Error('Could not parse URL path.');
}

this.path = path;
this.appName = appName;
this.appPath = appPath;
}
}
74 changes: 73 additions & 1 deletion x-pack/examples/ui_actions_enhanced_examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ 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.
This plugin holds few examples on how to add drilldown types to dashboard. See
`./public/drilldowns/` folder.

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.
Expand Down Expand Up @@ -34,3 +35,74 @@ One can see how middle-click or Ctrl + click behavior could be supported using
### `dashboard_to_discover_drilldown`

`dashboard_to_discover_drilldown` shows how a real-world drilldown could look like.


## Drilldown Manager examples

*Drilldown Manager* is a collectio of code and React components that allows you
to add drilldowns to any app. To see examples of how drilldows can be added to
your app, run Kibana with `--run-examples` flag:

```
yarn start --run-examples
```

Then go to "Developer examples" and "UI Actions Enhanced", where you can see examples
where *Drilldown Manager* is used outside of the Dashboard app:

![image](https://user-images.githubusercontent.com/9773803/94044547-969a3400-fdce-11ea-826a-cbd0773a4000.png)

These examples show how you can create your custom UI Actions triggers and add
drilldowns to them, or use an embeddable in your app and add drilldows to it.


### Trigger examples

The `/public/triggers` folder shows how you can create custom triggers for your app.
Triggers are things that trigger some action in UI, like "user click".

Once you have defined your triggers, you need to register them in your plugin:

```ts
export class MyPlugin implements Plugin {
public setup(core, { uiActionsEnhanced: uiActions }: SetupDependencies) {
uiActions.registerTrigger(myTrigger);
}
}
```

### `app1_hello_world_drilldown`

`app1_hello_world_drilldown` is a basic example that shows how you can add the most
basic drilldown to your custom trigger.

### `appx_to_dashboard_drilldown`

`app1_to_dashboard_drilldown` and `app2_to_dashboard_drilldown` show how the Dashboard
drilldown can be used in other apps, outside of Dashboard.

Basically you define it:

```ts
type Trigger = typeof MY_TRIGGER_TRIGGER;
type Context = MyAppClickContext;

export class App1ToDashboardDrilldown extends AbstractDashboardDrilldown<Trigger> {
public readonly supportedTriggers = () => [MY_TRIGGER] as Trigger[];

protected async getURL(config: Config, context: Context): Promise<KibanaURL> {
return 'https://...';
}
}
```

and then you register it in your plugin:

```ts
export class MyPlugin implements Plugin {
public setup(core, { uiActionsEnhanced: uiActions }: SetupDependencies) {
const drilldown = new App2ToDashboardDrilldown(/* You can pass in dependencies here. */);
uiActions.registerDrilldown(drilldown);
}
}
```
15 changes: 13 additions & 2 deletions x-pack/examples/ui_actions_enhanced_examples/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@
"configPath": ["ui_actions_enhanced_examples"],
"server": false,
"ui": true,
"requiredPlugins": ["uiActions","uiActionsEnhanced", "data", "discover"],
"requiredPlugins": [
"uiActions",
"uiActionsEnhanced",
"data",
"discover",
"dashboard",
"dashboardEnhanced",
"developerExamples"
],
"optionalPlugins": [],
"requiredBundles": [
"dashboardEnhanced",
"embeddable",
"kibanaUtils",
"kibanaReact"
"kibanaReact",
"share"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 * as React from 'react';
import {
EuiPageBody,
EuiPageContent,
EuiPageContentBody,
EuiPageHeader,
EuiPageHeaderSection,
EuiTitle,
} from '@elastic/eui';

export interface PageProps {
title?: React.ReactNode;
}

export const Page: React.FC<PageProps> = ({ title = 'Untitled', children }) => {
return (
<EuiPageBody style={{ maxWidth: 1200, margin: '0 auto' }}>
<EuiPageHeader>
<EuiPageHeaderSection>
<EuiTitle size="l">
<h1>{title}</h1>
</EuiTitle>
</EuiPageHeaderSection>
</EuiPageHeader>
<EuiPageContent>
<EuiPageContentBody style={{ maxWidth: 800, margin: '0 auto' }}>
{children}
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
);
};
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 './section';
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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 { EuiTitle, EuiSpacer } from '@elastic/eui';

export interface Props {
title: React.ReactNode;
}

export const Section: React.FC<Props> = ({ title, children }) => {
return (
<section>
<EuiTitle size="m">
<h2>{title}</h2>
</EuiTitle>
<EuiSpacer />
{children}
</section>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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 { EuiPage } from '@elastic/eui';
import { Page } from '../../components/page';
import { DrilldownsManager } from '../drilldowns_manager';

export const App: React.FC = () => {
return (
<EuiPage>
<Page title={'UI Actions Enhanced'}>
<DrilldownsManager />
</Page>
</EuiPage>
);
};
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 './app';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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 { EuiHorizontalRule } from '@elastic/eui';
import React from 'react';
import { Section } from '../../components/section/section';
import { SampleMlJob, SampleApp1ClickContext } from '../../triggers';
import { DrilldownsWithoutEmbeddableExample } from '../drilldowns_without_embeddable_example';
import { DrilldownsWithoutEmbeddableSingleButtonExample } from '../drilldowns_without_embeddable_single_button_example/drilldowns_without_embeddable_single_button_example';
import { DrilldownsWithEmbeddableExample } from '../drilldowns_with_embeddable_example';

export const job: SampleMlJob = {
job_id: '123',
job_type: 'anomaly_detector',
description: 'This is some ML job.',
};

export const context: SampleApp1ClickContext = { job };

export const DrilldownsManager: React.FC = () => {
return (
<div>
<Section title={'Drilldowns Manager'}>
<DrilldownsWithoutEmbeddableExample />

<EuiHorizontalRule margin="xxl" />

<DrilldownsWithoutEmbeddableSingleButtonExample />

<EuiHorizontalRule margin="xxl" />

<DrilldownsWithEmbeddableExample />
</Section>
</div>
);
};
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 './drilldowns_manager';
Loading

0 comments on commit 59e4e06

Please sign in to comment.