feat: add name to webhook (#4)

* feat(migration): add name column to webhook table

* feat(webhooks): add name parameter to webhook params

* feat(webhooks): add example webhook name constant and input field to form

* fix(webhooks): add webhook name label and placeholder to multiple locales in the form

* feat(webhooks): display webhook name in the UI and include it in the API response

* Revert 'fix(webhooks): add webhook name label and placeholder to multiple locales in the form'

This reverts commit e547778a1c038c934e22ceb25935f541cb09e2cd.

* test(webhooks): add tests for creating and updating webhooks with name attribute

* chore(webhooks): add name property to webhook definitions in Swagger documentation

* chore(webhooks): remove unnecessary input touch event for webhook name field

* chore(webhooks): apply review changes requested

* chore(webhooks): revert auto lint changes in commit 18ec4cafeb72fd385b70f65f1873d7cfb65216a6
This commit is contained in:
Cayo P. R. Oliveira 2025-02-14 11:43:15 -03:00 committed by gabrieljablonski
parent 846b9fb9ce
commit f6bdc40c24
13 changed files with 67 additions and 5 deletions

View File

@ -23,7 +23,7 @@ class Api::V1::Accounts::WebhooksController < Api::V1::Accounts::BaseController
private
def webhook_params
params.require(:webhook).permit(:inbox_id, :url, subscriptions: [])
params.require(:webhook).permit(:inbox_id, :name, :url, subscriptions: [])
end
def fetch_webhook

View File

@ -44,6 +44,10 @@
"CONTACT_UPDATED": "Contact updated"
}
},
"NAME": {
"LABEL": "Webhook Name",
"PLACEHOLDER": "Enter the name of the webhook"
},
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",

View File

@ -53,6 +53,7 @@ export default {
data() {
return {
url: this.value.url || '',
name: this.value.name || '',
subscriptions: this.value.subscriptions || [],
supportedWebhookEvents: SUPPORTED_WEBHOOK_EVENTS,
};
@ -66,11 +67,15 @@ export default {
}
);
},
webhookNameInputPlaceholder() {
return this.$t('INTEGRATION_SETTINGS.WEBHOOK.FORM.NAME.PLACEHOLDER');
},
},
methods: {
onSubmit() {
this.$emit('submit', {
url: this.url,
name: this.name,
subscriptions: this.subscriptions,
});
},
@ -95,6 +100,15 @@ export default {
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.END_POINT.ERROR') }}
</span>
</label>
<label>
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.NAME.LABEL') }}
<input
v-model="name"
type="text"
name="name"
:placeholder="webhookNameInputPlaceholder"
/>
</label>
<label :class="{ error: v$.url.$error }" class="mb-2">
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.SUBSCRIPTIONS.LABEL') }}
</label>

View File

@ -37,8 +37,18 @@ const subscribedEvents = computed(() => {
<template>
<tr>
<td class="py-4 ltr:pr-4 rtl:pl-4">
<div class="font-medium break-words text-slate-700 dark:text-slate-100">
{{ webhook.url }}
<div
class="flex gap-2 font-medium break-words text-slate-700 dark:text-slate-100"
>
<template v-if="webhook.name">
{{ webhook.name }}
<span class="text-slate-500 dark:text-slate-400">
{{ webhook.url }}
</span>
</template>
<template v-else>
{{ webhook.url }}
</template>
</div>
<div class="block mt-1 text-sm text-slate-500 dark:text-slate-400">
<span class="font-medium">

View File

@ -3,6 +3,7 @@
# Table name: webhooks
#
# id :bigint not null, primary key
# name :string
# subscriptions :jsonb
# url :string
# webhook_type :integer default("account_type")

View File

@ -1,4 +1,5 @@
json.id webhook.id
json.name webhook.name
json.url webhook.url
json.account_id webhook.account_id
json.subscriptions webhook.subscriptions

View File

@ -0,0 +1,5 @@
class AddNameToWebhooks < ActiveRecord::Migration[7.0]
def change
add_column :webhooks, :name, :string, null: true
end
end

View File

@ -1055,6 +1055,7 @@ ActiveRecord::Schema[7.0].define(version: 2025_04_02_233933) do
t.datetime "updated_at", null: false
t.integer "webhook_type", default: 0
t.jsonb "subscriptions", default: ["conversation_status_changed", "conversation_updated", "conversation_created", "contact_created", "contact_updated", "message_created", "message_updated", "webwidget_triggered"]
t.string "name"
t.index ["account_id", "url"], name: "index_webhooks_on_account_id_and_url", unique: true
end

View File

@ -3,7 +3,7 @@ require 'rails_helper'
RSpec.describe 'Webhooks API', type: :request do
let(:account) { create(:account) }
let(:inbox) { create(:inbox, account: account) }
let(:webhook) { create(:webhook, account: account, inbox: inbox, url: 'https://hello.com') }
let(:webhook) { create(:webhook, account: account, inbox: inbox, url: 'https://hello.com', name: 'My Webhook') }
let(:administrator) { create(:user, account: account, role: :administrator) }
let(:agent) { create(:user, account: account, role: :agent) }
@ -49,6 +49,16 @@ RSpec.describe 'Webhooks API', type: :request do
expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'
end
it 'creates webhook with name' do
post "/api/v1/accounts/#{account.id}/webhooks",
params: { account_id: account.id, inbox_id: inbox.id, url: 'https://hello.com', name: 'My Webhook' },
headers: administrator.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['payload']['webhook']['name']).to eql 'My Webhook'
end
it 'throws error when invalid url provided' do
post "/api/v1/accounts/#{account.id}/webhooks",
params: { account_id: account.id, inbox_id: inbox.id, url: 'javascript:alert(1)' },
@ -103,11 +113,12 @@ RSpec.describe 'Webhooks API', type: :request do
context 'when it is an authenticated admin user' do
it 'updates webhook' do
put "/api/v1/accounts/#{account.id}/webhooks/#{webhook.id}",
params: { url: 'https://hello.com' },
params: { url: 'https://hello.com', name: 'Another Webhook' },
headers: administrator.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'
expect(response.parsed_body['payload']['webhook']['name']).to eql 'Another Webhook'
end
end
end

View File

@ -3,6 +3,7 @@ FactoryBot.define do
account_id { 1 }
inbox_id { 1 }
url { 'https://api.chatwoot.com' }
name { 'My Webhook' }
subscriptions do
%w[
conversation_status_changed

View File

@ -3,6 +3,9 @@ properties:
url:
type: string
description: The url where the events should be sent
name:
type: string
description: The name of the webhook
subscriptions:
type: array
items:

View File

@ -6,6 +6,9 @@ properties:
url:
type: string
description: The url to which the events will be send
name:
type: string
description: The name of the webhook
subscriptions:
type: array
items:

View File

@ -6132,6 +6132,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
"name": {
"type": "string",
"description": "The name of the webhook"
},
"subscriptions": {
"type": "array",
"items": {
@ -6730,6 +6734,10 @@
"type": "string",
"description": "The url where the events should be sent"
},
"name": {
"type": "string",
"description": "The name of the webhook"
},
"subscriptions": {
"type": "array",
"items": {