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

fix(generator): more cleanup to plugin framework #18027

Merged
merged 9 commits into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions docs/src/pages/docs/Contributing/creating-viz-plugins.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
name: Creating Visualization Plugins
menu: Contributing
route: /docs/contributing/creating-viz
index: 9
version: 1
---

## Creating Visualization Plugins

Visualizations in Superset are implemented in JavaScript or TypeScript. Superset
comes preinstalled with several visualizations types (hereafter "viz plugins") that
can be found under the `superset-frontend/plugins` directory. Plugins are added to
the application in the `superset-frontend/src/visualizations/presets/MainPreset.js`.
The Superset project is always happy to review proposals for new high quality viz
plugins. However, for highly custom viz types it is recommended to maintain a fork
of Superset, and add the custom built plugins by hand.

### Prerequisites

In order to create a new visualization plugin, you need the following:

- Run MacOS or Linux (Windows is not officially supported, but may work)
- Node 16
- npm 7 or 8

### Creating a simple Hello World plugin

To get started, you need the Superset Yeoman Generator. It is recommended to use the
version of the template that ships with the version of Superset you are using. This
can be installed by doing the following:

```bash
npm i -g yo
cd superset-frontend/packages/superset-generator
npm link
```

After this you can proceed to create your viz plugin. Create a new directory wherever
you have your repos (we'll assume under `~/src/`) with the prefix
`superset-plugin-chart` and run the Yeoman generator:

```bash
cd ~/src
mkdir superset-plugin-chart-hello-world
cd superset-plugin-chart-hello-world
yo @superset-ui/superset
```

After that the generator will ask a few questions (the defaults should be fine):

```
$ yo @superset-ui/superset

_-----_ ╭──────────────────────────╮
| | │ Welcome to the │
|--(o)--| │ generator-superset │
`---------´ │ generator! │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `

? Package name: superset-plugin-chart-hello-world
? Description: Hello World
? What type of chart would you like? Time-series chart
create package.json
create .gitignore
create babel.config.js
create jest.config.js
create README.md
create tsconfig.json
create src/index.ts
create src/plugin/buildQuery.ts
create src/plugin/controlPanel.ts
create src/plugin/index.ts
create src/plugin/transformProps.ts
create src/types.ts
create src/SupersetPluginChartHelloWorld.tsx
create test/index.test.ts
create test/__mocks__/mockExportString.js
create test/plugin/buildQuery.test.ts
create test/plugin/transformProps.test.ts
create types/external.d.ts
create src/images/thumbnail.png
```

To add the package to Superset, go to the `superset-frontend` subdirectory in your
Superset source folder (assuming both the `superset-plugin-chart-hello-world` plugin
and `superset` repos are in the same root directory) and run

```bash
npm i -S ../../superset-plugin-chart-hello-world
```

If you publish your package to npm, you can naturally install directly from there, too.
After this edit the `superset-frontend/src/visualizations/presets/MainPreset.js`
and make the following changes:

```js
import { SupersetPluginChartHelloWorld } from 'superset-plugin-chart-hello-world';
```

to import the plugin and later add the following to the array that's passed to the
`plugins` property:

```js
new SupersetPluginChartHelloWorld().configure({ key: 'ext-hello-world' }),
```

After that the plugin should show up when you run Superset, e.g. the development server:

```bash
npm run dev-server
```
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ module.exports = class extends Generator {
name: 'packageName',
message: 'Package name:',
// Default to current folder name
default: _.kebabCase(
this.appname.replace('superset plugin chart', '').trim(),
),
default: _.kebabCase(this.appname),
},
{
type: 'input',
Expand Down Expand Up @@ -77,6 +75,7 @@ module.exports = class extends Generator {
};

[
['gitignore.erb', '.gitignore'],
['babel.config.erb', 'babel.config.js'],
['jest.config.erb', 'jest.config.js'],
['package.erb', 'package.json'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,40 @@
## superset-plugin-chart-<%= packageName %>
# <%= packageName %>

This plugin provides <%= description %> for Superset.
This is the <%= description %> Superset Chart Plugin.

### Usage

Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
To build the plugin, run the following commands:

```js
import <%= packageLabel %>ChartPlugin from '@superset-ui/plugin-chart-<%= packageName %>';
```
npm i --force
Copy link
Member Author

Choose a reason for hiding this comment

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

this is unfortunately needed due to the conflicting versions we currently have in our deps (React, AntD etc) 😏

Copy link
Member

Choose a reason for hiding this comment

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

We can also use --legacy-peer-deps, looks a bit less aggressive 😛

Copy link
Member Author

Choose a reason for hiding this comment

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

With --legacy-peer-deps, the React and the core packages won't be present due to them being peer dependencies, so running tests will fail:

npm run test
src/types.ts:19:68 - error TS2307: Cannot find module '@superset-ui/core' or its corresponding type declarations.

19 import { QueryFormData, supersetTheme, TimeseriesDataRecord } from '@superset-ui/core';
                                                                      ~~~~~~~~~~~~~~~~~~~

src/SupersetPluginChartHelloWorld.tsx:19:45 - error TS2307: Cannot find module 'react' or its corresponding type declarations.

19 import React, { useEffect, createRef } from 'react';
                                               ~~~~~~~

npm run build
```

To run the plugin in development mode (=rebuilding whenever changes are made), start the dev server with the following command:

new <%= packageLabel %>ChartPlugin()
.configure({ key: '<%= packageName %>' })
.register();
```
npm run dev
```

To add the package to Superset, go to the `superset-frontend` subdirectory in your Superset source folder (assuming both the `<%= packageName %>` plugin and `superset` repos are in the same root directory) and run
```
npm i -S ../../<%= packageName %>
```

Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui/?selectedKind=plugin-chart-<%= packageName %>) for more details.
After this edit the `superset-frontend/src/visualizations/presets/MainPreset.js` and make the following changes:

```js
<SuperChart
chartType="<%= packageName %>"
width={600}
height={600}
formData={...}
queriesData={[{
data: {...},
}]}
/>
```

### File structure generated

```
├── package.json
├── README.md
├── tsconfig.json
├── src
│   ├── <%= packageLabel %>.tsx
│   ├── images
│   │   └── thumbnail.png
│   ├── index.ts
│   ├── plugin
│   │   ├── buildQuery.ts
│   │   ├── controlPanel.ts
│   │   ├── index.ts
│   │   └── transformProps.ts
│   └── types.ts
├── test
│   └── index.test.ts
└── types
└── external.d.ts
import { <%= packageLabel %> } from '<%= packageName %>';
```

to import the plugin and later add the following to the array that's passed to the `plugins` property:
```js
new <%= packageLabel %>().configure({ key: '<%= packageName %>' }),
```

After that the plugin should show up when you run Superset, e.g. the development server:

```
npm run dev-server
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# IDEs
.idea/

# build
esm
lib
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
{
"name": "superset-plugin-chart-<%= packageName %>",
"name": "<%= packageName %>",
"version": "0.1.0",
"description": "Superset Chart - <%= description %>",
"description": "<%= description %>",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"files": [
"esm",
"lib"
],
"private": true,
"scripts": {
"build": "npm run build-cjs && npm run build-esm && npm run ts-types",
"build-cjs": "babel src --extensions \".ts,.tsx,.js,.jsx\" --copy-files --out-dir lib",
"build-clean": "npm run clean && npm run build",
"build-esm": "BABEL_OUTPUT=esm babel src --extensions \".ts,.tsx,.js,.jsx\" --copy-files --out-dir esm",
"clean": "rm -rf {lib,esm,tsconfig.tsbuildinfo}",
"dev": "webpack --mode=development --color --watch",
"dev": "BABEL_OUTPUT=esm babel src --extensions \".ts,.tsx,.js,.jsx\" --watch --copy-files --out-dir esm",
"prebuild": "rimraf {lib,esm,tsconfig.tsbuildinfo}",
"postbuild": "npm run test",
"ts-types": "tsc --build",
"test": "jest"
},
"author": "Superset",
"author": "My Name",
"license": "Apache-2.0",
"publishConfig": {
"access": "public"
},
"dependencies": {
},
"dependencies": {},
"peerDependencies": {
"react": "^16.13.1",
"@superset-ui/core": "*",
"@superset-ui/chart-controls": "*"
"@superset-ui/chart-controls": "^0.18.25",
"@superset-ui/core": "^0.18.25",
villebro marked this conversation as resolved.
Show resolved Hide resolved
"react": "^16.13.1"
},
"devDependencies": {
"@airbnb/config-babel": "^2.0.1",
"@babel/cli": "^7.16.0",
"@types/jest": "^26.0.4",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0",
"jest": "^26.6.3",
"thread-loader": "^3.0.4",
"ts-loader": "^9.2.5",
"typescript": "^4.1.2",
"url-loader": "^4.1.1"
"rimraf": "^3.0.2",
"typescript": "^4.1.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/
// eslint-disable-next-line import/prefer-default-export
export { default as <%= packageLabel %>ChartPlugin } from './plugin';
export { default as <%= packageLabel %> } from './plugin';
/**
* Note: this file exports the default export from <%= packageLabel %>.tsx.
* If you want to export multiple visualization modules, you will need to
Expand Down
Loading