mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
allow bundled widgets to be hidden from dropdown, and nested (#714)
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.
This commit is contained in:
parent
7c4d9e2caf
commit
07bb90b5a6
@ -551,7 +551,9 @@ export class CustomSectionConfig extends Disposable {
|
||||
// Options for the select-box (all widgets definitions and Custom URL)
|
||||
const options = Computed.create(holder, use => [
|
||||
{label: 'Custom URL', value: 'custom'},
|
||||
...(use(this._widgets) || []).map(w => ({
|
||||
...(use(this._widgets) || [])
|
||||
.filter(w => w?.published !== false)
|
||||
.map(w => ({
|
||||
label: w.source?.name ? `${w.name} (${w.source.name})` : w.name,
|
||||
value: (w.source?.pluginId || '') + ':' + w.widgetId,
|
||||
})),
|
||||
|
@ -31,6 +31,11 @@ export interface ICustomWidget {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -267,7 +267,7 @@ export function getWidgetsInPlugins(gristServer: GristServer,
|
||||
gristServer.getTag() + '/widgets/' + plugin.id + '/';
|
||||
places.push({
|
||||
urlBase,
|
||||
dir: plugin.path,
|
||||
dir: path.resolve(plugin.path, path.dirname(components.widgets)),
|
||||
file: path.join(plugin.path, components.widgets),
|
||||
name: plugin.manifest.name || plugin.id,
|
||||
pluginId: plugin.id,
|
||||
|
@ -734,12 +734,14 @@ describe('CustomWidgets', function () {
|
||||
oldEnv = new EnvironmentSnapshot();
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
afterEach(async function() {
|
||||
oldEnv.restore();
|
||||
await server.restart();
|
||||
await gu.reloadDoc();
|
||||
});
|
||||
|
||||
it('can add widgets via plugins', async function () {
|
||||
for (const variant of ['flat', 'nested'] as const) {
|
||||
it(`can add widgets via plugins (${variant} layout)`, async function () {
|
||||
// Double-check that using one external widget, we see
|
||||
// just that widget listed.
|
||||
widgets = [widget1];
|
||||
@ -751,7 +753,7 @@ describe('CustomWidgets', function () {
|
||||
]);
|
||||
|
||||
// Get a temporary directory that will be cleaned up,
|
||||
// and populated it as follows:
|
||||
// and populated it as follows ('flat' variant)
|
||||
// plugins/
|
||||
// my-widgets/
|
||||
// manifest.yml # a plugin manifest, listing widgets.json
|
||||
@ -759,21 +761,26 @@ describe('CustomWidgets', function () {
|
||||
// p1.html # one of the widgets in widgets.json
|
||||
// p2.html # another of the widgets in widgets.json
|
||||
// grist-plugin-api.js # a dummy api file, to check it is overridden
|
||||
// In 'nested' variant, widgets.json and the files it refers to are in
|
||||
// a subdirectory.
|
||||
const dir = await createTmpDir();
|
||||
const pluginDir = path.join(dir, 'plugins', 'my-widgets');
|
||||
const widgetDir = variant === 'nested' ? path.join(pluginDir, 'nested') : pluginDir;
|
||||
await fse.mkdirp(pluginDir);
|
||||
await fse.mkdirp(widgetDir);
|
||||
|
||||
// A plugin, with some widgets in it.
|
||||
await fse.writeFile(path.join(pluginDir, 'manifest.yml'), `
|
||||
name: My Widgets
|
||||
components:
|
||||
widgets: widgets.json
|
||||
`);
|
||||
await fse.writeFile(
|
||||
path.join(pluginDir, 'manifest.yml'),
|
||||
`name: My Widgets\n` +
|
||||
`components:\n` +
|
||||
` widgets: ${variant === 'nested' ? 'nested/' : ''}widgets.json\n`
|
||||
);
|
||||
|
||||
// A list of a pair of custom widgets, with the widget
|
||||
// source in the same directory.
|
||||
await fse.writeFile(
|
||||
path.join(pluginDir, 'widgets.json'),
|
||||
path.join(widgetDir, 'widgets.json'),
|
||||
JSON.stringify([
|
||||
{
|
||||
widgetId: 'p1',
|
||||
@ -785,12 +792,18 @@ describe('CustomWidgets', function () {
|
||||
name: 'P2',
|
||||
url: './p2.html',
|
||||
},
|
||||
{
|
||||
widgetId: 'p3',
|
||||
name: 'P3',
|
||||
url: './p3.html',
|
||||
published: false,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
// The first widget - just contains the text P1.
|
||||
await fse.writeFile(
|
||||
path.join(pluginDir, 'p1.html'),
|
||||
path.join(widgetDir, 'p1.html'),
|
||||
'<html><body>P1</body></html>',
|
||||
);
|
||||
|
||||
@ -799,10 +812,10 @@ describe('CustomWidgets', function () {
|
||||
// (but the js bundled with the widget just throws an
|
||||
// alert).
|
||||
await fse.writeFile(
|
||||
path.join(pluginDir, 'p2.html'),
|
||||
path.join(widgetDir, 'p2.html'),
|
||||
`
|
||||
<html>
|
||||
<script src="./grist-plugin-api.js"></script>
|
||||
<head><script src="./grist-plugin-api.js"></script></head>
|
||||
<body>
|
||||
<div id="readout"></div>
|
||||
<script>
|
||||
@ -814,11 +827,18 @@ describe('CustomWidgets', function () {
|
||||
</html>
|
||||
`
|
||||
);
|
||||
|
||||
// The third widget - just contains the text P3.
|
||||
await fse.writeFile(
|
||||
path.join(widgetDir, 'p3.html'),
|
||||
'<html><body>P3</body></html>',
|
||||
);
|
||||
|
||||
// A dummy grist-plugin-api.js - hopefully the actual
|
||||
// js for the current version of Grist will be served in
|
||||
// its place.
|
||||
await fse.writeFile(
|
||||
path.join(pluginDir, 'grist-plugin-api.js'),
|
||||
path.join(widgetDir, 'grist-plugin-api.js'),
|
||||
'alert("Error: built in api version used");',
|
||||
);
|
||||
|
||||
@ -875,5 +895,6 @@ describe('CustomWidgets', function () {
|
||||
assert.equal(await getWidgetText(), 'P2');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user