mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Embeddable add panel examples (#57319)
* Embeddable add panel examples * add tests * Fix type error after merge * address code review comments Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
5946729097
commit
63cfffbe11
14 changed files with 428 additions and 79 deletions
|
@ -23,9 +23,13 @@ import {
|
|||
MultiTaskTodoEmbeddable,
|
||||
MULTI_TASK_TODO_EMBEDDABLE,
|
||||
MultiTaskTodoInput,
|
||||
MultiTaskTodoOutput,
|
||||
} from './multi_task_todo_embeddable';
|
||||
|
||||
export class MultiTaskTodoEmbeddableFactory extends EmbeddableFactory {
|
||||
export class MultiTaskTodoEmbeddableFactory extends EmbeddableFactory<
|
||||
MultiTaskTodoInput,
|
||||
MultiTaskTodoOutput
|
||||
> {
|
||||
public readonly type = MULTI_TASK_TODO_EMBEDDABLE;
|
||||
|
||||
public isEditable() {
|
||||
|
@ -36,6 +40,15 @@ export class MultiTaskTodoEmbeddableFactory extends EmbeddableFactory {
|
|||
return new MultiTaskTodoEmbeddable(initialInput, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check out todo_embeddable_factory for a better example that asks for data from
|
||||
* the user. This just returns default data. That's okay too though, if you want to
|
||||
* start with default data and expose an "edit" action to modify it.
|
||||
*/
|
||||
public async getExplicitInput() {
|
||||
return { title: 'default title', tasks: ['Im default data'] };
|
||||
}
|
||||
|
||||
public getDisplayName() {
|
||||
return i18n.translate('embeddableExamples.multiTaskTodo.displayName', {
|
||||
defaultMessage: 'Multi-task todo item',
|
||||
|
|
|
@ -17,11 +17,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { IEmbeddableSetup, IEmbeddableStart } from '../../../src/plugins/embeddable/public';
|
||||
import {
|
||||
IEmbeddableSetup,
|
||||
IEmbeddableStart,
|
||||
EmbeddableFactory,
|
||||
} from '../../../src/plugins/embeddable/public';
|
||||
import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public';
|
||||
import { HelloWorldEmbeddableFactory, HELLO_WORLD_EMBEDDABLE } from './hello_world';
|
||||
import { TODO_EMBEDDABLE, TodoEmbeddableFactory } from './todo';
|
||||
import { MULTI_TASK_TODO_EMBEDDABLE, MultiTaskTodoEmbeddableFactory } from './multi_task_todo';
|
||||
import { TODO_EMBEDDABLE, TodoEmbeddableFactory, TodoInput, TodoOutput } from './todo';
|
||||
import {
|
||||
MULTI_TASK_TODO_EMBEDDABLE,
|
||||
MultiTaskTodoEmbeddableFactory,
|
||||
MultiTaskTodoOutput,
|
||||
MultiTaskTodoInput,
|
||||
} from './multi_task_todo';
|
||||
import {
|
||||
SEARCHABLE_LIST_CONTAINER,
|
||||
SearchableListContainerFactory,
|
||||
|
@ -45,12 +54,9 @@ export class EmbeddableExamplesPlugin
|
|||
new HelloWorldEmbeddableFactory()
|
||||
);
|
||||
|
||||
deps.embeddable.registerEmbeddableFactory(TODO_EMBEDDABLE, new TodoEmbeddableFactory());
|
||||
|
||||
deps.embeddable.registerEmbeddableFactory(
|
||||
MULTI_TASK_TODO_EMBEDDABLE,
|
||||
new MultiTaskTodoEmbeddableFactory()
|
||||
);
|
||||
deps.embeddable.registerEmbeddableFactory<
|
||||
EmbeddableFactory<MultiTaskTodoInput, MultiTaskTodoOutput>
|
||||
>(MULTI_TASK_TODO_EMBEDDABLE, new MultiTaskTodoEmbeddableFactory());
|
||||
}
|
||||
|
||||
public start(core: CoreStart, deps: EmbeddableExamplesStartDependencies) {
|
||||
|
@ -66,6 +72,11 @@ export class EmbeddableExamplesPlugin
|
|||
LIST_CONTAINER,
|
||||
new ListContainerFactory(deps.embeddable.getEmbeddableFactory)
|
||||
);
|
||||
|
||||
deps.embeddable.registerEmbeddableFactory<EmbeddableFactory<TodoInput, TodoOutput>>(
|
||||
TODO_EMBEDDABLE,
|
||||
new TodoEmbeddableFactory(core.overlays.openModal)
|
||||
);
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { IContainer, EmbeddableFactory } from '../../../../src/plugins/embeddable/public';
|
||||
import { TodoEmbeddable, TODO_EMBEDDABLE, TodoInput } from './todo_embeddable';
|
||||
|
||||
export class TodoEmbeddableFactory extends EmbeddableFactory {
|
||||
public readonly type = TODO_EMBEDDABLE;
|
||||
|
||||
public isEditable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public async create(initialInput: TodoInput, parent?: IContainer) {
|
||||
return new TodoEmbeddable(initialInput, parent);
|
||||
}
|
||||
|
||||
public getDisplayName() {
|
||||
return i18n.translate('embeddableExamples.todo.displayName', {
|
||||
defaultMessage: 'Todo item',
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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 { EuiModalBody } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { OverlayStart } from 'kibana/public';
|
||||
import { EuiFieldText } from '@elastic/eui';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import { toMountPoint } from '../../../../src/plugins/kibana_react/public';
|
||||
import { IContainer, EmbeddableFactory } from '../../../../src/plugins/embeddable/public';
|
||||
import { TodoEmbeddable, TODO_EMBEDDABLE, TodoInput, TodoOutput } from './todo_embeddable';
|
||||
|
||||
function TaskInput({ onSave }: { onSave: (task: string) => void }) {
|
||||
const [task, setTask] = useState('');
|
||||
return (
|
||||
<EuiModalBody>
|
||||
<EuiFieldText
|
||||
data-test-subj="taskInputField"
|
||||
value={task}
|
||||
placeholder="Enter task here"
|
||||
onChange={e => setTask(e.target.value)}
|
||||
/>
|
||||
<EuiButton data-test-subj="createTodoEmbeddable" onClick={() => onSave(task)}>
|
||||
Save
|
||||
</EuiButton>
|
||||
</EuiModalBody>
|
||||
);
|
||||
}
|
||||
|
||||
export class TodoEmbeddableFactory extends EmbeddableFactory<
|
||||
TodoInput,
|
||||
TodoOutput,
|
||||
TodoEmbeddable
|
||||
> {
|
||||
public readonly type = TODO_EMBEDDABLE;
|
||||
|
||||
constructor(private openModal: OverlayStart['openModal']) {
|
||||
super();
|
||||
}
|
||||
|
||||
public isEditable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public async create(initialInput: TodoInput, parent?: IContainer) {
|
||||
return new TodoEmbeddable(initialInput, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used when dynamically creating a new embeddable to add to a
|
||||
* container. Some input may be inherited from the container, but not all. This can be
|
||||
* used to collect specific embeddable input that the container will not provide, like
|
||||
* in this case, the task string.
|
||||
*/
|
||||
public async getExplicitInput() {
|
||||
return new Promise<{ task: string }>(resolve => {
|
||||
const onSave = (task: string) => resolve({ task });
|
||||
const overlay = this.openModal(
|
||||
toMountPoint(
|
||||
<TaskInput
|
||||
onSave={(task: string) => {
|
||||
onSave(task);
|
||||
overlay.close();
|
||||
}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public getDisplayName() {
|
||||
return i18n.translate('embeddableExamples.todo.displayName', {
|
||||
defaultMessage: 'Todo item',
|
||||
});
|
||||
}
|
||||
}
|
|
@ -5,6 +5,6 @@
|
|||
"configPath": ["embeddable_explorer"],
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["embeddable", "embeddableExamples"],
|
||||
"requiredPlugins": ["uiActions", "inspector", "embeddable", "embeddableExamples"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -23,11 +23,21 @@ import { BrowserRouter as Router, Route, withRouter, RouteComponentProps } from
|
|||
|
||||
import { EuiPage, EuiPageSideBar, EuiSideNav } from '@elastic/eui';
|
||||
|
||||
import { IEmbeddableStart } from 'src/plugins/embeddable/public';
|
||||
import { AppMountContext, AppMountParameters, CoreStart } from '../../../src/core/public';
|
||||
import { IEmbeddableStart } from '../../../src/plugins/embeddable/public';
|
||||
import { UiActionsStart } from '../../../src/plugins/ui_actions/public';
|
||||
import { Start as InspectorStartContract } from '../../../src/plugins/inspector/public';
|
||||
import {
|
||||
AppMountContext,
|
||||
AppMountParameters,
|
||||
CoreStart,
|
||||
SavedObjectsStart,
|
||||
IUiSettingsClient,
|
||||
OverlayStart,
|
||||
} from '../../../src/core/public';
|
||||
import { HelloWorldEmbeddableExample } from './hello_world_embeddable_example';
|
||||
import { TodoEmbeddableExample } from './todo_embeddable_example';
|
||||
import { ListContainerExample } from './list_container_example';
|
||||
import { EmbeddablePanelExample } from './embeddable_panel_example';
|
||||
|
||||
interface PageDef {
|
||||
title: string;
|
||||
|
@ -61,15 +71,29 @@ const Nav = withRouter(({ history, navigateToApp, pages }: NavProps) => {
|
|||
);
|
||||
});
|
||||
|
||||
interface Props {
|
||||
basename: string;
|
||||
navigateToApp: CoreStart['application']['navigateToApp'];
|
||||
embeddableApi: IEmbeddableStart;
|
||||
uiActionsApi: UiActionsStart;
|
||||
overlays: OverlayStart;
|
||||
notifications: CoreStart['notifications'];
|
||||
inspector: InspectorStartContract;
|
||||
savedObject: SavedObjectsStart;
|
||||
uiSettingsClient: IUiSettingsClient;
|
||||
}
|
||||
|
||||
const EmbeddableExplorerApp = ({
|
||||
basename,
|
||||
navigateToApp,
|
||||
embeddableApi,
|
||||
}: {
|
||||
basename: string;
|
||||
navigateToApp: CoreStart['application']['navigateToApp'];
|
||||
embeddableApi: IEmbeddableStart;
|
||||
}) => {
|
||||
inspector,
|
||||
uiSettingsClient,
|
||||
savedObject,
|
||||
overlays,
|
||||
uiActionsApi,
|
||||
notifications,
|
||||
}: Props) => {
|
||||
const pages: PageDef[] = [
|
||||
{
|
||||
title: 'Hello world embeddable',
|
||||
|
@ -90,6 +114,22 @@ const EmbeddableExplorerApp = ({
|
|||
id: 'listContainerSection',
|
||||
component: <ListContainerExample getEmbeddableFactory={embeddableApi.getEmbeddableFactory} />,
|
||||
},
|
||||
{
|
||||
title: 'Dynamically adding children to a container',
|
||||
id: 'embeddablePanelExamplae',
|
||||
component: (
|
||||
<EmbeddablePanelExample
|
||||
uiActionsApi={uiActionsApi}
|
||||
getAllEmbeddableFactories={embeddableApi.getEmbeddableFactories}
|
||||
getEmbeddableFactory={embeddableApi.getEmbeddableFactory}
|
||||
overlays={overlays}
|
||||
uiSettingsClient={uiSettingsClient}
|
||||
savedObject={savedObject}
|
||||
notifications={notifications}
|
||||
inspector={inspector}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const routes = pages.map((page, i) => (
|
||||
|
@ -108,19 +148,8 @@ const EmbeddableExplorerApp = ({
|
|||
);
|
||||
};
|
||||
|
||||
export const renderApp = (
|
||||
core: CoreStart,
|
||||
embeddableApi: IEmbeddableStart,
|
||||
{ appBasePath, element }: AppMountParameters
|
||||
) => {
|
||||
ReactDOM.render(
|
||||
<EmbeddableExplorerApp
|
||||
basename={appBasePath}
|
||||
navigateToApp={core.application.navigateToApp}
|
||||
embeddableApi={embeddableApi}
|
||||
/>,
|
||||
element
|
||||
);
|
||||
export const renderApp = (props: Props, element: AppMountParameters['element']) => {
|
||||
ReactDOM.render(<EmbeddableExplorerApp {...props} />, element);
|
||||
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
||||
|
|
164
examples/embeddable_explorer/public/embeddable_panel_example.tsx
Normal file
164
examples/embeddable_explorer/public/embeddable_panel_example.tsx
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* 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, useEffect, useRef } from 'react';
|
||||
import {
|
||||
EuiPanel,
|
||||
EuiPageBody,
|
||||
EuiPageContent,
|
||||
EuiPageContentBody,
|
||||
EuiPageHeader,
|
||||
EuiPageHeaderSection,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { OverlayStart, CoreStart, SavedObjectsStart, IUiSettingsClient } from 'kibana/public';
|
||||
import {
|
||||
GetEmbeddableFactory,
|
||||
EmbeddablePanel,
|
||||
IEmbeddableStart,
|
||||
IEmbeddable,
|
||||
} from '../../../src/plugins/embeddable/public';
|
||||
import {
|
||||
HELLO_WORLD_EMBEDDABLE,
|
||||
TODO_EMBEDDABLE,
|
||||
MULTI_TASK_TODO_EMBEDDABLE,
|
||||
SEARCHABLE_LIST_CONTAINER,
|
||||
} from '../../embeddable_examples/public';
|
||||
import { UiActionsStart } from '../../../src/plugins/ui_actions/public';
|
||||
import { Start as InspectorStartContract } from '../../../src/plugins/inspector/public';
|
||||
import { getSavedObjectFinder } from '../../../src/plugins/saved_objects/public';
|
||||
|
||||
interface Props {
|
||||
getAllEmbeddableFactories: IEmbeddableStart['getEmbeddableFactories'];
|
||||
getEmbeddableFactory: GetEmbeddableFactory;
|
||||
uiActionsApi: UiActionsStart;
|
||||
overlays: OverlayStart;
|
||||
notifications: CoreStart['notifications'];
|
||||
inspector: InspectorStartContract;
|
||||
savedObject: SavedObjectsStart;
|
||||
uiSettingsClient: IUiSettingsClient;
|
||||
}
|
||||
|
||||
export function EmbeddablePanelExample({
|
||||
inspector,
|
||||
notifications,
|
||||
overlays,
|
||||
getAllEmbeddableFactories,
|
||||
getEmbeddableFactory,
|
||||
uiActionsApi,
|
||||
savedObject,
|
||||
uiSettingsClient,
|
||||
}: Props) {
|
||||
const searchableInput = {
|
||||
id: '1',
|
||||
title: 'My searchable todo list',
|
||||
panels: {
|
||||
'1': {
|
||||
type: HELLO_WORLD_EMBEDDABLE,
|
||||
explicitInput: {
|
||||
id: '1',
|
||||
title: 'Hello',
|
||||
},
|
||||
},
|
||||
'2': {
|
||||
type: TODO_EMBEDDABLE,
|
||||
explicitInput: {
|
||||
id: '2',
|
||||
task: 'Goes out on Wednesdays!',
|
||||
icon: 'broom',
|
||||
title: 'Take out the trash',
|
||||
},
|
||||
},
|
||||
'3': {
|
||||
type: MULTI_TASK_TODO_EMBEDDABLE,
|
||||
explicitInput: {
|
||||
id: '3',
|
||||
icon: 'searchProfilerApp',
|
||||
title: 'Learn more',
|
||||
tasks: ['Go to school', 'Watch planet earth', 'Read the encyclopedia'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [embeddable, setEmbeddable] = useState<IEmbeddable | undefined>(undefined);
|
||||
|
||||
const ref = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = true;
|
||||
if (!embeddable) {
|
||||
const factory = getEmbeddableFactory(SEARCHABLE_LIST_CONTAINER);
|
||||
const promise = factory?.create(searchableInput);
|
||||
if (promise) {
|
||||
promise.then(e => {
|
||||
if (ref.current) {
|
||||
setEmbeddable(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
ref.current = false;
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiPageBody>
|
||||
<EuiPageHeader>
|
||||
<EuiPageHeaderSection>
|
||||
<EuiTitle size="l">
|
||||
<h1>The embeddable panel component</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageHeaderSection>
|
||||
</EuiPageHeader>
|
||||
<EuiPageContent>
|
||||
<EuiPageContentBody>
|
||||
<EuiText>
|
||||
You can render your embeddable inside the EmbeddablePanel component. This adds some
|
||||
extra rendering and offers a context menu with pluggable actions. Using EmbeddablePanel
|
||||
to render your embeddable means you get access to the "e;Add panel flyout"e;.
|
||||
Now you can see how to add embeddables to your container, and how
|
||||
"e;getExplicitInput"e; is used to grab input not provided by the container.
|
||||
</EuiText>
|
||||
<EuiPanel data-test-subj="embeddedPanelExample" paddingSize="none" role="figure">
|
||||
{embeddable ? (
|
||||
<EmbeddablePanel
|
||||
embeddable={embeddable}
|
||||
getActions={uiActionsApi.getTriggerCompatibleActions}
|
||||
getEmbeddableFactory={getEmbeddableFactory}
|
||||
getAllEmbeddableFactories={getAllEmbeddableFactories}
|
||||
overlays={overlays}
|
||||
notifications={notifications}
|
||||
inspector={inspector}
|
||||
SavedObjectFinder={getSavedObjectFinder(savedObject, uiSettingsClient)}
|
||||
/>
|
||||
) : (
|
||||
<EuiText>Loading...</EuiText>
|
||||
)}
|
||||
</EuiPanel>
|
||||
|
||||
<EuiSpacer />
|
||||
</EuiPageContentBody>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
);
|
||||
}
|
|
@ -60,7 +60,7 @@ export function ListContainerExample({ getEmbeddableFactory }: Props) {
|
|||
type: TODO_EMBEDDABLE,
|
||||
explicitInput: {
|
||||
id: '2',
|
||||
task: 'Goes out on Wenesdays!',
|
||||
task: 'Goes out on Wednesdays!',
|
||||
icon: 'broom',
|
||||
title: 'Take out the trash',
|
||||
},
|
||||
|
@ -91,7 +91,7 @@ export function ListContainerExample({ getEmbeddableFactory }: Props) {
|
|||
type: TODO_EMBEDDABLE,
|
||||
explicitInput: {
|
||||
id: '2',
|
||||
task: 'Goes out on Wenesdays!',
|
||||
task: 'Goes out on Wednesdays!',
|
||||
icon: 'broom',
|
||||
title: 'Take out the trash',
|
||||
},
|
||||
|
@ -102,7 +102,7 @@ export function ListContainerExample({ getEmbeddableFactory }: Props) {
|
|||
id: '3',
|
||||
icon: 'searchProfilerApp',
|
||||
title: 'Learn more',
|
||||
tasks: ['Go to school', 'Watch planet earth', 'Read the encylopedia'],
|
||||
tasks: ['Go to school', 'Watch planet earth', 'Read the encyclopedia'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -151,6 +151,11 @@ export function ListContainerExample({ getEmbeddableFactory }: Props) {
|
|||
The first HelloWorldEmbeddable does not emit the hasMatch output variable, so the
|
||||
container chooses to hide it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Check out the "e;Dynamically adding children"e; section, to see how to add
|
||||
children to this container, and see it rendered inside an `EmbeddablePanel` component.
|
||||
</p>
|
||||
</EuiText>
|
||||
|
||||
<EuiSpacer />
|
||||
|
|
|
@ -18,17 +18,38 @@
|
|||
*/
|
||||
|
||||
import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
|
||||
import { UiActionsService } from '../../../src/plugins/ui_actions/public';
|
||||
import { IEmbeddableStart } from '../../../src/plugins/embeddable/public';
|
||||
import { Start as InspectorStart } from '../../../src/plugins/inspector/public';
|
||||
|
||||
export class EmbeddableExplorerPlugin implements Plugin {
|
||||
public setup(core: CoreSetup<{ embeddable: IEmbeddableStart }>) {
|
||||
interface StartDeps {
|
||||
uiActions: UiActionsService;
|
||||
embeddable: IEmbeddableStart;
|
||||
inspector: InspectorStart;
|
||||
}
|
||||
|
||||
export class EmbeddableExplorerPlugin implements Plugin<void, void, {}, StartDeps> {
|
||||
public setup(core: CoreSetup<StartDeps>) {
|
||||
core.application.register({
|
||||
id: 'embeddableExplorer',
|
||||
title: 'Embeddable explorer',
|
||||
async mount(params: AppMountParameters) {
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const { renderApp } = await import('./app');
|
||||
return renderApp(coreStart, depsStart.embeddable, params);
|
||||
return renderApp(
|
||||
{
|
||||
notifications: coreStart.notifications,
|
||||
inspector: depsStart.inspector,
|
||||
embeddableApi: depsStart.embeddable,
|
||||
uiActionsApi: depsStart.uiActions,
|
||||
basename: params.appBasePath,
|
||||
uiSettingsClient: coreStart.uiSettings,
|
||||
savedObject: coreStart.savedObjects,
|
||||
overlays: coreStart.overlays,
|
||||
navigateToApp: coreStart.application.navigateToApp,
|
||||
},
|
||||
params.element
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,7 +24,10 @@ export interface EmbeddableApi {
|
|||
getEmbeddableFactory: (embeddableFactoryId: string) => EmbeddableFactory;
|
||||
getEmbeddableFactories: GetEmbeddableFactories;
|
||||
// TODO: Make `registerEmbeddableFactory` receive only `factory` argument.
|
||||
registerEmbeddableFactory: (id: string, factory: EmbeddableFactory) => void;
|
||||
registerEmbeddableFactory: <TEmbeddableFactory extends EmbeddableFactory>(
|
||||
id: string,
|
||||
factory: TEmbeddableFactory
|
||||
) => void;
|
||||
}
|
||||
|
||||
export interface EmbeddableDependencies {
|
||||
|
|
|
@ -33,6 +33,13 @@ export default async function({ readConfigFile }) {
|
|||
...functionalConfig.get('services'),
|
||||
...services,
|
||||
},
|
||||
uiSettings: {
|
||||
defaults: {
|
||||
'accessibility:disableAnimations': true,
|
||||
'dateFormat:tz': 'UTC',
|
||||
'telemetry:optIn': false,
|
||||
},
|
||||
},
|
||||
pageObjects: functionalConfig.get('pageObjects'),
|
||||
servers: functionalConfig.get('servers'),
|
||||
esTestCluster: functionalConfig.get('esTestCluster'),
|
||||
|
|
43
test/examples/embeddables/adding_children.ts
Normal file
43
test/examples/embeddables/adding_children.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { PluginFunctionalProviderContext } from 'test/plugin_functional/services';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function({ getService }: PluginFunctionalProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
|
||||
describe('creating and adding children', () => {
|
||||
before(async () => {
|
||||
await testSubjects.click('embeddablePanelExamplae');
|
||||
});
|
||||
|
||||
it('Can create a new child', async () => {
|
||||
await testSubjects.click('embeddablePanelToggleMenuIcon');
|
||||
await testSubjects.click('embeddablePanelAction-ADD_PANEL_ACTION_ID');
|
||||
await testSubjects.click('createNew');
|
||||
await testSubjects.click('createNew-TODO_EMBEDDABLE');
|
||||
await testSubjects.setValue('taskInputField', 'new task');
|
||||
await testSubjects.click('createTodoEmbeddable');
|
||||
const tasks = await testSubjects.getVisibleTextAll('todoEmbeddableTask');
|
||||
expect(tasks).to.eql(['Goes out on Wednesdays!', 'new task']);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -39,5 +39,6 @@ export default function({
|
|||
loadTestFile(require.resolve('./hello_world_embeddable'));
|
||||
loadTestFile(require.resolve('./todo_embeddable'));
|
||||
loadTestFile(require.resolve('./list_container'));
|
||||
loadTestFile(require.resolve('./adding_children'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ export default function({ getService }: PluginFunctionalProviderContext) {
|
|||
expect(text).to.eql(['HELLO WORLD!', 'HELLO WORLD!']);
|
||||
|
||||
const tasks = await testSubjects.getVisibleTextAll('multiTaskTodoTask');
|
||||
expect(tasks).to.eql(['Go to school', 'Watch planet earth', 'Read the encylopedia']);
|
||||
expect(tasks).to.eql(['Go to school', 'Watch planet earth', 'Read the encyclopedia']);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue