mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Kibana developer examples landing page (#67049)
* Kibana developer examples * Batch explorer tests should be run in examples config * Fix tests * add codeowner for new developer examples plugin & readme cleanup * Try to frame embeddable wording based on what a developer's goals are. * Add noopener noreferer, fix bad merge * Remove bfetch.png Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c29fcbb46b
commit
f89e911f64
40 changed files with 510 additions and 109 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -34,6 +34,7 @@
|
|||
/src/legacy/core_plugins/kibana/public/home/np_ready/ @elastic/kibana-core-ui
|
||||
|
||||
# App Architecture
|
||||
/examples/developer_examples/ @elastic/kibana-app-arch
|
||||
/examples/url_generators_examples/ @elastic/kibana-app-arch
|
||||
/examples/url_generators_explorer/ @elastic/kibana-app-arch
|
||||
/packages/kbn-interpreter/ @elastic/kibana-app-arch
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["triggers_actions_ui", "charts", "data", "alerts", "actions"],
|
||||
"requiredPlugins": ["triggers_actions_ui", "charts", "data", "alerts", "actions", "developerExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import { PluginSetupContract as AlertingSetup } from '../../../x-pack/plugins/alerts/public';
|
||||
import { ChartsPluginStart } from '../../../src/plugins/charts/public';
|
||||
import { TriggersAndActionsUIPublicPluginSetup } from '../../../x-pack/plugins/triggers_actions_ui/public';
|
||||
|
@ -25,6 +25,7 @@ import { DataPublicPluginStart } from '../../../src/plugins/data/public';
|
|||
import { getAlertType as getAlwaysFiringAlertType } from './alert_types/always_firing';
|
||||
import { getAlertType as getPeopleInSpaceAlertType } from './alert_types/astros';
|
||||
import { registerNavigation } from './alert_types';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
|
||||
export type Setup = void;
|
||||
export type Start = void;
|
||||
|
@ -32,6 +33,7 @@ export type Start = void;
|
|||
export interface AlertingExamplePublicSetupDeps {
|
||||
alerts: AlertingSetup;
|
||||
triggers_actions_ui: TriggersAndActionsUIPublicPluginSetup;
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export interface AlertingExamplePublicStartDeps {
|
||||
|
@ -44,11 +46,12 @@ export interface AlertingExamplePublicStartDeps {
|
|||
export class AlertingExamplePlugin implements Plugin<Setup, Start, AlertingExamplePublicSetupDeps> {
|
||||
public setup(
|
||||
core: CoreSetup<AlertingExamplePublicStartDeps, Start>,
|
||||
{ alerts, triggers_actions_ui }: AlertingExamplePublicSetupDeps
|
||||
{ alerts, triggers_actions_ui, developerExamples }: AlertingExamplePublicSetupDeps
|
||||
) {
|
||||
core.application.register({
|
||||
id: 'AlertingExample',
|
||||
title: 'Alerting Example',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const { renderApp } = await import('./application');
|
||||
|
@ -60,6 +63,21 @@ export class AlertingExamplePlugin implements Plugin<Setup, Start, AlertingExamp
|
|||
triggers_actions_ui.alertTypeRegistry.register(getPeopleInSpaceAlertType());
|
||||
|
||||
registerNavigation(alerts);
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'AlertingExample',
|
||||
title: 'Alerting',
|
||||
description: `This alerting example walks you through how to set up a new alert.`,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href: 'https://github.com/elastic/kibana/tree/master/x-pack/plugins/alerting',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["bfetch"],
|
||||
"requiredPlugins": ["bfetch", "developerExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup } from 'kibana/public';
|
||||
import { Plugin, CoreSetup, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import { BfetchPublicSetup, BfetchPublicStart } from '../../../src/plugins/bfetch/public';
|
||||
import { mount } from './mount';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
|
||||
export interface ExplorerService {
|
||||
double: (number: { num: number }) => Promise<{ num: number }>;
|
||||
|
@ -27,6 +28,7 @@ export interface ExplorerService {
|
|||
|
||||
export interface BfetchExplorerSetupPlugins {
|
||||
bfetch: BfetchPublicSetup;
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export interface BfetchExplorerStartPlugins {
|
||||
|
@ -36,9 +38,9 @@ export interface BfetchExplorerStartPlugins {
|
|||
export class BfetchExplorerPlugin implements Plugin {
|
||||
public setup(
|
||||
core: CoreSetup<BfetchExplorerStartPlugins, void>,
|
||||
plugins: BfetchExplorerSetupPlugins
|
||||
{ bfetch, developerExamples }: BfetchExplorerSetupPlugins
|
||||
) {
|
||||
const double = plugins.bfetch.batchedFunction<{ num: number }, { num: number }>({
|
||||
const double = bfetch.batchedFunction<{ num: number }, { num: number }>({
|
||||
url: '/bfetch_explorer/double',
|
||||
});
|
||||
|
||||
|
@ -49,8 +51,25 @@ export class BfetchExplorerPlugin implements Plugin {
|
|||
core.application.register({
|
||||
id: 'bfetch-explorer',
|
||||
title: 'bfetch explorer',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
mount: mount(core, explorer),
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'bfetch-explorer',
|
||||
title: 'bfetch',
|
||||
description:
|
||||
'bfetch is a service that allows to batch HTTP requests and streams responses back.',
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href: 'https://github.com/elastic/kibana/blob/master/src/plugins/bfetch/README.md',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
36
examples/developer_examples/README.md
Normal file
36
examples/developer_examples/README.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
## Developer examples
|
||||
|
||||
Owner: Kibana application architecture team
|
||||
|
||||
The developer examples app is a landing page where developers go to search for working, tested examples of various developer
|
||||
services. Add your a link to your example using the developerExamples `register` function offered on the `setup` contract:
|
||||
|
||||
```ts
|
||||
setup(core, { developerExamples }) {
|
||||
developerExamples.register({
|
||||
appId: 'myFooExampleApp',
|
||||
title: 'Foo services',
|
||||
description: `Foo services let you do bar and zed.`,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href: 'https://github.com/elastic/kibana/tree/master/src/plugins/foo/README.md',
|
||||
iconType: 'logoGithub',
|
||||
target: '_blank',
|
||||
size: 's',
|
||||
},
|
||||
],
|
||||
image: img,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Run Kibana with developer examples via:
|
||||
|
||||
```
|
||||
yarn start --run-examples
|
||||
```
|
||||
|
||||
Then navigate to "Developer examples":
|
||||
|
||||
<img src="./navigation.png" height="400px" />
|
9
examples/developer_examples/kibana.json
Normal file
9
examples/developer_examples/kibana.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "developerExamples",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": [],
|
||||
"optionalPlugins": []
|
||||
}
|
BIN
examples/developer_examples/navigation.png
Normal file
BIN
examples/developer_examples/navigation.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
117
examples/developer_examples/public/app.tsx
Normal file
117
examples/developer_examples/public/app.tsx
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
import React, { useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import {
|
||||
EuiText,
|
||||
EuiPageContent,
|
||||
EuiCard,
|
||||
EuiPageContentHeader,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFieldSearch,
|
||||
EuiListGroup,
|
||||
EuiHighlight,
|
||||
EuiLink,
|
||||
EuiButtonIcon,
|
||||
} from '@elastic/eui';
|
||||
import { AppMountParameters } from '../../../src/core/public';
|
||||
import { ExampleDefinition } from './types';
|
||||
|
||||
interface Props {
|
||||
examples: ExampleDefinition[];
|
||||
navigateToApp: (appId: string) => void;
|
||||
getUrlForApp: (appId: string) => string;
|
||||
}
|
||||
|
||||
function DeveloperExamples({ examples, navigateToApp, getUrlForApp }: Props) {
|
||||
const [search, setSearch] = useState<string>('');
|
||||
|
||||
const lcSearch = search.toLowerCase();
|
||||
const filteredExamples = !lcSearch
|
||||
? examples
|
||||
: examples.filter((def) => {
|
||||
if (def.description.toLowerCase().indexOf(lcSearch) >= 0) return true;
|
||||
if (def.title.toLowerCase().indexOf(lcSearch) >= 0) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiPageContent>
|
||||
<EuiPageContentHeader>
|
||||
<EuiText>
|
||||
<h1>Developer examples</h1>
|
||||
<p>
|
||||
The following examples showcase services and APIs that are available to developers.
|
||||
<EuiFieldSearch
|
||||
placeholder="Search"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
isClearable={true}
|
||||
aria-label="Search developer examples"
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiPageContentHeader>
|
||||
<EuiFlexGroup wrap>
|
||||
{filteredExamples.map((def) => (
|
||||
<EuiFlexItem style={{ minWidth: 300, maxWidth: 500 }} key={def.appId}>
|
||||
<EuiCard
|
||||
description={
|
||||
<EuiHighlight search={search} highlightAll={true}>
|
||||
{def.description}
|
||||
</EuiHighlight>
|
||||
}
|
||||
title={
|
||||
<React.Fragment>
|
||||
<EuiLink
|
||||
onClick={() => {
|
||||
navigateToApp(def.appId);
|
||||
}}
|
||||
>
|
||||
<EuiHighlight search={search} highlightAll={true}>
|
||||
{def.title}
|
||||
</EuiHighlight>
|
||||
</EuiLink>
|
||||
<EuiButtonIcon
|
||||
iconType="popout"
|
||||
onClick={() =>
|
||||
window.open(getUrlForApp(def.appId), '_blank', 'noopener, noreferrer')
|
||||
}
|
||||
>
|
||||
Open in new tab
|
||||
</EuiButtonIcon>
|
||||
</React.Fragment>
|
||||
}
|
||||
image={def.image}
|
||||
footer={def.links ? <EuiListGroup size={'s'} listItems={def.links} /> : undefined}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContent>
|
||||
);
|
||||
}
|
||||
|
||||
export const renderApp = (props: Props, element: AppMountParameters['element']) => {
|
||||
ReactDOM.render(<DeveloperExamples {...props} />, element);
|
||||
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
|
@ -17,4 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export * from '../../../../../examples/bfetch_explorer/public';
|
||||
import { DeveloperExamplesPlugin } from './plugin';
|
||||
|
||||
export const plugin = () => new DeveloperExamplesPlugin();
|
||||
|
||||
export { DeveloperExamplesSetup } from './plugin';
|
68
examples/developer_examples/public/plugin.ts
Normal file
68
examples/developer_examples/public/plugin.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import {
|
||||
CoreSetup,
|
||||
Plugin,
|
||||
AppMountParameters,
|
||||
DEFAULT_APP_CATEGORIES,
|
||||
} from '../../../src/core/public';
|
||||
|
||||
import { ExampleDefinition } from './types';
|
||||
|
||||
export interface DeveloperExamplesSetup {
|
||||
register: (def: ExampleDefinition) => void;
|
||||
}
|
||||
|
||||
export class DeveloperExamplesPlugin implements Plugin<DeveloperExamplesSetup, void> {
|
||||
private examplesRegistry: ExampleDefinition[] = [];
|
||||
|
||||
public setup(core: CoreSetup) {
|
||||
const examples = this.examplesRegistry;
|
||||
core.application.register({
|
||||
id: 'developerExamples',
|
||||
title: 'Developer examples',
|
||||
order: -2000,
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
async mount(params: AppMountParameters) {
|
||||
const { renderApp } = await import('./app');
|
||||
const [coreStart] = await core.getStartServices();
|
||||
return renderApp(
|
||||
{
|
||||
examples,
|
||||
navigateToApp: (appId: string) => coreStart.application.navigateToApp(appId),
|
||||
getUrlForApp: (appId: string) => coreStart.application.getUrlForApp(appId),
|
||||
},
|
||||
params.element
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const api: DeveloperExamplesSetup = {
|
||||
register: (def) => {
|
||||
this.examplesRegistry.push(def);
|
||||
},
|
||||
};
|
||||
return api;
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
||||
public stop() {}
|
||||
}
|
|
@ -17,4 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export * from '../../../../../examples/bfetch_explorer/server';
|
||||
import { EuiListGroupItemProps } from '@elastic/eui';
|
||||
|
||||
export interface ExampleDefinition {
|
||||
/**
|
||||
* The application id that is the landing page for the example.
|
||||
*/
|
||||
appId: string;
|
||||
title: string;
|
||||
description: string;
|
||||
image?: string;
|
||||
/**
|
||||
* Any additional links you want to show, for example to the github README.
|
||||
*/
|
||||
links?: EuiListGroupItemProps[];
|
||||
}
|
15
examples/developer_examples/tsconfig.json
Normal file
15
examples/developer_examples/tsconfig.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"public/**/*.ts",
|
||||
"public/**/*.tsx",
|
||||
"server/**/*.ts",
|
||||
"../../typings/**/*",
|
||||
],
|
||||
"exclude": []
|
||||
}
|
|
@ -4,6 +4,6 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["uiActions", "inspector", "embeddable", "embeddableExamples"],
|
||||
"requiredPlugins": ["uiActions", "inspector", "embeddable", "embeddableExamples", "developerExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
BIN
examples/embeddable_explorer/public/embeddables.png
Normal file
BIN
examples/embeddable_explorer/public/embeddables.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
|
@ -16,12 +16,13 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
|
||||
import { EmbeddableExamplesStart } from 'examples/embeddable_examples/public/plugin';
|
||||
import { Plugin, CoreSetup, AppMountParameters, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import { UiActionsService } from '../../../src/plugins/ui_actions/public';
|
||||
import { EmbeddableStart } from '../../../src/plugins/embeddable/public';
|
||||
import { Start as InspectorStart } from '../../../src/plugins/inspector/public';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
import img from './embeddables.png';
|
||||
|
||||
interface StartDeps {
|
||||
uiActions: UiActionsService;
|
||||
|
@ -30,11 +31,16 @@ interface StartDeps {
|
|||
embeddableExamples: EmbeddableExamplesStart;
|
||||
}
|
||||
|
||||
interface SetupDeps {
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export class EmbeddableExplorerPlugin implements Plugin<void, void, {}, StartDeps> {
|
||||
public setup(core: CoreSetup<StartDeps>) {
|
||||
public setup(core: CoreSetup<StartDeps>, { developerExamples }: SetupDeps) {
|
||||
core.application.register({
|
||||
id: 'embeddableExplorer',
|
||||
title: 'Embeddable explorer',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const { renderApp } = await import('./app');
|
||||
|
@ -55,6 +61,25 @@ export class EmbeddableExplorerPlugin implements Plugin<void, void, {}, StartDep
|
|||
);
|
||||
},
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'embeddableExplorer',
|
||||
title: 'Embeddables',
|
||||
description: `Multiple embeddable examples showcase how to build custom dashboard widgets, how to build your own custom "container"
|
||||
(like a dashboard but imagine you want to render the panels differently), and how to embed anything that can show up in a dashboard
|
||||
in your own UI and app, that comes pre-connected with actions built by other developers.
|
||||
`,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href: 'https://github.com/elastic/kibana/tree/master/src/plugins/embeddable/README.md',
|
||||
iconType: 'logoGithub',
|
||||
target: '_blank',
|
||||
size: 's',
|
||||
},
|
||||
],
|
||||
image: img,
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["data", "demoSearch"],
|
||||
"requiredPlugins": ["data", "demoSearch", "developerExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -17,20 +17,47 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import { AppPluginStartDependencies } from './types';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
interface SetupDeps {
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export class SearchExplorerPlugin implements Plugin {
|
||||
public setup(core: CoreSetup<AppPluginStartDependencies, void>) {
|
||||
public setup(
|
||||
core: CoreSetup<AppPluginStartDependencies, void>,
|
||||
{ developerExamples }: SetupDeps
|
||||
) {
|
||||
core.application.register({
|
||||
id: 'searchExplorer',
|
||||
title: 'Search Explorer',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const { renderApp } = await import('./application');
|
||||
return renderApp(coreStart, depsStart, params);
|
||||
},
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'searchExplorer',
|
||||
title: 'Data search strategy services',
|
||||
description: `Data search services can be used to query Elasticsearch in away that supports background search
|
||||
and partial results, when available. It also automatically incorporates settings such as requestTimeout and includeFrozen.
|
||||
Use the provided ES search strategy, or register your own.
|
||||
`,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href:
|
||||
'https://github.com/elastic/kibana/blob/master/src/plugins/data/public/search/README.md',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["navigation", "data"],
|
||||
"requiredPlugins": ["navigation", "data", "developerExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -17,15 +17,21 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { AppMountParameters, CoreSetup, Plugin } from 'kibana/public';
|
||||
import { AppMountParameters, CoreSetup, Plugin, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import { AppPluginDependencies } from './with_data_services/types';
|
||||
import { PLUGIN_ID, PLUGIN_NAME } from '../common';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
|
||||
interface SetupDeps {
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export class StateContainersExamplesPlugin implements Plugin {
|
||||
public setup(core: CoreSetup) {
|
||||
public setup(core: CoreSetup, { developerExamples }: SetupDeps) {
|
||||
core.application.register({
|
||||
id: 'stateContainersExampleBrowserHistory',
|
||||
title: 'State containers example - browser history routing',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const { renderApp, History } = await import('./todo/app');
|
||||
return renderApp(params, {
|
||||
|
@ -38,6 +44,7 @@ export class StateContainersExamplesPlugin implements Plugin {
|
|||
core.application.register({
|
||||
id: 'stateContainersExampleHashHistory',
|
||||
title: 'State containers example - hash history routing',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const { renderApp, History } = await import('./todo/app');
|
||||
return renderApp(params, {
|
||||
|
@ -51,6 +58,7 @@ export class StateContainersExamplesPlugin implements Plugin {
|
|||
core.application.register({
|
||||
id: PLUGIN_ID,
|
||||
title: PLUGIN_NAME,
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
// Load application bundle
|
||||
const { renderApp } = await import('./with_data_services/application');
|
||||
|
@ -60,6 +68,62 @@ export class StateContainersExamplesPlugin implements Plugin {
|
|||
return renderApp(coreStart, depsStart as AppPluginDependencies, params);
|
||||
},
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'stateContainersExampleBrowserHistory',
|
||||
title: 'State containers using browser history',
|
||||
description: `An example todo app that uses browser history and state container utilities like createStateContainerReactHelpers,
|
||||
createStateContainer, createKbnUrlStateStorage, createSessionStorageStateStorage,
|
||||
syncStates and getStateFromKbnUrl to keep state in sync with the URL. Change some parameters, navigate away and then back, and the
|
||||
state should be preserved.`,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href:
|
||||
'https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_containers/README.md',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'stateContainersExampleHashHistory',
|
||||
title: 'State containers using hash history',
|
||||
description: `An example todo app that uses hash history and state container utilities like createStateContainerReactHelpers,
|
||||
createStateContainer, createKbnUrlStateStorage, createSessionStorageStateStorage,
|
||||
syncStates and getStateFromKbnUrl to keep state in sync with the URL. Change some parameters, navigate away and then back, and the
|
||||
state should be preserved.`,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href:
|
||||
'https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_containers/README.md',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: PLUGIN_ID,
|
||||
title: 'Sync state from a query bar with the url',
|
||||
description: `Shows how to use data.syncQueryStateWitUrl in combination with state container utilities from kibana_utils to
|
||||
show a query bar that stores state in the url and is kept in sync.
|
||||
`,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href:
|
||||
'https://github.com/elastic/kibana/blob/master/src/plugins/data/public/query/state_sync/README.md',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
|
@ -27,7 +27,7 @@ import { createKbnUrlStateStorage } from '../../../../src/plugins/kibana_utils/p
|
|||
export const renderApp = (
|
||||
{ notifications, http }: CoreStart,
|
||||
{ navigation, data }: AppPluginDependencies,
|
||||
{ appBasePath, element, history }: AppMountParameters
|
||||
{ element, history }: AppMountParameters
|
||||
) => {
|
||||
const kbnUrlStateStorage = createKbnUrlStateStorage({ useHash: false, history });
|
||||
|
||||
|
|
|
@ -78,14 +78,7 @@ const {
|
|||
useContainer: useAppStateContainer,
|
||||
} = createStateContainerReactHelpers<ReduxLikeStateContainer<AppState>>();
|
||||
|
||||
const App = ({
|
||||
notifications,
|
||||
http,
|
||||
navigation,
|
||||
data,
|
||||
history,
|
||||
kbnUrlStateStorage,
|
||||
}: StateDemoAppDeps) => {
|
||||
const App = ({ navigation, data, history, kbnUrlStateStorage }: StateDemoAppDeps) => {
|
||||
const appStateContainer = useAppStateContainer();
|
||||
const appState = useAppState();
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["uiActions", "uiActionsExamples"],
|
||||
"requiredPlugins": ["uiActions", "uiActionsExamples", "developerExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
|
||||
import { UiActionsStart, UiActionsSetup } from 'src/plugins/ui_actions/public';
|
||||
import { UiActionsStart, UiActionsSetup } from '../../../src/plugins/ui_actions/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import {
|
||||
PHONE_TRIGGER,
|
||||
USER_TRIGGER,
|
||||
|
@ -39,6 +39,8 @@ import {
|
|||
ACTION_VIEW_IN_MAPS,
|
||||
ACTION_PHONE_USER,
|
||||
} from './actions/actions';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
import image from './ui_actions.png';
|
||||
|
||||
interface StartDeps {
|
||||
uiActions: UiActionsStart;
|
||||
|
@ -46,6 +48,7 @@ interface StartDeps {
|
|||
|
||||
interface SetupDeps {
|
||||
uiActions: UiActionsSetup;
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
declare module '../../../src/plugins/ui_actions/public' {
|
||||
|
@ -66,7 +69,7 @@ declare module '../../../src/plugins/ui_actions/public' {
|
|||
}
|
||||
|
||||
export class UiActionsExplorerPlugin implements Plugin<void, void, {}, StartDeps> {
|
||||
public setup(core: CoreSetup<{ uiActions: UiActionsStart }>, deps: SetupDeps) {
|
||||
public setup(core: CoreSetup<StartDeps>, deps: SetupDeps) {
|
||||
deps.uiActions.registerTrigger({
|
||||
id: COUNTRY_TRIGGER,
|
||||
});
|
||||
|
@ -98,6 +101,7 @@ export class UiActionsExplorerPlugin implements Plugin<void, void, {}, StartDeps
|
|||
core.application.register({
|
||||
id: 'uiActionsExplorer',
|
||||
title: 'Ui Actions Explorer',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const { renderApp } = await import('./app');
|
||||
|
@ -107,6 +111,24 @@ export class UiActionsExplorerPlugin implements Plugin<void, void, {}, StartDeps
|
|||
);
|
||||
},
|
||||
});
|
||||
|
||||
deps.developerExamples.register({
|
||||
appId: 'uiActionsExplorer',
|
||||
title: 'Ui Actions & Triggers',
|
||||
description: `Ui Actions can be used to make any part of your UI extensible. It has built in support for
|
||||
context menus, but you can also render all actions attached to a given trigger however you like, just how
|
||||
panel badges and panel notifications does.`,
|
||||
image,
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href: 'https://github.com/elastic/kibana/blob/master/src/plugins/ui_actions/README.md',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
BIN
examples/ui_actions_explorer/public/ui_actions.png
Normal file
BIN
examples/ui_actions_explorer/public/ui_actions.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 106 KiB |
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { SharePluginStart, SharePluginSetup } from '../../../src/plugins/share/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters } from '../../../src/core/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import {
|
||||
HelloLinkGeneratorState,
|
||||
createHelloPageLinkGenerator,
|
||||
|
@ -58,6 +58,7 @@ export class AccessLinksExamplesPlugin implements Plugin<void, void, SetupDeps,
|
|||
core.application.register({
|
||||
id: APP_ID,
|
||||
title: 'Access links examples',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const { renderApp } = await import('./app');
|
||||
return renderApp(
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["share", "urlGeneratorsExamples"],
|
||||
"requiredPlugins": ["share", "urlGeneratorsExamples", "developerExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -16,19 +16,24 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { SharePluginStart } from 'src/plugins/share/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters } from '../../../src/core/public';
|
||||
import { SharePluginStart } from '../../../src/plugins/share/public';
|
||||
import { Plugin, CoreSetup, AppMountParameters, AppNavLinkStatus } from '../../../src/core/public';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
|
||||
interface StartDeps {
|
||||
share: SharePluginStart;
|
||||
}
|
||||
|
||||
export class AccessLinksExplorerPlugin implements Plugin<void, void, {}, StartDeps> {
|
||||
public setup(core: CoreSetup<StartDeps>) {
|
||||
interface SetupDeps {
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export class AccessLinksExplorerPlugin implements Plugin<void, void, SetupDeps, StartDeps> {
|
||||
public setup(core: CoreSetup<StartDeps>, { developerExamples }: SetupDeps) {
|
||||
core.application.register({
|
||||
id: 'urlGeneratorsExplorer',
|
||||
title: 'Access links explorer',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const depsStart = (await core.getStartServices())[1];
|
||||
const { renderApp } = await import('./app');
|
||||
|
@ -40,6 +45,26 @@ export class AccessLinksExplorerPlugin implements Plugin<void, void, {}, StartDe
|
|||
);
|
||||
},
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
title: 'Url generators',
|
||||
description: `Url generators offer are a backward compatible safe way to persist a URL in a saved object.
|
||||
Store the url generator id and state, instead of the href string. When the link is recreated at run time, the service
|
||||
will run the state through any necessary migrations. Registrators can change their URL structure
|
||||
without breaking these links stored in saved objects.
|
||||
`,
|
||||
appId: 'urlGeneratorsExplorer',
|
||||
links: [
|
||||
{
|
||||
label: 'README',
|
||||
href:
|
||||
'https://github.com/elastic/kibana/blob/master/src/plugins/share/public/url_generators/README.md',
|
||||
iconType: 'logoGithub',
|
||||
size: 's',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
|
@ -18,15 +18,14 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../../functional/ftr_provider_context';
|
||||
import { FtrProviderContext } from '../../functional/ftr_provider_context';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const appsMenu = getService('appsMenu');
|
||||
|
||||
describe('batchedFunction', () => {
|
||||
beforeEach(async () => {
|
||||
await appsMenu.clickLink('bfetch explorer');
|
||||
await testSubjects.click('count-until');
|
||||
await testSubjects.click('double-integers');
|
||||
});
|
|
@ -17,18 +17,17 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../../functional/ftr_provider_context';
|
||||
import { FtrProviderContext } from '../../functional/ftr_provider_context';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function ({ getService, getPageObjects, loadTestFile }: FtrProviderContext) {
|
||||
const browser = getService('browser');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const PageObjects = getPageObjects(['common', 'header']);
|
||||
|
||||
describe('bfetch explorer', function () {
|
||||
before(async () => {
|
||||
await browser.setWindowSize(1300, 900);
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
await appsMenu.clickLink('bfetch explorer');
|
||||
await PageObjects.common.navigateToApp('bfetch-explorer', { insertTimestamp: false });
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./batched_function'));
|
|
@ -27,6 +27,7 @@ export default async function ({ readConfigFile }) {
|
|||
testFiles: [
|
||||
require.resolve('./search'),
|
||||
require.resolve('./embeddables'),
|
||||
require.resolve('./bfetch_explorer'),
|
||||
require.resolve('./ui_actions'),
|
||||
require.resolve('./state_sync'),
|
||||
],
|
||||
|
|
|
@ -26,14 +26,12 @@ export default function ({
|
|||
loadTestFile,
|
||||
}: PluginFunctionalProviderContext) {
|
||||
const browser = getService('browser');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const PageObjects = getPageObjects(['common', 'header']);
|
||||
|
||||
describe('embeddable explorer', function () {
|
||||
before(async () => {
|
||||
await browser.setWindowSize(1300, 900);
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
await appsMenu.clickLink('Embeddable explorer');
|
||||
await PageObjects.common.navigateToApp('embeddableExplorer');
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./hello_world_embeddable'));
|
||||
|
|
|
@ -22,7 +22,6 @@ import { FtrProviderContext } from 'test/functional/ftr_provider_context';
|
|||
// eslint-disable-next-line import/no-default-export
|
||||
export default function ({ getService, getPageObjects, loadTestFile }: FtrProviderContext) {
|
||||
const browser = getService('browser');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const PageObjects = getPageObjects(['common', 'header']);
|
||||
|
@ -36,8 +35,7 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid
|
|||
defaultIndex: 'logstash-*',
|
||||
});
|
||||
await browser.setWindowSize(1300, 900);
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
await appsMenu.clickLink('Search Explorer');
|
||||
await PageObjects.common.navigateToApp('searchExplorer');
|
||||
});
|
||||
|
||||
after(async function () {
|
||||
|
|
|
@ -26,12 +26,10 @@ export default function ({
|
|||
loadTestFile,
|
||||
}: PluginFunctionalProviderContext) {
|
||||
const browser = getService('browser');
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
|
||||
describe('state sync examples', function () {
|
||||
before(async () => {
|
||||
await browser.setWindowSize(1300, 900);
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./todo_app'));
|
||||
|
|
|
@ -26,7 +26,6 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
const testSubjects = getService('testSubjects');
|
||||
const find = getService('find');
|
||||
const retry = getService('retry');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const browser = getService('browser');
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
const log = getService('log');
|
||||
|
@ -38,7 +37,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
|
||||
before(async () => {
|
||||
base = await PageObjects.common.getHostPort();
|
||||
await appsMenu.clickLink('State containers example - browser history routing');
|
||||
await PageObjects.common.navigateToApp(appId, { insertTimestamp: false });
|
||||
});
|
||||
|
||||
it('links are rendered correctly and state is preserved in links', async () => {
|
||||
|
@ -119,7 +118,9 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
|
||||
describe('TODO app with hash history ', async () => {
|
||||
before(async () => {
|
||||
await appsMenu.clickLink('State containers example - hash history routing');
|
||||
await PageObjects.common.navigateToApp('stateContainersExampleHashHistory', {
|
||||
insertTimestamp: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('Links are rendered correctly and state is preserved in links', async () => {
|
||||
|
|
|
@ -26,14 +26,12 @@ export default function ({
|
|||
loadTestFile,
|
||||
}: PluginFunctionalProviderContext) {
|
||||
const browser = getService('browser');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const PageObjects = getPageObjects(['common', 'header']);
|
||||
|
||||
describe('ui actions explorer', function () {
|
||||
before(async () => {
|
||||
await browser.setWindowSize(1300, 900);
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
await appsMenu.clickLink('Ui Actions Explorer');
|
||||
await PageObjects.common.navigateToApp('uiActionsExplorer');
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./ui_actions'));
|
||||
|
|
|
@ -37,7 +37,6 @@ export default async function ({ readConfigFile }) {
|
|||
require.resolve('./test_suites/embeddable_explorer'),
|
||||
require.resolve('./test_suites/core_plugins'),
|
||||
require.resolve('./test_suites/management'),
|
||||
require.resolve('./test_suites/bfetch_explorer'),
|
||||
require.resolve('./test_suites/doc_views'),
|
||||
],
|
||||
services: {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"id": "kbn_tp_bfetch_explorer",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["kbn_tp_bfetch_explorer"],
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["bfetch"],
|
||||
"optionalPlugins": []
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"name": "kbn_tp_bfetch_explorer",
|
||||
"version": "1.0.0",
|
||||
"main": "target/examples/kbn_tp_bfetch_explorer",
|
||||
"kibana": {
|
||||
"version": "kibana",
|
||||
"templateVersion": "1.0.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"kbn": "node ../../scripts/kbn.js",
|
||||
"build": "rm -rf './target' && tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "3.7.2"
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target",
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"node",
|
||||
"jest",
|
||||
"react"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"public/**/*.ts",
|
||||
"public/**/*.tsx",
|
||||
"server/**/*.ts",
|
||||
"server/**/*.tsx",
|
||||
"../../../../typings/**/*",
|
||||
],
|
||||
"exclude": []
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue