Skip to content

Commit

Permalink
Merge branch 'master' into ts-project-refs-es_ui/grokdebugger
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine committed Jan 29, 2021
2 parents 5593916 + 46c9e64 commit d6beb79
Show file tree
Hide file tree
Showing 67 changed files with 1,494 additions and 326 deletions.
4 changes: 2 additions & 2 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ It also provides a stateful version of it on the start contract.
Content is fetched from the remote (https://feeds.elastic.co and https://feeds-staging.elastic.co in dev mode) once a day, with periodic checks if the content needs to be refreshed. All newsfeed content is hosted remotely.
|{kib-repo}blob/{branch}/src/plugins/presentation_util/README.md[presentationUtil]
|Utilities and components used by the presentation-related plugins
|{kib-repo}blob/{branch}/src/plugins/presentation_util/README.mdx[presentationUtil]
|The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas).
|{kib-repo}blob/{branch}/src/plugins/region_map/README.md[regionMap]
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@
"@storybook/addon-essentials": "^6.0.26",
"@storybook/addon-knobs": "^6.0.26",
"@storybook/addon-storyshots": "^6.0.26",
"@storybook/addon-docs": "^6.0.26",
"@storybook/components": "^6.0.26",
"@storybook/core": "^6.0.26",
"@storybook/core-events": "^6.0.26",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
* Public License, v 1.
*/

import pkg from '../../../../package.json';
import { getVersionInfo } from './version_info';
import { kibanaPackageJSON as pkg } from '@kbn/dev-utils';

jest.mock('./get_build_number');
import { getVersionInfo } from '../version_info';

jest.mock('../get_build_number');

