Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lens] Initial Commit #35627

2 changes: 2 additions & 0 deletions x-pack/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { translations } from './plugins/translations';
import { upgradeAssistant } from './plugins/upgrade_assistant';
import { uptime } from './plugins/uptime';
import { ossTelemetry } from './plugins/oss_telemetry';
import { visualizationLens } from './plugins/visualization_lens';

module.exports = function (kibana) {
return [
Expand Down Expand Up @@ -75,5 +76,6 @@ module.exports = function (kibana) {
upgradeAssistant(kibana),
uptime(kibana),
ossTelemetry(kibana),
visualizationLens(kibana),
];
};
7 changes: 7 additions & 0 deletions x-pack/plugins/visualization_lens/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export const PLUGIN_ID = 'visualization_lens';
7 changes: 7 additions & 0 deletions x-pack/plugins/visualization_lens/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export * from './constants';
73 changes: 73 additions & 0 deletions x-pack/plugins/visualization_lens/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as Joi from 'joi';
import { Server } from 'hapi';
import { resolve } from 'path';

import { PLUGIN_ID } from './common';

const NOT_INTERNATIONALIZED_PRODUCT_NAME = 'Lens Visualizations';

export const visualizationLens = (kibana: any) => {
return new kibana.Plugin({
id: PLUGIN_ID,
configPrefix: `xpack.${PLUGIN_ID}`,
require: ['kibana', 'elasticsearch', 'xpack_main', 'interpreter'],
publicDir: resolve(__dirname, 'public'),

uiExports: {
app: {
title: NOT_INTERNATIONALIZED_PRODUCT_NAME,
description: 'Explore and visualize data.',
main: `plugins/${PLUGIN_ID}/app`,
icon: 'plugins/kibana/assets/visualize.svg',
euiIconType: 'visualizeApp',
order: 8950, // Uptime is 8900
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved
},
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
},

config: () => {
return Joi.object({
enabled: Joi.boolean().default(true),
}).default();
},

init(server: Server) {
server.plugins.xpack_main.registerFeature({
id: PLUGIN_ID,
name: NOT_INTERNATIONALIZED_PRODUCT_NAME,
icon: 'visualizeApp',
navLinkId: PLUGIN_ID,
app: [PLUGIN_ID, 'kibana'],
catalogue: [PLUGIN_ID],
privileges: {
all: {
api: [PLUGIN_ID],
catalogue: [PLUGIN_ID],
savedObject: {
all: [],
read: [],
},
ui: ['show'],
},
read: {
api: [PLUGIN_ID],
catalogue: [PLUGIN_ID],
savedObject: {
all: [],
read: [],
},
ui: ['show'],
},
},
});
},
});
};

export { editorFrame } from './public';
11 changes: 11 additions & 0 deletions x-pack/plugins/visualization_lens/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"author": "Elastic",
"name": "visualization_lens",
"version": "7.0.0",
"private": true,
"license": "Elastic-License",
"devDependencies": {},
"dependencies": {
"@elastic/charts": "^4.0.0"
}
}
46 changes: 46 additions & 0 deletions x-pack/plugins/visualization_lens/public/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { I18nProvider } from '@kbn/i18n/react';
import { IScope } from 'angular';
import React, { useCallback } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import chrome from 'ui/chrome';

import { PLUGIN_ID } from '../common';

import { editorFrame } from '.';

// Side effect of loading this is to register
import './indexpattern_datasource';

function Lens() {
const renderFrame = useCallback(node => {
if (node !== null) {
editorFrame.render(node);
}
}, []);

return (
<I18nProvider>
<div>
<h1>Lens</h1>

<div ref={renderFrame} />
</div>
</I18nProvider>
);
}

// TODO: Convert this to the "new platform" way of doing UI
function App($scope: IScope, $element: JQLite) {
const el = $element[0];
$scope.$on('$destroy', () => unmountComponentAtNode(el));

return render(<Lens />, el);
}

