mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) configure typedoc for generating plugin api documentation
Summary: This annotates the plugin api sufficiently to generate some documentation for it. See https://github.com/gristlabs/grist-help/pull/139 Contains some small code tweaks for things that caused typedoc some trouble. Test Plan: manual inspection of output Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D3342
This commit is contained in:
parent
d8af25de9d
commit
c6d66e15bf
@ -69,40 +69,58 @@ export interface GristAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* GristDocAPI interface is implemented by Grist, and allows getting information from and
|
||||
* interacting with the Grist document to which a plugin is attached.
|
||||
* Allows getting information from and nteracting with the Grist document to which a plugin or widget is attached.
|
||||
*/
|
||||
export interface GristDocAPI {
|
||||
// Returns the docName that identifies the document.
|
||||
/**
|
||||
* Returns an identifier for the document.
|
||||
*/
|
||||
getDocName(): Promise<string>;
|
||||
|
||||
// Returns a sorted list of table IDs.
|
||||
/**
|
||||
* Returns a sorted list of table IDs.
|
||||
*/
|
||||
listTables(): Promise<string[]>;
|
||||
|
||||
// Returns a complete table of data in the format {colId: [values]}, including the 'id' column.
|
||||
// Do not modify the returned arrays in-place, especially if used directly (not over RPC).
|
||||
// TODO: return type is Promise{[colId: string]: CellValue[]}> but cannot be specified because
|
||||
// ts-interface-builder does not properly support index-signature.
|
||||
/**
|
||||
* Returns a complete table of data in the format {colId: [values]}, including the 'id' column.
|
||||
* Do not modify the returned arrays in-place, especially if used directly (not over RPC).
|
||||
* TODO: return type is Promise{[colId: string]: CellValue[]}> but cannot be specified because
|
||||
* ts-interface-builder does not properly support index-signature.
|
||||
*/
|
||||
fetchTable(tableId: string): Promise<any>;
|
||||
|
||||
// Applies an array of user actions.
|
||||
// todo: return type should be Promise<ApplyUAResult>, but this requires importing modules from
|
||||
// `app/common` which is not currently supported by the build.
|
||||
/**
|
||||
* Applies an array of user actions.
|
||||
* TODO: return type should be Promise<ApplyUAResult>, but this requires importing modules from
|
||||
* `app/common` which is not currently supported by the build.
|
||||
*/
|
||||
applyUserActions(actions: any[][], options?: any): Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for the data backing a single widget.
|
||||
*/
|
||||
export interface GristView {
|
||||
// Like fetchTable, but gets data for the custom section specifically, if there is any.
|
||||
// TODO: return type is Promise{[colId: string]: CellValue[]}> but cannot be specified because
|
||||
// ts-interface-builder does not properly support index-signature.
|
||||
/**
|
||||
* Like [[GristDocAPI.fetchTable]], but gets data for the custom section specifically, if there is any.
|
||||
* TODO: return type is Promise{[colId: string]: CellValue[]}> but cannot be specified because
|
||||
* ts-interface-builder does not properly support index-signature.
|
||||
*/
|
||||
fetchSelectedTable(): Promise<any>;
|
||||
|
||||
// Similar TODO to fetchSelectedTable for return type.
|
||||
/**
|
||||
* Similar TODO to `fetchSelectedTable()` for return type.
|
||||
*/
|
||||
fetchSelectedRecord(rowId: number): Promise<any>;
|
||||
|
||||
// Allow custom widget to be listed as a possible source for linking with SELECT BY.
|
||||
/**
|
||||
* Allow custom widget to be listed as a possible source for linking with SELECT BY.
|
||||
*/
|
||||
allowSelectBy(): Promise<void>;
|
||||
|
||||
// Set the list of selected rows to be used against any linked widget. Requires `allowSelectBy()`.
|
||||
/**
|
||||
* Set the list of selected rows to be used against any linked widget. Requires `allowSelectBy()`.
|
||||
*/
|
||||
setSelectedRows(rowIds: number[]): Promise<void>;
|
||||
}
|
||||
|
1
app/plugin/README.md
Normal file
1
app/plugin/README.md
Normal file
@ -0,0 +1 @@
|
||||
Methods here are available for use in Grist custom widgets.
|
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Where to append the content that a plugin renders.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export type RenderTarget = "fullscreen" | number;
|
||||
|
||||
|
@ -4,22 +4,32 @@ import * as Types from 'app/plugin/DocApiTypes';
|
||||
* Offer CRUD-style operations on a table.
|
||||
*/
|
||||
export interface TableOperations {
|
||||
// Create a record or records.
|
||||
/**
|
||||
* Create a record or records.
|
||||
*/
|
||||
create(records: Types.NewRecord, options?: OpOptions): Promise<Types.MinimalRecord>;
|
||||
create(records: Types.NewRecord[], options?: OpOptions): Promise<Types.MinimalRecord[]>;
|
||||
|
||||
// Update a record or records.
|
||||
/**
|
||||
* Update a record or records.
|
||||
*/
|
||||
update(records: Types.Record|Types.Record[], options?: OpOptions): Promise<void>;
|
||||
|
||||
// Delete a record or records.
|
||||
/**
|
||||
* Delete a record or records.
|
||||
*/
|
||||
destroy(recordId: Types.RecordId): Promise<Types.RecordId>;
|
||||
destroy(recordIds: Types.RecordId[]): Promise<Types.RecordId[]>;
|
||||
|
||||
// Add or update a record or records.
|
||||
/**
|
||||
* Add or update a record or records.
|
||||
*/
|
||||
upsert(records: Types.AddOrUpdateRecord|Types.AddOrUpdateRecord[],
|
||||
options?: UpsertOptions): Promise<void>;
|
||||
|
||||
// Determine the tableId of the table.
|
||||
/**
|
||||
* Determine the tableId of the table.
|
||||
*/
|
||||
getTableId(): Promise<string>;
|
||||
|
||||
// TODO: offer a way to query the table.
|
||||
@ -32,7 +42,7 @@ export interface TableOperations {
|
||||
* This can be disabled.
|
||||
*/
|
||||
export interface OpOptions {
|
||||
parseStrings?: boolean;
|
||||
parseStrings?: boolean; /** whether to parse strings based on the column type. */
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,8 +50,8 @@ export interface OpOptions {
|
||||
* onMany is first, and allowEmptyRequire is false.
|
||||
*/
|
||||
export interface UpsertOptions extends OpOptions {
|
||||
add?: boolean; // permit inserting a record
|
||||
update?: boolean; // permit updating a record
|
||||
onMany?: 'none' | 'first' | 'all'; // whether to update none, one, or all matching records
|
||||
allowEmptyRequire?: boolean; // allow "wildcard" operation
|
||||
add?: boolean; /** permit inserting a record */
|
||||
update?: boolean; /** permit updating a record */
|
||||
onMany?: 'none' | 'first' | 'all'; /** whether to update none, one, or all matching records */
|
||||
allowEmptyRequire?: boolean; /** allow "wildcard" operation */
|
||||
}
|
||||
|
@ -46,46 +46,103 @@ export const rpc: Rpc = new Rpc({logger: createRpcLogger()});
|
||||
|
||||
export const api = rpc.getStub<GristAPI>(RPC_GRISTAPI_INTERFACE, checkers.GristAPI);
|
||||
export const coreDocApi = rpc.getStub<GristDocAPI>('GristDocAPI@grist', checkers.GristDocAPI);
|
||||
|
||||
/**
|
||||
* Interface for the records backing a custom widget.
|
||||
*/
|
||||
export const viewApi = rpc.getStub<GristView>('GristView', checkers.GristView);
|
||||
|
||||
/**
|
||||
* Interface for the state of a custom widget.
|
||||
*/
|
||||
export const widgetApi = rpc.getStub<WidgetAPI>('WidgetAPI', checkers.WidgetAPI);
|
||||
|
||||
/**
|
||||
* Interface for the mapping of a custom widget.
|
||||
*/
|
||||
export const sectionApi = rpc.getStub<CustomSectionAPI>('CustomSectionAPI', checkers.CustomSectionAPI);
|
||||
|
||||
/**
|
||||
* Shortcut for [[GristView.allowSelectBy]].
|
||||
*/
|
||||
export const allowSelectBy = viewApi.allowSelectBy;
|
||||
|
||||
/**
|
||||
* Shortcut for [[GristView.setSelectedRows]].
|
||||
*/
|
||||
export const setSelectedRows = viewApi.setSelectedRows;
|
||||
|
||||
export const docApi: GristDocAPI & GristView = {
|
||||
...coreDocApi,
|
||||
...viewApi,
|
||||
|
||||
// Change fetchSelectedTable() to decode data by default, replacing e.g. ['D', timestamp] with
|
||||
// a moment date. New option `keepEncoded` skips the decoding step.
|
||||
async fetchSelectedTable(options: {keepEncoded?: boolean} = {}) {
|
||||
/**
|
||||
* Fetches data backing the widget as for [[GristView.fetchSelectedTable]],
|
||||
* but decoding data by default, replacing e.g. ['D', timestamp] with
|
||||
* a moment date. Option `keepEncoded` skips the decoding step.
|
||||
*/
|
||||
export async function fetchSelectedTable(options: {keepEncoded?: boolean} = {}) {
|
||||
const table = await viewApi.fetchSelectedTable();
|
||||
return options.keepEncoded ? table :
|
||||
mapValues<any[], any[]>(table, (col) => col.map(decodeObject));
|
||||
},
|
||||
}
|
||||
|
||||
// Change fetchSelectedRecord() to decode data by default, replacing e.g. ['D', timestamp] with
|
||||
// a moment date. New option `keepEncoded` skips the decoding step.
|
||||
async fetchSelectedRecord(rowId: number, options: {keepEncoded?: boolean} = {}) {
|
||||
/**
|
||||
* Fetches current selected record as for [[GristView.fetchSelectedRecord]],
|
||||
* but decoding data by default, replacing e.g. ['D', timestamp] with
|
||||
* a moment date. Option `keepEncoded` skips the decoding step.
|
||||
*/
|
||||
export async function fetchSelectedRecord(rowId: number, options: {keepEncoded?: boolean} = {}) {
|
||||
const rec = await viewApi.fetchSelectedRecord(rowId);
|
||||
return options.keepEncoded ? rec :
|
||||
mapValues(rec, decodeObject);
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A collection of methods for fetching document data. The
|
||||
* fetchSelectedTable and fetchSelectedRecord methods are
|
||||
* overridden to decode data by default.
|
||||
*/
|
||||
export const docApi: GristDocAPI & GristView = {
|
||||
...coreDocApi,
|
||||
...viewApi,
|
||||
fetchSelectedTable,
|
||||
fetchSelectedRecord,
|
||||
};
|
||||
|
||||
export const on = rpc.on.bind(rpc);
|
||||
|
||||
// Exposing widgetApi methods in a module scope.
|
||||
|
||||
/**
|
||||
* Shortcut for [[WidgetAPI.getOption]]
|
||||
*/
|
||||
export const getOption = widgetApi.getOption.bind(widgetApi);
|
||||
|
||||
/**
|
||||
* Shortcut for [[WidgetAPI.setOption]]
|
||||
*/
|
||||
export const setOption = widgetApi.setOption.bind(widgetApi);
|
||||
|
||||
/**
|
||||
* Shortcut for [[WidgetAPI.setOptions]]
|
||||
*/
|
||||
export const setOptions = widgetApi.setOptions.bind(widgetApi);
|
||||
|
||||
/**
|
||||
* Shortcut for [[WidgetAPI.getOptions]]
|
||||
*/
|
||||
export const getOptions = widgetApi.getOptions.bind(widgetApi);
|
||||
|
||||
/**
|
||||
* Shortcut for [[WidgetAPI.clearOptions]]
|
||||
*/
|
||||
export const clearOptions = widgetApi.clearOptions.bind(widgetApi);
|
||||
|
||||
// Get access to a table in the document. If no tableId specified, this
|
||||
// will use the current selected table (for custom widgets).
|
||||
// If a table does not exist, there will be no error until an operation
|
||||
// on the table is attempted.
|
||||
/**
|
||||
* Get access to a table in the document. If no tableId specified, this
|
||||
* will use the current selected table (for custom widgets).
|
||||
* If a table does not exist, there will be no error until an operation
|
||||
* on the table is attempted.
|
||||
*/
|
||||
export function getTable(tableId?: string): TableOperations {
|
||||
return new TableOperationsImpl({
|
||||
async getTableId() {
|
||||
@ -100,7 +157,9 @@ export function getTable(tableId?: string): TableOperations {
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Get the current selected table (for custom widgets).
|
||||
/**
|
||||
* Get the current selected table (for custom widgets).
|
||||
*/
|
||||
export const selectedTable: TableOperations = getTable();
|
||||
|
||||
// Get the ID of the current selected table (for custom widgets).
|
||||
@ -240,13 +299,15 @@ export function mapColumnNamesBack(data: any, options: {
|
||||
return mapColumnNames(data, {...options, reverse: true});
|
||||
}
|
||||
|
||||
// For custom widgets, add a handler that will be called whenever the
|
||||
// row with the cursor changes - either by switching to a different row, or
|
||||
// by some value within the row potentially changing. Handler may
|
||||
// in the future be called with null if the cursor moves away from
|
||||
// any row.
|
||||
// TODO: currently this will be called even if the content of a different row
|
||||
// changes.
|
||||
/**
|
||||
* For custom widgets, add a handler that will be called whenever the
|
||||
* row with the cursor changes - either by switching to a different row, or
|
||||
* by some value within the row potentially changing. Handler may
|
||||
* in the future be called with null if the cursor moves away from
|
||||
* any row.
|
||||
* TODO: currently this will be called even if the content of a different row
|
||||
* changes.
|
||||
*/
|
||||
export function onRecord(callback: (data: RowRecord | null, mappings: WidgetColumnMap | null) => unknown) {
|
||||
on('message', async function(msg) {
|
||||
if (!msg.tableId || !msg.rowId) { return; }
|
||||
@ -254,8 +315,11 @@ export function onRecord(callback: (data: RowRecord | null, mappings: WidgetColu
|
||||
callback(rec, await getMappingsIfChanged(msg));
|
||||
});
|
||||
}
|
||||
// For custom widgets, add a handler that will be called whenever the
|
||||
// selected records change. Handler will be called with a list of records.
|
||||
|
||||
/**
|
||||
* For custom widgets, add a handler that will be called whenever the
|
||||
* selected records change. Handler will be called with a list of records.
|
||||
*/
|
||||
export function onRecords(callback: (data: RowRecord[], mappings: WidgetColumnMap | null) => unknown) {
|
||||
on('message', async function(msg) {
|
||||
if (!msg.tableId || !msg.dataChange) { return; }
|
||||
@ -274,10 +338,13 @@ export function onRecords(callback: (data: RowRecord[], mappings: WidgetColumnMa
|
||||
}
|
||||
|
||||
|
||||
// For custom widgets, add a handler that will be called whenever the
|
||||
// widget options change (and on initial ready message). Handler will be
|
||||
// called with an object containing save json options, or null if no options were saved.
|
||||
// Second parameter
|
||||
/**
|
||||
* For custom widgets, add a handler that will be called whenever the
|
||||
* widget options change (and on initial ready message). Handler will be
|
||||
* called with an object containing saved json options, or null if no options were saved.
|
||||
* The second parameter has information about the widgets relationship with
|
||||
* the document that contains it.
|
||||
*/
|
||||
export function onOptions(callback: (options: any, settings: InteractionOptions) => unknown) {
|
||||
on('message', async function(msg) {
|
||||
if (msg.settings) {
|
||||
@ -297,6 +364,7 @@ export function onOptions(callback: (options: any, settings: InteractionOptions)
|
||||
* `name`. Calling `addImporter(...)` from another component than a `safeBrowser` component is not
|
||||
* currently supported.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export async function addImporter(name: string, path: string, mode: 'fullscreen' | 'inline', options?: RenderOptions) {
|
||||
// checker is omitted for implementation because call was already checked by grist.
|
||||
@ -315,7 +383,10 @@ export async function addImporter(name: string, path: string, mode: 'fullscreen'
|
||||
});
|
||||
}
|
||||
|
||||
interface ReadyPayload extends Omit<InteractionOptionsRequest, "hasCustomOptions"> {
|
||||
/**
|
||||
* Options when initializing connection to Grist.
|
||||
*/
|
||||
export interface ReadyPayload extends Omit<InteractionOptionsRequest, "hasCustomOptions"> {
|
||||
/**
|
||||
* Handler that will be called by Grist to open additional configuration panel inside the Custom Widget.
|
||||
*/
|
||||
@ -354,6 +425,7 @@ export function ready(settings?: ReadyPayload): void {
|
||||
})();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function getPluginPath(location: Location) {
|
||||
return location.pathname.replace(/^\/plugins\//, '');
|
||||
}
|
||||
@ -393,6 +465,7 @@ if (typeof window !== 'undefined') {
|
||||
rpc.setSendMessage((data) => { return; });
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function createRpcLogger(): IRpcLogger {
|
||||
let prefix: string;
|
||||
if (typeof window !== 'undefined') {
|
||||
|
@ -90,7 +90,7 @@ export class TestServerMerged implements IMochaServer {
|
||||
// logging. Server code uses a global logger, so it's hard to separate out (especially so if
|
||||
// we ever run different servers for different tests).
|
||||
const serverLog = process.env.VERBOSE ? 'inherit' : nodeLogFd;
|
||||
const env = {
|
||||
const env: Record<string, string> = {
|
||||
TYPEORM_DATABASE: this._getDatabaseFile(),
|
||||
TEST_CLEAN_DATABASE: reset ? 'true' : '',
|
||||
GRIST_DATA_DIR: this.testDocDir,
|
||||
|
@ -70,7 +70,7 @@ export class GristClient {
|
||||
if (this._pending.length) {
|
||||
return this._pending.shift();
|
||||
}
|
||||
await new Promise(resolve => this._consumer = resolve);
|
||||
await new Promise<void>(resolve => this._consumer = resolve);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,5 +6,14 @@
|
||||
{ "path": "./app" },
|
||||
{ "path": "./stubs/app" },
|
||||
{ "path": "./test" },
|
||||
]
|
||||
],
|
||||
"typedocOptions": {
|
||||
"entryPoints": [
|
||||
"app/plugin/grist-plugin-api.ts",
|
||||
"app/plugin/TableOperations.ts",
|
||||
],
|
||||
"excludeInternal": "true",
|
||||
"excludeNotDocumented": "true",
|
||||
"out": "doc"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user