diff --git a/x-pack/plugins/canvas/PLUGINS.mdx b/x-pack/plugins/canvas/PLUGINS.mdx new file mode 100644 index 0000000000000..0f93948d663a0 --- /dev/null +++ b/x-pack/plugins/canvas/PLUGINS.mdx @@ -0,0 +1,239 @@ +--- +id: canvasPlugins +slug: /playground/kibana/canvas-plugins +title: Develop Canvas plugins +summary: Introduction to +date: 2021-02-18 +tags: ['kibana', 'canvas', 'plugins'] +related: [] +--- + +To develop your own Canvas plugins, you simply create a Kibana plugin, and register your customizations with Canvas. + +The following is a step-by-step guide to adding your own custom random number Canvas plugin. + +## Generating a Kibana plugin + +```bash +# in the kibana directory +# Rename canvas_example to whatever you want your plugin to be named +node scripts/generate_plugin.js canvas_example +``` + +This will prompt you for some input. Generally, you can answer as follows: + +``` +❯ node scripts/generate_plugin.js canvas_example +? Would you like to create the plugin in a different folder? No +? Provide a short description An awesome Kibana plugin +? What Kibana version are you targeting? master +? Should an app component be generated? No +? Should a server API be generated? No +? Should translation files be generated? No +? Would you like to use a custom eslint file? No +``` + +Once this has completed, go to your plugin directory: + +```bash +cd plugins/canvas_example +``` + +Open that folder in your code editor of choice: `code .` + +### Creating a Canvas element and function +Open your plugin's `kibana.json` file. Make sure that `ui` has a value of true, and that `'canvas'` is included in `requiredPlugins`. It should look something like this. + +```json +{ + "id": "canvasExample", + "version": "7.8.0", + "server": false, + "ui": true, + "requiredPlugins": ["canvas"], + "optionalPlugins": [] +} +``` + +In your plugin folder, create a new folder `public` and an `index.ts` file within it. + +This `index.ts` will need export a Kibana Plugin. You can use this as a starting point for your plugin. + +```typescript +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; +import { CanvasSetup } from '../../../x-pack/plugins/canvas/public'; + +interface CanvasExampleSetupPlugins { + canvas: CanvasSetup; +} + +interface CanvasExampleStartPlugins {} + +class CanvasExamplePlugin + implements Plugin { + setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) {} + + start(core: CoreStart) {} +} + +export const plugin = () => new CanvasExamplePlugin(); +``` + + +Now that the Kibana plugin boilerplate is out of the way, you can start adding functionality to Canvas. + +Let's start by adding a new function. + +In your `index.ts` add a new function definition: + +```typescript +const canvasFunctions = [ + () => ({ + name: 'random', + help: 'Make a random number between 1 and 100', + args: {}, + fn() { + return Math.floor(Math.random() * 100) + 1; + } + }), +]; +``` + +Then, in the `setup` method of your plugin, you can add this new function definition to Canvas: + +```typescript +setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { + plugins.canvas.addFunctions(canvasFunctions); +} +``` + +Now, let's add a new Element type. In your `index.ts` add a new element definition: + +```typescript +const elements = [ + () => ({ + name: 'randomNumber', + displayName: 'Random Number', + help: 'A random number between 1 and 100', + image: 'https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb59c89a07c05b937/5c583a6602ac90e80ba0ab8f/icon-white-circle-elastic-stack.svg', + expression: 'random | metric "Random Number"', + }), +]; +``` + +And then, in the `setup` method of the plugin, add this new element definition to Canvas, just like you did with the function: + +```typescript +setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { + plugins.canvas.addFunctions(canvasFunctions); + plugins.canvas.addElements(elements); +} +``` + +Now, your 'Random Number' element will show up in the list of other Canvas elements. + +### Trying out your new plugin + +In the terminal, in your plugin's directory, run: + +```bash +# In plugins/canvas_example +yarn start +``` + +- Pull up Kibana in your browser: `http://localhost:5601` +- Go to canvas, and click: "Create workpad" +- Click: "Add element" +- Click: "Other" +- Click: "Random Number" + +### Adding a server-side function + +> Server side functions may be deprecated in a later version of Kibana + +Now, let's add a function which runs on the server. + +In your plugin's `kibana.json` file, set `server` to true, and add `"expressions"` as a requiredPlugin. + +```typescript +{ + "id": "canvasExample", + "version": "8.0.0", + "server": false, + "ui": true, + "requiredPlugins": ["canvas", "expressions"], + "optionalPlugins": [] +} +``` + +Now, much like we made the client plugin, we'll make a server plugin. + +Start by making the `server` directory and an `index.ts` file with a shell for your server plugin: + +```typescript +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/server'; +import { ExpressionsServerSetup } from '../../../src/plugins/expressions/server'; + +interface CanvasExamplePluginsSetup { + expressions: ExpressionsServerSetup; +} + +class CanvasExamplePlugin implements Plugin { + setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) {} + + start(core: CoreStart) {} +} + +export const plugin = () => new CanvasExamplePlugin(); +``` + +Now, we'll create a simple function definition that we will register on the server: + +```typescript +const serverFunctions = [ + () => ({ + name: 'serverTime', + help: 'Get the server time in milliseconds', + args: {}, + fn() { + return Date.now(); + }, + }), +]; +``` + +And then in our setup method, register it with the Expressions plugin: + +```typescript +setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) { + serverFunctions.forEach((f) => plugins.expressions.registerFunction(f)); +} +``` + +Now, let's try out our new server function. + +- Refresh your browser. +- In the same Canvas workpad: + - Add another Random Number element as before + - Click that element to select it + - Click "Expression editor" + - Modify the expression to look like this: `serverTime | metric "Server Time in ms"` + - Click "Run" + +You should now see one random number and one "Server Time in ms" value. + +> More information about building Kibana Plugins can be found in [src/core](https://github.com/elastic/kibana/blob/master/src/core/README.md) + +### My Canvas Plugin stopped working + +If your Kibana Server is crashing on startup with a message like + +> **FATAL** Error: Unmet requirement "canvas" for plugin "your_plugin_name" + +or + +> **FATAL** Error: Unmet requirement "interpreter" for plugin "your_plugin_name" + +then your plugin was likely created to work on a previous version of Kibana. Starting with version 7.8, the plugin system was redesigned and caused breaking changes to these earlier plugins. + +The good news is that all of your existing Canvas extension code can be reused, it just needs to be in an updated Kibana plugin. Follow the [instructions](#generating-a-kibana-plugin) for creating a new Canvas Kibana plugin, and then add in your existing functions and elements. diff --git a/x-pack/plugins/canvas/README.md b/x-pack/plugins/canvas/README.md index f77585b5b062c..754a4dc29d007 100644 --- a/x-pack/plugins/canvas/README.md +++ b/x-pack/plugins/canvas/README.md @@ -6,246 +6,6 @@ Canvas is included with X-Pack and requires a Basic license or better to use. -## Developing in Canvas - -To develop your own Canvas plugins, you simply create a Kibana plugin, and register your customizations with Canvas. - -The following is a step-by-step guide to adding your own custom random number Canvas plugin. - -### Generating a Kibana plugin - -```bash -# in the kibana directory -# Rename canvas_example to whatever you want your plugin to be named -node scripts/generate_plugin.js canvas_example -``` - -This will prompt you for some input. Generally, you can answer as follows: - -``` -❯ node scripts/generate_plugin.js canvas_example -? Would you like to create the plugin in a different folder? No -? Provide a short description An awesome Kibana plugin -? What Kibana version are you targeting? master -? Should an app component be generated? No -? Should a server API be generated? No -? Should translation files be generated? No -? Would you like to use a custom eslint file? No -``` - -Once this has completed, go to your plugin directory: - -```bash -cd plugins/canvas_example -``` - -Open that folder in your code editor of choice: `code .` - -#### Creating a Canvas element and function -Open your plugin's `kibana.json` file. Make sure that `ui` has a value of true, and that `'canvas'` is included in `requiredPlugins`. It should look something like this. - -```json -{ - "id": "canvasExample", - "version": "7.8.0", - "server": false, - "ui": true, - "requiredPlugins": ["canvas"], - "optionalPlugins": [] -} -``` - -In your plugin folder, create a new folder `public` and an `index.ts` file within it. - -This `index.ts` will need export a Kibana Plugin. You can use this as a starting point for your plugin. - -```typescript -import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; -import { CanvasSetup } from '../../../x-pack/plugins/canvas/public'; - -interface CanvasExampleSetupPlugins { - canvas: CanvasSetup; -} - -interface CanvasExampleStartPlugins {} - -class CanvasExamplePlugin - implements Plugin { - setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) {} - - start(core: CoreStart) {} -} - -export const plugin = () => new CanvasExamplePlugin(); -``` - - -Now that the Kibana plugin boilerplate is out of the way, you can start adding functionality to Canvas. - -Let's start by adding a new function. - -In your `index.ts` add a new function definition: - -```typescript -const canvasFunctions = [ - () => ({ - name: 'random', - help: 'Make a random number between 1 and 100', - args: {}, - fn() { - return Math.floor(Math.random() * 100) + 1; - } - }), -]; -``` - -Then, in the `setup` method of your plugin, you can add this new function definition to Canvas: - -```typescript -setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { - plugins.canvas.addFunctions(canvasFunctions); -} -``` - -Now, let's add a new Element type. In your `index.ts` add a new element definition: - -```typescript -const elements = [ - () => ({ - name: 'randomNumber', - displayName: 'Random Number', - help: 'A random number between 1 and 100', - image: 'https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb59c89a07c05b937/5c583a6602ac90e80ba0ab8f/icon-white-circle-elastic-stack.svg', - expression: 'random | metric "Random Number"', - }), -]; -``` - -And then, in the `setup` method of the plugin, add this new element definition to Canvas, just like you did with the function: - -```typescript -setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { - plugins.canvas.addFunctions(canvasFunctions); - plugins.canvas.addElements(elements); -} -``` - -Now, your 'Random Number' element will show up in the list of other Canvas elements. - -#### Trying out your new plugin - -In the terminal, in your plugin's directory, run: - -```bash -# In plugins/canvas_example -yarn start -``` - -- Pull up Kibana in your browser: `http://localhost:5601` -- Go to canvas, and click: "Create workpad" -- Click: "Add element" -- Click: "Other" -- Click: "Random Number" - -#### Adding a server-side function - -> Server side functions may be deprecated in a later version of Kibana - -Now, let's add a function which runs on the server. - -In your plugin's `kibana.json` file, set `server` to true, and add `"expressions"` as a requiredPlugin. - -```typescript -{ - "id": "canvasExample", - "version": "8.0.0", - "server": false, - "ui": true, - "requiredPlugins": ["canvas", "expressions"], - "optionalPlugins": [] -} -``` - -Now, much like we made the client plugin, we'll make a server plugin. - -Start by making the `server` directory and an `index.ts` file with a shell for your server plugin: - -```typescript -import { Plugin, CoreSetup, CoreStart } from '../../../src/core/server'; -import { ExpressionsServerSetup } from '../../../src/plugins/expressions/server'; - -interface CanvasExamplePluginsSetup { - expressions: ExpressionsServerSetup; -} - -class CanvasExamplePlugin implements Plugin { - setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) {} - - start(core: CoreStart) {} -} - -export const plugin = () => new CanvasExamplePlugin(); -``` - -Now, we'll create a simple function definition that we will register on the server: - -```typescript -const serverFunctions = [ - () => ({ - name: 'serverTime', - help: 'Get the server time in milliseconds', - args: {}, - fn() { - return Date.now(); - }, - }), -]; -``` - -And then in our setup method, register it with the Expressions plugin: - -```typescript -setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) { - serverFunctions.forEach((f) => plugins.expressions.registerFunction(f)); -} -``` - -Now, let's try out our new server function. - -- Refresh your browser. -- In the same Canvas workpad: - - Add another Random Number element as before - - Click that element to select it - - Click "Expression editor" - - Modify the expression to look like this: `serverTime | metric "Server Time in ms"` - - Click "Run" - -You should now see one random number and one "Server Time in ms" value. - -> More information about building Kibana Plugins can be found in [src/core](https://github.com/elastic/kibana/blob/master/src/core/README.md) - -#### My Canvas Plugin stopped working - -If your Kibana Server is crashing on startup with a message like - -> **FATAL** Error: Unmet requirement "canvas" for plugin "your_plugin_name" - -or - -> **FATAL** Error: Unmet requirement "interpreter" for plugin "your_plugin_name" - -then your plugin was likely created to work on a previous version of Kibana. Starting with version 7.8, the plugin system was redesigned and caused breaking changes to these earlier plugins. - -The good news is that all of your existing Canvas extension code can be reused, it just needs to be in an updated Kibana plugin. Follow the [instructions](#generating-a-kibana-plugin) for creating a new Canvas Kibana plugin, and then add in your existing functions and elements. - -## Scripts - -There are several scripts available once you are in that path as well. - -- `node scripts/lint` - local linter setup, can also be used with the `--fix` flag for automatic fixes. -- `node scripts/test` - local test runner, does not require a real Kibana instance. Runs all the same unit tests the normal runner does, just limited to Canvas, and *waaaaaay* faster (currently 12 seconds or less). -- `node scripts/test_dev` - Same as above, but watches for changes and only runs tests for the given scope (browser, server, or common). - ## Feature Questions **Why are there no tooltips** diff --git a/x-pack/plugins/canvas/shareable_runtime/README.md b/x-pack/plugins/canvas/shareable_runtime/README.mdx similarity index 88% rename from x-pack/plugins/canvas/shareable_runtime/README.md rename to x-pack/plugins/canvas/shareable_runtime/README.mdx index 3839e7c4ecb3f..8f1c9e06ca788 100644 --- a/x-pack/plugins/canvas/shareable_runtime/README.md +++ b/x-pack/plugins/canvas/shareable_runtime/README.mdx @@ -1,35 +1,12 @@ -# Canvas Shareable Workpads - -- [Introduction](#introduction) -- [Quick Start](#quick-start) -- [Using the Runtime](#using-the-runtime) - - [Assumptions](#assumptions) - - [Restrictions](#restrictions) - - [JS](#js) - - [HTML](#html) - - [Options](#options) -- [Testing](#testing) - - [Download a ZIP from Canvas](#download-a-zip-from-canvas) - - [Test the Runtime Directly from Webpack](#test-the-runtime-directly-from-webpack) - - [Run the Canvas Storybook](#run-the-canvas-storybook) - - [Run the Jest Tests](#run-the-jest-tests) - - [Gathering Test Coverage](#gathering-test-coverage) -- [Building](#building) - - [Build Options](#build-options) -- [Development](#development) - - [Prerequisite](#prerequisite) - - [Webpack Dev Server](#webpack-dev-server) - - [Gathering Statistics](#gathering-statistics) -- [Architecture](#architecture) - - [The Build](#the-build) - - [Supported Expressions](#supported-expressions) - - [Expression Interpreter](#expression-interpreter) - - [Build Size](#build-size) - - [The App](#the-app) - - [App State](#app-state) - - [CSS](#css) - -## Introduction +--- +id: canvasShareableWorkpads +slug: /playground/kibana/canvas-shareable-workpads +title: Share a Canvas Workpad on a Website +summary: How to share a static snapshot of a workpad on an external website. +date: 2021-02-18 +tags: ['kibana', 'canvas', 'share'] +related: [] +--- The Canvas Shareable Runtime is designed to render Shareable Canvas Workpads outside of Kibana in a different website or application. It uses the intermediate, "transient" state of a workpad, which is a JSON-blob state after element expressions are initially evaluated against their data sources, but before the elements are rendered to the screen. This "transient" state, therefore, has no dependency or access to ES/Kibana data, making it lightweight and portable. @@ -228,11 +205,7 @@ The `index.html` file contains a call to the `CanvasShareable` runtime. Currentl ``` -There are three workpads available, in `test/workpads`: - -- `hello.json` - A simple 'Hello, Canvas' workpad. -- `austin.json` - A workpad from an Elastic{ON} talk in Austin, TX. -- `test.json` - A couple of pages with customized CSS animations and charts. +There are three test workpads available, in `test/workpads`. ### Gathering Statistics