From f38df564a90661f78da238970afbf0665cfdf195 Mon Sep 17 00:00:00 2001 From: George Gevoian Date: Tue, 26 Sep 2023 16:37:27 -0400 Subject: [PATCH] (core) Add Command API to Grist Plugin API Summary: The new Command API provides limited access to Grist Commands from within cusotm widgets. This includes the ability to perform undo and redo, which is bound to the same keyboard shortcut as Grist by default. Test Plan: Browser tests. Reviewers: jarek Reviewed By: jarek Subscribers: paulfitz, jarek Differential Revision: https://phab.getgrist.com/D4050 --- app/client/components/CustomView.ts | 5 +++++ app/client/components/WidgetFrame.ts | 22 ++++++++++++++++++++++ app/plugin/grist-plugin-api.ts | 8 ++++++++ package.json | 1 + static/custom-widget.html | 1 + test/fixtures/sites/readout/page.js | 1 + test/nbrowser/CustomView.ts | 27 ++++++++++++++++++++++++++- yarn.lock | 5 +++++ 8 files changed, 69 insertions(+), 1 deletion(-) diff --git a/app/client/components/CustomView.ts b/app/client/components/CustomView.ts index ae14ed61..32f1b019 100644 --- a/app/client/components/CustomView.ts +++ b/app/client/components/CustomView.ts @@ -3,6 +3,7 @@ import * as commands from 'app/client/components/commands'; import {Cursor} from 'app/client/components/Cursor'; import {GristDoc} from 'app/client/components/GristDoc'; import { + CommandAPI, ConfigNotifier, CustomSectionAPIImpl, GristDocAPIImpl, @@ -240,6 +241,10 @@ export class CustomView extends Disposable { access, this._promptAccess.bind(this)), new MinimumLevel(AccessLevel.none)); + frame.exposeAPI( + "CommandAPI", + new CommandAPI(access), + new MinimumLevel(AccessLevel.none)); frame.useEvents(RecordNotifier.create(frame, view), new MinimumLevel(AccessLevel.read_table)); frame.useEvents(TableNotifier.create(frame, view), new MinimumLevel(AccessLevel.read_table)); frame.exposeAPI( diff --git a/app/client/components/WidgetFrame.ts b/app/client/components/WidgetFrame.ts index 731b57a4..6c08d5c7 100644 --- a/app/client/components/WidgetFrame.ts +++ b/app/client/components/WidgetFrame.ts @@ -1,4 +1,6 @@ import BaseView from 'app/client/components/BaseView'; +import {CommandName} from 'app/client/components/commandList'; +import * as commands from 'app/client/components/commands'; import {GristDoc} from 'app/client/components/GristDoc'; import {hooks} from 'app/client/Hooks'; import {get as getBrowserGlobals} from 'app/client/lib/browserGlobals'; @@ -484,6 +486,26 @@ export class WidgetAPIImpl implements WidgetAPI { } } +const COMMAND_MINIMUM_ACCESS_LEVELS: Map = new Map([ + ['undo', AccessLevel.full], + ['redo', AccessLevel.full], +]); + +export class CommandAPI { + constructor(private _currentAccess: AccessLevel) {} + + public async run(commandName: CommandName): Promise { + const minimumAccess = COMMAND_MINIMUM_ACCESS_LEVELS.get(commandName); + if (minimumAccess === undefined || !isSatisfied(this._currentAccess, minimumAccess)) { + // If the command name is unrecognized, or the current access level doesn't meet the + // command's minimum access level, do nothing. + return; + } + + return await commands.allCommands[commandName].run(); + } +} + /************************ * Events that are sent to the CustomWidget. * diff --git a/app/plugin/grist-plugin-api.ts b/app/plugin/grist-plugin-api.ts index f617b33e..9c3fbf51 100644 --- a/app/plugin/grist-plugin-api.ts +++ b/app/plugin/grist-plugin-api.ts @@ -65,6 +65,8 @@ export const widgetApi = rpc.getStub('WidgetAPI', checkers.WidgetAPI) */ export const sectionApi = rpc.getStub('CustomSectionAPI', checkers.CustomSectionAPI); +export const commandApi = rpc.getStub('CommandAPI'); + /** * Shortcut for [[GristView.allowSelectBy]]. */ @@ -437,6 +439,12 @@ export async function addImporter(name: string, path: string, mode: 'fullscreen' }); } +export function enableKeyboardShortcuts() { + const Mousetrap = require('mousetrap'); + Mousetrap.bind('mod+z', () => commandApi.run('undo')); + Mousetrap.bind(['mod+shift+z', 'ctrl+y'], () => commandApi.run('redo')); +} + /** * Options when initializing connection to Grist. */ diff --git a/package.json b/package.json index 3a6c451d..21eabdb8 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@types/minio": "7.0.15", "@types/mocha": "5.2.5", "@types/moment-timezone": "0.5.9", + "@types/mousetrap": "1.6.2", "@types/node": "^14", "@types/node-fetch": "2.6.2", "@types/pidusage": "2.0.1", diff --git a/static/custom-widget.html b/static/custom-widget.html index f7492ae6..c01c8764 100644 --- a/static/custom-widget.html +++ b/static/custom-widget.html @@ -7,6 +7,7 @@