Kibana developer examples landing page (#67049) (#68705)

* 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>
# Conflicts:
#	.github/CODEOWNERS
This commit is contained in:
Stacey Gammon 2020-06-10 07:55:11 -04:00 committed by GitHub
parent e8cc6b423b
commit 86ea134591
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 509 additions and 109 deletions

View file

@ -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": []
}

View file

@ -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() {}

View file

@ -4,6 +4,6 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["bfetch"],
"requiredPlugins": ["bfetch", "developerExamples"],
"optionalPlugins": []
}

View file

@ -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() {}

View 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" />

View file

@ -0,0 +1,9 @@
{
"id": "developerExamples",
"version": "0.0.1",
"kibanaVersion": "kibana",
"server": false,
"ui": true,
"requiredPlugins": [],
"optionalPlugins": []
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View 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);
};

View file

@ -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';

View 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() {}
}

View file

@ -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[];
}

View file

@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./target",
"skipLibCheck": true
},
"include": [
"index.ts",
"public/**/*.ts",
"public/**/*.tsx",
"server/**/*.ts",
"../../typings/**/*",
],
"exclude": []
}

View file

@ -4,6 +4,6 @@
"kibanaVersion": "kibana",
"server": false,
"ui": true,
"requiredPlugins": ["uiActions", "inspector", "embeddable", "embeddableExamples"],
"requiredPlugins": ["uiActions", "inspector", "embeddable", "embeddableExamples", "developerExamples"],
"optionalPlugins": []
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -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() {}

View file

@ -4,6 +4,6 @@
"kibanaVersion": "kibana",
"server": false,
"ui": true,
"requiredPlugins": ["data", "demoSearch"],
"requiredPlugins": ["data", "demoSearch", "developerExamples"],
"optionalPlugins": []
}

View file

@ -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() {}

View file

@ -4,6 +4,6 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["navigation", "data"],
"requiredPlugins": ["navigation", "data", "developerExamples"],
"optionalPlugins": []
}

View file

@ -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() {}

View file

@ -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 });

View file

@ -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();

View file

@ -4,6 +4,6 @@
"kibanaVersion": "kibana",
"server": false,
"ui": true,
"requiredPlugins": ["uiActions", "uiActionsExamples"],
"requiredPlugins": ["uiActions", "uiActionsExamples", "developerExamples"],
"optionalPlugins": []
}

View file

@ -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() {}

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View file

@ -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(

View file

@ -4,6 +4,6 @@
"kibanaVersion": "kibana",
"server": false,
"ui": true,
"requiredPlugins": ["share", "urlGeneratorsExamples"],
"requiredPlugins": ["share", "urlGeneratorsExamples", "developerExamples"],
"optionalPlugins": []
}

View file

@ -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() {}

View file

@ -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');
});

View file

@ -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'));

View file

@ -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'),
],

View file

@ -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'));

View file

@ -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 () {

View file

@ -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'));

View file

@ -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 () => {

View file

@ -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'));

View file

@ -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: {

View file

@ -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": []
}

View file

@ -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"
}
}

View file

@ -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": []
}