Typescriptify ui/embeddable folder (#19648) (#19683)

* 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
This commit is contained in:
Stacey Gammon 2018-06-05 15:23:32 -04:00 committed by GitHub
parent 4d7229ba17
commit d131af8da8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 187 additions and 117 deletions

View file

@ -84,6 +84,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",

View file

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

View file

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

View file

@ -1,76 +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 { PropTypes } from 'prop-types';
/**
* @typedef {Object} EmbeddableMetadata - data that does not change over the course of the embeddables life span.
* @property {string} title
* @property {string|undefined} editUrl
* @property {IndexPattern} indexPattern
*/
export const embeddableShape = PropTypes.shape({
metadata: PropTypes.object.isRequired,
onContainerStateChanged: PropTypes.func.isRequired,
render: PropTypes.func.isRequired,
destroy: PropTypes.func.isRequired,
});
export class Embeddable {
/**
*
* @param {Object|undefined} config
* @param {EmbeddableMetadata|undefined} config.metadata optional metadata
* @param {function|undefined} config.render optional render method
* @param {function|undefined} config.destroy optional destroy method
* @param {function|undefined} config.onContainerStateChanged optional onContainerStateChanged method
*/
constructor(config = {}) {
/**
* @type {EmbeddableMetadata}
*/
this.metadata = config.metadata || {};
if (config.render) {
this.render = config.render;
}
if (config.destroy) {
this.destroy = config.destroy;
}
if (config.onContainerStateChanged) {
this.onContainerStateChanged = config.onContainerStateChanged;
}
}
/**
* @param {ContainerState} containerState
*/
onContainerStateChanged(/*containerState*/) {}
/**
* @param {Element} domNode - the dom node to mount the rendered embeddable on
* @param {ContainerState} containerState
*/
render(/*domNode, containerState*/) {}
destroy() {}
}

View file

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

View file

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

View file

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

View file

@ -19,4 +19,6 @@
export { EmbeddableFactory } from './embeddable_factory';
export * from './embeddable';
export { EmbeddableFactoriesRegistryProvider } from './embeddable_factories_registry';
export {
EmbeddableFactoriesRegistryProvider,
} from './embeddable_factories_registry';

View file

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

View file

@ -1,7 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"ui/*": ["src/ui/public/*"]
},
// Support .tsx files and transform JSX into calls to React.createElement
"jsx": "react",

View file

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