chrome.setRootController(PLUGIN_ID, App);
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved
70 changes: 70 additions & 0 deletions x-pack/plugins/visualization_lens/public/editor_frame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useCallback } from 'react';
import { render } from 'react-dom';
import { Datasource, Visualization, EditorFrameAPI } from './types';

function EditorFrameComponent(props: {
datasources: Array<Datasource<unknown>>;
visualizations: Array<Visualization<unknown>>;
}) {
const renderDatasource = (datasource: Datasource<unknown>) => {
return useCallback(
node => {
datasource.renderDataPanel({
domElement: node,
});
},
[datasource]
);
};

return (
<div>
<h2>Editor Frame</h2>

{props.datasources.map((datasource, index) => (
<div key={index} ref={renderDatasource(datasource)} />
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved
))}
</div>
);
}

class EditorFrame {
constructor() {}

private datasources: Array<Datasource<unknown>> = [];
private visualizations: Array<Visualization<unknown>> = [];

public setup(): EditorFrameAPI {
return {
render: (domElement: Element) => {
render(
<EditorFrameComponent
datasources={this.datasources}
visualizations={this.visualizations}
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved
/>,
domElement
);
},
registerDatasource: (datasource: Datasource<unknown>) => {
this.datasources.push(datasource);
},
registerVisualization: (visualization: Visualization<unknown>) => {
this.visualizations.push(visualization);
},
};
}

public stop() {
return {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you might want to clean up registered items in the stop method here -- this won't do anything today, but once we are officially on the new platform it will be called if core needs to gracefully shut down the plugin

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right

}
}

export { EditorFrame };
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved

export const editorFrame = new EditorFrame().setup();
Empty file.
8 changes: 8 additions & 0 deletions x-pack/plugins/visualization_lens/public/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export * from './editor_frame';
export * from './types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

// TODO: Figure out how to separate this out into another plugin
import { editorFrame } from '../../';

import { indexPatternDatasource } from './indexpattern';

editorFrame.registerDatasource(indexPatternDatasource);

export * from './indexpattern';
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { render } from 'react-dom';
import { Datasource, Operation, DataType } from '../';

interface IndexPatternPrivateState {
query: object;
}

class IndexPatternDatasource implements Datasource<IndexPatternPrivateState> {
private state: IndexPatternPrivateState;

constructor(state?: IndexPatternPrivateState) {
if (state) {
this.state = state;
} else {
this.state = {
query: {},
};
}
}

toExpression() {
return `${JSON.stringify(this.state.query)}`;
}

renderDataPanel({ domElement }: { domElement: Element }) {
render(<div>Index Pattern Data Source</div>, domElement);
}

getPublicAPI() {
return {
getTableSpec: () => [],
getOperationForColumnId: () => ({
id: '',
// User-facing label for the operation
label: '',
dataType: 'string' as DataType,
// A bucketed operation has many values the same
isBucketed: false,
}),

// Called by dimension
getDimensionPanelComponent: (props: any) => (
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved
domElement: Element,
operations: Operation[]
) => {},

removeColumnInTableSpec: (columnId: string) => [],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These feel like pretty different methods from the others. Should TableSpec itself be a class that has methods like these? (I'm generally a fan of data + functions, but if we're going OO, we may as well stick with it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where we landed is that the TableSpec is owned by the data source, so it makes sense to have manipulation methods on the datasource public API. The OO-ness of this change is something I'm actually going to change in the next update

moveColumnTo: (columnId: string, targetIndex: number) => {},
duplicateColumn: (columnId: string) => [],
};
}

getDatasourceSuggestionsForField() {
return [];
}

getDatasourceSuggestionsFromCurrentState() {
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved
return [];
}
}

export { IndexPatternDatasource };
wylieconlon marked this conversation as resolved.
Show resolved Hide resolved

export const indexPatternDatasource = new IndexPatternDatasource();
Loading