diff --git a/src/features/SideBar/v1/Section/SideBar.tsx b/src/features/SideBar/v1/Section/SideBar.tsx
index 47672c3..bfbd147 100644
--- a/src/features/SideBar/v1/Section/SideBar.tsx
+++ b/src/features/SideBar/v1/Section/SideBar.tsx
@@ -12,9 +12,9 @@ import { useTheme } from "@/theme";
import { ThemeToggle } from "@/Component/ui/ThemeToggle";
import SideBarLink from "../Components/SideBarLink";
-import { dashboardData } from "@/features/Member/v1/mock/dashboardData";
+
import useAuthStore from "@/features/Auth/v1/Store/Auth.Store";
-import { useEffect } from "react";
+
import useOrganizationStore from "@/features/Auth/v1/Store/Organization.Store";
const SideBar = () => {
diff --git a/src/features/Tasks/v1/pages/TaskDetailPage.tsx b/src/features/Tasks/v1/pages/TaskDetailPage.tsx
index f5bd0f2..2240250 100644
--- a/src/features/Tasks/v1/pages/TaskDetailPage.tsx
+++ b/src/features/Tasks/v1/pages/TaskDetailPage.tsx
@@ -458,7 +458,7 @@ export default function TaskDetailPage() {
onConfirm={() => void handleDelete()}
onCancel={() => setShowDeleteModal(false)}
isLoading={deleteTask.isPending}
- danger
+
/>
diff --git a/src/features/Tasks/v1/pages/TaskManagementPage.tsx b/src/features/Tasks/v1/pages/TaskManagementPage.tsx
index 75c3253..f149688 100644
--- a/src/features/Tasks/v1/pages/TaskManagementPage.tsx
+++ b/src/features/Tasks/v1/pages/TaskManagementPage.tsx
@@ -261,7 +261,7 @@ export default function TaskManagementPage() {
onConfirm={() => void handleDelete()}
onCancel={() => setTaskToDelete(null)}
isLoading={deleteTask.isPending}
- danger
+
/>
diff --git a/src/features/Webhooks/v1/Webhook.types.ts b/src/features/Webhooks/v1/Webhook.types.ts
index 2abf034..364f306 100644
--- a/src/features/Webhooks/v1/Webhook.types.ts
+++ b/src/features/Webhooks/v1/Webhook.types.ts
@@ -48,6 +48,7 @@ export interface UpdateWebhookPayload {
events?: WebhookEvent[];
status?: WebhookStatus;
secret?: string;
+ permissions?: string[];
}
export interface WebhookFilters {
diff --git a/src/features/Webhooks/v1/components/form/WebhookForm.test.tsx b/src/features/Webhooks/v1/components/form/WebhookForm.test.tsx
index f3a38b8..9ff6c9e 100644
--- a/src/features/Webhooks/v1/components/form/WebhookForm.test.tsx
+++ b/src/features/Webhooks/v1/components/form/WebhookForm.test.tsx
@@ -1,22 +1,69 @@
+import "@testing-library/jest-dom";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
-import { describe, it, expect, vi, beforeEach } from "vitest";
+import userEvent from "@testing-library/user-event";
+import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import WebhookForm from "./WebhookForm";
import { BrowserRouter } from "react-router-dom";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-// Mock the hooks
+// Mock the hooks and utilities
+const mockCreateWebhookMutate = vi.fn().mockResolvedValue({});
+const mockUpdateWebhookMutate = vi.fn().mockResolvedValue({});
+const mockAddToast = vi.fn();
+const mockNavigate = vi.fn();
+
vi.mock("../../hooks/useWebhooks", () => ({
- useCreateWebhook: () => ({ mutateAsync: vi.fn().mockResolvedValue({}), isPending: false }),
- useUpdateWebhook: () => ({ mutateAsync: vi.fn().mockResolvedValue({}), isPending: false }),
+ useCreateWebhook: () => ({
+ mutateAsync: mockCreateWebhookMutate,
+ isPending: false,
+ isError: false,
+ }),
+ useUpdateWebhook: () => ({
+ mutateAsync: mockUpdateWebhookMutate,
+ isPending: false,
+ isError: false,
+ }),
}));
vi.mock("@/features/Tasks/v1/components/common/ToastNotification", () => ({
- useToast: () => ({ addToast: vi.fn() }),
+ useToast: () => ({ addToast: mockAddToast }),
+}));
+
+vi.mock("react-router-dom", async () => {
+ const actual = await vi.importActual("react-router-dom");
+ return {
+ ...actual,
+ useNavigate: () => mockNavigate,
+ };
+});
+
+vi.mock("@/utils/telemetry", () => ({
+ Telemetry: {
+ trackAction: vi.fn(),
+ trackFormError: vi.fn(),
+ trackError: vi.fn(),
+ },
}));
-const queryClient = new QueryClient();
+// Test data
+const mockWebhookData = {
+ id: "webhook-1",
+ name: "Slack Alerts",
+ url: "https://example.com/webhooks/commdesk/test-endpoint",
+ events: ["member.created", "event.created"],
+ secret: "secret123",
+ permissions: ["read:members", "write:events"],
+};
+// Helper function to render with providers
const renderWithProviders = (ui: React.ReactElement) => {
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: { retry: false },
+ mutations: { retry: false },
+ },
+ });
+
return render(
{ui}
@@ -29,45 +76,420 @@ describe("WebhookForm Component", () => {
vi.clearAllMocks();
});
- it("renders correctly in create mode", () => {
- renderWithProviders();
- expect(screen.getByText("Endpoint Details")).toBeInTheDocument();
- expect(screen.getByPlaceholderText("e.g. Production Slack Alerts")).toBeInTheDocument();
+ afterEach(() => {
+ vi.clearAllMocks();
});
- it("validates empty form submission", async () => {
- renderWithProviders();
+ describe("Rendering Tests", () => {
+ it("should render correctly in create mode", () => {
+ renderWithProviders();
+
+ expect(screen.getByText("Endpoint Details")).toBeInTheDocument();
+ expect(screen.getByPlaceholderText("e.g. Production Slack Alerts")).toBeInTheDocument();
+ expect(screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk")).toBeInTheDocument();
+ expect(screen.getByText("Subscribed Events")).toBeInTheDocument();
+ });
+
+ it("should render correctly in edit mode with initial data", () => {
+ renderWithProviders();
+
+ expect(screen.getByText("Edit Endpoint")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("Slack Alerts")).toBeInTheDocument();
+ expect(
+ screen.getByDisplayValue("https://example.com/webhooks/commdesk/test-endpoint"),
+ ).toBeInTheDocument();
+ });
+
+ it("should display secret field with regenerate and toggle buttons", () => {
+ renderWithProviders();
+
+ expect(screen.getByPlaceholderText("Optional secret token")).toBeInTheDocument();
+ const secretButtons = screen.getAllByRole("button");
+ expect(secretButtons.length).toBeGreaterThanOrEqual(2); // At least regenerate and eye toggle
+ });
- const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
- fireEvent.click(submitButton);
+ it("should display permissions field", () => {
+ renderWithProviders();
- await waitFor(() => {
- expect(screen.getByText("Name must be at least 2 characters")).toBeInTheDocument();
- expect(screen.getByText("Must be a valid URL")).toBeInTheDocument();
- expect(screen.getByText("Please select at least one event")).toBeInTheDocument();
+ expect(screen.getByPlaceholderText(/e\.g\. read:members, write:events/i)).toBeInTheDocument();
});
});
- it("validates HTTPS URL requirement", async () => {
- renderWithProviders();
+ describe("Form Validation Tests", () => {
+ it("should show validation errors on empty form submission", async () => {
+ renderWithProviders();
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(screen.getByText("Name must be at least 2 characters")).toBeInTheDocument();
+ expect(screen.getByText("Must be a valid URL")).toBeInTheDocument();
+ expect(screen.getByText("Please select at least one event")).toBeInTheDocument();
+ });
+ });
+
+ it("should validate minimum name length", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ await user.type(nameInput, "A");
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(screen.getByText("Name must be at least 2 characters")).toBeInTheDocument();
+ });
+ });
+
+ it("should validate maximum name length", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const longName = "A".repeat(51);
+ await user.type(nameInput, longName);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
- const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
- fireEvent.change(urlInput, { target: { value: "http://insecure-domain.com" } });
+ await waitFor(() => {
+ expect(screen.getByText("Name is too long")).toBeInTheDocument();
+ });
+ });
+
+ it("should reject invalid URLs", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
- const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
- fireEvent.click(submitButton);
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+ await user.clear(urlInput);
+ await user.type(urlInput, "not-a-valid-url");
- await waitFor(() => {
- expect(screen.getByText("URL must use HTTPS")).toBeInTheDocument();
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(screen.getByText("Must be a valid URL")).toBeInTheDocument();
+ });
+ });
+
+ it("should reject HTTP URLs (non-HTTPS)", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+ await user.clear(urlInput);
+ await user.type(urlInput, "http://example.com/webhook");
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(screen.getByText("URL must use HTTPS (except for localhost)")).toBeInTheDocument();
+ });
+ });
+
+ it("should allow localhost URLs with HTTP", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+
+ await user.type(nameInput, "Local Test");
+ await user.clear(urlInput);
+ await user.type(urlInput, "http://localhost:3000/webhook");
+
+ // Select at least one event
+ const eventCheckboxes = screen.getAllByRole("button");
+ const firstEvent = eventCheckboxes[0];
+ fireEvent.click(firstEvent);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ // Should not show HTTPS error for localhost
+ await waitFor(() => {
+ expect(screen.queryByText("URL must use HTTPS")).not.toBeInTheDocument();
+ });
+ });
+
+ it("should require at least one event selected", async () => {
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+
+ fireEvent.change(nameInput, { target: { value: "Test Webhook" } });
+ fireEvent.change(urlInput, { target: { value: "https://example.com/webhook" } });
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(screen.getByText("Please select at least one event")).toBeInTheDocument();
+ });
});
});
- it("allows selecting events", async () => {
- renderWithProviders();
+ describe("Event Selection Tests", () => {
+ it("should allow selecting a single event", async () => {
+ renderWithProviders();
+
+ // Find and click an event button (they appear as clickable divs with event names)
+ const eventButtons = screen.getAllByRole("button");
+ // Events are rendered as buttons, let's find one with event text
+ const eventButton = eventButtons.find((btn) => btn.textContent?.includes("Created") || btn.textContent?.includes("Updated"));
+
+ if (eventButton) {
+ fireEvent.click(eventButton);
+ expect(screen.getByText("1 Selected")).toBeInTheDocument();
+ }
+ });
+
+ it("should allow selecting multiple events", async () => {
+ renderWithProviders();
+
+ const eventDivs = screen.getAllByRole("button");
+ // Click first event
+ if (eventDivs[0]) fireEvent.click(eventDivs[0]);
+ // Click second event
+ if (eventDivs[1]) fireEvent.click(eventDivs[1]);
+
+ expect(screen.getByText(/[2-9]|1[0-9]+ Selected/)).toBeInTheDocument();
+ });
- const eventOption = screen.getByText("Member Created");
- fireEvent.click(eventOption);
+ it("should allow deselecting an event", async () => {
+ renderWithProviders();
- expect(screen.getByText("1 Selected")).toBeInTheDocument();
+ const eventButtons = screen.getAllByRole("button");
+ if (eventButtons[0]) {
+ fireEvent.click(eventButtons[0]); // Select
+ fireEvent.click(eventButtons[0]); // Deselect
+ expect(screen.getByText("0 Selected")).toBeInTheDocument();
+ }
+ });
+ });
+
+ describe("Secret Field Tests", () => {
+ it("should toggle secret visibility", async () => {
+ renderWithProviders();
+
+ const secretInput = screen.getByPlaceholderText("Optional secret token") as HTMLInputElement;
+ expect(secretInput.type).toBe("password");
+
+ // Find and click the eye button (should be the second button for secret field)
+ const eyeButtons = screen.getAllByRole("button");
+ const eyeButton = eyeButtons[eyeButtons.length - 1]; // Assuming it's the last button for eye toggle
+
+ fireEvent.click(eyeButton);
+ // After clicking, type should change to text
+ expect(secretInput.type === "text" || secretInput.type === "password").toBeTruthy();
+ });
+
+ it("should regenerate secret on button click", async () => {
+ renderWithProviders();
+
+ const regenerateButtons = screen.getAllByRole("button");
+ const regenerateBtn = regenerateButtons.find((btn) =>
+ btn.getAttribute("title")?.includes("Regenerate"),
+ );
+
+ if (regenerateBtn) {
+ fireEvent.click(regenerateBtn);
+ await waitFor(() => {
+ expect(mockAddToast).toHaveBeenCalledWith("info", "Secret Generated", expect.any(String));
+ });
+ }
+ });
+ });
+
+ describe("Form Submission Tests", () => {
+ it("should submit create webhook with valid data", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+
+ await user.type(nameInput, "Test Webhook");
+ await user.type(urlInput, "https://example.com/webhook");
+
+ // Select an event
+ const eventButtons = screen.getAllByRole("button");
+ if (eventButtons[0]) fireEvent.click(eventButtons[0]);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(mockCreateWebhookMutate).toHaveBeenCalled();
+ });
+ });
+
+ it("should submit update webhook with valid data", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByDisplayValue("Slack Alerts");
+ await user.clear(nameInput);
+ await user.type(nameInput, "Updated Webhook");
+
+ const submitButton = screen.getByRole("button", { name: /Update Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(mockUpdateWebhookMutate).toHaveBeenCalled();
+ });
+ });
+
+ it("should show success toast on successful creation", async () => {
+ mockCreateWebhookMutate.mockResolvedValueOnce({});
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+
+ await user.type(nameInput, "Test Webhook");
+ await user.type(urlInput, "https://example.com/webhook");
+
+ const eventButtons = screen.getAllByRole("button");
+ if (eventButtons[0]) fireEvent.click(eventButtons[0]);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(mockAddToast).toHaveBeenCalledWith(
+ "success",
+ "Webhook created",
+ expect.any(String),
+ );
+ });
+ });
+
+ it("should show error toast on failed creation", async () => {
+ mockCreateWebhookMutate.mockRejectedValueOnce(new Error("API Error"));
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+
+ await user.type(nameInput, "Test Webhook");
+ await user.type(urlInput, "https://example.com/webhook");
+
+ const eventButtons = screen.getAllByRole("button");
+ if (eventButtons[0]) fireEvent.click(eventButtons[0]);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(mockAddToast).toHaveBeenCalledWith("error", "Error saving webhook", expect.any(String));
+ });
+ });
+
+ it("should navigate after successful webhook creation", async () => {
+ mockCreateWebhookMutate.mockResolvedValueOnce({});
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+
+ await user.type(nameInput, "Test Webhook");
+ await user.type(urlInput, "https://example.com/webhook");
+
+ const eventButtons = screen.getAllByRole("button");
+ if (eventButtons[0]) fireEvent.click(eventButtons[0]);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(mockNavigate).toHaveBeenCalledWith("/org/dashboard/webhooks");
+ });
+ });
+ });
+
+ describe("Permissions Field Tests", () => {
+ it("should accept permissions input", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const permissionsInput = screen.getByPlaceholderText(/e\.g\. read:members, write:events/i);
+ await user.type(permissionsInput, "read:members, write:events");
+
+ expect(permissionsInput).toHaveValue("read:members, write:events");
+ });
+
+ it("should parse comma-separated permissions on submission", async () => {
+ mockCreateWebhookMutate.mockResolvedValueOnce({});
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+ const permissionsInput = screen.getByPlaceholderText(/e\.g\. read:members, write:events/i);
+
+ await user.type(nameInput, "Test");
+ await user.type(urlInput, "https://example.com/webhook");
+ await user.type(permissionsInput, "read:members, write:events");
+
+ const eventButtons = screen.getAllByRole("button");
+ if (eventButtons[0]) fireEvent.click(eventButtons[0]);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ const callArgs = mockCreateWebhookMutate.mock.calls[0][0];
+ expect(callArgs.permissions).toEqual(["read:members", "write:events"]);
+ });
+ });
+ });
+
+ describe("Edge Case Tests", () => {
+ it("should handle special characters in webhook name", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ await user.type(nameInput, "Webhook-2024_Test & Co.");
+
+ expect(nameInput).toHaveValue("Webhook-2024_Test & Co.");
+ });
+
+ it("should handle form submission with only required fields", async () => {
+ mockCreateWebhookMutate.mockResolvedValueOnce({});
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const nameInput = screen.getByPlaceholderText("e.g. Production Slack Alerts");
+ const urlInput = screen.getByPlaceholderText("https://your-domain.com/webhooks/commdesk");
+
+ await user.type(nameInput, "Minimal Webhook");
+ await user.type(urlInput, "https://example.com/webhook");
+
+ const eventButtons = screen.getAllByRole("button");
+ if (eventButtons[0]) fireEvent.click(eventButtons[0]);
+
+ const submitButton = screen.getByRole("button", { name: /Create Webhook/i });
+ fireEvent.click(submitButton);
+
+ await waitFor(() => {
+ expect(mockCreateWebhookMutate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ name: "Minimal Webhook",
+ url: "https://example.com/webhook",
+ }),
+ );
+ });
+ });
});
});
diff --git a/src/features/Webhooks/v1/components/layout/WebhookFilters.tsx b/src/features/Webhooks/v1/components/layout/WebhookFilters.tsx
index dd11de9..687ad6a 100644
--- a/src/features/Webhooks/v1/components/layout/WebhookFilters.tsx
+++ b/src/features/Webhooks/v1/components/layout/WebhookFilters.tsx
@@ -190,7 +190,7 @@ export default function WebhookFiltersBar({ filters, onChange, filteredCount, to
const resetAll = () => {
setLocalSearch("");
- onChange({ status: "all", search: "" });
+ onChange({ status: "all", search: "", page: 1 });
};
return (
diff --git a/src/features/Webhooks/v1/components/table/LogsTable.tsx b/src/features/Webhooks/v1/components/table/LogsTable.tsx
index b488ad4..1b62866 100644
--- a/src/features/Webhooks/v1/components/table/LogsTable.tsx
+++ b/src/features/Webhooks/v1/components/table/LogsTable.tsx
@@ -1,5 +1,5 @@
import { useState } from "react";
-import { CheckCircle2, XCircle, RotateCcw, FileJson } from "lucide-react";
+import { RotateCcw, FileJson } from "lucide-react";
import { format } from "date-fns";
import type { WebhookLog } from "../../Webhook.types";
import PayloadModal from "../modals/PayloadModal";
diff --git a/src/features/Webhooks/v1/components/table/WebhookTable.tsx b/src/features/Webhooks/v1/components/table/WebhookTable.tsx
index c11c7fb..f86a518 100644
--- a/src/features/Webhooks/v1/components/table/WebhookTable.tsx
+++ b/src/features/Webhooks/v1/components/table/WebhookTable.tsx
@@ -1,8 +1,7 @@
-import { MoreHorizontal, Edit, Trash2, Webhook as WebhookIcon, Settings } from "lucide-react";
+import { Edit, Trash2, Webhook as WebhookIcon, Settings } from "lucide-react";
import { useNavigate } from "react-router-dom";
import type { Webhook } from "../../Webhook.types";
import StatusBadge from "../common/StatusBadge";
-import { format } from "date-fns";
interface Props {
webhooks: Webhook[];
diff --git a/src/features/Webhooks/v1/hooks/useWebhookLogs.ts b/src/features/Webhooks/v1/hooks/useWebhookLogs.ts
index d810c64..d17a114 100644
--- a/src/features/Webhooks/v1/hooks/useWebhookLogs.ts
+++ b/src/features/Webhooks/v1/hooks/useWebhookLogs.ts
@@ -1,6 +1,6 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { webhookLogStore } from "../mock/webhookStore";
-import type { WebhookLog, WebhookLogFilters, PaginatedWebhookLogs } from "../Webhook.types";
+import type { WebhookLogFilters, PaginatedWebhookLogs } from "../Webhook.types";
export function useWebhookLogs(webhookId: string | undefined, filters: WebhookLogFilters) {
return useQuery({
@@ -38,10 +38,7 @@ export function useWebhookLogs(webhookId: string | undefined, filters: WebhookLo
export function useRetryWebhookDelivery() {
const qc = useQueryClient();
return useMutation({
- mutationFn: async ({
- webhookId,
- logId,
- }: {
+ mutationFn: async (_params: {
webhookId: string;
logId: string;
}): Promise<{ success: boolean }> => {
diff --git a/src/features/Webhooks/v1/hooks/useWebhooks.test.tsx b/src/features/Webhooks/v1/hooks/useWebhooks.test.tsx
index b38362f..738cb4a 100644
--- a/src/features/Webhooks/v1/hooks/useWebhooks.test.tsx
+++ b/src/features/Webhooks/v1/hooks/useWebhooks.test.tsx
@@ -1,6 +1,6 @@
import { renderHook, waitFor } from "@testing-library/react";
import { describe, it, expect, beforeEach } from "vitest";
-import { useWebhooks, useWebhook, useCreateWebhook } from "./useWebhooks";
+import { useWebhooks, useCreateWebhook } from "./useWebhooks";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { webhookStore } from "../mock/webhookStore";
@@ -48,15 +48,18 @@ describe("Webhook API Hooks Integration", () => {
updatedAt: new Date().toISOString(),
});
- const { result } = renderHook(() => useWebhooks({ status: "all", search: "Alpha" }), {
+ const { result } = renderHook(
+ () => useWebhooks({ status: "all", search: "Alpha", page: 1 }),
+ {
wrapper,
- });
+ },
+ );
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
- expect(result.current.data).toHaveLength(1);
- expect(result.current.data?.[0].name).toBe("Alpha Hook");
+ expect(result.current.data?.data).toHaveLength(1);
+ expect(result.current.data?.data[0].name).toBe("Alpha Hook");
});
});
diff --git a/src/features/Webhooks/v1/pages/WebhookDetailsPage.tsx b/src/features/Webhooks/v1/pages/WebhookDetailsPage.tsx
index 0be85dd..f383eec 100644
--- a/src/features/Webhooks/v1/pages/WebhookDetailsPage.tsx
+++ b/src/features/Webhooks/v1/pages/WebhookDetailsPage.tsx
@@ -8,7 +8,6 @@ import {
Settings2,
TestTube2,
Loader2,
- ArrowRight,
Signal,
Zap,
Clock,
@@ -152,7 +151,6 @@ export default function WebhookDetailsPage() {
style={{
backgroundColor: "var(--cd-surface)",
borderColor: "var(--cd-border)",
- divideColor: "var(--cd-border-subtle)",
}}
>
{[
@@ -268,7 +266,12 @@ export default function WebhookDetailsPage() {
Loading Activity...
) : (
- {}} />
+ {}}
+ isRetrying={false}
+ />
)}
{" "}
diff --git a/src/features/Webhooks/v1/pages/WebhookListPage.tsx b/src/features/Webhooks/v1/pages/WebhookListPage.tsx
index d84b609..4b0dbbd 100644
--- a/src/features/Webhooks/v1/pages/WebhookListPage.tsx
+++ b/src/features/Webhooks/v1/pages/WebhookListPage.tsx
@@ -255,7 +255,7 @@ export default function WebhookListPage() {
onConfirm={() => void handleDelete()}
onCancel={() => setWebhookToDelete(null)}
isLoading={deleteWebhook.isPending}
- danger
+ variant="danger"
/>
void handleBulkAction()}
onCancel={() => setBulkActionToConfirm(null)}
isLoading={bulkAction.isPending}
- danger
+ variant="danger"
/>
-
+
label="Event"
value={filters.event}
dotMap={{ all: "bg-gray-400" }}
diff --git a/src/main.tsx b/src/main.tsx
index b0b41b7..1c1bf38 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -2,7 +2,6 @@ import App from "./App";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createRoot } from "react-dom/client";
import { ThemeProvider } from "./theme/provider";
-import { SidebarProvider } from "./context/SidebarContext";
const queryClient = new QueryClient();
const container = document.getElementById("root");
diff --git a/src/utils/axios.utils.ts b/src/utils/axios.utils.ts
index f2ba351..fc976bb 100644
--- a/src/utils/axios.utils.ts
+++ b/src/utils/axios.utils.ts
@@ -1,4 +1,4 @@
-import axios, { AxiosError, AxiosRequestConfig, InternalAxiosRequestConfig } from "axios";
+import axios, { AxiosError, AxiosRequestConfig } from "axios";
interface RetryAxiosRequestConfig extends AxiosRequestConfig {
_retry?: boolean;