From fa9048f584c43b1a6817d6b9847e14c1b8214cc5 Mon Sep 17 00:00:00 2001 From: Bram Wiepjes <bramw@protonmail.com> Date: Tue, 25 Feb 2025 10:52:35 +0000 Subject: [PATCH] Send notification when webhook is deactivated --- .../builder/locale/en/LC_MESSAGES/django.po | 4 +- backend/src/baserow/contrib/database/apps.py | 4 + .../database/locale/en/LC_MESSAGES/django.po | 28 +++++-- .../database/webhooks/notification_types.py | 81 +++++++++++++++++++ .../contrib/database/webhooks/tasks.py | 9 +++ .../core/locale/en/LC_MESSAGES/django.po | 4 +- .../baserow/core/notifications_summary.html | 18 ----- .../core/notifications_summary.mjml.eta | 6 -- .../test_webhook_notification_types.py | 37 +++++++++ .../database/webhooks/test_webhook_tasks.py | 69 ++++++++++++++++ ...ication_when_a_webhook_is_deactivated.json | 7 ++ .../locale/en/LC_MESSAGES/django.po | 11 ++- .../WebhookDeactivatedNotification.vue | 29 +++++++ .../components/webhook/WebhookModal.vue | 2 +- web-frontend/modules/database/locales/en.json | 3 + .../modules/database/notificationTypes.js | 25 ++++++ web-frontend/modules/database/pages/table.vue | 1 + .../modules/database/pages/table/webhooks.vue | 37 +++++++++ web-frontend/modules/database/plugin.js | 5 ++ web-frontend/modules/database/routes.js | 5 ++ web-frontend/test/helpers/components.js | 1 + 21 files changed, 348 insertions(+), 38 deletions(-) create mode 100644 backend/src/baserow/contrib/database/webhooks/notification_types.py create mode 100644 backend/tests/baserow/contrib/database/webhooks/test_webhook_notification_types.py create mode 100644 changelog/entries/unreleased/feature/send_notification_when_a_webhook_is_deactivated.json create mode 100644 web-frontend/modules/database/components/notifications/WebhookDeactivatedNotification.vue create mode 100644 web-frontend/modules/database/pages/table/webhooks.vue diff --git a/backend/src/baserow/contrib/builder/locale/en/LC_MESSAGES/django.po b/backend/src/baserow/contrib/builder/locale/en/LC_MESSAGES/django.po index 306c9b390..d5b6ada07 100644 --- a/backend/src/baserow/contrib/builder/locale/en/LC_MESSAGES/django.po +++ b/backend/src/baserow/contrib/builder/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-01-15 11:59+0000\n" +"POT-Creation-Date: 2025-02-11 17:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -46,7 +46,7 @@ msgstr "" msgid "Last name" msgstr "" -#: src/baserow/contrib/builder/data_providers/data_provider_types.py:452 +#: src/baserow/contrib/builder/data_providers/data_provider_types.py:555 #, python-format msgid "%(user_source_name)s member" msgstr "" diff --git a/backend/src/baserow/contrib/database/apps.py b/backend/src/baserow/contrib/database/apps.py index 3149bf2fe..a460bfe91 100755 --- a/backend/src/baserow/contrib/database/apps.py +++ b/backend/src/baserow/contrib/database/apps.py @@ -946,6 +946,9 @@ class DatabaseConfig(AppConfig): from baserow.contrib.database.views.notification_types import ( FormSubmittedNotificationType, ) + from baserow.contrib.database.webhooks.notification_types import ( + WebhookDeactivatedNotificationType, + ) from baserow.core.notifications.registries import notification_type_registry notification_type_registry.register(CollaboratorAddedToRowNotificationType()) @@ -953,6 +956,7 @@ class DatabaseConfig(AppConfig): UserMentionInRichTextFieldNotificationType() ) notification_type_registry.register(FormSubmittedNotificationType()) + notification_type_registry.register(WebhookDeactivatedNotificationType()) # The signals must always be imported last because they use the registries # which need to be filled first. diff --git a/backend/src/baserow/contrib/database/locale/en/LC_MESSAGES/django.po b/backend/src/baserow/contrib/database/locale/en/LC_MESSAGES/django.po index cf1987b19..75eb3173a 100644 --- a/backend/src/baserow/contrib/database/locale/en/LC_MESSAGES/django.po +++ b/backend/src/baserow/contrib/database/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-01-15 11:59+0000\n" +"POT-Creation-Date: 2025-02-11 17:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -38,11 +38,11 @@ msgid "" "\"%(database_name)s\" (%(database_id)s)." msgstr "" -#: src/baserow/contrib/database/airtable/actions.py:22 +#: src/baserow/contrib/database/airtable/actions.py:23 msgid "Import database from Airtable" msgstr "" -#: src/baserow/contrib/database/airtable/actions.py:24 +#: src/baserow/contrib/database/airtable/actions.py:25 #, python-format msgid "" "Imported database " @@ -80,7 +80,7 @@ msgstr "" msgid "The data sync synchronized" msgstr "" -#: src/baserow/contrib/database/data_sync/handler.py:186 +#: src/baserow/contrib/database/data_sync/handler.py:187 #: src/baserow/contrib/database/table/handler.py:548 msgid "Grid" msgstr "" @@ -148,8 +148,8 @@ msgid "" "%(new_primary_field_name)s" msgstr "" -#: src/baserow/contrib/database/fields/models.py:415 -#: src/baserow/contrib/database/fields/models.py:594 +#: src/baserow/contrib/database/fields/models.py:453 +#: src/baserow/contrib/database/fields/models.py:632 msgid "The format of the duration." msgstr "" @@ -601,12 +601,12 @@ msgstr "" msgid "Row (%(row_id)s) created via form submission" msgstr "" -#: src/baserow/contrib/database/views/notification_types.py:84 +#: src/baserow/contrib/database/views/notification_types.py:86 #, python-format msgid "%(form_name)s has been submitted in %(table_name)s" msgstr "" -#: src/baserow/contrib/database/views/notification_types.py:101 +#: src/baserow/contrib/database/views/notification_types.py:103 #, python-format msgid "and 1 more field" msgid_plural "and %(count)s more fields" @@ -645,3 +645,15 @@ msgid "" "Webhook \"%(webhook_name)s\" (%(webhook_id)s) as %(webhook_request_method)s " "to %(webhook_url)s\" updated" msgstr "" + +#: src/baserow/contrib/database/webhooks/notification_types.py:70 +#, python-format +msgid "%(name)s webhook has been deactivated." +msgstr "" + +#: src/baserow/contrib/database/webhooks/notification_types.py:77 +#, python-format +msgid "" +"The webhook failed more than %(max_failures)s consecutive times and was " +"therefore deactivated." +msgstr "" diff --git a/backend/src/baserow/contrib/database/webhooks/notification_types.py b/backend/src/baserow/contrib/database/webhooks/notification_types.py new file mode 100644 index 000000000..e11c15d52 --- /dev/null +++ b/backend/src/baserow/contrib/database/webhooks/notification_types.py @@ -0,0 +1,81 @@ +from dataclasses import asdict, dataclass +from typing import List, Optional + +from django.conf import settings +from django.utils.translation import gettext as _ + +from baserow.core.models import WORKSPACE_USER_PERMISSION_ADMIN, WorkspaceUser +from baserow.core.notifications.handler import NotificationHandler +from baserow.core.notifications.models import NotificationRecipient +from baserow.core.notifications.registries import ( + EmailNotificationTypeMixin, + NotificationType, +) + +from .models import TableWebhook + + +@dataclass +class DeactivatedWebhookData: + webhook_id: int + table_id: int + database_id: int + webhook_name: str + + @classmethod + def from_webhook(cls, webhook): + return cls( + webhook_id=webhook.id, + table_id=webhook.table_id, + database_id=webhook.table.database_id, + webhook_name=webhook.name, + ) + + +class WebhookDeactivatedNotificationType(EmailNotificationTypeMixin, NotificationType): + type = "webhook_deactivated" + has_web_frontend_route = True + + @classmethod + def notify_admins_in_workspace( + cls, webhook: TableWebhook + ) -> Optional[List[NotificationRecipient]]: + """ + Creates a notification for each user that is subscribed to receive comments on + the row on which the comment was created. + + :param webhook: The comment that was created. + :return: + """ + + workspace = webhook.table.database.workspace + admins_workspace_users = WorkspaceUser.objects.filter( + workspace=workspace, + permissions=WORKSPACE_USER_PERMISSION_ADMIN, + user__profile__to_be_deleted=False, + user__is_active=True, + ).select_related("user") + admins_in_workspace = [admin.user for admin in admins_workspace_users] + + return NotificationHandler.create_direct_notification_for_users( + notification_type=WebhookDeactivatedNotificationType.type, + recipients=admins_in_workspace, + data=asdict(DeactivatedWebhookData.from_webhook(webhook)), + sender=None, + workspace=webhook.table.database.workspace, + ) + + @classmethod + def get_notification_title_for_email(cls, notification, context): + return _("%(name)s webhook has been deactivated.") % { + "name": notification.data["webhook_name"], + } + + @classmethod + def get_notification_description_for_email(cls, notification, context): + return _( + "The webhook failed more than %(max_failures)s consecutive times and " + "was therefore deactivated." + ) % { + "max_failures": settings.BASEROW_WEBHOOKS_MAX_CONSECUTIVE_TRIGGER_FAILURES, + } diff --git a/backend/src/baserow/contrib/database/webhooks/tasks.py b/backend/src/baserow/contrib/database/webhooks/tasks.py index 223865416..e4bec1d88 100644 --- a/backend/src/baserow/contrib/database/webhooks/tasks.py +++ b/backend/src/baserow/contrib/database/webhooks/tasks.py @@ -88,6 +88,7 @@ def call_webhook( from .handler import WebhookHandler from .models import TableWebhook, TableWebhookCall + from .notification_types import WebhookDeactivatedNotificationType if self.request.retries > retries: retries = self.request.retries @@ -187,6 +188,14 @@ def call_webhook( webhook.active = False webhook.save() + # Send a notification to the workspace admins that the webhook was + # deactivated. + transaction.on_commit( + lambda: WebhookDeactivatedNotificationType.notify_admins_in_workspace( + webhook + ) + ) + # After the transaction successfully commits we can delay the next call # in the queue, so that only one call is triggered concurrently. transaction.on_commit(lambda: schedule_next_task_in_queue(webhook_id)) diff --git a/backend/src/baserow/core/locale/en/LC_MESSAGES/django.po b/backend/src/baserow/core/locale/en/LC_MESSAGES/django.po index 5c3844515..7a41c9d85 100644 --- a/backend/src/baserow/core/locale/en/LC_MESSAGES/django.po +++ b/backend/src/baserow/core/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-01-15 11:59+0000\n" +"POT-Creation-Date: 2025-02-11 17:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -242,7 +242,7 @@ msgstr "" msgid "Decimal number" msgstr "" -#: src/baserow/core/handler.py:2109 src/baserow/core/user/handler.py:267 +#: src/baserow/core/handler.py:2122 src/baserow/core/user/handler.py:267 #, python-format msgid "%(name)s's workspace" msgstr "" diff --git a/backend/src/baserow/core/templates/baserow/core/notifications_summary.html b/backend/src/baserow/core/templates/baserow/core/notifications_summary.html index e26965f31..27429a172 100644 --- a/backend/src/baserow/core/templates/baserow/core/notifications_summary.html +++ b/backend/src/baserow/core/templates/baserow/core/notifications_summary.html @@ -230,24 +230,6 @@ </tr> <!-- htmlmin:ignore -->{% endif %} <!-- htmlmin:ignore --> - <tr> - <td align="left" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;"> - <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;"> - <tbody> - <tr> - <td align="center" bgcolor="#5190ef" role="presentation" style="border:none;border-radius:4px;cursor:auto;mso-padding-alt:12px 30px;background:#5190ef;" valign="middle"> - <a href="{{ baserow_embedded_share_url }}" style="display:inline-block;background:#5190ef;color:#ffffff;font-family:Inter,sans-serif;font-size:15px;font-weight:600;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:12px 30px;mso-padding-alt:0px;border-radius:4px;" target="_blank"> {% trans "View in Baserow" %} </a> - </td> - </tr> - </tbody> - </table> - </td> - </tr> - <tr> - <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;"> - <div style="font-family:Inter,sans-serif;font-size:12px;line-height:1;text-align:left;color:#9c9c9f;">{{ baserow_embedded_share_url }}</div> - </td> - </tr> <tr> <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;"> <div style="font-family:Inter,sans-serif;font-size:13px;line-height:170%;text-align:left;color:#070810;">{% blocktrans trimmed %} Baserow is an open source no-code database tool which allows you to collaborate on projects, customers and more. It gives you the powers of a developer without leaving your browser. {% endblocktrans %}</div> diff --git a/backend/src/baserow/core/templates/baserow/core/notifications_summary.mjml.eta b/backend/src/baserow/core/templates/baserow/core/notifications_summary.mjml.eta index 30d79e603..36a0b4f56 100644 --- a/backend/src/baserow/core/templates/baserow/core/notifications_summary.mjml.eta +++ b/backend/src/baserow/core/templates/baserow/core/notifications_summary.mjml.eta @@ -31,12 +31,6 @@ {% endblocktrans %} </mj-text> <mj-raw><!-- htmlmin:ignore -->{% endif %}<!-- htmlmin:ignore --></mj-raw> - <mj-button mj-class="button mt-20" href="{{ baserow_embedded_share_url }}"> - {% trans "View in Baserow" %} - </mj-button> - <mj-text mj-class="button-url"> - {{ baserow_embedded_share_url }} - </mj-text> <mj-text mj-class="text"> {% blocktrans trimmed %} Baserow is an open source no-code database tool which allows you to collaborate diff --git a/backend/tests/baserow/contrib/database/webhooks/test_webhook_notification_types.py b/backend/tests/baserow/contrib/database/webhooks/test_webhook_notification_types.py new file mode 100644 index 000000000..55b545e90 --- /dev/null +++ b/backend/tests/baserow/contrib/database/webhooks/test_webhook_notification_types.py @@ -0,0 +1,37 @@ +import pytest + +from baserow.contrib.database.webhooks.notification_types import ( + WebhookDeactivatedNotificationType, +) + + +@pytest.mark.django_db(transaction=True) +def test_webhook_deactivated_notification_can_be_render_as_email( + api_client, data_fixture +): + user = data_fixture.create_user() + workspace = data_fixture.create_workspace(user=user) + database = data_fixture.create_database_application(workspace=workspace) + table = data_fixture.create_database_table(database=database) + webhook = data_fixture.create_table_webhook( + table=table, active=True, failed_triggers=1 + ) + + notification_recipients = ( + WebhookDeactivatedNotificationType.notify_admins_in_workspace(webhook) + ) + notification = notification_recipients[0].notification + + assert WebhookDeactivatedNotificationType.get_notification_title_for_email( + notification, {} + ) == "%(name)s webhook has been deactivated." % { + "name": notification.data["webhook_name"], + } + + assert ( + WebhookDeactivatedNotificationType.get_notification_description_for_email( + notification, {} + ) + == "The webhook failed more than 8 consecutive times and " + "was therefore deactivated." + ) diff --git a/backend/tests/baserow/contrib/database/webhooks/test_webhook_tasks.py b/backend/tests/baserow/contrib/database/webhooks/test_webhook_tasks.py index 4532e61d0..08ccb63b5 100644 --- a/backend/tests/baserow/contrib/database/webhooks/test_webhook_tasks.py +++ b/backend/tests/baserow/contrib/database/webhooks/test_webhook_tasks.py @@ -10,7 +10,12 @@ import responses from celery.exceptions import Retry from baserow.contrib.database.webhooks.models import TableWebhook, TableWebhookCall +from baserow.contrib.database.webhooks.notification_types import ( + WebhookDeactivatedNotificationType, +) from baserow.contrib.database.webhooks.tasks import call_webhook +from baserow.core.models import WorkspaceUser +from baserow.core.notifications.models import Notification from baserow.core.redis import RedisQueue from baserow.test_utils.helpers import stub_getaddrinfo @@ -361,3 +366,67 @@ def test_can_call_webhook_to_localhost_when_private_addresses_allowed( assert not call.error assert call.response_status == 201 assert webhook.active + + +@pytest.mark.django_db(transaction=True) +@responses.activate +@override_settings( + BASEROW_WEBHOOKS_MAX_RETRIES_PER_CALL=1, + BASEROW_WEBHOOKS_MAX_CONSECUTIVE_TRIGGER_FAILURES=1, +) +@patch("baserow.contrib.database.webhooks.tasks.RedisQueue", MemoryQueue) +@patch("baserow.contrib.database.webhooks.tasks.cache", MagicMock()) +@patch("baserow.ws.tasks.broadcast_to_users.apply") +def test_call_webhook_failed_reached_notification_send( + mocked_broadcast_to_users, data_fixture +): + user_1 = data_fixture.create_user() + user_2 = data_fixture.create_user() + admin_1 = data_fixture.create_user() + admin_2 = data_fixture.create_user() + workspace = data_fixture.create_workspace() + + WorkspaceUser.objects.create( + user=user_1, workspace=workspace, order=1, permissions="MEMBER" + ) + WorkspaceUser.objects.create( + user=user_2, workspace=workspace, order=2, permissions="MEMBER" + ) + WorkspaceUser.objects.create( + user=admin_1, workspace=workspace, order=3, permissions="ADMIN" + ) + WorkspaceUser.objects.create( + user=admin_2, workspace=workspace, order=4, permissions="ADMIN" + ) + + database = data_fixture.create_database_application(workspace=workspace) + table = data_fixture.create_database_table(database=database) + webhook = data_fixture.create_table_webhook( + table=table, active=True, failed_triggers=1 + ) + + call_webhook.push_request(retries=1) + call_webhook.run( + webhook_id=webhook.id, + event_id="00000000-0000-0000-0000-000000000000", + event_type="rows.created", + method="POST", + url="http://localhost/", + headers={"Baserow-header-1": "Value 1"}, + payload={"type": "rows.created"}, + ) + + all_notifications = list(Notification.objects.all()) + assert len(all_notifications) == 1 + recipient_ids = [r.id for r in all_notifications[0].recipients.all()] + assert recipient_ids == [admin_1.id, admin_2.id] + assert all_notifications[0].type == WebhookDeactivatedNotificationType.type + assert all_notifications[0].broadcast is False + assert all_notifications[0].workspace_id == workspace.id + assert all_notifications[0].sender is None + assert all_notifications[0].data == { + "database_id": database.id, + "table_id": table.id, + "webhook_id": webhook.id, + "webhook_name": webhook.name, + } diff --git a/changelog/entries/unreleased/feature/send_notification_when_a_webhook_is_deactivated.json b/changelog/entries/unreleased/feature/send_notification_when_a_webhook_is_deactivated.json new file mode 100644 index 000000000..8782d0a45 --- /dev/null +++ b/changelog/entries/unreleased/feature/send_notification_when_a_webhook_is_deactivated.json @@ -0,0 +1,7 @@ +{ + "type": "feature", + "message": "Send notification to all admins when a webhook is deactivated.", + "issue_number": null, + "bullet_points": [], + "created_at": "2025-02-11" +} diff --git a/enterprise/backend/src/baserow_enterprise/locale/en/LC_MESSAGES/django.po b/enterprise/backend/src/baserow_enterprise/locale/en/LC_MESSAGES/django.po index 689290852..f6f380813 100644 --- a/enterprise/backend/src/baserow_enterprise/locale/en/LC_MESSAGES/django.po +++ b/enterprise/backend/src/baserow_enterprise/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-17 08:48+0000\n" +"POT-Creation-Date: 2025-02-11 17:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -62,6 +62,15 @@ msgstr "" msgid "REDONE" msgstr "" +#: src/baserow_enterprise/data_sync/actions.py:21 +msgid "Update periodic data sync interval" +msgstr "" + +#: src/baserow_enterprise/data_sync/actions.py:22 +#, python-format +msgid "Data sync table \"%(table_name)s\" (%(table_id)s) updated" +msgstr "" + #: src/baserow_enterprise/role/actions.py:28 msgid "Assign multiple roles" msgstr "" diff --git a/web-frontend/modules/database/components/notifications/WebhookDeactivatedNotification.vue b/web-frontend/modules/database/components/notifications/WebhookDeactivatedNotification.vue new file mode 100644 index 000000000..7ec787bcd --- /dev/null +++ b/web-frontend/modules/database/components/notifications/WebhookDeactivatedNotification.vue @@ -0,0 +1,29 @@ +<template> + <nuxt-link + class="notification-panel__notification-link" + :to="route" + @click.native="markAsReadAndHandleClick" + > + <div class="notification-panel__notification-content-title"> + <i18n path="webhookDeactivatedNotification.body" tag="span"> + <template #name> + <strong>{{ notification.data.webhook_name }}</strong> + </template> + </i18n> + </div> + </nuxt-link> +</template> + +<script> +import notificationContent from '@baserow/modules/core/mixins/notificationContent' + +export default { + name: 'WebhookDeactivatedNotification', + mixins: [notificationContent], + methods: { + handleClick() { + this.$emit('close-panel') + }, + }, +} +</script> diff --git a/web-frontend/modules/database/components/webhook/WebhookModal.vue b/web-frontend/modules/database/components/webhook/WebhookModal.vue index edeefa357..4b60f0db8 100644 --- a/web-frontend/modules/database/components/webhook/WebhookModal.vue +++ b/web-frontend/modules/database/components/webhook/WebhookModal.vue @@ -1,5 +1,5 @@ <template> - <Modal> + <Modal @hidden="$emit('hidden')"> <h2 class="box__title"> {{ $t('webhookModal.title', { name: table.name }) }} </h2> diff --git a/web-frontend/modules/database/locales/en.json b/web-frontend/modules/database/locales/en.json index 65fb0d147..ff711f42e 100644 --- a/web-frontend/modules/database/locales/en.json +++ b/web-frontend/modules/database/locales/en.json @@ -1054,5 +1054,8 @@ "configureDataSyncSettings": { "title": "Change data sync", "syncTable": "Sync when save" + }, + "webhookDeactivatedNotification": { + "body": "{name} webhook has been deactivated because it failed too many times consecutively." } } diff --git a/web-frontend/modules/database/notificationTypes.js b/web-frontend/modules/database/notificationTypes.js index 17090201a..787153f68 100644 --- a/web-frontend/modules/database/notificationTypes.js +++ b/web-frontend/modules/database/notificationTypes.js @@ -3,6 +3,7 @@ import NotificationSenderInitialsIcon from '@baserow/modules/core/components/not import CollaboratorAddedToRowNotification from '@baserow/modules/database/components/notifications/CollaboratorAddedToRowNotification' import UserMentionInRichTextFieldNotification from '@baserow/modules/database/components/notifications/UserMentionInRichTextFieldNotification' import FormSubmittedNotification from '@baserow/modules/database/components/notifications/FormSubmittedNotification' +import WebhookDeactivatedNotification from '@baserow/modules/database/components/notifications/WebhookDeactivatedNotification' export class CollaboratorAddedToRowNotificationType extends NotificationType { static getType() { @@ -78,3 +79,27 @@ export class UserMentionInRichTextFieldNotificationType extends NotificationType } } } + +export class WebhookDeactivatedNotificationType extends NotificationType { + static getType() { + return 'webhook_deactivated' + } + + getIconComponent() { + return null + } + + getContentComponent() { + return WebhookDeactivatedNotification + } + + getRoute(notificationData) { + return { + name: 'database-table-open-webhooks', + params: { + databaseId: notificationData.database_id, + tableId: notificationData.table_id, + }, + } + } +} diff --git a/web-frontend/modules/database/pages/table.vue b/web-frontend/modules/database/pages/table.vue index 5fd1c56dc..8196d303d 100644 --- a/web-frontend/modules/database/pages/table.vue +++ b/web-frontend/modules/database/pages/table.vue @@ -17,6 +17,7 @@ (row, activeSearchTerm) => setAdjacentRow(false, row, activeSearchTerm) " ></Table> + <NuxtChild :database="database" :table="table" :fields="fields" /> </div> </template> diff --git a/web-frontend/modules/database/pages/table/webhooks.vue b/web-frontend/modules/database/pages/table/webhooks.vue new file mode 100644 index 000000000..2beca9afc --- /dev/null +++ b/web-frontend/modules/database/pages/table/webhooks.vue @@ -0,0 +1,37 @@ +<template> + <div> + <WebhookModal + ref="webhookModal" + :database="database" + :table="table" + :fields="fields" + @hidden="$router.push({ name: 'database-table', params: $route.params })" + /> + </div> +</template> +<script> +import WebhookModal from '@baserow/modules/database/components/webhook/WebhookModal' + +export default { + components: { WebhookModal }, + props: { + database: { + type: Object, + required: true, + }, + table: { + type: Object, + required: true, + }, + fields: { + type: Array, + required: true, + }, + }, + mounted() { + this.$nextTick(() => { + this.$refs.webhookModal.show() + }) + }, +} +</script> diff --git a/web-frontend/modules/database/plugin.js b/web-frontend/modules/database/plugin.js index 81080b112..85709d98c 100644 --- a/web-frontend/modules/database/plugin.js +++ b/web-frontend/modules/database/plugin.js @@ -319,6 +319,7 @@ import { CollaboratorAddedToRowNotificationType, FormSubmittedNotificationType, UserMentionInRichTextFieldNotificationType, + WebhookDeactivatedNotificationType, } from '@baserow/modules/database/notificationTypes' import { HistoryRowModalSidebarType } from '@baserow/modules/database/rowModalSidebarTypes' import { FieldsDataProviderType } from '@baserow/modules/database/dataProviderTypes' @@ -1019,6 +1020,10 @@ export default (context) => { 'notification', new UserMentionInRichTextFieldNotificationType(context) ) + app.$registry.register( + 'notification', + new WebhookDeactivatedNotificationType(context) + ) app.$registry.register( 'rowModalSidebar', diff --git a/web-frontend/modules/database/routes.js b/web-frontend/modules/database/routes.js index f256948da..5d0364791 100644 --- a/web-frontend/modules/database/routes.js +++ b/web-frontend/modules/database/routes.js @@ -23,6 +23,11 @@ export const routes = [ path: 'row/:rowId', name: 'database-table-row', }, + { + path: 'webhooks', + name: 'database-table-open-webhooks', + component: path.resolve(__dirname, 'pages/table/webhooks.vue'), + }, ], }, // These redirect exist because the original api docs path was `/api/docs`, but diff --git a/web-frontend/test/helpers/components.js b/web-frontend/test/helpers/components.js index e5b8c6617..150f169f4 100644 --- a/web-frontend/test/helpers/components.js +++ b/web-frontend/test/helpers/components.js @@ -39,6 +39,7 @@ export const bootstrapVueContext = (configureContext) => { jest.isolateModules(() => { context.vueTestUtils = require('@vue/test-utils') context.vueTestUtils.config.stubs.nuxt = { template: '<div />' } + context.vueTestUtils.config.stubs.NuxtChild = { template: '<div />' } context.vueTestUtils.config.stubs['nuxt-link'] = { template: '<a><slot /></a>', }