Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
60 changes: 60 additions & 0 deletions .github/workflows/marketplace.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Validates the plugin marketplace on every PR that touches it, and syncs
# marketplace/ to S3 via salmon on merge to main.
name: Marketplace

on:
pull_request:
branches:
- main
paths:
- 'marketplace/**'
- 'tools/validate-marketplace.mjs'
- '.github/workflows/marketplace.yml'
push:
branches:
- main
paths:
- 'marketplace/**'
- 'tools/validate-marketplace.mjs'
- '.github/workflows/marketplace.yml'

jobs:
# Schema + link validation for marketplace.json.
marketplace-validate:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm

- name: Install dependencies
run: npm ci --ignore-scripts

- name: Validate marketplace.json
run: npm run validate-marketplace

# Publish to S3 only after a marketplace change lands on main.
marketplace-sync:
needs: marketplace-validate
if: github.event_name == 'push'
runs-on: ubuntu-24.04
permissions:
id-token: write # Auth to AWS with OIDC
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Sync marketplace to S3
uses: deephaven/salmon-sync@v1
with:
source: marketplace/
destination: deephaven/deephaven-plugins/marketplace/
production: true
temporary: false
aws-role: ${{ vars.DOCS_AWS_ROLE }}
48 changes: 48 additions & 0 deletions marketplace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Plugin marketplace

