Skip to content

Commit

Permalink
Prep for embed saved object refactor + helper (elastic#62486)
Browse files Browse the repository at this point in the history
  • Loading branch information
stacey-gammon committed Apr 6, 2020
1 parent daa5a7a commit 8bd7c9c
Show file tree
Hide file tree
Showing 26 changed files with 234 additions and 303 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,25 @@ export class ListContainer extends Container<{}, ContainerInput> {
public readonly type = LIST_CONTAINER;
private node?: HTMLElement;

constructor(
input: ContainerInput,
getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']
) {
super(input, { embeddableLoaded: {} }, getEmbeddableFactory);
constructor(input: ContainerInput, private embeddableServices: EmbeddableStart) {
super(input, { embeddableLoaded: {} }, embeddableServices.getEmbeddableFactory);
}

// This container has no input itself.
getInheritedInput(id: string) {
return {};
getInheritedInput() {
return {
viewMode: this.input.viewMode,
};
}

public render(node: HTMLElement) {
this.node = node;
if (this.node) {
ReactDOM.unmountComponentAtNode(this.node);
}
ReactDOM.render(<ListContainerComponent embeddable={this} />, node);
ReactDOM.render(
<ListContainerComponent embeddable={this} embeddableServices={this.embeddableServices} />,
node
);
}

public destroy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,35 @@ import {
withEmbeddableSubscription,
ContainerInput,
ContainerOutput,
EmbeddableStart,
} from '../../../../src/plugins/embeddable/public';
import { EmbeddableListItem } from './embeddable_list_item';

interface Props {
embeddable: IContainer;
input: ContainerInput;
output: ContainerOutput;
embeddableServices: EmbeddableStart;
}

function renderList(embeddable: IContainer, panels: ContainerInput['panels']) {
function renderList(
embeddable: IContainer,
panels: ContainerInput['panels'],
embeddableServices: EmbeddableStart
) {
let number = 0;
const list = Object.values(panels).map(panel => {
const child = embeddable.getChild(panel.explicitInput.id);
number++;
return (
<EuiPanel key={number.toString()}>
<EuiFlexGroup>
<EuiFlexGroup gutterSize="none">
<EuiFlexItem grow={false}>
<EuiText>
<h3>{number}</h3>
</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EmbeddableListItem embeddable={child} />
<embeddableServices.EmbeddablePanel embeddable={child} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
Expand All @@ -56,12 +61,12 @@ function renderList(embeddable: IContainer, panels: ContainerInput['panels']) {
return list;
}

export function ListContainerComponentInner(props: Props) {
export function ListContainerComponentInner({ embeddable, input, embeddableServices }: Props) {
return (
<div>
<h2 data-test-subj="listContainerTitle">{props.embeddable.getTitle()}</h2>
<h2 data-test-subj="listContainerTitle">{embeddable.getTitle()}</h2>
<EuiSpacer size="l" />
{renderList(props.embeddable, props.input.panels)}
{renderList(embeddable, input.panels, embeddableServices)}
</div>
);
}
Expand All @@ -71,4 +76,9 @@ export function ListContainerComponentInner(props: Props) {
// anything on input or output state changes. If you don't want that to happen (for example
// if you expect something on input or output state to change frequently that your react
// component does not care about, then you should probably hook this up manually).
export const ListContainerComponent = withEmbeddableSubscription(ListContainerComponentInner);
export const ListContainerComponent = withEmbeddableSubscription<
ContainerInput,
ContainerOutput,
IContainer,
{ embeddableServices: EmbeddableStart }
>(ListContainerComponentInner);
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
import { LIST_CONTAINER, ListContainer } from './list_container';

interface StartServices {
getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
embeddableServices: EmbeddableStart;
}

export class ListContainerFactory implements EmbeddableFactoryDefinition {
Expand All @@ -40,8 +40,8 @@ export class ListContainerFactory implements EmbeddableFactoryDefinition {
}

public create = async (initialInput: ContainerInput) => {
const { getEmbeddableFactory } = await this.getStartServices();
return new ListContainer(initialInput, getEmbeddableFactory);
const { embeddableServices } = await this.getStartServices();
return new ListContainer(initialInput, embeddableServices);
};

public getDisplayName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function wrapSearchTerms(task: string, search?: string) {
);
}

function renderTasks(tasks: MultiTaskTodoOutput['tasks'], search?: string) {
function renderTasks(tasks: MultiTaskTodoInput['tasks'], search?: string) {
return tasks.map(task => (
<EuiListGroupItem
key={task}
Expand All @@ -65,16 +65,15 @@ function renderTasks(tasks: MultiTaskTodoOutput['tasks'], search?: string) {
}

export function MultiTaskTodoEmbeddableComponentInner({
input: { title, icon, search },
output: { tasks },
input: { title, icon, search, tasks },
}: Props) {
return (
<EuiFlexGroup>
<EuiFlexGroup gutterSize="none">
<EuiFlexItem grow={false}>
{icon ? <EuiIcon type={icon} size="l" /> : <EuiAvatar name={title} size="l" />}
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGrid columns={1}>
<EuiFlexGrid columns={1} gutterSize="none">
<EuiFlexItem>
<EuiText data-test-subj="multiTaskTodoTitle">
<h3>{wrapSearchTerms(title, search)}</h3>
Expand All @@ -89,6 +88,8 @@ export function MultiTaskTodoEmbeddableComponentInner({
);
}

export const MultiTaskTodoEmbeddableComponent = withEmbeddableSubscription(
MultiTaskTodoEmbeddableComponentInner
);
export const MultiTaskTodoEmbeddableComponent = withEmbeddableSubscription<
MultiTaskTodoInput,
MultiTaskTodoOutput,
MultiTaskTodoEmbeddable
>(MultiTaskTodoEmbeddableComponentInner);
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,27 @@ export interface MultiTaskTodoInput extends EmbeddableInput {
title: string;
}

// This embeddable has output! It's the tasks list that is filtered.
// Output state is something only the embeddable itself can update. It
// can be something completely internal, or it can be state that is
// This embeddable has output! Output state is something only the embeddable itself
// can update. It can be something completely internal, or it can be state that is
// derived from input state and updates when input does.
export interface MultiTaskTodoOutput extends EmbeddableOutput {
tasks: string[];
hasMatch: boolean;
}

function getFilteredTasks(tasks: string[], search?: string) {
const filteredTasks: string[] = [];
if (search === undefined) return tasks;
function getHasMatch(tasks: string[], title?: string, search?: string) {
if (search === undefined || search === '') return false;

tasks.forEach(task => {
if (task.match(search)) {
filteredTasks.push(task);
}
});
if (title && title.match(search)) return true;

const match = tasks.find(task => task.match(search));
if (match) return true;

return filteredTasks;
return false;
}

function getOutput(input: MultiTaskTodoInput) {
const tasks = getFilteredTasks(input.tasks, input.search);
return { tasks, hasMatch: tasks.length > 0 || (input.search && input.title.match(input.search)) };
const hasMatch = getHasMatch(input.tasks, input.title, input.search);
return { hasMatch };
}

export class MultiTaskTodoEmbeddable extends Embeddable<MultiTaskTodoInput, MultiTaskTodoOutput> {
Expand Down
7 changes: 2 additions & 5 deletions examples/embeddable_examples/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,17 @@ export class EmbeddableExamplesPlugin
new MultiTaskTodoEmbeddableFactory()
);

// These are registered in the start method because `getEmbeddableFactory `
// is only available in start. We could reconsider this I think and make it
// available in both.
deps.embeddable.registerEmbeddableFactory(
SEARCHABLE_LIST_CONTAINER,
new SearchableListContainerFactory(async () => ({
getEmbeddableFactory: (await core.getStartServices())[1].embeddable.getEmbeddableFactory,
embeddableServices: (await core.getStartServices())[1].embeddable,
}))
);

deps.embeddable.registerEmbeddableFactory(
LIST_CONTAINER,
new ListContainerFactory(async () => ({
getEmbeddableFactory: (await core.getStartServices())[1].embeddable.getEmbeddableFactory,
embeddableServices: (await core.getStartServices())[1].embeddable,
}))
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,8 @@ export class SearchableListContainer extends Container<ChildInput, SearchableCon
public readonly type = SEARCHABLE_LIST_CONTAINER;
private node?: HTMLElement;

constructor(
input: SearchableContainerInput,
getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']
) {
super(input, { embeddableLoaded: {} }, getEmbeddableFactory);
constructor(input: SearchableContainerInput, private embeddableServices: EmbeddableStart) {
super(input, { embeddableLoaded: {} }, embeddableServices.getEmbeddableFactory);
}

// TODO: add a more advanced example here where inherited child input is derived from container
Expand All @@ -53,6 +50,7 @@ export class SearchableListContainer extends Container<ChildInput, SearchableCon
return {
id,
search: this.getInput().search,
viewMode: this.input.viewMode,
};
}

Expand All @@ -61,7 +59,13 @@ export class SearchableListContainer extends Container<ChildInput, SearchableCon
ReactDOM.unmountComponentAtNode(this.node);
}
this.node = node;
ReactDOM.render(<SearchableListContainerComponent embeddable={this} />, node);
ReactDOM.render(
<SearchableListContainerComponent
embeddable={this}
embeddableServices={this.embeddableServices}
/>,
node
);
}

public destroy() {
Expand Down
Loading

0 comments on commit 8bd7c9c

Please sign in to comment.