diff --git a/client/src/actions/core.js b/client/src/actions/core.js
index 8f87fe82..aebc9174 100644
--- a/client/src/actions/core.js
+++ b/client/src/actions/core.js
@@ -8,6 +8,7 @@ import ActionTypes from '../constants/ActionTypes';
const initializeCore = (
user,
board,
+ webhooks,
users,
projects,
projectManagers,
@@ -33,6 +34,7 @@ const initializeCore = (
payload: {
user,
board,
+ webhooks,
users,
projects,
projectManagers,
diff --git a/client/src/actions/index.js b/client/src/actions/index.js
index 626d23c6..46a254a1 100644
--- a/client/src/actions/index.js
+++ b/client/src/actions/index.js
@@ -8,6 +8,7 @@ import socket from './socket';
import login from './login';
import core from './core';
import modals from './modals';
+import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@@ -35,6 +36,7 @@ export default {
...login,
...core,
...modals,
+ ...webhooks,
...users,
...projects,
...projectManagers,
diff --git a/client/src/actions/socket.js b/client/src/actions/socket.js
index 65881221..8e6f07f4 100644
--- a/client/src/actions/socket.js
+++ b/client/src/actions/socket.js
@@ -14,6 +14,7 @@ const handleSocketReconnect = (
config,
user,
board,
+ webhooks,
users,
projects,
projectManagers,
@@ -40,6 +41,7 @@ const handleSocketReconnect = (
config,
user,
board,
+ webhooks,
users,
projects,
projectManagers,
diff --git a/client/src/actions/users.js b/client/src/actions/users.js
index bdf00bde..101d65c6 100644
--- a/client/src/actions/users.js
+++ b/client/src/actions/users.js
@@ -67,6 +67,7 @@ const handleUserUpdate = (
boardIds,
config,
board,
+ webhooks,
users,
projects,
projectManagers,
@@ -95,6 +96,7 @@ const handleUserUpdate = (
boardIds,
config,
board,
+ webhooks,
users,
projects,
projectManagers,
diff --git a/client/src/actions/webhooks.js b/client/src/actions/webhooks.js
new file mode 100644
index 00000000..41e35dbe
--- /dev/null
+++ b/client/src/actions/webhooks.js
@@ -0,0 +1,104 @@
+/*!
+ * Copyright (c) 2024 PLANKA Software GmbH
+ * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
+ */
+
+import ActionTypes from '../constants/ActionTypes';
+
+const createWebhook = (webhook) => ({
+ type: ActionTypes.WEBHOOK_CREATE,
+ payload: {
+ webhook,
+ },
+});
+
+createWebhook.success = (localId, webhook) => ({
+ type: ActionTypes.WEBHOOK_CREATE__SUCCESS,
+ payload: {
+ localId,
+ webhook,
+ },
+});
+
+createWebhook.failure = (localId, error) => ({
+ type: ActionTypes.WEBHOOK_CREATE__FAILURE,
+ payload: {
+ localId,
+ error,
+ },
+});
+
+const handleWebhookCreate = (webhook) => ({
+ type: ActionTypes.WEBHOOK_CREATE_HANDLE,
+ payload: {
+ webhook,
+ },
+});
+
+const updateWebhook = (id, data) => ({
+ type: ActionTypes.WEBHOOK_UPDATE,
+ payload: {
+ id,
+ data,
+ },
+});
+
+updateWebhook.success = (webhook) => ({
+ type: ActionTypes.WEBHOOK_UPDATE__SUCCESS,
+ payload: {
+ webhook,
+ },
+});
+
+updateWebhook.failure = (id, error) => ({
+ type: ActionTypes.WEBHOOK_UPDATE__FAILURE,
+ payload: {
+ id,
+ error,
+ },
+});
+
+const handleWebhookUpdate = (webhook) => ({
+ type: ActionTypes.WEBHOOK_UPDATE_HANDLE,
+ payload: {
+ webhook,
+ },
+});
+
+const deleteWebhook = (id) => ({
+ type: ActionTypes.WEBHOOK_DELETE,
+ payload: {
+ id,
+ },
+});
+
+deleteWebhook.success = (webhook) => ({
+ type: ActionTypes.WEBHOOK_DELETE__SUCCESS,
+ payload: {
+ webhook,
+ },
+});
+
+deleteWebhook.failure = (id, error) => ({
+ type: ActionTypes.WEBHOOK_DELETE__FAILURE,
+ payload: {
+ id,
+ error,
+ },
+});
+
+const handleWebhookDelete = (webhook) => ({
+ type: ActionTypes.WEBHOOK_DELETE_HANDLE,
+ payload: {
+ webhook,
+ },
+});
+
+export default {
+ createWebhook,
+ handleWebhookCreate,
+ updateWebhook,
+ handleWebhookUpdate,
+ deleteWebhook,
+ handleWebhookDelete,
+};
diff --git a/client/src/api/index.js b/client/src/api/index.js
index ca98d773..70a1bb4c 100755
--- a/client/src/api/index.js
+++ b/client/src/api/index.js
@@ -7,6 +7,7 @@ import http from './http';
import socket from './socket';
import config from './config';
import accessTokens from './access-tokens';
+import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@@ -35,6 +36,7 @@ export { http, socket };
export default {
...config,
...accessTokens,
+ ...webhooks,
...users,
...projects,
...projectManagers,
diff --git a/client/src/api/webhooks.js b/client/src/api/webhooks.js
new file mode 100755
index 00000000..ae29ba06
--- /dev/null
+++ b/client/src/api/webhooks.js
@@ -0,0 +1,23 @@
+/*!
+ * Copyright (c) 2024 PLANKA Software GmbH
+ * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
+ */
+
+import socket from './socket';
+
+/* Actions */
+
+const getWebhooks = (headers) => socket.get('/webhooks', undefined, headers);
+
+const createWebhook = (data, headers) => socket.post('/webhooks', data, headers);
+
+const updateWebhook = (id, data, headers) => socket.patch(`/webhooks/${id}`, data, headers);
+
+const deleteWebhook = (id, headers) => socket.delete(`/webhooks/${id}`, undefined, headers);
+
+export default {
+ getWebhooks,
+ createWebhook,
+ updateWebhook,
+ deleteWebhook,
+};
diff --git a/client/src/components/common/AdministrationModal/AdministrationModal.jsx b/client/src/components/common/AdministrationModal/AdministrationModal.jsx
index 8dbdcc94..d79d22ec 100644
--- a/client/src/components/common/AdministrationModal/AdministrationModal.jsx
+++ b/client/src/components/common/AdministrationModal/AdministrationModal.jsx
@@ -12,6 +12,7 @@ import { Modal, Tab } from 'semantic-ui-react';
import entryActions from '../../../entry-actions';
import { useClosableModal } from '../../../hooks';
import UsersPane from './UsersPane';
+import WebhooksPane from './WebhooksPane';
import styles from './AdministrationModal.module.scss';
@@ -37,6 +38,12 @@ const AdministrationModal = React.memo(() => {
}),
render: () =>