(core) support for bundling custom widgets with the Grist app

Summary:
This adds support for bundling custom widgets with the Grist app, as follows:

 * Adds a new `widgets` component to plugins mechanism.
 * When a set of widgets is provided in a plugin, the html/js/css assets for those widgets are served on the existing untrusted user content port.
 * Any bundled `grist-plugin-api.js` will be served with the Grist app's own version of that file. It is important that bundled widgets not refer to https://docs.getgrist.com for the plugin js, since they must be capable of working offline.
 * The logic for configuring that port is updated a bit.
 * I removed the CustomAttachedView class in favor of applying settings of bundled custom widgets more directly, without modification on view.

Any Grist installation via docker will need an extra step now, since there is an extra port that needs exposing for full functionality. I did add a `GRIST_TRUST_PLUGINS` option for anyone who really doesn't want to do this, and would prefer to trust the plugins and have them served on the same port.

Actually making use of bundling will be another step. It'll be important to mesh it with our SaaS's use of APP_STATIC_URL for serving most static assets.

Design sketch: https://grist.quip.com/bJlWACWzr2R9/Bundled-custom-widgets

Test Plan: added a test

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D4069
This commit is contained in:
Paul Fitzpatrick
2023-10-27 15:34:42 -04:00
parent cb0ce9b20f
commit cc9a9ae8c5
26 changed files with 961 additions and 227 deletions

View File

@@ -10,10 +10,12 @@ export const PublishedPlugin = t.iface(["BarePlugin"], {
});
export const BarePlugin = t.iface([], {
"name": t.opt("string"),
"components": t.iface([], {
"safeBrowser": t.opt("string"),
"safePython": t.opt("string"),
"unsafeNode": t.opt("string"),
"widgets": t.opt("string"),
"deactivate": t.opt(t.iface([], {
"inactivitySec": t.opt("number"),
})),

View File

@@ -35,6 +35,11 @@ export interface PublishedPlugin extends BarePlugin {
* as those being developed).
*/
export interface BarePlugin {
/**
* An optional human-readable name.
*/
name?: string;
/**
* Components describe how the plugin runs. A plugin may provide UI and behavior that runs in
* the browser, Python code that runs in a secure sandbox, and arbitrary code that runs in Node.
@@ -82,6 +87,13 @@ export interface BarePlugin {
*/
unsafeNode?: string;
/**
* Relative path to a specialized manifest of custom widgets.
* I'm unsure how this fits into components and contributions,
* this seemed the least-worst spot for it.
*/
widgets?: string;
/**
* Options for when to deactivate the plugin, i.e. when to stop any plugin processes. (Note
* that we may in the future also add options for when to activate the plugin, which is for