`marketplace.json` is the source of truth for the plugin directory shown at [deephaven.io/plugins](https://deephaven.io/plugins). On merge to `main` this folder is synced to S3 and the website reads it from there, so a merged PR is all it takes to list, update, or remove a plugin.

## Add your plugin

1. Add an entry to the `plugins` array in [`marketplace.json`](./marketplace.json). The fields are documented in [`marketplace.schema.json`](./marketplace.schema.json); editors that understand `$schema` will autocomplete and validate as you type. The required fields are `name`, `description`, `author`, `repo`, and `image`:

```json
{
"name": "My Plugin",
"description": "One sentence describing what it does, shown on the card.",
"author": "your-github-handle",
"repo": "https://github.com/your-github-handle/your-plugin",
"image": "/marketplace/images/my-plugin.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-my-plugin",
"url": "https://pypi.org/project/deephaven-plugin-my-plugin/"
},
"tags": ["python"]
}
```

2. Add a card image to [`images/`](./images) and reference it as `/marketplace/images/<file>.png`. It must be a PNG committed to that folder (external URLs are not allowed); keep it under 300 KB and roughly 16:9 (600×338 works well).

3. Validate locally, then open a PR:

```sh
npm run validate-marketplace
```

CI runs the same check on every PR that touches this folder and blocks merge until it passes. Use `npm run validate-marketplace -- --skip-links` to skip the (slower) external link checks while iterating.

## What the validator enforces

Beyond the JSON schema, [`tools/validate-marketplace.mjs`](../tools/validate-marketplace.mjs) checks that:

- plugin names are unique,
- the `repo` owner matches the `author` (the author drives the official badge),
- the `official` tag and `preInstalled` flag are reserved for Deephaven-owned plugins,
- each plugin's `image` is a PNG that exists directly in `images/` and is under 300 KB,
- no image in `images/` is orphaned (unreferenced by any plugin), and
- every link resolves: `repo`, `href`, `registry.url`, and the author's GitHub profile.

## Reserved fields

`author: "deephaven"` plugins get the official badge automatically, and only they may set `preInstalled: true`. Don't add the `official` tag by hand; it is derived from the author.
Binary file added marketplace/images/ag-grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/deephaven-ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/matplotlib.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/microphone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/notebook.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/plotly-express.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/python-remote-file-source.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/theme-pack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/tones.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added marketplace/images/voice-table.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
134 changes: 134 additions & 0 deletions marketplace/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{
"$schema": "./marketplace.schema.json",
"plugins": [
{
"name": "deephaven.ui",
"description": "A reactive Python UI framework for building real-time data apps and dashboards entirely in Python.",
"author": "Deephaven",
"repo": "https://github.com/deephaven/deephaven-plugins/tree/main/plugins/ui",
"href": "/core/ui/docs",
"image": "/marketplace/images/deephaven-ui.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-ui",
"url": "https://pypi.org/project/deephaven-plugin-ui/"
},
"tags": ["ui", "dashboards", "python"],
"preInstalled": true
},
{
"name": "Plotly Express",
"description": "A Plotly Express wrapper that plots real-time, ticking Deephaven tables with automatic downsampling.",
"author": "Deephaven",
"repo": "https://github.com/deephaven/deephaven-plugins/tree/main/plugins/plotly-express",
"href": "/core/plotly/docs",
"image": "/marketplace/images/plotly-express.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-plotly-express",
"url": "https://pypi.org/project/deephaven-plugin-plotly-express/"
},
"tags": ["plotting", "python"],
"preInstalled": true
},
{
"name": "Matplotlib",
"description": "Display Matplotlib and Seaborn figures in Deephaven, with support for live updates from ticking tables.",
"author": "Deephaven",
"repo": "https://github.com/deephaven/deephaven-plugin-matplotlib",
"image": "/marketplace/images/matplotlib.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-matplotlib",
"url": "https://pypi.org/project/deephaven-plugin-matplotlib/"
},
"tags": ["plotting", "python"]
},
{
"name": "AG Grid",
"description": "Display and interact with Deephaven tables using AG Grid.",
"author": "Deephaven",
"repo": "https://github.com/deephaven/deephaven-plugins/tree/main/plugins/ag-grid",
"image": "/marketplace/images/ag-grid.png",
"tags": ["tables", "ui", "python"]
},
{
"name": "Theme Pack",
"description": "A pack of additional UI themes for customizing the look of the Deephaven web IDE.",
"author": "Deephaven",
"repo": "https://github.com/deephaven/deephaven-plugins/tree/main/plugins/theme-pack",
"image": "/marketplace/images/theme-pack.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-theme-pack",
"url": "https://pypi.org/project/deephaven-plugin-theme-pack/"
},
"tags": ["themes"]
},
{
"name": "Python Remote File Source",
"description": "A bi-directional plugin that allows sourcing Python imports from a remote file source.",
"author": "Deephaven",
"repo": "https://github.com/deephaven/deephaven-plugins/tree/main/plugins/python-remote-file-source",
"image": "/marketplace/images/python-remote-file-source.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-python-remote-file-source",
"url": "https://pypi.org/project/deephaven-plugin-python-remote-file-source/"
},
"tags": ["tooling", "python"]
},
{
"name": "Tones",
"description": "A deephaven.ui plugin that plays audio tones from events or table data by wrapping Tone.js in Python components.",
"author": "dsmmcken",
"repo": "https://github.com/dsmmcken/deephaven-plugin-tones",
"image": "/marketplace/images/tones.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-tones",
"url": "https://pypi.org/project/deephaven-plugin-tones/"
},
"tags": ["audio", "ui", "python"]
},
{
"name": "Microphone",
"description": "A plugin for using microphone input in Deephaven.",
"author": "mofojed",
"repo": "https://github.com/mofojed/deephaven-plugin-microphone",
"image": "/marketplace/images/microphone.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-microphone",
"url": "https://pypi.org/project/deephaven-plugin-microphone/"
},
"tags": ["audio", "python"]
},
{
"name": "Voice Table",
"description": "A deephaven.ui plugin for controlling a table using voice input.",
"author": "mofojed",
"repo": "https://github.com/mofojed/deephaven-plugin-voice-table",
"image": "/marketplace/images/voice-table.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-voice-table",
"url": "https://pypi.org/project/deephaven-plugin-voice-table/"
},
"tags": ["audio", "tables", "python"]
},
{
"name": "Notebook",
"description": "An experimental plugin that creates and embeds simple Jupyter notebooks within Deephaven.",
"author": "jnumainville",
"repo": "https://github.com/jnumainville/deephaven-plugin-notebook",
"image": "/marketplace/images/notebook.png",
"registry": {
"kind": "pypi",
"package": "deephaven-plugin-notebook",
"url": "https://pypi.org/project/deephaven-plugin-notebook/"
},
"tags": ["notebooks", "experimental", "python"]
}
]
}
103 changes: 103 additions & 0 deletions marketplace/marketplace.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://deephaven.io/marketplace.schema.json",
"title": "Deephaven Plugin Directory",
"description": "Defines the list of plugins shown on deephaven.io/plugins. Open a PR against this file to add your plugin.",
"type": "object",
"required": ["plugins"],
"additionalProperties": false,
"properties": {
"$schema": {
"type": "string"
},
"plugins": {
"type": "array",
"items": { "$ref": "#/$defs/plugin" }
}
},
"$defs": {
"plugin": {
"type": "object",
"required": ["name", "description", "author", "repo", "image"],
"additionalProperties": false,
"properties": {
"name": {
"description": "Display name of the plugin. Don't prefix with \"Deephaven\", that's implied.",
"type": "string",
"minLength": 1,
"maxLength": 64
},
"description": {
"description": "Short description shown on the plugin card",
"type": "string",
"minLength": 1,
"maxLength": 280
},
"author": {
"description": "GitHub user or org that owns the plugin's repo",
"type": "string",
"pattern": "^[a-zA-Z0-9]([a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$"
},
"repo": {
"description": "GitHub repository URL (a path within a repo is allowed for monorepos)",
"type": "string",
"pattern": "^https://github\\.com/[^/]+/[^/]+"
},
"href": {
"description": "Where the card links to: an internal docs path (starts with /) or an external https URL. Defaults to the repo URL.",
"type": "string",
"pattern": "^(/|https://)"
},
"image": {
"description": "Card image: a PNG committed to marketplace/images/ in this repo, referenced as /marketplace/images/<file>.png",
"type": "string",
"pattern": "^/marketplace/images/[^/]+\\.png$"
},
"registry": {
"description": "Optional package registry listing where the plugin is published",
"type": "object",
"required": ["kind", "url"],
"additionalProperties": false,
"properties": {
"kind": {
"description": "Which registry the package is published to",
"type": "string",
"enum": ["pypi", "npm", "maven", "conda", "gradle", "other"]
},
"package": {
"description": "Package name on the registry",
"type": "string",
"minLength": 1,
"maxLength": 128
},
"url": {
"description": "URL of the package listing",
"type": "string",
"pattern": "^https://"
}
}
},
"minDeephavenVersion": {
"description": "Minimum Deephaven version the plugin is known to work with, e.g. 0.36.0",
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+(\\.[0-9]+)?$"
},
"preInstalled": {
"description": "Whether the plugin ships pre-installed with Deephaven. Reserved for Deephaven-owned plugins; enforced by the validator.",
"type": "boolean"
},
"tags": {
"description": "Tags used for filtering in the directory. \"official\" is reserved; it is derived automatically from the author.",
"type": "array",
"maxItems": 5,
"uniqueItems": true,
"items": {
"type": "string",
"minLength": 1,
"maxLength": 24
}
}
}
}
}
}
Loading
Loading