Skip to content

Commit

Permalink
Typescriptify ui/embeddable folder (#19648)
Browse files Browse the repository at this point in the history
* Typescriptify ui/embeddable folder

* Allow ts modules from ui/public folders to be imported

* Address review comments from Tim

* Address code review from Oleg

* remove lodash usage

* remove mappng to non public folder
  • Loading branch information
stacey-gammon authored Jun 5, 2018
1 parent 1617da9 commit 16fc1cf
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 117 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"@kbn/pm": "link:packages/kbn-pm",
"@kbn/test-subj-selector": "link:packages/kbn-test-subj-selector",
"@kbn/ui-framework": "link:packages/kbn-ui-framework",
"@types/prop-types": "^15.5.3",
"JSONStream": "1.1.1",
"accept-language-parser": "1.2.0",
"angular": "1.6.9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,19 @@ import * as columnActions from 'ui/doc_table/actions/columns';

export class SearchEmbeddable extends Embeddable {
constructor({ onEmbeddableStateChanged, savedSearch, editUrl, loader, $rootScope, $compile }) {
super();
super({
metadata: {
title: savedSearch.title,
editUrl,
indexPattern: savedSearch.searchSource.get('index')
}
});
this.onEmbeddableStateChanged = onEmbeddableStateChanged;
this.savedSearch = savedSearch;
this.loader = loader;
this.$rootScope = $rootScope;
this.$compile = $compile;
this.customization = {};

/**
* @type {EmbeddableMetadata}
*/
this.metadata = {
title: savedSearch.title,
editUrl,
indexPattern: this.savedSearch.searchSource.get('index'),
};
}

emitEmbeddableStateChange(embeddableState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ import _ from 'lodash';

export class VisualizeEmbeddable extends Embeddable {
constructor({ onEmbeddableStateChanged, savedVisualization, editUrl, loader }) {
super();
super({
metadata: {
title: savedVisualization.title,
editUrl,
indexPattern: savedVisualization.vis.indexPattern
}
});
this._onEmbeddableStateChanged = onEmbeddableStateChanged;
this.savedVisualization = savedVisualization;
this.loader = loader;
Expand All @@ -33,15 +39,6 @@ export class VisualizeEmbeddable extends Embeddable {
this.uiState = new PersistedState(parsedUiState);

this.uiState.on('change', this._uiStateChangeHandler);

/**
* @type {EmbeddableMetadata}
*/
this.metadata = {
title: savedVisualization.title,
editUrl,
indexPattern: this.savedVisualization.vis.indexPattern
};
}

_uiStateChangeHandler = () => {
Expand Down
76 changes: 0 additions & 76 deletions src/ui/public/embeddable/embeddable.js

This file was deleted.

95 changes: 95 additions & 0 deletions src/ui/public/embeddable/embeddable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* 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 * as PropTypes from 'prop-types';
import { ContainerState } from './types';

// TODO: we'll be able to get rid of this shape once all of dashboard is typescriptified too.
export const embeddableShape = PropTypes.shape({
destroy: PropTypes.func.isRequired,
metadata: PropTypes.object.isRequired,
onContainerStateChanged: PropTypes.func.isRequired,
render: PropTypes.func.isRequired,
});

interface EmbeddableMetadata {
// TODO: change to an array, embeddables should be able to specify multiple index patterns they use. Also
// see https://github.com/elastic/kibana/issues/19408 - this needs to be generalized to support embeddables that
// use dynamic index patterns (vega, TSVB) instead of saved object index patterns (most other visualizations).
/**
* Should specify any index pattern the embeddable uses. This will be used by the container to list out
* available fields to filter on.
*/
indexPattern?: object;

/**
* The title, or name, of the embeddable.
*/
title?: string;

/**
* A url to direct the user for managing the embeddable instance. We may want to eventually make this optional
* for non-instanced panels that can only be created and deleted but not edited. We also wish to eventually support
* in-place editing on the dashboard itself, so another option could be to supply an element, or fly out panel, to
* offer for editing directly on the dashboard.
*/
editUrl?: string;
}

interface EmbeddableOptions {
metadata?: EmbeddableMetadata;
render?: (domNode: HTMLElement, containerState: ContainerState) => void;
destroy?: () => void;
onContainerStateChanged?: (containerState: ContainerState) => void;
}

export abstract class Embeddable {
public readonly metadata: EmbeddableMetadata = {};

// TODO: Make title and editUrl required and move out of options parameter.
constructor(options: EmbeddableOptions = {}) {
this.metadata = options.metadata || {};

if (options.render) {
this.render = options.render;
}

if (options.destroy) {
this.destroy = options.destroy;
}

if (options.onContainerStateChanged) {
this.onContainerStateChanged = options.onContainerStateChanged;
}
}

public abstract onContainerStateChanged(containerState: ContainerState): void;

/**
* Embeddable should render itself at the given domNode.
*/
public abstract render(
domNode: HTMLElement,
containerState: ContainerState
): void;

public destroy(): void {
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
* under the License.
*/

// @ts-ignore: implicit any for JS file
import { uiRegistry } from '../registry/_registry';

/**
* Registry of functions (EmbeddableFactoryProviders) which return an EmbeddableFactory.
*/
export const EmbeddableFactoriesRegistryProvider = uiRegistry({
index: ['name'],
name: 'embeddableFactories',
index: ['name']
});

Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,24 @@
* under the License.
*/

/**
* @typedef {Object} EmbeddableState
* @property {Object} customization - any customization data that should be stored at the panel level. For
* example, pie slice colors, or custom per panel sort order or columns.
* @property {Object} stagedFilter - a possible filter the embeddable wishes dashboard to apply.
*/


/**
* @callback onEmbeddableStateChanged
* @param {EmbeddableState} embeddableState
*/
import { Embeddable } from './embeddable';
import { EmbeddableState } from './types';

/**
* The EmbeddableFactory creates and initializes an embeddable instance
*/
export class EmbeddableFactory {
export abstract class EmbeddableFactory {
/**
*
* @param {Object} containerMetadata. Currently just passing in panelState but it's more than we need, so we should
* @param {{ id: string }} containerMetadata. Currently just passing in panelState but it's more than we need, so we should
* decouple this to only include data given to us from the embeddable when it's added to the dashboard. Generally
* will be just the object id, but could be anything depending on the plugin.
* @param {onEmbeddableStateChanged} onEmbeddableStateChanged - embeddable should call this function with updated
* state whenever something changes that the dashboard should know about.
* @return {Promise.<Embeddable>}
*/
create(/* containerMetadata, onEmbeddableStateChanged*/) {
throw new Error('Must implement create.');
}
public abstract create(
containerMetadata: { id: string },
onEmbeddableStateChanged: (embeddableStateChanges: EmbeddableState) => void
): Promise<Embeddable>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@

export { EmbeddableFactory } from './embeddable_factory';
export * from './embeddable';
export { EmbeddableFactoriesRegistryProvider } from './embeddable_factories_registry';
export {
EmbeddableFactoriesRegistryProvider,
} from './embeddable_factories_registry';
57 changes: 57 additions & 0 deletions src/ui/public/embeddable/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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.
*/

export interface ContainerState {
// 'view' or 'edit'. Should probably be an enum but I'm undecided where to define it, here or in dashboard code.
viewMode: string;

timeRange: {
// To and From should be either an absolute time range in utc format or a relative one (e.g. now-15m)
to: string;
from: string;
};

// The shape will be up to the embeddable type.
embeddableCustomization?: object;

/**
* Whether or not panel titles are hidden. It is not the embeddable's responsibility to hide the title (the container
* handles that). This information is currently only used to determine the title for reporting (data-sharing-title
* attribute). If we move that out of the embeddables and push it to the container (as we probably should), then
* we shouldn't need to expose this information.
*/
hidePanelTitles: boolean;

/**
* Is the current panel in expanded mode
*/
isPanelExpanded: boolean;
}

export interface EmbeddableState {
/**
* Any customization data that should be stored at the panel level. For
* example, pie slice colors, or custom per panel sort order or columns.
*/
customization: object;
/**
* A possible filter the embeddable wishes dashboard to apply.
*/
stagedFilter: object;
}
4 changes: 3 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",

"paths": {
"ui/*": ["src/ui/public/*"]
},
// Support .tsx files and transform JSX into calls to React.createElement
"jsx": "react",

Expand Down
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@
dependencies:
"@types/retry" "*"

"@types/prop-types@^15.5.3":
version "15.5.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.3.tgz#bef071852dca2a2dbb65fecdb7bfb30cedae2de2"

"@types/react-dom@^16.0.5":
version "16.0.5"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.5.tgz#a757457662e3819409229e8f86795ff37b371f96"
Expand Down

0 comments on commit 16fc1cf

Please sign in to comment.