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

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

@ -1,5 +1,5 @@
<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'
const emit = defineEmits(['edit', 'add'])
@ -8,13 +8,13 @@ const { t } = useI18n()
const { $api, $e } = useNuxtApp()
const hooks = ref<Record<string, any>[]>([])
const hooks = ref<HookType[]>([])
const meta = inject(MetaInj, ref())
async function loadHooksList() {
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) => {
hook.notification = parseProp(hook.notification)
return hook
@ -24,25 +24,65 @@ async function loadHooksList() {
}
}
async function deleteHook(item: Record<string, any>, index: number) {
try {
if (item.id) {
await $api.dbTableWebhook.delete(item.id)
hooks.value.splice(index, 1)
} else {
hooks.value.splice(index, 1)
}
async function deleteHook(item: HookType, index: number) {
Modal.confirm({
title: `Do you want to delete '${item.title}'?`,
wrapClassName: 'nc-modal-hook-delete',
okText: 'Yes',
okType: 'danger',
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
message.success(t('msg.success.webhookDeleted'))
if (!hooks.value.length) {
hooks.value = []
async function copyHook(hook: HookType) {
try {
const newHook = await $api.dbTableWebhook.create(hook.fk_model_id!, {
...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) {
message.error(await extractSdkResponseErrorMsg(e))
}
$e('a:webhook:delete')
}
onMounted(() => {
@ -84,9 +124,12 @@ onMounted(() => {
</template>
<template #avatar>
<div class="mt-4">
<div class="my-1 px-2">
<MdiHook class="text-xl" />
</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>
</a-list-item-meta>
@ -96,7 +139,19 @@ onMounted(() => {
<div class="mr-2">{{ $t('labels.notifyVia') }} : {{ item?.notification?.type }}</div>
<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>
</template>

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

@ -429,6 +429,10 @@
"openTab": "Open new tab",
"iFrame": "Copy embeddable HTML code",
"addWebhook": "Add New Webhook",
"enableWebhook": "Enable Webhook",
"testWebhook": "Test Webhook",
"copyWebhook": "Copy Webhook",
"deleteWebhook": "Delete Webhook",
"newToken": "Add New Token",
"exportZip": "Export 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) => {
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 */
fk_column_id?: IdType;
/** Belong to which filter ID */
fk_parent_id?: IdType;
fk_parent_id?: StringOrNullType;
/** Is this filter grouped? */
is_group?: BoolType;
/** Logical Operator */
@ -1152,6 +1152,8 @@ export interface HookReqType {
title: string;
/** Hook Type */
type?: string | null;
/** Is this hook assoicated with some filters */
condition?: BoolType;
}
/**
@ -8752,16 +8754,16 @@ export class Api<
* @name Create
* @summary Create Table Hook
* @request POST:/api/v1/db/meta/tables/{tableId}/hooks
* @response `200` `HookReqType` OK
* @response `200` `HookType` OK
* @response `400` `{
\** @example BadRequest [Error]: <ERROR MESSAGE> *\
msg: string,
}`
*/
create: (tableId: IdType, data: AuditType, params: RequestParams = {}) =>
create: (tableId: IdType, data: HookReqType, params: RequestParams = {}) =>
this.request<
HookReqType,
HookType,
{
/** @example BadRequest [Error]: <ERROR MESSAGE> */
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> {
// const data = _data;
const view = await View.get(this.viewId);
// handle form view data submission
@ -2329,7 +2327,9 @@ class BaseModelSqlv2 {
operation,
});
for (const hook of hooks) {
invokeWebhook(hook, this.model, data, req?.user);
if (hook.active) {
invokeWebhook(hook, this.model, data, req?.user);
}
}
} catch (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',
'url',
'headers',
'condition',
'notification',
'retries',
'retry_interval',

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

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

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

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

Loading…
Cancel
Save