Browse Source

Merge pull request #5317 from nocodb/enhancement/webhooks

enhancement: webhooks
pull/5323/head
Raju Udava 2 years ago committed by GitHub
parent
commit
a4037a85ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      packages/nc-gui/components/webhook/Editor.vue
  2. 93
      packages/nc-gui/components/webhook/List.vue
  3. 4
      packages/nc-gui/lang/en.json
  4. 2
      packages/nc-gui/utils/filterUtils.ts
  5. 10
      packages/nocodb-sdk/src/lib/Api.ts
  6. 6
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts
  7. 1
      packages/nocodb/src/lib/models/Hook.ts
  8. 8
      packages/nocodb/src/lib/services/hook.svc.ts
  9. 410
      packages/nocodb/src/schema/swagger.json
  10. 2
      tests/playwright/pages/Dashboard/WebhookForm/index.ts

38
packages/nc-gui/components/webhook/Editor.vue

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { AuditType, HookType } from 'nocodb-sdk' import type { HookReqType, HookType } from 'nocodb-sdk'
import { import {
Form, Form,
MetaInj, MetaInj,
@ -58,6 +58,7 @@ const hook = reactive<
}, },
}, },
condition: false, condition: false,
active: true,
}) })
const urlTabKey = ref('body') const urlTabKey = ref('body')
@ -368,7 +369,7 @@ async function saveHooks() {
...hook.notification, ...hook.notification,
payload: hook.notification.payload, payload: hook.notification.payload,
}, },
} as AuditType) } as HookReqType)
} }
if (!hook.id && res) { if (!hook.id && res) {
@ -444,8 +445,7 @@ onMounted(async () => {
<a-button class="mr-3 nc-btn-webhook-test" size="large" @click="testWebhook"> <a-button class="mr-3 nc-btn-webhook-test" size="large" @click="testWebhook">
<div class="flex items-center"> <div class="flex items-center">
<MdiGestureDoubleTap class="mr-2" /> <MdiGestureDoubleTap class="mr-2" />
<!-- TODO: i18n --> {{ $t('activity.testWebhook') }}
Test Webhook
</div> </div>
</a-button> </a-button>
@ -462,6 +462,21 @@ onMounted(async () => {
<a-divider /> <a-divider />
<a-form :model="hook" name="create-or-edit-webhook"> <a-form :model="hook" name="create-or-edit-webhook">
<a-form-item>
<a-row type="flex">
<a-col :span="24">
<a-card>
<a-checkbox
:checked="Boolean(hook.active)"
class="nc-check-box-enable-webhook"
@update:checked="hook.active = $event"
>
{{ $t('activity.enableWebhook') }}
</a-checkbox>
</a-card>
</a-col>
</a-row>
</a-form-item>
<a-form-item> <a-form-item>
<a-row type="flex"> <a-row type="flex">
<a-col :span="24"> <a-col :span="24">
@ -573,14 +588,15 @@ onMounted(async () => {
<LazyApiClientHeaders v-model="hook.notification.payload.headers" /> <LazyApiClientHeaders v-model="hook.notification.payload.headers" />
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="auth" tab="Auth"> <!-- No in use at this moment -->
<LazyMonacoEditor v-model="hook.notification.payload.auth" class="min-h-60 max-h-80" /> <!-- <a-tab-pane key="auth" tab="Auth">-->
<!-- <LazyMonacoEditor v-model="hook.notification.payload.auth" class="min-h-60 max-h-80" />-->
<span class="text-gray-500 prose-sm p-2"> <!-- <span class="text-gray-500 prose-sm p-2">-->
For more about auth option refer <!-- For more about auth option refer-->
<a class="prose-sm" href="https://github.com/axios/axios#request-config" target="_blank">axios docs</a>. <!-- <a class="prose-sm" href ="https://github.com/axios/axios#request-config" target="_blank">axios docs</a>.-->
</span> <!-- </span>-->
</a-tab-pane> <!-- </a-tab-pane>-->
</a-tabs> </a-tabs>
</a-col> </a-col>
</a-row> </a-row>

93
packages/nc-gui/components/webhook/List.vue

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HookType } from 'nocodb-sdk' import type { FilterReqType, HookReqType, HookType } from 'nocodb-sdk'
import { MetaInj, extractSdkResponseErrorMsg, inject, message, onMounted, parseProp, ref, useI18n, useNuxtApp } from '#imports' import { MetaInj, extractSdkResponseErrorMsg, inject, message, onMounted, parseProp, ref, useI18n, useNuxtApp } from '#imports'
const emit = defineEmits(['edit', 'add']) const emit = defineEmits(['edit', 'add'])
@ -8,13 +8,13 @@ const { t } = useI18n()
const { $api, $e } = useNuxtApp() const { $api, $e } = useNuxtApp()
const hooks = ref<Record<string, any>[]>([]) const hooks = ref<HookType[]>([])
const meta = inject(MetaInj, ref()) const meta = inject(MetaInj, ref())
async function loadHooksList() { async function loadHooksList() {
try { try {
const hookList = (await $api.dbTableWebhook.list(meta.value?.id as string)).list as HookType[] const hookList = (await $api.dbTableWebhook.list(meta.value?.id as string)).list
hooks.value = hookList.map((hook) => { hooks.value = hookList.map((hook) => {
hook.notification = parseProp(hook.notification) hook.notification = parseProp(hook.notification)
return hook return hook
@ -24,25 +24,65 @@ async function loadHooksList() {
} }
} }
async function deleteHook(item: Record<string, any>, index: number) { async function deleteHook(item: HookType, index: number) {
try { Modal.confirm({
if (item.id) { title: `Do you want to delete '${item.title}'?`,
await $api.dbTableWebhook.delete(item.id) wrapClassName: 'nc-modal-hook-delete',
hooks.value.splice(index, 1) okText: 'Yes',
} else { okType: 'danger',
hooks.value.splice(index, 1) cancelText: 'No',
} async onOk() {
try {
if (item.id) {
await $api.dbTableWebhook.delete(item.id)
hooks.value.splice(index, 1)
} else {
hooks.value.splice(index, 1)
}
// Hook deleted successfully
message.success(t('msg.success.webhookDeleted'))
if (!hooks.value.length) {
hooks.value = []
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
$e('a:webhook:delete')
},
})
}
// Hook deleted successfully async function copyHook(hook: HookType) {
message.success(t('msg.success.webhookDeleted')) try {
if (!hooks.value.length) { const newHook = await $api.dbTableWebhook.create(hook.fk_model_id!, {
hooks.value = [] ...hook,
title: `${hook.title} - Copy`,
active: false,
} as HookReqType)
if (newHook) {
$e('a:webhook:copy')
// create the corresponding filters
const hookFilters = (await $api.dbTableWebhookFilter.read(hook.id!, {})).list
for (const hookFilter of hookFilters) {
await $api.dbTableWebhookFilter.create(newHook.id!, {
comparison_op: hookFilter.comparison_op,
comparison_sub_op: hookFilter.comparison_sub_op,
fk_column_id: hookFilter.fk_column_id,
fk_parent_id: hookFilter.fk_parent_id,
is_group: hookFilter.is_group,
logical_op: hookFilter.logical_op,
value: hookFilter.value,
} as FilterReqType)
}
newHook.notification = parseProp(newHook.notification)
hooks.value = [newHook, ...hooks.value]
} }
} catch (e: any) { } catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))
} }
$e('a:webhook:delete')
} }
onMounted(() => { onMounted(() => {
@ -84,9 +124,12 @@ onMounted(() => {
</template> </template>
<template #avatar> <template #avatar>
<div class="mt-4"> <div class="my-1 px-2">
<MdiHook class="text-xl" /> <MdiHook class="text-xl" />
</div> </div>
<div class="px-2 text-white rounded" :class="{ 'bg-green-500': item.active, 'bg-gray-500': !item.active }">
{{ item.active ? 'ON' : 'OFF' }}
</div>
</template> </template>
</a-list-item-meta> </a-list-item-meta>
@ -96,7 +139,19 @@ onMounted(() => {
<div class="mr-2">{{ $t('labels.notifyVia') }} : {{ item?.notification?.type }}</div> <div class="mr-2">{{ $t('labels.notifyVia') }} : {{ item?.notification?.type }}</div>
<div class="float-right pt-2 pr-1"> <div class="float-right pt-2 pr-1">
<MdiDeleteOutline class="text-xl nc-hook-delete-icon" @click.stop="deleteHook(item, index)" /> <a-tooltip placement="left">
<template #title>
{{ $t('activity.copyWebhook') }}
</template>
<MdiContentCopy class="text-xl nc-hook-copy-icon" @click.stop="copyHook(item)" />
</a-tooltip>
<a-tooltip placement="left">
<template #title>
{{ $t('activity.deleteWebhook') }}
</template>
<MdiDeleteOutline class="text-xl nc-hook-delete-icon" @click.stop="deleteHook(item, index)" />
</a-tooltip>
</div> </div>
</div> </div>
</template> </template>

4
packages/nc-gui/lang/en.json

@ -429,6 +429,10 @@
"openTab": "Open new tab", "openTab": "Open new tab",
"iFrame": "Copy embeddable HTML code", "iFrame": "Copy embeddable HTML code",
"addWebhook": "Add New Webhook", "addWebhook": "Add New Webhook",
"enableWebhook": "Enable Webhook",
"testWebhook": "Test Webhook",
"copyWebhook": "Copy Webhook",
"deleteWebhook": "Delete Webhook",
"newToken": "Add New Token", "newToken": "Add New Token",
"exportZip": "Export zip", "exportZip": "Export zip",
"importZip": "Import zip", "importZip": "Import zip",

2
packages/nc-gui/utils/filterUtils.ts

@ -1,4 +1,4 @@
import { isNumericCol, numericUITypes, UITypes } from 'nocodb-sdk' import { UITypes, isNumericCol, numericUITypes } from 'nocodb-sdk'
const getEqText = (fieldUiType: UITypes) => { const getEqText = (fieldUiType: UITypes) => {
if (isNumericCol(fieldUiType) || fieldUiType === UITypes.Time) { if (isNumericCol(fieldUiType) || fieldUiType === UITypes.Time) {

10
packages/nocodb-sdk/src/lib/Api.ts

@ -690,7 +690,7 @@ export interface FilterReqType {
/** Foreign Key to Column */ /** Foreign Key to Column */
fk_column_id?: IdType; fk_column_id?: IdType;
/** Belong to which filter ID */ /** Belong to which filter ID */
fk_parent_id?: IdType; fk_parent_id?: StringOrNullType;
/** Is this filter grouped? */ /** Is this filter grouped? */
is_group?: BoolType; is_group?: BoolType;
/** Logical Operator */ /** Logical Operator */
@ -1152,6 +1152,8 @@ export interface HookReqType {
title: string; title: string;
/** Hook Type */ /** Hook Type */
type?: string | null; type?: string | null;
/** Is this hook assoicated with some filters */
condition?: BoolType;
} }
/** /**
@ -8752,16 +8754,16 @@ export class Api<
* @name Create * @name Create
* @summary Create Table Hook * @summary Create Table Hook
* @request POST:/api/v1/db/meta/tables/{tableId}/hooks * @request POST:/api/v1/db/meta/tables/{tableId}/hooks
* @response `200` `HookReqType` OK * @response `200` `HookType` OK
* @response `400` `{ * @response `400` `{
\** @example BadRequest [Error]: <ERROR MESSAGE> *\ \** @example BadRequest [Error]: <ERROR MESSAGE> *\
msg: string, msg: string,
}` }`
*/ */
create: (tableId: IdType, data: AuditType, params: RequestParams = {}) => create: (tableId: IdType, data: HookReqType, params: RequestParams = {}) =>
this.request< this.request<
HookReqType, HookType,
{ {
/** @example BadRequest [Error]: <ERROR MESSAGE> */ /** @example BadRequest [Error]: <ERROR MESSAGE> */
msg: string; msg: string;

6
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts

@ -2247,8 +2247,6 @@ class BaseModelSqlv2 {
} }
private async handleHooks(hookName, data, req): Promise<void> { private async handleHooks(hookName, data, req): Promise<void> {
// const data = _data;
const view = await View.get(this.viewId); const view = await View.get(this.viewId);
// handle form view data submission // handle form view data submission
@ -2329,7 +2327,9 @@ class BaseModelSqlv2 {
operation, operation,
}); });
for (const hook of hooks) { for (const hook of hooks) {
invokeWebhook(hook, this.model, data, req?.user); if (hook.active) {
invokeWebhook(hook, this.model, data, req?.user);
}
} }
} catch (e) { } catch (e) {
console.log('hooks :: error', hookName, e); console.log('hooks :: error', hookName, e);

1
packages/nocodb/src/lib/models/Hook.ts

@ -125,6 +125,7 @@ export default class Hook implements HookType {
'async', 'async',
'url', 'url',
'headers', 'headers',
'condition',
'notification', 'notification',
'retries', 'retries',
'retry_interval', 'retry_interval',

8
packages/nocodb/src/lib/services/hook.svc.ts

@ -34,12 +34,13 @@ export async function hookCreate(param: {
validateHookPayload(param.hook.notification); validateHookPayload(param.hook.notification);
T.emit('evt', { evt_type: 'webhooks:created' });
// todo: type correction
const hook = await Hook.insert({ const hook = await Hook.insert({
...param.hook, ...param.hook,
fk_model_id: param.tableId, fk_model_id: param.tableId,
} as any); } as any);
T.emit('evt', { evt_type: 'webhooks:created' });
return hook; return hook;
} }
@ -56,8 +57,7 @@ export async function hookUpdate(param: { hookId: string; hook: HookReqType }) {
validateHookPayload(param.hook.notification); validateHookPayload(param.hook.notification);
// todo: correction in swagger return await Hook.update(param.hookId, param.hook);
return await Hook.update(param.hookId, param.hook as any);
} }
export async function hookTest(param: { export async function hookTest(param: {

410
packages/nocodb/src/schema/swagger.json

@ -11829,7 +11829,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/HookReq" "$ref": "#/components/schemas/Hook"
}, },
"examples": { "examples": {
"Example 1": { "Example 1": {
@ -11863,7 +11863,28 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/Audit" "$ref": "#/components/schemas/HookReq"
},
"examples": {
"Example 1": {
"value": {
"active": 0,
"async": 0,
"description": "This is my hook description",
"env": "all",
"event": "after",
"fk_model_id": "md_rsu68aqjsbyqtl",
"id": "string",
"notification": "{\"type\":\"URL\",\"payload\":{\"method\":\"POST\",\"body\":\"{{ json data }}\",\"headers\":[{}],\"parameters\":[{}],\"auth\":\"\",\"path\":\"http://example.com\"}}",
"null": null,
"operation": "insert",
"retries": 10,
"retry_interval": 60000,
"timeout": 60000,
"title": "My Webhook",
"condition": false
}
}
} }
} }
} }
@ -13560,6 +13581,9 @@
"description": "API Token", "description": "API Token",
"example": "DYh540o8hbWpUGdarekECKLdN5OhlgCUWutVJYX2" "example": "DYh540o8hbWpUGdarekECKLdN5OhlgCUWutVJYX2"
} }
},
"x-stoplight": {
"id": "q8h78qib3l9ko"
} }
}, },
"ApiTokenReq": { "ApiTokenReq": {
@ -13578,12 +13602,15 @@
"type": "string", "type": "string",
"example": "This API Token is for ABC application" "example": "This API Token is for ABC application"
} }
},
"x-stoplight": {
"id": "insn8kf1n4s6k"
} }
}, },
"ApiTokenList": { "ApiTokenList": {
"description": "Model for API Token List", "description": "Model for API Token List",
"x-stoplight": { "x-stoplight": {
"id": "5llg0az9z4tjc" "id": "r482re16lknrx"
}, },
"examples": [ "examples": [
{ {
@ -13686,6 +13713,9 @@
"type": "string", "type": "string",
"description": "Attachment URL" "description": "Attachment URL"
} }
},
"x-stoplight": {
"id": "g4rbip7xwyo6c"
} }
}, },
"AttachmentReq": { "AttachmentReq": {
@ -13721,6 +13751,9 @@
"type": "string", "type": "string",
"description": "Attachment URL to be uploaded via upload-by-url" "description": "Attachment URL to be uploaded via upload-by-url"
} }
},
"x-stoplight": {
"id": "13qyneoxa9jal"
} }
}, },
"Audit": { "Audit": {
@ -13843,6 +13876,9 @@
"description": "Detail", "description": "Detail",
"example": "<span class=\"\">Date</span> : <span class=\"text-decoration-line-through red px-2 lighten-4 black--text\">2023-03-12</span> <span class=\"black--text green lighten-4 px-2\"></span>" "example": "<span class=\"\">Date</span> : <span class=\"text-decoration-line-through red px-2 lighten-4 black--text\">2023-03-12</span> <span class=\"black--text green lighten-4 px-2\"></span>"
} }
},
"x-stoplight": {
"id": "l0ptb1ze54xw8"
} }
}, },
"AuditRowUpdateReq": { "AuditRowUpdateReq": {
@ -13880,6 +13916,9 @@
"value": { "value": {
"description": "The current value after the action" "description": "The current value after the action"
} }
},
"x-stoplight": {
"id": "56u0jsmndirwt"
} }
}, },
"Base": { "Base": {
@ -13954,6 +13993,9 @@
"example": "mysql2", "example": "mysql2",
"type": "string" "type": "string"
} }
},
"x-stoplight": {
"id": "af5ft42zw0uds"
} }
}, },
"BaseList": { "BaseList": {
@ -14053,7 +14095,10 @@
"description": "Paginated Info" "description": "Paginated Info"
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "ixksiq5jlmtt8"
}
}, },
"BaseReq": { "BaseReq": {
"description": "Model for Base Request", "description": "Model for Base Request",
@ -14106,7 +14151,10 @@
} }
}, },
"title": "Base Request", "title": "Base Request",
"type": "object" "type": "object",
"x-stoplight": {
"id": "noplj8yr34xzd"
}
}, },
"Bool": { "Bool": {
"description": "Model for Bool", "description": "Model for Bool",
@ -14125,7 +14173,10 @@
"type": "null" "type": "null"
} }
], ],
"title": "Bool Model" "title": "Bool Model",
"x-stoplight": {
"id": "1mdcm71g7euvt"
}
}, },
"Column": { "Column": {
"description": "Model for Column", "description": "Model for Column",
@ -14410,6 +14461,9 @@
"$ref": "#/components/schemas/Bool", "$ref": "#/components/schemas/Bool",
"description": "Is Visible?" "description": "Is Visible?"
} }
},
"x-stoplight": {
"id": "jcj9uwgl3rnum"
} }
}, },
"ColumnList": { "ColumnList": {
@ -14515,7 +14569,10 @@
} }
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "vs478sn3czrc2"
}
}, },
"ColumnReq": { "ColumnReq": {
"allOf": [ "allOf": [
@ -14604,7 +14661,10 @@
} }
], ],
"title": "Column Request Model", "title": "Column Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "gz9531uzue95g"
}
}, },
"CommentReq": { "CommentReq": {
"description": "Model for Comment Request", "description": "Model for Comment Request",
@ -14634,7 +14694,10 @@
"example": "3" "example": "3"
} }
}, },
"required": ["fk_model_id", "row_id"] "required": ["fk_model_id", "row_id"],
"x-stoplight": {
"id": "bsshnshrcy8f7"
}
}, },
"Filter": { "Filter": {
"description": "Model for Filter", "description": "Model for Filter",
@ -14790,7 +14853,10 @@
}, },
"readOnly": true, "readOnly": true,
"title": "Filter Model", "title": "Filter Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "ugwuw0aemt5y2"
}
}, },
"FilterList": { "FilterList": {
"description": "Model for Filter List", "description": "Model for Filter List",
@ -14876,7 +14942,10 @@
} }
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "5wly9iyeixwxs"
}
}, },
"FilterReq": { "FilterReq": {
"description": "Model for Filter Request", "description": "Model for Filter Request",
@ -14890,6 +14959,11 @@
"value": "foo" "value": "foo"
} }
], ],
"title": "Filter Request Model",
"type": "object",
"x-stoplight": {
"id": "3rypg89wx0qp1"
},
"properties": { "properties": {
"comparison_op": { "comparison_op": {
"description": "Comparison Operator", "description": "Comparison Operator",
@ -14962,7 +15036,7 @@
"description": "Foreign Key to Column" "description": "Foreign Key to Column"
}, },
"fk_parent_id": { "fk_parent_id": {
"$ref": "#/components/schemas/Id", "$ref": "#/components/schemas/StringOrNull",
"description": "Belong to which filter ID" "description": "Belong to which filter ID"
}, },
"is_group": { "is_group": {
@ -14978,9 +15052,7 @@
"description": "The filter value. Can be NULL for some operators." "description": "The filter value. Can be NULL for some operators."
} }
}, },
"readOnly": true, "readOnly": true
"title": "Filter Request Model",
"type": "object"
}, },
"Form": { "Form": {
"description": "Model for Form", "description": "Model for Form",
@ -15109,6 +15181,9 @@
"description": "Form View Title", "description": "Form View Title",
"example": "Form View 1" "example": "Form View 1"
} }
},
"x-stoplight": {
"id": "luvu108gux43l"
} }
}, },
"FormUpdateReq": { "FormUpdateReq": {
@ -15177,6 +15252,9 @@
"$ref": "#/components/schemas/StringOrNull", "$ref": "#/components/schemas/StringOrNull",
"description": "Custom message after the form is successfully submitted" "description": "Custom message after the form is successfully submitted"
} }
},
"x-stoplight": {
"id": "j9hvt9lds2o4q"
} }
}, },
"FormColumn": { "FormColumn": {
@ -15268,6 +15346,9 @@
"$ref": "#/components/schemas/StringOrNull", "$ref": "#/components/schemas/StringOrNull",
"description": "Form Column UUID (Not in use)" "description": "Form Column UUID (Not in use)"
} }
},
"x-stoplight": {
"id": "uga344v068snf"
} }
}, },
"FormColumnReq": { "FormColumnReq": {
@ -15332,6 +15413,9 @@
"$ref": "#/components/schemas/Bool", "$ref": "#/components/schemas/Bool",
"description": "Is this column shown in Form?" "description": "Is this column shown in Form?"
} }
},
"x-stoplight": {
"id": "7x7zkufy7a93t"
} }
}, },
"Formula": { "Formula": {
@ -15370,6 +15454,9 @@
"type": "string", "type": "string",
"description": "Error Message" "description": "Error Message"
} }
},
"x-stoplight": {
"id": "3h68x9a08nvlu"
} }
}, },
"FormulaColumnReq": { "FormulaColumnReq": {
@ -15404,6 +15491,9 @@
"type": "string", "type": "string",
"description": "UI Data Type" "description": "UI Data Type"
} }
},
"x-stoplight": {
"id": "rd9929r4qa3c0"
} }
}, },
"Gallery": { "Gallery": {
@ -15495,7 +15585,10 @@
} }
}, },
"title": "Gallery Model", "title": "Gallery Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "at47gz5aqeuv5"
}
}, },
"GalleryColumn": { "GalleryColumn": {
"description": "Model for Gallery Column", "description": "Model for Gallery Column",
@ -15527,12 +15620,15 @@
} }
}, },
"title": "Gallery Column Model", "title": "Gallery Column Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "4mx8vfd16y55g"
}
}, },
"GalleryUpdateReq": { "GalleryUpdateReq": {
"description": "Model for Gallery View Update Request", "description": "Model for Gallery View Update Request",
"x-stoplight": { "x-stoplight": {
"id": "mgch3vcokvxml" "id": "uiz5gs88mmt1a"
}, },
"examples": [ "examples": [
{ {
@ -15583,7 +15679,10 @@
} }
}, },
"title": "Geo Location Model", "title": "Geo Location Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "cphi852bw9h6n"
}
}, },
"Grid": { "Grid": {
"description": "Model for Grid", "description": "Model for Grid",
@ -15690,6 +15789,9 @@
} }
} }
} }
},
"x-stoplight": {
"id": "b84k9hlbnco1o"
} }
}, },
"GridColumn": { "GridColumn": {
@ -15771,6 +15873,9 @@
"id": "azwh6zn37qzkc" "id": "azwh6zn37qzkc"
} }
} }
},
"x-stoplight": {
"id": "r2fo58lue2zws"
} }
}, },
"GridColumnReq": { "GridColumnReq": {
@ -15806,12 +15911,15 @@
} }
}, },
"title": "Grid Column Request Model", "title": "Grid Column Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "1viyr55m2bzy3"
}
}, },
"GridUpdateReq": { "GridUpdateReq": {
"description": "Model for Grid View Update", "description": "Model for Grid View Update",
"x-stoplight": { "x-stoplight": {
"id": "d7x12vwf1fgz4" "id": "rmiv1e1jrzj71"
}, },
"examples": [ "examples": [
{ {
@ -15929,12 +16037,15 @@
"type": "string", "type": "string",
"description": "Hook Type" "description": "Hook Type"
} }
},
"x-stoplight": {
"id": "0rlu88fc7ctax"
} }
}, },
"HookReq": { "HookReq": {
"description": "Model for Hook", "description": "Model for Hook",
"x-stoplight": { "x-stoplight": {
"id": "8yxb4tz9u2ahz" "id": "yogkf6qrh2el9"
}, },
"examples": [ "examples": [
{ {
@ -15951,7 +16062,8 @@
"retries": 10, "retries": 10,
"retry_interval": 60000, "retry_interval": 60000,
"timeout": 60000, "timeout": 60000,
"title": "My Webhook" "title": "My Webhook",
"condition": false
} }
], ],
"title": "Hook Request Model", "title": "Hook Request Model",
@ -16022,6 +16134,13 @@
"type": { "type": {
"type": ["string", "null"], "type": ["string", "null"],
"description": "Hook Type" "description": "Hook Type"
},
"condition": {
"$ref": "#/components/schemas/Bool",
"x-stoplight": {
"id": "wwzoum7rrlwun"
},
"description": "Is this hook assoicated with some filters"
} }
}, },
"required": ["event", "notification", "operation", "title"] "required": ["event", "notification", "operation", "title"]
@ -16102,7 +16221,10 @@
"$ref": "#/components/schemas/Paginated" "$ref": "#/components/schemas/Paginated"
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "xhy5z4cp53e19"
}
}, },
"HookLog": { "HookLog": {
"description": "Model for Hook Log", "description": "Model for Hook Log",
@ -16180,6 +16302,9 @@
"type": { "type": {
"type": "string" "type": "string"
} }
},
"x-stoplight": {
"id": "uwhlr759v7ftb"
} }
}, },
"HookTestReq": { "HookTestReq": {
@ -16231,7 +16356,10 @@
"description": "Payload to be sent" "description": "Payload to be sent"
} }
}, },
"required": ["hook", "payload"] "required": ["hook", "payload"],
"x-stoplight": {
"id": "7fzbka372uhws"
}
}, },
"Id": { "Id": {
"description": "Model for ID", "description": "Model for ID",
@ -16239,7 +16367,10 @@
"maxLength": 20, "maxLength": 20,
"minLength": 0, "minLength": 0,
"title": "ID Model", "title": "ID Model",
"type": "string" "type": "string",
"x-stoplight": {
"id": "q0pbjcp2vwe2s"
}
}, },
"Kanban": { "Kanban": {
"description": "Model for Kanban", "description": "Model for Kanban",
@ -16303,6 +16434,9 @@
"description": "Kanban Title", "description": "Kanban Title",
"example": "My Kanban" "example": "My Kanban"
} }
},
"x-stoplight": {
"id": "y0wib3uswcjv3"
} }
}, },
"KanbanColumn": { "KanbanColumn": {
@ -16373,6 +16507,9 @@
"example": 1, "example": 1,
"description": "Column Order" "description": "Column Order"
} }
},
"x-stoplight": {
"id": "jq9x7ac9cr56v"
} }
}, },
"KanbanUpdateReq": { "KanbanUpdateReq": {
@ -16447,6 +16584,9 @@
}, },
"description": "Meta Info" "description": "Meta Info"
} }
},
"x-stoplight": {
"id": "ds5bt314hgogd"
} }
}, },
"LicenseReq": { "LicenseReq": {
@ -16466,7 +16606,10 @@
} }
}, },
"title": "License Key Request Model", "title": "License Key Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "ydf14317b0zdt"
}
}, },
"LinkToAnotherColumnReq": { "LinkToAnotherColumnReq": {
"description": "Model for LinkToAnotherColumn Request", "description": "Model for LinkToAnotherColumn Request",
@ -16512,7 +16655,10 @@
}, },
"required": ["childId", "parentId", "title", "type", "uidt"], "required": ["childId", "parentId", "title", "type", "uidt"],
"title": "LinkToAnotherColumn Request Model", "title": "LinkToAnotherColumn Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "72l8lzwwxd36o"
}
}, },
"LinkToAnotherRecord": { "LinkToAnotherRecord": {
"description": "Model for LinkToAnotherRecord", "description": "Model for LinkToAnotherRecord",
@ -16585,7 +16731,10 @@
} }
}, },
"title": "LinkToAnotherRecord Model", "title": "LinkToAnotherRecord Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "dyp9tqjqy0vjn"
}
}, },
"Lookup": { "Lookup": {
"description": "Model for Lookup", "description": "Model for Lookup",
@ -16622,6 +16771,9 @@
"description": "The order among the list", "description": "The order among the list",
"example": 1 "example": 1
} }
},
"x-stoplight": {
"id": "oin5vuleupbau"
} }
}, },
"LookupColumnReq": { "LookupColumnReq": {
@ -16656,6 +16808,9 @@
"type": "string", "type": "string",
"description": "UI DataType" "description": "UI DataType"
} }
},
"x-stoplight": {
"id": "pas3o57wv14yl"
} }
}, },
"Map": { "Map": {
@ -16730,12 +16885,15 @@
} }
}, },
"title": "Map Model", "title": "Map Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "g54ldc4p8ukcb"
}
}, },
"MapUpdateReq": { "MapUpdateReq": {
"description": "Model for Map", "description": "Model for Map",
"x-stoplight": { "x-stoplight": {
"id": "o1v53xl8b6hn9" "id": "np6n7vwe0bpbc"
}, },
"examples": [ "examples": [
{ {
@ -16808,7 +16966,10 @@
} }
}, },
"title": "Map Column Model", "title": "Map Column Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "jwohh924xkrki"
}
}, },
"Meta": { "Meta": {
"description": "Model for Meta", "description": "Model for Meta",
@ -16824,7 +16985,10 @@
"type": "string" "type": "string"
} }
], ],
"title": "Meta Model" "title": "Meta Model",
"x-stoplight": {
"id": "3bua8s1l4ia18"
}
}, },
"ModelRoleVisibility": { "ModelRoleVisibility": {
"description": "Model for ModelRoleVisibility", "description": "Model for ModelRoleVisibility",
@ -16864,7 +17028,10 @@
} }
}, },
"title": "ModelRoleVisibility Model", "title": "ModelRoleVisibility Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "qd2r14lgbgil5"
}
}, },
"NormalColumnRequest": { "NormalColumnRequest": {
"description": "Model for Normal Column Request", "description": "Model for Normal Column Request",
@ -17040,7 +17207,10 @@
}, },
"title": "Normal Column Request Model", "title": "Normal Column Request Model",
"type": "object", "type": "object",
"required": ["column_name"] "required": ["column_name"],
"x-stoplight": {
"id": "lbdjjckrjmr9a"
}
}, },
"OrgUserReq": { "OrgUserReq": {
"description": "Model for Organisation User Update Request", "description": "Model for Organisation User Update Request",
@ -17062,7 +17232,10 @@
} }
}, },
"title": "Organisation User Request Model", "title": "Organisation User Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "odog9hoqfpbii"
}
}, },
"Paginated": { "Paginated": {
"description": "Model for Paginated", "description": "Model for Paginated",
@ -17101,7 +17274,10 @@
} }
}, },
"title": "Paginated Model", "title": "Paginated Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "x9joizn5gys68"
}
}, },
"Password": { "Password": {
"description": "Model for Password", "description": "Model for Password",
@ -17109,7 +17285,10 @@
"examples": ["password123456789"], "examples": ["password123456789"],
"minLength": 8, "minLength": 8,
"title": "Password Model", "title": "Password Model",
"type": "string" "type": "string",
"x-stoplight": {
"id": "bn4nxlclrh5pl"
}
}, },
"PasswordChangeReq": { "PasswordChangeReq": {
"description": "Model for Password Change Request", "description": "Model for Password Change Request",
@ -17130,7 +17309,10 @@
}, },
"required": ["currentPassword", "newPassword"], "required": ["currentPassword", "newPassword"],
"title": "Password Change Request Model", "title": "Password Change Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "0bt6ueal1r1ai"
}
}, },
"PasswordForgotReq": { "PasswordForgotReq": {
"description": "Model for Password Forgot Request", "description": "Model for Password Forgot Request",
@ -17148,7 +17330,10 @@
}, },
"required": ["email"], "required": ["email"],
"title": "Password Forgot Request Model", "title": "Password Forgot Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "ucprs67a4yk4e"
}
}, },
"PasswordResetReq": { "PasswordResetReq": {
"description": "Model for Password Reset Request", "description": "Model for Password Reset Request",
@ -17167,7 +17352,10 @@
}, },
"required": ["password"], "required": ["password"],
"title": "Password Reset Request Model", "title": "Password Reset Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "kgww333t4d6oi"
}
}, },
"Plugin": { "Plugin": {
"description": "Model for Plugin", "description": "Model for Plugin",
@ -17281,6 +17469,9 @@
"description": "Plugin Version", "description": "Plugin Version",
"example": "0.0.1" "example": "0.0.1"
} }
},
"x-stoplight": {
"id": "yddgye9ktoowm"
} }
}, },
"PluginReq": { "PluginReq": {
@ -17302,6 +17493,9 @@
"$ref": "#/components/schemas/StringOrNull", "$ref": "#/components/schemas/StringOrNull",
"description": "Plugin Input" "description": "Plugin Input"
} }
},
"x-stoplight": {
"id": "8n2qkaa4mmbwk"
} }
}, },
"PluginTestReq": { "PluginTestReq": {
@ -17341,7 +17535,10 @@
"example": "Email" "example": "Email"
} }
}, },
"required": ["title", "input", "category"] "required": ["title", "input", "category"],
"x-stoplight": {
"id": "xburi6p29sjxt"
}
}, },
"Project": { "Project": {
"description": "Model for Project", "description": "Model for Project",
@ -17428,6 +17625,9 @@
"example": "my-project", "example": "my-project",
"type": "string" "type": "string"
} }
},
"x-stoplight": {
"id": "mws3mrzua4dgn"
} }
}, },
"ProjectList": { "ProjectList": {
@ -17521,7 +17721,10 @@
"description": "Pagination Info" "description": "Pagination Info"
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "xyl4jpahycz9z"
}
}, },
"ProjectReq": { "ProjectReq": {
"description": "Model for Project Request", "description": "Model for Project Request",
@ -17571,12 +17774,15 @@
}, },
"required": ["title"], "required": ["title"],
"title": "Project Request Model", "title": "Project Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "q30kb0cjsqejc"
}
}, },
"ProjectUpdateReq": { "ProjectUpdateReq": {
"description": "Model for Project Update Request", "description": "Model for Project Update Request",
"x-stoplight": { "x-stoplight": {
"id": "4zgrec70wyz4c" "id": "c3vcm2zuncet0"
}, },
"examples": [ "examples": [
{ {
@ -17639,7 +17845,10 @@
"description": "Project User Role" "description": "Project User Role"
} }
}, },
"required": ["email", "roles"] "required": ["email", "roles"],
"x-stoplight": {
"id": "9t06rq4mfxpsi"
}
}, },
"Rollup": { "Rollup": {
"description": "Model for Rollup", "description": "Model for Rollup",
@ -17685,6 +17894,9 @@
"avgDistinct" "avgDistinct"
] ]
} }
},
"x-stoplight": {
"id": "vx9w2nz7au6ra"
} }
}, },
"RollupColumnReq": { "RollupColumnReq": {
@ -17733,6 +17945,9 @@
"type": "string", "type": "string",
"description": "UI DataType" "description": "UI DataType"
} }
},
"x-stoplight": {
"id": "4dhjg4qtqyxgt"
} }
}, },
"SelectOption": { "SelectOption": {
@ -17772,6 +17987,9 @@
"description": "The order among the options", "description": "The order among the options",
"example": 1 "example": 1
} }
},
"x-stoplight": {
"id": "phvjpv4bedapu"
} }
}, },
"SelectOptions": { "SelectOptions": {
@ -17800,7 +18018,10 @@
} }
} }
}, },
"required": ["options"] "required": ["options"],
"x-stoplight": {
"id": "kjpgrmx40vtbs"
}
}, },
"SharedBaseReq": { "SharedBaseReq": {
"description": "Model for Shared Base Request", "description": "Model for Shared Base Request",
@ -17825,6 +18046,9 @@
"description": "The role given the target user", "description": "The role given the target user",
"example": "editor" "example": "editor"
} }
},
"x-stoplight": {
"id": "oinjv6cau9px7"
} }
}, },
"SharedView": { "SharedView": {
@ -17860,7 +18084,10 @@
"uuid": null "uuid": null
} }
} }
] ],
"x-stoplight": {
"id": "80fgtmpmd1hxi"
}
}, },
"SharedViewList": { "SharedViewList": {
"description": "Model for Shared View List", "description": "Model for Shared View List",
@ -17951,7 +18178,10 @@
"description": "Paginated Info" "description": "Paginated Info"
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "4nhixasc8ncwz"
}
}, },
"SharedViewReq": { "SharedViewReq": {
"description": "Model for Shared View Request", "description": "Model for Shared View Request",
@ -17972,6 +18202,9 @@
"$ref": "#/components/schemas/StringOrNull", "$ref": "#/components/schemas/StringOrNull",
"description": "Password to restrict access" "description": "Password to restrict access"
} }
},
"x-stoplight": {
"id": "bnn8fqklepl7j"
} }
}, },
"SignInReq": { "SignInReq": {
@ -17995,7 +18228,10 @@
}, },
"required": ["email", "password"], "required": ["email", "password"],
"title": "Signin Request Model", "title": "Signin Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "u8vbpvxi9gs2z"
}
}, },
"SignUpReq": { "SignUpReq": {
"description": "Model for Signup Request", "description": "Model for Signup Request",
@ -18051,7 +18287,10 @@
"description": "Ignore Subscription" "description": "Ignore Subscription"
} }
}, },
"required": ["email", "password"] "required": ["email", "password"],
"x-stoplight": {
"id": "tw6fyw78ih8dx"
}
}, },
"Sort": { "Sort": {
"description": "Model for Sort", "description": "Model for Sort",
@ -18101,6 +18340,9 @@
"example": "p_9sx43moxhqtjm3", "example": "p_9sx43moxhqtjm3",
"readOnly": true "readOnly": true
} }
},
"x-stoplight": {
"id": "9vo9f9qec4rwf"
} }
}, },
"SortList": { "SortList": {
@ -18179,7 +18421,10 @@
} }
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "wwcmyc9odjaxt"
}
}, },
"SortReq": { "SortReq": {
"description": "Model for Sort Request", "description": "Model for Sort Request",
@ -18202,6 +18447,9 @@
"enum": ["asc", "desc"], "enum": ["asc", "desc"],
"type": "string" "type": "string"
} }
},
"x-stoplight": {
"id": "g320wvsh90rcp"
} }
}, },
"StringOrNull": { "StringOrNull": {
@ -18216,7 +18464,10 @@
"type": "null" "type": "null"
} }
], ],
"title": "StringOrNull Model" "title": "StringOrNull Model",
"x-stoplight": {
"id": "n57pb7pryq2zm"
}
}, },
"Table": { "Table": {
"description": "Model for Table", "description": "Model for Table",
@ -18642,7 +18893,10 @@
"type": "string" "type": "string"
} }
}, },
"required": ["table_name", "title"] "required": ["table_name", "title"],
"x-stoplight": {
"id": "jnbkhtbvk6np6"
}
}, },
"TableList": { "TableList": {
"description": "Model for Table List", "description": "Model for Table List",
@ -18769,7 +19023,10 @@
"description": "Paginated Info" "description": "Paginated Info"
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "dki89c4lat66i"
}
}, },
"TableReq": { "TableReq": {
"description": "Model for Table Request", "description": "Model for Table Request",
@ -18907,7 +19164,10 @@
}, },
"required": ["columns", "table_name"], "required": ["columns", "table_name"],
"title": "Table Request Model", "title": "Table Request Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "rx8c69o5719vx"
}
}, },
"User": { "User": {
"description": "Model for User", "description": "Model for User",
@ -18956,7 +19216,10 @@
"type": "string" "type": "string"
} }
}, },
"required": ["email", "email_verified", "firstname", "id", "lastname"] "required": ["email", "email_verified", "firstname", "id", "lastname"],
"x-stoplight": {
"id": "cls6abm42ey04"
}
}, },
"UserInfo": { "UserInfo": {
"description": "Model for User Info", "description": "Model for User Info",
@ -18997,7 +19260,10 @@
} }
}, },
"title": "User Info Model", "title": "User Info Model",
"type": "object" "type": "object",
"x-stoplight": {
"id": "tvl09i4n62jnc"
}
}, },
"UserList": { "UserList": {
"description": "Model for User List", "description": "Model for User List",
@ -19075,7 +19341,10 @@
"description": "Paginated Info" "description": "Paginated Info"
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "kxaws22o5xk74"
}
}, },
"View": { "View": {
"description": "Model for View", "description": "Model for View",
@ -19186,7 +19455,10 @@
"description": "Associated View Model" "description": "Associated View Model"
} }
}, },
"required": ["fk_model_id", "show", "title", "type"] "required": ["fk_model_id", "show", "title", "type"],
"x-stoplight": {
"id": "t38y987y9rgv5"
}
}, },
"ViewList": { "ViewList": {
"description": "Model for View List", "description": "Model for View List",
@ -19311,12 +19583,15 @@
"description": "Paginated Info" "description": "Paginated Info"
} }
}, },
"required": ["list", "pageInfo"] "required": ["list", "pageInfo"],
"x-stoplight": {
"id": "kjdjlqsioesz5"
}
}, },
"ViewCreateReq": { "ViewCreateReq": {
"type": "object", "type": "object",
"x-stoplight": { "x-stoplight": {
"id": "36edbe4aa5d24" "id": "cuum3lv94tb57"
}, },
"title": "ViewCreateReq", "title": "ViewCreateReq",
"description": "Model for View Create Request", "description": "Model for View Create Request",
@ -19385,7 +19660,7 @@
"ViewUpdateReq": { "ViewUpdateReq": {
"description": "Model for View Update Request", "description": "Model for View Update Request",
"x-stoplight": { "x-stoplight": {
"id": "1f9fe53ec13a2" "id": "zlgpq6n2pg2rj"
}, },
"examples": [ "examples": [
{ {
@ -19450,7 +19725,7 @@
"ViewColumnUpdateReq": { "ViewColumnUpdateReq": {
"description": "Model for View Column Update Request", "description": "Model for View Column Update Request",
"x-stoplight": { "x-stoplight": {
"id": "xyhyykbk7kw0a" "id": "zt66lex00hzth"
}, },
"examples": [ "examples": [
{ {
@ -19479,7 +19754,7 @@
"ViewColumnReq": { "ViewColumnReq": {
"description": "Model for View Column Request", "description": "Model for View Column Request",
"x-stoplight": { "x-stoplight": {
"id": "94h1qcjiv7yex" "id": "chpsc3sgvhehw"
}, },
"examples": [ "examples": [
{ {
@ -19568,7 +19843,10 @@
"type": "object" "type": "object"
}, },
"title": "Visibility Rule Request Model", "title": "Visibility Rule Request Model",
"type": "array" "type": "array",
"x-stoplight": {
"id": "bmgsfkt8woxh5"
}
} }
}, },
"responses": { "responses": {

2
tests/playwright/pages/Dashboard/WebhookForm/index.ts

@ -124,9 +124,11 @@ export class WebhookFormPage extends BasePage {
await this.toolbar.actions.click('Webhooks'); await this.toolbar.actions.click('Webhooks');
await this.get().locator(`.nc-hook-delete-icon`).nth(index).click(); await this.get().locator(`.nc-hook-delete-icon`).nth(index).click();
await this.rootPage.locator('.ant-modal-confirm-confirm button:has-text("Yes")').click();
await this.verifyToast({ message: 'Hook deleted successfully' }); await this.verifyToast({ message: 'Hook deleted successfully' });
// click escape to close the drawer // click escape to close the drawer
await this.get().click();
await this.get().press('Escape'); await this.get().press('Escape');
} }

Loading…
Cancel
Save