describe('isRelease = true', () => {
it('returns unchanged package.version, build sha, and build number', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ function generator({
ubiImageFlavor,
architecture,
}: TemplateContext) {
const fileArchitecture = architecture === 'aarch64' ? 'arm64' : 'amd64';
return dedent(`
#!/usr/bin/env bash
#
Expand Down Expand Up @@ -56,9 +55,9 @@ function generator({
retry_docker_pull ${baseOSImage}
echo "Building: kibana${imageFlavor}${ubiImageFlavor}-docker"; \\
docker build -t ${imageTag}${imageFlavor}${ubiImageFlavor}:${version}-${fileArchitecture} -f Dockerfile . || exit 1;
docker build -t ${imageTag}${imageFlavor}${ubiImageFlavor}:${version} -f Dockerfile . || exit 1;
docker save ${imageTag}${imageFlavor}${ubiImageFlavor}:${version}-${fileArchitecture} | gzip -c > ${dockerTargetFilename}
docker save ${imageTag}${imageFlavor}${ubiImageFlavor}:${version} | gzip -c > ${dockerTargetFilename}
exit 0
`);
Expand Down
1 change: 1 addition & 0 deletions src/dev/storybook/aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export const storybookAliases = {
security_solution: 'x-pack/plugins/security_solution/.storybook',
ui_actions_enhanced: 'x-pack/plugins/ui_actions_enhanced/.storybook',
observability: 'x-pack/plugins/observability/.storybook',
presentation: 'src/plugins/presentation_util/storybook',
};
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ function wrapQueryStringInputInContext(testProps: any, storage?: any) {
);
}

describe('QueryStringInput', () => {
// FAILING: https://github.com/elastic/kibana/issues/85715
// FAILING: https://github.com/elastic/kibana/issues/89603
// FAILING: https://github.com/elastic/kibana/issues/89641
describe.skip('QueryStringInput', () => {
beforeEach(() => {
jest.clearAllMocks();
});
Expand All @@ -102,7 +105,7 @@ describe('QueryStringInput', () => {
await waitFor(() => getByText('KQL'));
});

it.skip('Should pass the query language to the language switcher', () => {
it('Should pass the query language to the language switcher', () => {
const component = mount(
wrapQueryStringInputInContext({
query: luceneQuery,
Expand All @@ -113,7 +116,7 @@ describe('QueryStringInput', () => {
expect(component.find(QueryLanguageSwitcher).prop('language')).toBe(luceneQuery.language);
});

it.skip('Should disable autoFocus on EuiTextArea when disableAutoFocus prop is true', () => {
it('Should disable autoFocus on EuiTextArea when disableAutoFocus prop is true', () => {
const component = mount(
wrapQueryStringInputInContext({
query: kqlQuery,
Expand Down
3 changes: 0 additions & 3 deletions src/plugins/presentation_util/README.md

This file was deleted.

211 changes: 211 additions & 0 deletions src/plugins/presentation_util/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
id: presentationUtilPlugin
slug: /kibana-dev-docs/presentationPlugin
title: Presentation Utility Plugin
summary: Introduction to the Presentation Utility Plugin.
date: 2020-01-12
tags: ['kibana', 'presentation', 'services']
related: []
---

## Introduction

The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas).

## Plugin Services Toolkit

While Kibana provides a `useKibana` hook for use in a plugin, the number of services it provides is very large. This presents a set of difficulties:

- a direct dependency upon the Kibana environment;
- a requirement to mock the full Kibana environment when testing or using Storybook;
- a lack of knowledge as to what services are being consumed at any given time.

To mitigate these difficulties, the Presentation Team creates services within the plugin that then consume Kibana-provided (or other) services. This is a toolkit for creating simple services within a plugin.

### Overview

- A `PluginServiceFactory` is a function that will return a set of functions-- which comprise a `Service`-- given a set of parameters.
- A `PluginServiceProvider` is an object that use a factory to start, stop or provide a `Service`.
- A `PluginServiceRegistry` is a collection of providers for a given environment, (e.g. Kibana, Jest, Storybook, stub, etc).
- A `PluginServices` object uses a registry to provide services throughout the plugin.

### Defining Services

To start, a plugin should define a set of services it wants to provide to itself or other plugins.

<DocAccordion buttonContent="Service Definition Example" initialIsOpen>
```ts
export interface PresentationDashboardsService {
findDashboards: (
query: string,
fields: string[]
) => Promise<Array<SimpleSavedObject<DashboardSavedObject>>>;
findDashboardsByTitle: (title: string) => Promise<Array<SimpleSavedObject<DashboardSavedObject>>>;
}

export interface PresentationFooService {
getFoo: () => string;
setFoo: (bar: string) => void;
}

export interface PresentationUtilServices {
dashboards: PresentationDashboardsService;
foo: PresentationFooService;
}
```
</DocAccordion>

This definition will be used in the toolkit to ensure services are complete and as expected.

### Plugin Services

The `PluginServices` class hosts a registry of service providers from which a plugin can access its services. It uses the service definition as a generic.

```ts
export const pluginServices = new PluginServices<PresentationUtilServices>();
```

This can be placed in the `index.ts` file of a `services` directory within your plugin.

Once created, it simply requires a `PluginServiceRegistry` to be started and set.

### Service Provider Registry

Each environment in which components are used requires a `PluginServiceRegistry` to specify how the providers are started. For example, simple stubs of services require no parameters to start, (so the `StartParameters` generic remains unspecified)

<DocAccordion buttonContent="Stubbed Service Registry Example" initialIsOpen>
```ts
export const providers: PluginServiceProviders<PresentationUtilServices> = {
dashboards: new PluginServiceProvider(dashboardsServiceFactory),
foo: new PluginServiceProvider(fooServiceFactory),
};

export const serviceRegistry = new PluginServiceRegistry<PresentationUtilServices>(providers);
```
</DocAccordion>

By contrast, a registry that uses Kibana can provide `KibanaPluginServiceParams` to determine how to start its providers, so the `StartParameters` generic is given:

<DocAccordion buttonContent="Kibana Service Registry Example" initialIsOpen>
```ts
export const providers: PluginServiceProviders<
PresentationUtilServices,
KibanaPluginServiceParams<PresentationUtilPluginStart>
> = {
dashboards: new PluginServiceProvider(dashboardsServiceFactory),
foo: new PluginServiceProvider(fooServiceFactory),
};

export const serviceRegistry = new PluginServiceRegistry<
PresentationUtilServices,
KibanaPluginServiceParams<PresentationUtilPluginStart>
>(providers);
```
</DocAccordion>

### Service Provider

A `PluginServiceProvider` is a container for a Service Factory that is responsible for starting, stopping and providing a service implementation. A Service Provider doesn't change, rather the factory and the relevant `StartParameters` change.

### Service Factories

A Service Factory is nothing more than a function that uses `StartParameters` to return a set of functions that conforms to a portion of the `Services` specification. For each service, a factory is provided for each environment.

Given a service definition:

```ts
export interface PresentationFooService {
getFoo: () => string;
setFoo: (bar: string) => void;
}
```

a factory for a stubbed version might look like this:

```ts
type FooServiceFactory = PluginServiceFactory<PresentationFooService>;

export const fooServiceFactory: FooServiceFactory = () => ({
getFoo: () => 'bar',
setFoo: (bar) => { console.log(`${bar} set!`)},
});
```

and a factory for a Kibana version might look like this:

```ts
export type FooServiceFactory = KibanaPluginServiceFactory<
PresentationFooService,
PresentationUtilPluginStart
>;

export const fooServiceFactory: FooServiceFactory = ({
coreStart,
startPlugins,
}) => {
// ...do something with Kibana services...

return {
getFoo: //...
setFoo: //...
}
}
```

### Using Services

Once your services and providers are defined, and you have at least one set of factories, you can use `PluginServices` to provide the services to your React components:

<DocAccordion buttonContent="Services starting in a plugin" initialIsOpen>
```ts
// plugin.ts
import { pluginServices } from './services';
import { registry } from './services/kibana';

public async start(
coreStart: CoreStart,
startPlugins: StartDeps
): Promise<PresentationUtilPluginStart> {
pluginServices.setRegistry(registry.start({ coreStart, startPlugins }));
return {};
}
```
</DocAccordion>

and wrap your root React component with the `PluginServices` context:

<DocAccordion buttonContent="Providing services in a React context" initialIsOpen>
```ts
import { pluginServices } from './services';

const ContextProvider = pluginServices.getContextProvider(),

return(
<I18nContext>
<WhateverElse>
<ContextProvider>{application}</ContextProvider>
</WhateverElse>
</I18nContext>
)
```
</DocAccordion>

and then, consume your services using provided hooks in a component:

<DocAccordion buttonContent="Consuming services in a component" initialIsOpen>
```ts
// component.ts

import { pluginServices } from '../services';

export function MyComponent() {
// Retrieve all context hooks from `PluginServices`, destructuring for the one we're using
const { foo } = pluginServices.getHooks();

// Use the `useContext` hook to access the API.
const { getFoo } = foo.useService();

// ...
}
```
</DocAccordion>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* and the Server Side Public License, v 1; you may not use this file except in
* compliance with, at your election, the Elastic License or the Server Side
* Public License, v 1.
*/

import React from 'react';
import { action } from '@storybook/addon-actions';

import { DashboardPicker } from './dashboard_picker';

export default {
component: DashboardPicker,
title: 'Dashboard Picker',
argTypes: {
isDisabled: {
control: 'boolean',
defaultValue: false,
},
},
};

export const Example = ({ isDisabled }: { isDisabled: boolean }) => (
<DashboardPicker onChange={action('onChange')} isDisabled={isDisabled} />
);
Loading

0 comments on commit d6beb79

Please sign in to comment.