mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Typescript embeddable factories (#27146)
* Typescript embeddable factories * address review comments * Format messages * Fixes * Fix i18n ids
This commit is contained in:
parent
2371e58590
commit
3e43a65a18
11 changed files with 180 additions and 90 deletions
|
@ -84,11 +84,9 @@ export class SearchEmbeddable extends Embeddable {
|
|||
$compile,
|
||||
}: SearchEmbeddableConfig) {
|
||||
super({
|
||||
metadata: {
|
||||
title: savedSearch.title,
|
||||
editUrl,
|
||||
indexPattern: savedSearch.searchSource.getField('index'),
|
||||
},
|
||||
title: savedSearch.title,
|
||||
editUrl,
|
||||
indexPattern: savedSearch.searchSource.getField('index'),
|
||||
});
|
||||
this.onEmbeddableStateChanged = onEmbeddableStateChanged;
|
||||
this.savedSearch = savedSearch;
|
||||
|
|
|
@ -24,11 +24,10 @@ import { SearchEmbeddable } from './search_embeddable';
|
|||
|
||||
export class SearchEmbeddableFactory extends EmbeddableFactory {
|
||||
constructor($compile, $rootScope, searchLoader) {
|
||||
super();
|
||||
super({ name: 'search' });
|
||||
this.$compile = $compile;
|
||||
this.searchLoader = searchLoader;
|
||||
this.$rootScope = $rootScope;
|
||||
this.name = 'search';
|
||||
}
|
||||
|
||||
getEditPath(panelId) {
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 { I18nProvider } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Embeddable } from 'ui/embeddable';
|
||||
import { DisabledLabVisualization } from './disabled_lab_visualization';
|
||||
|
||||
export class DisabledLabEmbeddable extends Embeddable {
|
||||
private domNode?: HTMLElement;
|
||||
|
||||
constructor(title: string) {
|
||||
super({ title });
|
||||
}
|
||||
|
||||
public render(domNode: HTMLElement) {
|
||||
if (this.metadata.title) {
|
||||
this.domNode = domNode;
|
||||
ReactDOM.render(
|
||||
<I18nProvider>
|
||||
<DisabledLabVisualization title={this.metadata.title} />
|
||||
</I18nProvider>,
|
||||
domNode
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
if (this.domNode) {
|
||||
ReactDOM.unmountComponentAtNode(this.domNode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
|
||||
export function DisabledLabVisualization({ title }: { title: string }) {
|
||||
return (
|
||||
<div className="visDisabledLabVisualization">
|
||||
<div
|
||||
className="kuiVerticalRhythm visDisabledLabVisualization__icon kuiIcon fa-flask"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div className="kuiVerticalRhythm">
|
||||
<FormattedMessage
|
||||
id="kbn.visualize.disabledLabVisualizationTitle"
|
||||
defaultMessage="{title} is a lab visualization."
|
||||
values={{ title }}
|
||||
/>
|
||||
</div>
|
||||
<div className="kuiVerticalRhythm">
|
||||
<FormattedMessage
|
||||
id="kbn.visualize.disabledLabVisualizationMessage"
|
||||
defaultMessage="Please turn on lab-mode in the advanced settings to see lab visualizations."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -56,11 +56,9 @@ export class VisualizeEmbeddable extends Embeddable {
|
|||
loader,
|
||||
}: VisualizeEmbeddableConfiguration) {
|
||||
super({
|
||||
metadata: {
|
||||
title: savedVisualization.title,
|
||||
editUrl,
|
||||
indexPattern: savedVisualization.vis.indexPattern,
|
||||
},
|
||||
title: savedVisualization.title,
|
||||
editUrl,
|
||||
indexPattern: savedVisualization.vis.indexPattern,
|
||||
});
|
||||
this.onEmbeddableStateChanged = onEmbeddableStateChanged;
|
||||
this.savedVisualization = savedVisualization;
|
||||
|
|
|
@ -17,22 +17,31 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
import { Embeddable, EmbeddableFactory } from 'ui/embeddable';
|
||||
import { getVisualizeLoader } from 'ui/visualize/loader';
|
||||
import { EmbeddableFactory } from 'ui/embeddable';
|
||||
import { getVisualizeLoader, VisualizeLoader } from 'ui/visualize/loader';
|
||||
import { VisualizeEmbeddable } from './visualize_embeddable';
|
||||
|
||||
import labDisabledTemplate from './visualize_lab_disabled.html';
|
||||
import { Legacy } from 'kibana';
|
||||
import { OnEmbeddableStateChanged } from 'ui/embeddable/embeddable_factory';
|
||||
import { VisSavedObject } from 'ui/visualize/loader/types';
|
||||
import { SavedVisualizations } from '../types';
|
||||
import { DisabledLabEmbeddable } from './disabled_lab_embeddable';
|
||||
|
||||
export interface VisualizeEmbeddableInstanceConfiguration {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class VisualizeEmbeddableFactory extends EmbeddableFactory {
|
||||
constructor(savedVisualizations, config) {
|
||||
super();
|
||||
this._config = config;
|
||||
private savedVisualizations: SavedVisualizations;
|
||||
private config: Legacy.KibanaConfig;
|
||||
|
||||
constructor(savedVisualizations: SavedVisualizations, config: Legacy.KibanaConfig) {
|
||||
super({ name: 'visualization' });
|
||||
this.config = config;
|
||||
this.savedVisualizations = savedVisualizations;
|
||||
this.name = 'visualization';
|
||||
}
|
||||
|
||||
getEditPath(panelId) {
|
||||
public getEditPath(panelId: string) {
|
||||
return this.savedVisualizations.urlFor(panelId);
|
||||
}
|
||||
|
||||
|
@ -44,25 +53,22 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory {
|
|||
* @param {function} onEmbeddableStateChanged
|
||||
* @return {Promise.<{ metadata, onContainerStateChanged, render, destroy }>}
|
||||
*/
|
||||
create(panelMetadata, onEmbeddableStateChanged) {
|
||||
public create(
|
||||
panelMetadata: VisualizeEmbeddableInstanceConfiguration,
|
||||
onEmbeddableStateChanged: OnEmbeddableStateChanged
|
||||
) {
|
||||
const visId = panelMetadata.id;
|
||||
const editUrl = this.getEditPath(visId);
|
||||
|
||||
const waitFor = [getVisualizeLoader(), this.savedVisualizations.get(visId)];
|
||||
return Promise.all(waitFor).then(([loader, savedObject]) => {
|
||||
const isLabsEnabled = this._config.get('visualize:enableLabs');
|
||||
const waitFor: [Promise<VisualizeLoader>, Promise<VisSavedObject>] = [
|
||||
getVisualizeLoader(),
|
||||
this.savedVisualizations.get(visId),
|
||||
];
|
||||
return Promise.all(waitFor).then(([loader, savedObject]: [VisualizeLoader, VisSavedObject]) => {
|
||||
const isLabsEnabled = this.config.get<boolean>('visualize:enableLabs');
|
||||
|
||||
if (!isLabsEnabled && savedObject.vis.type.stage === 'experimental') {
|
||||
return new Embeddable({
|
||||
metadata: {
|
||||
title: savedObject.title,
|
||||
},
|
||||
render: domNode => {
|
||||
const template = $(labDisabledTemplate);
|
||||
template.find('.visDisabledLabVisualization__title').text(savedObject.title);
|
||||
$(domNode).html(template);
|
||||
},
|
||||
});
|
||||
return new DisabledLabEmbeddable(savedObject.title);
|
||||
} else {
|
||||
return new VisualizeEmbeddable({
|
||||
onEmbeddableStateChanged,
|
|
@ -17,13 +17,17 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { VisualizeEmbeddableFactory } from './visualize_embeddable_factory';
|
||||
import { Legacy } from 'kibana';
|
||||
import { EmbeddableFactoriesRegistryProvider } from 'ui/embeddable/embeddable_factories_registry';
|
||||
import { IPrivate } from 'ui/private';
|
||||
import { SavedVisualizations } from '../types';
|
||||
import { VisualizeEmbeddableFactory } from './visualize_embeddable_factory';
|
||||
|
||||
export function visualizeEmbeddableFactoryProvider(Private) {
|
||||
export function visualizeEmbeddableFactoryProvider(Private: IPrivate) {
|
||||
const VisualizeEmbeddableFactoryProvider = (
|
||||
savedVisualizations,
|
||||
config) => {
|
||||
savedVisualizations: SavedVisualizations,
|
||||
config: Legacy.KibanaConfig
|
||||
) => {
|
||||
return new VisualizeEmbeddableFactory(savedVisualizations, config);
|
||||
};
|
||||
return Private(VisualizeEmbeddableFactoryProvider);
|
|
@ -1,15 +0,0 @@
|
|||
<div class="visDisabledLabVisualization">
|
||||
<div class="kuiVerticalRhythm visDisabledLabVisualization__icon kuiIcon fa-flask" aria-hidden="true"></div>
|
||||
<div
|
||||
class="kuiVerticalRhythm"
|
||||
><em class="visDisabledLabVisualization__title"></em>
|
||||
{{ ::'kbn.visualize.embeddableVisualization.labVisualizationInfoText' | i18n: {
|
||||
defaultMessage: 'is a lab visualization.',
|
||||
description: 'Part of "{visTitle} is a lab visualization."' } }}
|
||||
</div>
|
||||
<div
|
||||
class="kuiVerticalRhythm"
|
||||
i18n-id="kbn.visualize.embeddableVisualization.labModeHelpText"
|
||||
i18n-default-message="Please turn on lab-mode in the advanced settings to see lab visualizations."
|
||||
></div>
|
||||
</div>
|
25
src/legacy/core_plugins/kibana/public/visualize/types.d.ts
vendored
Normal file
25
src/legacy/core_plugins/kibana/public/visualize/types.d.ts
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 { VisSavedObject } from 'ui/visualize/loader/types';
|
||||
|
||||
export interface SavedVisualizations {
|
||||
urlFor: (id: string) => string;
|
||||
get: (id: string) => Promise<VisSavedObject>;
|
||||
}
|
|
@ -17,18 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import * as PropTypes from 'prop-types';
|
||||
import { Adapters } from 'ui/inspector';
|
||||
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,
|
||||
});
|
||||
|
||||
export 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
|
||||
|
@ -53,39 +44,17 @@ export interface EmbeddableMetadata {
|
|||
editUrl?: string;
|
||||
}
|
||||
|
||||
interface EmbeddableOptions {
|
||||
metadata?: EmbeddableMetadata;
|
||||
render?: (domNode: HTMLElement, containerState: ContainerState) => void;
|
||||
destroy?: () => void;
|
||||
onContainerStateChanged?: (containerState: ContainerState) => void;
|
||||
reload?: () => 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;
|
||||
}
|
||||
|
||||
if (options.reload) {
|
||||
this.reload = options.reload;
|
||||
}
|
||||
constructor(metadata: EmbeddableMetadata = {}) {
|
||||
this.metadata = metadata || {};
|
||||
}
|
||||
|
||||
public abstract onContainerStateChanged(containerState: ContainerState): void;
|
||||
public onContainerStateChanged(containerState: ContainerState): void {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Embeddable should render itself at the given domNode.
|
||||
|
|
|
@ -26,6 +26,17 @@ export type OnEmbeddableStateChanged = (embeddableStateChanges: EmbeddableState)
|
|||
* The EmbeddableFactory creates and initializes an embeddable instance
|
||||
*/
|
||||
export abstract class EmbeddableFactory {
|
||||
public readonly name: string;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name - a unique identified for this factory, which will be used to map an embeddable spec to
|
||||
* a factory that can generate an instance of it.
|
||||
*/
|
||||
constructor({ name }: { name: string }) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{ id: string }} containerMetadata. Currently just passing in panelState but it's more than we need, so we should
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue