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 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]; }