Skip to content

Commit

Permalink
Embeddable add panel examples (#57319)
Browse files Browse the repository at this point in the history
* Embeddable add panel examples

* add tests

* Fix type error after merge

* address code review comments

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
stacey-gammon and elasticmachine authored Feb 19, 2020
1 parent 5946729 commit 63cfffb
Show file tree
Hide file tree
Showing 14 changed files with 428 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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',
Expand Down
29 changes: 20 additions & 9 deletions examples/embeddable_examples/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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) {
Expand All @@ -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() {}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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',
});
}
}
2 changes: 1 addition & 1 deletion examples/embeddable_explorer/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"configPath": ["embeddable_explorer"],
"server": false,
"ui": true,
"requiredPlugins": ["embeddable", "embeddableExamples"],
"requiredPlugins": ["uiActions", "inspector", "embeddable", "embeddableExamples"],
"optionalPlugins": []
}
69 changes: 49 additions & 20 deletions examples/embeddable_explorer/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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',
Expand All @@ -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) => (
Expand All @@ -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);
};
Loading

0 comments on commit 63cfffb

Please sign in to comment.