Change how a builtin custom widget bundle is found (#783)

This change makes builtin custom widget bundles work on grist-electron,
by finding the package in a slightly more flexible way.

It also includes a related change to make a widget manifest fetched
from the network optional if a flag is present, with an error being
logged rather than thrown. This could make it harder to track down
why custom widgets aren't available, but makes it easier to make
grist-electron work (including calendars) when the network is shut off.
Ideally we'd do something fancier when we can.
pull/784/head
Paul Fitzpatrick 6 months ago committed by GitHub
parent 735360c441
commit 0a69501e58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1999,9 +1999,15 @@ export class FlexServer implements GristServer {
const userRoot = path.resolve(process.env.GRIST_USER_ROOT || getAppPathTo(this.appRoot, '.grist'));
this.info.push(['userRoot', userRoot]);
// Some custom widgets may be included as an npm package called @gristlabs/grist-widget.
// The package doesn't actually contain node code, but should be in the same vicinity
// as other packages that do, so we can use require.resolve on one of them to find it.
// This seems a little overcomplicated, but works well when grist-core is bundled within
// a larger project like grist-electron.
// TODO: maybe add a little node code to @gristlabs/grist-widget so it can be resolved
// directly?
const gristLabsModules = path.dirname(path.dirname(require.resolve('@gristlabs/express-session')));
const bundledRoot = isAffirmative(process.env.GRIST_SKIP_BUNDLED_WIDGETS) ? undefined : path.join(
getAppPathTo(this.appRoot, 'node_modules'),
'@gristlabs', 'grist-widget', 'dist'
gristLabsModules, 'grist-widget', 'dist'
);
this.info.push(['bundledRoot', bundledRoot]);
const pluginManager = new PluginManager(this.appRoot, userRoot, bundledRoot);

@ -4,7 +4,7 @@ import * as fse from 'fs-extra';
import fetch from 'node-fetch';
import * as path from 'path';
import {ApiError} from 'app/common/ApiError';
import {removeTrailingSlash} from 'app/common/gutil';
import {isAffirmative, removeTrailingSlash} from 'app/common/gutil';
import {GristServer} from 'app/server/lib/GristServer';
import LRUCache from 'lru-cache';
import * as url from 'url';
@ -96,7 +96,8 @@ export class CombinedWidgetRepository implements IWidgetRepository {
* Repository that gets a list of widgets from a URL.
*/
export class UrlWidgetRepository implements IWidgetRepository {
constructor(private _staticUrl = STATIC_URL) {}
constructor(private _staticUrl = STATIC_URL,
private _required: boolean = true) {}
public async getWidgets(): Promise<ICustomWidget[]> {
if (!this._staticUrl) {
@ -126,10 +127,16 @@ export class UrlWidgetRepository implements IWidgetRepository {
fixUrls(widgets, this._staticUrl);
return widgets;
} catch (err) {
if (!(err instanceof ApiError)) {
throw new ApiError(String(err), 500);
if (this._required) {
if (!(err instanceof ApiError)) {
throw new ApiError(String(err), 500);
}
throw err;
} else {
log.error("WidgetRepository: Error fetching widget list - " +
String(err));
return [];
}
throw err;
}
}
}
@ -177,7 +184,9 @@ export class WidgetRepositoryImpl implements IWidgetRepository {
const repos: IWidgetRepository[] = [];
this._staticUrl = overrideUrl ?? STATIC_URL;
if (this._staticUrl) {
this._urlWidgets = new UrlWidgetRepository(this._staticUrl);
const optional = isAffirmative(process.env.GRIST_WIDGET_LIST_URL_OPTIONAL);
this._urlWidgets = new UrlWidgetRepository(this._staticUrl,
!optional);
repos.push(this._urlWidgets);
}
if (this._diskWidgets) { repos.push(this._diskWidgets); }

Loading…
Cancel
Save