mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
07bb90b5a6
This makes a few refinements to bundling widgets: * A widget with `published: false` is not shown in the custom widget dropdown in the UI. This is so widgets can be bundled with the app for "native" use (like the calendar widget) without immediately resulting in an extra listing in the UI. (There are improvements we'd like to make to the UI to better communicate widget provenance and quality eventually, which would be a helpful alternative to just a binary flag.) * A relative path to the custom widget manifest is respected. This will make the bundling process marginally neater.
95 lines
2.2 KiB
TypeScript
95 lines
2.2 KiB
TypeScript
import sortBy = require('lodash/sortBy');
|
|
|
|
/**
|
|
* Custom widget manifest definition.
|
|
*/
|
|
export interface ICustomWidget {
|
|
/**
|
|
* Widget friendly name, used on the UI.
|
|
*/
|
|
name: string;
|
|
/**
|
|
* Widget unique id, probably in npm package format @gristlabs/custom-widget-name.
|
|
*
|
|
* There could be multiple versions of the same widget with the
|
|
* same id, e.g. a bundled version and an external version.
|
|
*/
|
|
widgetId: string;
|
|
/**
|
|
* Custom widget main page URL.
|
|
*/
|
|
url: string;
|
|
/**
|
|
* Optional desired access level.
|
|
*/
|
|
accessLevel?: AccessLevel;
|
|
/**
|
|
* If set, Grist will render the widget after `grist.ready()`.
|
|
*
|
|
* This is used to defer showing a widget on initial load until it has finished
|
|
* applying the Grist theme.
|
|
*/
|
|
renderAfterReady?: boolean;
|
|
|
|
/**
|
|
* If set to false, do not offer to user in UI.
|
|
*/
|
|
published?: boolean;
|
|
|
|
/**
|
|
* If the widget came from a plugin, we track that here.
|
|
*/
|
|
source?: {
|
|
pluginId: string;
|
|
name: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Widget access level.
|
|
*/
|
|
export enum AccessLevel {
|
|
/**
|
|
* Default, no access to Grist.
|
|
*/
|
|
none = "none",
|
|
/**
|
|
* Read only access to table the widget is based on.
|
|
*/
|
|
read_table = "read table",
|
|
/**
|
|
* Full access to document on user's behalf.
|
|
*/
|
|
full = "full",
|
|
}
|
|
|
|
export function isSatisfied(current: AccessLevel, minimum: AccessLevel) {
|
|
function ordered(level: AccessLevel) {
|
|
switch(level) {
|
|
case AccessLevel.none: return 0;
|
|
case AccessLevel.read_table: return 1;
|
|
case AccessLevel.full: return 2;
|
|
default: throw new Error(`Unrecognized access level ${level}`);
|
|
}
|
|
}
|
|
return ordered(current) >= ordered(minimum);
|
|
}
|
|
|
|
/**
|
|
* Find the best match for a widgetId/pluginId combination among the
|
|
* given widgets. An exact widgetId match is required. A pluginId match
|
|
* is preferred but not required.
|
|
*/
|
|
export function matchWidget(widgets: ICustomWidget[], options: {
|
|
widgetId: string,
|
|
pluginId?: string,
|
|
}): ICustomWidget|undefined {
|
|
const prefs = sortBy(widgets, (w) => {
|
|
return [w.widgetId !== options.widgetId,
|
|
(w.source?.pluginId||'') !== options.pluginId];
|
|
});
|
|
if (prefs.length === 0) { return; }
|
|
if (prefs[0].widgetId !== options.widgetId) { return; }
|
|
return prefs[0];
|
|
}
|