mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* [Discover] Remove Angular from doc viewer (#109368) * Remove angular from doc viewer * Remove types * Remove plugin_functional for angular doc_view, since testing angular is no longer necessary * Update doc_views.ts * Delete test/plugin_functional/test_suites/doc_views directory * Update config.ts Co-authored-by: Matthias Wilhelm <matthias.wilhelm@elastic.co> Co-authored-by: Matthias Wilhelm <ankertal@gmail.com>
This commit is contained in:
parent
4642866c85
commit
9e06a9afcc
13 changed files with 4 additions and 287 deletions
|
@ -1052,8 +1052,7 @@
|
|||
"description": [],
|
||||
"signature": [
|
||||
"{ addDocView(docViewRaw: ComponentDocViewInput | ",
|
||||
"RenderDocViewInput",
|
||||
" | DirectiveDocViewInput | ",
|
||||
"RenderDocViewInput |",
|
||||
"DocViewInputFn",
|
||||
"): void; }"
|
||||
],
|
||||
|
@ -1391,4 +1390,4 @@
|
|||
],
|
||||
"objects": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { auto, IController } from 'angular';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import angular, { ICompileService } from 'angular';
|
||||
import { DocViewRenderProps, AngularScope, AngularDirective } from './doc_views_types';
|
||||
import { DocViewerError } from '../components/doc_viewer/doc_viewer_render_error';
|
||||
|
||||
/**
|
||||
* Compiles and injects the give angular template into the given dom node
|
||||
* returns a function to cleanup the injected angular element
|
||||
*/
|
||||
export async function injectAngularElement(
|
||||
domNode: Element,
|
||||
template: string,
|
||||
scopeProps: DocViewRenderProps,
|
||||
Controller: IController,
|
||||
getInjector: () => Promise<auto.IInjectorService>
|
||||
): Promise<() => void> {
|
||||
const $injector = await getInjector();
|
||||
const rootScope: AngularScope = $injector.get('$rootScope');
|
||||
const $compile: ICompileService = $injector.get('$compile');
|
||||
const newScope = Object.assign(rootScope.$new(), scopeProps);
|
||||
|
||||
if (typeof Controller === 'function') {
|
||||
// when a controller is defined, expose the value it produces to the view as `$ctrl`
|
||||
// see: https://docs.angularjs.org/api/ng/provider/$compileProvider#component
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(newScope as any).$ctrl = $injector.instantiate(Controller, {
|
||||
$scope: newScope,
|
||||
});
|
||||
}
|
||||
|
||||
const $target = angular.element(domNode);
|
||||
const $element = angular.element(template);
|
||||
|
||||
newScope.$apply(() => {
|
||||
const linkFn = $compile($element);
|
||||
$target.empty().append($element);
|
||||
linkFn(newScope);
|
||||
});
|
||||
|
||||
return () => {
|
||||
newScope.$destroy();
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Converts a given legacy angular directive to a render function
|
||||
* for usage in a react component. Note that the rendering is async
|
||||
*/
|
||||
export function convertDirectiveToRenderFn(
|
||||
directive: AngularDirective,
|
||||
getInjector: () => Promise<auto.IInjectorService>
|
||||
) {
|
||||
return (domNode: Element, props: DocViewRenderProps) => {
|
||||
let rejected = false;
|
||||
|
||||
const cleanupFnPromise = injectAngularElement(
|
||||
domNode,
|
||||
directive.template,
|
||||
props,
|
||||
directive.controller,
|
||||
getInjector
|
||||
);
|
||||
cleanupFnPromise.catch((e) => {
|
||||
rejected = true;
|
||||
render(<DocViewerError error={e} />, domNode);
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (!rejected) {
|
||||
// for cleanup
|
||||
// http://roubenmeschian.com/rubo/?p=51
|
||||
cleanupFnPromise.then((cleanup) => cleanup());
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
|
@ -6,33 +6,16 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { auto } from 'angular';
|
||||
import { convertDirectiveToRenderFn } from './doc_views_helpers';
|
||||
import { DocView, DocViewInput, ElasticSearchHit, DocViewInputFn } from './doc_views_types';
|
||||
|
||||
export class DocViewsRegistry {
|
||||
private docViews: DocView[] = [];
|
||||
private angularInjectorGetter: (() => Promise<auto.IInjectorService>) | null = null;
|
||||
|
||||
setAngularInjectorGetter = (injectorGetter: () => Promise<auto.IInjectorService>) => {
|
||||
this.angularInjectorGetter = injectorGetter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends and adds the given doc view to the registry array
|
||||
*/
|
||||
addDocView(docViewRaw: DocViewInput | DocViewInputFn) {
|
||||
const docView = typeof docViewRaw === 'function' ? docViewRaw() : docViewRaw;
|
||||
if (docView.directive) {
|
||||
// convert angular directive to render function for backwards compatibility
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(docView.render as any) = convertDirectiveToRenderFn(docView.directive as any, () => {
|
||||
if (!this.angularInjectorGetter) {
|
||||
throw new Error('Angular was not initialized');
|
||||
}
|
||||
return this.angularInjectorGetter();
|
||||
});
|
||||
}
|
||||
if (typeof docView.shouldShow !== 'function') {
|
||||
docView.shouldShow = () => true;
|
||||
}
|
||||
|
|
|
@ -7,17 +7,10 @@
|
|||
*/
|
||||
|
||||
import { ComponentType } from 'react';
|
||||
import { IScope } from 'angular';
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { IndexPattern } from '../../../../data/public';
|
||||
|
||||
export interface AngularDirective {
|
||||
controller: (...injectedServices: unknown[]) => void;
|
||||
template: string;
|
||||
}
|
||||
|
||||
export type AngularScope = IScope;
|
||||
|
||||
export type ElasticSearchHit<T = unknown> = estypes.SearchHit<T>;
|
||||
|
||||
export interface FieldMapping {
|
||||
|
@ -67,13 +60,7 @@ interface ComponentDocViewInput extends BaseDocViewInput {
|
|||
directive?: undefined;
|
||||
}
|
||||
|
||||
interface DirectiveDocViewInput extends BaseDocViewInput {
|
||||
component?: undefined;
|
||||
render?: undefined;
|
||||
directive: ng.IDirective;
|
||||
}
|
||||
|
||||
export type DocViewInput = ComponentDocViewInput | RenderDocViewInput | DirectiveDocViewInput;
|
||||
export type DocViewInput = ComponentDocViewInput | RenderDocViewInput;
|
||||
|
||||
export type DocView = DocViewInput & {
|
||||
shouldShow: NonNullable<DocViewInput['shouldShow']>;
|
||||
|
|
|
@ -317,7 +317,6 @@ export class DiscoverPlugin
|
|||
stopUrlTracker();
|
||||
};
|
||||
|
||||
this.docViewsRegistry.setAngularInjectorGetter(this.getEmbeddableInjector);
|
||||
core.application.register({
|
||||
id: 'discover',
|
||||
title: 'Discover',
|
||||
|
|
|
@ -29,7 +29,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
require.resolve('./test_suites/panel_actions'),
|
||||
require.resolve('./test_suites/core_plugins'),
|
||||
require.resolve('./test_suites/management'),
|
||||
require.resolve('./test_suites/doc_views'),
|
||||
require.resolve('./test_suites/application_links'),
|
||||
require.resolve('./test_suites/data_plugin'),
|
||||
require.resolve('./test_suites/saved_objects_management'),
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"id": "docViewPlugin",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["discover"]
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"name": "docViewPlugin",
|
||||
"version": "1.0.0",
|
||||
"main": "target/test/plugin_functional/plugins/doc_views_plugin",
|
||||
"kibana": {
|
||||
"version": "kibana",
|
||||
"templateVersion": "1.0.0"
|
||||
},
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0",
|
||||
"scripts": {
|
||||
"kbn": "node ../../../../scripts/kbn.js",
|
||||
"build": "rm -rf './target' && ../../../../node_modules/.bin/tsc"
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { DocViewsPlugin } from './plugin';
|
||||
|
||||
export const plugin = () => new DocViewsPlugin();
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import angular from 'angular';
|
||||
import React from 'react';
|
||||
import { Plugin, CoreSetup } from 'kibana/public';
|
||||
import { DiscoverSetup } from '../../../../../src/plugins/discover/public';
|
||||
|
||||
angular.module('myDocView', []).directive('myHit', () => ({
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
hit: '=hit',
|
||||
},
|
||||
template: '<h1 data-test-subj="angular-docview">{{hit._index}}</h1>',
|
||||
}));
|
||||
|
||||
function MyHit(props: { index: string }) {
|
||||
return <h1 data-test-subj="react-docview">{props.index}</h1>;
|
||||
}
|
||||
|
||||
export class DocViewsPlugin implements Plugin<void, void> {
|
||||
public setup(core: CoreSetup, { discover }: { discover: DiscoverSetup }) {
|
||||
discover.docViews.addDocView({
|
||||
directive: {
|
||||
controller: function MyController($injector: any) {
|
||||
$injector.loadNewModules(['myDocView']);
|
||||
},
|
||||
template: `<my-hit hit="hit"></my-hit>`,
|
||||
},
|
||||
order: 1,
|
||||
title: 'Angular doc view',
|
||||
});
|
||||
|
||||
discover.docViews.addDocView({
|
||||
component: (props) => {
|
||||
return <MyHit index={props.hit._index as string} />;
|
||||
},
|
||||
order: 2,
|
||||
title: 'React doc view',
|
||||
});
|
||||
}
|
||||
|
||||
public start() {}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target/types"
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"public/**/*.ts",
|
||||
"public/**/*.tsx",
|
||||
"../../../../typings/**/*"
|
||||
],
|
||||
"exclude": [],
|
||||
"references": [
|
||||
{ "path": "../../../../src/core/tsconfig.json" },
|
||||
{ "path": "../../../../src/plugins/discover/tsconfig.json" },
|
||||
]
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const find = getService('find');
|
||||
const PageObjects = getPageObjects(['common', 'discover', 'timePicker']);
|
||||
|
||||
describe('custom doc views', function () {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToApp('discover');
|
||||
await PageObjects.timePicker.setDefaultAbsoluteRange();
|
||||
});
|
||||
|
||||
it('should show custom doc views', async () => {
|
||||
await testSubjects.click('docTableExpandToggleColumn');
|
||||
const angularTab = await find.byButtonText('Angular doc view');
|
||||
const reactTab = await find.byButtonText('React doc view');
|
||||
expect(await angularTab.isDisplayed()).to.be(true);
|
||||
expect(await reactTab.isDisplayed()).to.be(true);
|
||||
});
|
||||
|
||||
it('should render angular doc view', async () => {
|
||||
const angularTab = await find.byButtonText('Angular doc view');
|
||||
await angularTab.click();
|
||||
const angularContent = await testSubjects.find('angular-docview');
|
||||
expect(await angularContent.getVisibleText()).to.be('logstash-2015.09.22');
|
||||
});
|
||||
|
||||
it('should render react doc view', async () => {
|
||||
const reactTab = await find.byButtonText('React doc view');
|
||||
await reactTab.click();
|
||||
const reactContent = await testSubjects.find('react-docview');
|
||||
expect(await reactContent.getVisibleText()).to.be('logstash-2015.09.22');
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
export default function ({ getService, loadTestFile }: PluginFunctionalProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('doc views', function () {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/discover');
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./doc_views'));
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue