Webhook trigger update by column (#832)

Add functionality to filter webhooks based on a column or columns.
This commit is contained in:
CamilleLegeron
2024-04-12 22:04:37 +02:00
committed by GitHub
parent 73a02fdebd
commit 76ef4d54f8
13 changed files with 270 additions and 58 deletions

View File

@@ -37,7 +37,7 @@ const WEBHOOK_COLUMNS = [
id: 'vt_webhook_fc1',
colId: 'tableId',
type: 'Choice',
label: 'Table',
label: t('Table'),
// widgetOptions are configured later, since the choices depend
// on the user tables in the document.
},
@@ -45,13 +45,13 @@ const WEBHOOK_COLUMNS = [
id: 'vt_webhook_fc2',
colId: 'url',
type: 'Text',
label: 'URL',
label: t('URL'),
},
{
id: 'vt_webhook_fc3',
colId: 'eventTypes',
type: 'ChoiceList',
label: 'Event Types',
label: t('Event Types'),
widgetOptions: JSON.stringify({
widget: 'TextBox',
alignment: 'left',
@@ -59,11 +59,17 @@ const WEBHOOK_COLUMNS = [
choiceOptions: {},
}),
},
{
id: 'vt_webhook_fc10',
colId: 'watchedColIdsText',
type: 'Text',
label: t('Filter for changes in these columns (semicolon-separated ids)'),
},
{
id: 'vt_webhook_fc4',
colId: 'enabled',
type: 'Bool',
label: 'Enabled',
label: t('Enabled'),
widgetOptions: JSON.stringify({
widget: 'Switch',
}),
@@ -72,31 +78,31 @@ const WEBHOOK_COLUMNS = [
id: 'vt_webhook_fc5',
colId: 'isReadyColumn',
type: 'Text',
label: 'Ready Column',
label: t('Ready Column'),
},
{
id: 'vt_webhook_fc6',
colId: 'webhookId',
type: 'Text',
label: 'Webhook Id',
label: t('Webhook Id'),
},
{
id: 'vt_webhook_fc7',
colId: 'name',
type: 'Text',
label: 'Name',
label: t('Name'),
},
{
id: 'vt_webhook_fc8',
colId: 'memo',
type: 'Text',
label: 'Memo',
label: t('Memo'),
},
{
id: 'vt_webhook_fc9',
colId: 'status',
type: 'Text',
label: 'Status',
label: t('Status'),
},
] as const;
@@ -107,8 +113,8 @@ const WEBHOOK_VIEW_FIELDS: Array<(typeof WEBHOOK_COLUMNS)[number]['colId']> = [
'name', 'memo',
'eventTypes', 'url',
'tableId', 'isReadyColumn',
'webhookId', 'enabled',
'status'
'watchedColIdsText', 'webhookId',
'enabled', 'status'
];
/**
@@ -127,9 +133,9 @@ class WebhookExternalTable implements IExternalTable {
public name = 'GristHidden_WebhookTable';
public initialActions = _prepareWebhookInitialActions(this.name);
public saveableFields = [
'tableId', 'url', 'eventTypes', 'enabled', 'name', 'memo', 'isReadyColumn',
'tableId', 'watchedColIdsText', 'url', 'eventTypes', 'enabled', 'name', 'memo', 'isReadyColumn',
];
public webhooks: ObservableArray<WebhookSummary> = observableArray<WebhookSummary>([]);
public webhooks: ObservableArray<UIWebhookSummary> = observableArray<UIWebhookSummary>([]);
public constructor(private _docApi: DocAPI) {
}
@@ -151,7 +157,7 @@ class WebhookExternalTable implements IExternalTable {
}
const colIds = new Set(getColIdsFromDocAction(d) || []);
if (colIds.has('webhookId') || colIds.has('status')) {
throw new Error(`Sorry, not all fields can be edited.`);
throw new Error(t(`Sorry, not all fields can be edited.`));
}
}
}
@@ -162,7 +168,7 @@ class WebhookExternalTable implements IExternalTable {
continue;
}
await this._removeWebhook(rec);
reportMessage(`Removed webhook.`);
reportMessage(t(`Removed webhook.`));
}
const updates = new Set(delta.updateRows);
const t2 = editor;
@@ -227,6 +233,7 @@ class WebhookExternalTable implements IExternalTable {
for (const webhook of webhooks) {
const values = _mapWebhookValues(webhook);
const rowId = rowMap.get(webhook.id);
if (rowId) {
toRemove.delete(rowId);
actions.push(
@@ -269,7 +276,12 @@ class WebhookExternalTable implements IExternalTable {
private _initalizeWebhookList(webhooks: WebhookSummary[]){
this.webhooks.removeAll();
this.webhooks.push(...webhooks);
this.webhooks.push(
...webhooks.map(webhook => {
const uiWebhook: UIWebhookSummary = {...webhook};
uiWebhook.fields.watchedColIdsText = webhook.fields.watchedColIds ? webhook.fields.watchedColIds.join(";") : "";
return uiWebhook;
}));
}
private _getErrorString(e: ApiError): string {
@@ -308,6 +320,9 @@ class WebhookExternalTable implements IExternalTable {
if (fields.eventTypes) {
fields.eventTypes = without(fields.eventTypes, 'L');
}
fields.watchedColIds = fields.watchedColIdsText
? fields.watchedColIdsText.split(";").filter((colId: string) => colId.trim() !== "")
: [];
return fields;
}
}
@@ -355,12 +370,12 @@ export class WebhookPage extends DisposableWithEvents {
public async reset() {
await this.docApi.flushWebhooks();
reportSuccess('Cleared webhook queue.');
reportSuccess(t('Cleared webhook queue.'));
}
public async resetSelected(id: string) {
await this.docApi.flushWebhook(id);
reportSuccess(`Cleared webhook ${id} queue.`);
reportSuccess(t(`Cleared webhook ${id} queue.`));
}
}
@@ -440,16 +455,21 @@ function _prepareWebhookInitialActions(tableId: string): DocAction[] {
/**
* Map a webhook summary to a webhook table raw record. The main
* difference is that `eventTypes` is tweaked to be in a cell format,
* and `status` is converted to a string.
* `status` is converted to a string,
* and `watchedColIdsText` is converted to list in a cell format.
*/
function _mapWebhookValues(webhookSummary: WebhookSummary): Partial<WebhookSchemaType> {
function _mapWebhookValues(webhookSummary: UIWebhookSummary): Partial<WebhookSchemaType> {
const fields = webhookSummary.fields;
const {eventTypes} = fields;
const {eventTypes, watchedColIdsText} = fields;
const watchedColIds = watchedColIdsText
? watchedColIdsText.split(";").filter(colId => colId.trim() !== "")
: [];
return {
...fields,
webhookId: webhookSummary.id,
status: JSON.stringify(webhookSummary.usage),
eventTypes: [GristObjCode.List, ...eventTypes],
watchedColIds: [GristObjCode.List, ...watchedColIds],
};
}
@@ -457,6 +477,11 @@ type WebhookSchemaType = {
[prop in keyof WebhookSummary['fields']]: WebhookSummary['fields'][prop]
} & {
eventTypes: [GristObjCode, ...unknown[]];
watchedColIds: [GristObjCode, ...unknown[]];
status: string;
webhookId: string;
}
type UIWebhookSummary = WebhookSummary & {
fields: {watchedColIdsText?: string;}
}