@invect/webhooks 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -0
- package/dist/backend/index.cjs +12 -3
- package/dist/backend/index.cjs.map +1 -1
- package/dist/backend/index.d.cts +115 -0
- package/dist/backend/index.d.cts.map +1 -0
- package/dist/backend/index.d.mts +115 -0
- package/dist/backend/index.d.mts.map +1 -0
- package/dist/backend/index.d.ts +1 -1
- package/dist/backend/index.d.ts.map +1 -1
- package/dist/backend/index.mjs +12 -3
- package/dist/backend/index.mjs.map +1 -1
- package/dist/backend/plugin.d.ts +9 -2
- package/dist/backend/plugin.d.ts.map +1 -1
- package/dist/backend/webhook-dedup.service.d.ts.map +1 -1
- package/dist/backend/webhook-signature.service.d.ts.map +1 -1
- package/dist/frontend/components/CreateWebhookModal.d.ts.map +1 -1
- package/dist/frontend/components/WebhookDetailPanel.d.ts.map +1 -1
- package/dist/frontend/components/WebhooksPage.d.ts.map +1 -1
- package/dist/frontend/hooks/useWebhookQueries.d.ts +1 -1
- package/dist/frontend/hooks/useWebhookQueries.d.ts.map +1 -1
- package/dist/frontend/index.cjs +46 -46
- package/dist/frontend/index.cjs.map +1 -1
- package/dist/frontend/index.d.cts +70 -0
- package/dist/frontend/index.d.cts.map +1 -0
- package/dist/frontend/index.d.mts +70 -0
- package/dist/frontend/index.d.mts.map +1 -0
- package/dist/frontend/index.d.ts +2 -2
- package/dist/frontend/index.d.ts.map +1 -1
- package/dist/frontend/index.mjs +28 -28
- package/dist/frontend/index.mjs.map +1 -1
- package/dist/frontend/plugins/webhooksFrontendPlugin.d.ts +2 -2
- package/dist/frontend/plugins/webhooksFrontendPlugin.d.ts.map +1 -1
- package/dist/shared/types.d.cts +2 -0
- package/dist/shared/types.d.mts +2 -0
- package/dist/types-cBOT0AqR.d.cts +83 -0
- package/dist/types-cBOT0AqR.d.cts.map +1 -0
- package/dist/types-zH7xu7mA.d.mts +83 -0
- package/dist/types-zH7xu7mA.d.mts.map +1 -0
- package/package.json +49 -50
package/dist/frontend/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Check, ChevronDown, ChevronRight, Clock, Copy, ExternalLink, Eye, EyeOff, Globe, Hash, Loader2, Plus, Search, ToggleLeft, ToggleRight, Trash2, Workflow } from "lucide-react";
|
|
2
2
|
import { useRef, useState } from "react";
|
|
3
|
-
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, PageLayout, useApiBaseURL, useFlows } from "@invect/
|
|
3
|
+
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, PageLayout, useApiBaseURL, useFlows } from "@invect/ui";
|
|
4
4
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/frontend/hooks/useWebhookQueries.ts
|
|
7
7
|
/**
|
|
8
8
|
* React hooks for the webhooks plugin API.
|
|
9
9
|
*
|
|
10
|
-
* Uses @invect/
|
|
10
|
+
* Uses @invect/ui's ApiContext for the base URL.
|
|
11
11
|
*/
|
|
12
12
|
async function apiFetch(baseUrl, path, init) {
|
|
13
13
|
const res = await fetch(`${baseUrl}${path}`, {
|
|
@@ -466,7 +466,7 @@ const WebhookDetailPanel = ({ trigger, flowName, onClose }) => {
|
|
|
466
466
|
})]
|
|
467
467
|
})]
|
|
468
468
|
}) }), /* @__PURE__ */ jsx("div", {
|
|
469
|
-
className: "flex gap-1
|
|
469
|
+
className: "flex gap-1 px-6 mt-4 -mx-6 border-b",
|
|
470
470
|
children: [{
|
|
471
471
|
key: "overview",
|
|
472
472
|
label: "Overview"
|
|
@@ -480,7 +480,7 @@ const WebhookDetailPanel = ({ trigger, flowName, onClose }) => {
|
|
|
480
480
|
}, key))
|
|
481
481
|
})]
|
|
482
482
|
}), /* @__PURE__ */ jsx("div", {
|
|
483
|
-
className: "flex-1
|
|
483
|
+
className: "flex-1 px-6 pb-6 overflow-y-auto",
|
|
484
484
|
children: section === "overview" ? /* @__PURE__ */ jsx(OverviewSection, {
|
|
485
485
|
trigger,
|
|
486
486
|
flowName,
|
|
@@ -500,24 +500,24 @@ const OverviewSection = ({ trigger, flowName, onToggleEnabled, onDelete, isToggl
|
|
|
500
500
|
/* @__PURE__ */ jsxs("div", {
|
|
501
501
|
className: "space-y-1",
|
|
502
502
|
children: [/* @__PURE__ */ jsx("label", {
|
|
503
|
-
className: "text-xs font-medium text-muted-foreground
|
|
503
|
+
className: "text-xs font-medium tracking-wide uppercase text-muted-foreground",
|
|
504
504
|
children: "Webhook URL"
|
|
505
505
|
}), /* @__PURE__ */ jsx(CopyableField, { value: `/plugins/webhooks/receive/${trigger.webhookPath}` })]
|
|
506
506
|
}),
|
|
507
507
|
trigger.hmacEnabled && trigger.hmacHeaderName && /* @__PURE__ */ jsxs("div", {
|
|
508
508
|
className: "space-y-1",
|
|
509
509
|
children: [/* @__PURE__ */ jsx("label", {
|
|
510
|
-
className: "text-xs font-medium text-muted-foreground
|
|
510
|
+
className: "text-xs font-medium tracking-wide uppercase text-muted-foreground",
|
|
511
511
|
children: "HMAC Authentication"
|
|
512
512
|
}), /* @__PURE__ */ jsxs("div", {
|
|
513
|
-
className: "rounded-lg
|
|
513
|
+
className: "p-3 space-y-1 border rounded-lg bg-muted/30",
|
|
514
514
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
515
515
|
className: "flex items-center justify-between",
|
|
516
516
|
children: [/* @__PURE__ */ jsx("span", {
|
|
517
517
|
className: "text-xs text-muted-foreground",
|
|
518
518
|
children: "Signature Header"
|
|
519
519
|
}), /* @__PURE__ */ jsx("span", {
|
|
520
|
-
className: "text-sm
|
|
520
|
+
className: "font-mono text-sm",
|
|
521
521
|
children: trigger.hmacHeaderName
|
|
522
522
|
})]
|
|
523
523
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -535,12 +535,12 @@ const OverviewSection = ({ trigger, flowName, onToggleEnabled, onDelete, isToggl
|
|
|
535
535
|
trigger.allowedIps && /* @__PURE__ */ jsxs("div", {
|
|
536
536
|
className: "space-y-1",
|
|
537
537
|
children: [/* @__PURE__ */ jsx("label", {
|
|
538
|
-
className: "text-xs font-medium text-muted-foreground
|
|
538
|
+
className: "text-xs font-medium tracking-wide uppercase text-muted-foreground",
|
|
539
539
|
children: "IP Whitelist"
|
|
540
540
|
}), /* @__PURE__ */ jsx("div", {
|
|
541
|
-
className: "rounded-lg
|
|
541
|
+
className: "p-3 border rounded-lg bg-muted/30",
|
|
542
542
|
children: /* @__PURE__ */ jsx("span", {
|
|
543
|
-
className: "text-sm
|
|
543
|
+
className: "font-mono text-sm break-all",
|
|
544
544
|
children: trigger.allowedIps
|
|
545
545
|
})
|
|
546
546
|
})]
|
|
@@ -549,21 +549,21 @@ const OverviewSection = ({ trigger, flowName, onToggleEnabled, onDelete, isToggl
|
|
|
549
549
|
className: "grid grid-cols-2 gap-4 py-2",
|
|
550
550
|
children: [
|
|
551
551
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
|
|
552
|
-
className: "text-xs text-muted-foreground
|
|
552
|
+
className: "block mb-1 text-xs text-muted-foreground",
|
|
553
553
|
children: "Methods"
|
|
554
554
|
}), /* @__PURE__ */ jsx("span", {
|
|
555
|
-
className: "text-sm
|
|
555
|
+
className: "font-mono text-sm",
|
|
556
556
|
children: trigger.allowedMethods
|
|
557
557
|
})] }),
|
|
558
558
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
|
|
559
|
-
className: "text-xs text-muted-foreground
|
|
559
|
+
className: "block mb-1 text-xs text-muted-foreground",
|
|
560
560
|
children: "Authentication"
|
|
561
561
|
}), /* @__PURE__ */ jsx("span", {
|
|
562
562
|
className: "text-sm",
|
|
563
563
|
children: getAuthModeConfig$1(trigger).label
|
|
564
564
|
})] }),
|
|
565
565
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
|
|
566
|
-
className: "text-xs text-muted-foreground
|
|
566
|
+
className: "block mb-1 text-xs text-muted-foreground",
|
|
567
567
|
children: "Created"
|
|
568
568
|
}), /* @__PURE__ */ jsx("span", {
|
|
569
569
|
className: "text-sm",
|
|
@@ -600,29 +600,29 @@ const OverviewSection = ({ trigger, flowName, onToggleEnabled, onDelete, isToggl
|
|
|
600
600
|
]
|
|
601
601
|
}),
|
|
602
602
|
trigger.flowId && /* @__PURE__ */ jsx("div", {
|
|
603
|
-
className: "rounded-lg
|
|
603
|
+
className: "p-3 border rounded-lg bg-muted/30",
|
|
604
604
|
children: /* @__PURE__ */ jsxs("div", {
|
|
605
605
|
className: "flex items-center gap-2",
|
|
606
606
|
children: [/* @__PURE__ */ jsx(Workflow, { className: "w-4 h-4 text-muted-foreground shrink-0" }), /* @__PURE__ */ jsxs("div", {
|
|
607
607
|
className: "flex-1 min-w-0",
|
|
608
608
|
children: [/* @__PURE__ */ jsx("span", {
|
|
609
|
-
className: "text-xs text-muted-foreground
|
|
609
|
+
className: "block text-xs text-muted-foreground",
|
|
610
610
|
children: "Linked Flow"
|
|
611
611
|
}), /* @__PURE__ */ jsxs("a", {
|
|
612
612
|
href: `/invect/flow/${trigger.flowId}`,
|
|
613
|
-
className: "text-sm font-medium text-primary hover:underline
|
|
613
|
+
className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
|
|
614
614
|
children: [flowName ?? trigger.flowId, /* @__PURE__ */ jsx(ExternalLink, { className: "w-3 h-3" })]
|
|
615
615
|
})]
|
|
616
616
|
})]
|
|
617
617
|
})
|
|
618
618
|
}),
|
|
619
|
-
trigger.lastPayload
|
|
619
|
+
trigger.lastPayload !== null && trigger.lastPayload !== void 0 && /* @__PURE__ */ jsxs("div", {
|
|
620
620
|
className: "space-y-1",
|
|
621
621
|
children: [/* @__PURE__ */ jsx("label", {
|
|
622
|
-
className: "text-xs font-medium text-muted-foreground
|
|
622
|
+
className: "text-xs font-medium tracking-wide uppercase text-muted-foreground",
|
|
623
623
|
children: "Last Payload"
|
|
624
624
|
}), /* @__PURE__ */ jsx("pre", {
|
|
625
|
-
className: "
|
|
625
|
+
className: "p-3 overflow-auto font-mono text-xs rounded-lg bg-muted max-h-32",
|
|
626
626
|
children: JSON.stringify(trigger.lastPayload, null, 2)
|
|
627
627
|
})]
|
|
628
628
|
}),
|
|
@@ -636,7 +636,7 @@ const OverviewSection = ({ trigger, flowName, onToggleEnabled, onDelete, isToggl
|
|
|
636
636
|
}), /* @__PURE__ */ jsxs("button", {
|
|
637
637
|
onClick: onDelete,
|
|
638
638
|
disabled: isDeleting,
|
|
639
|
-
className: "inline-flex items-center gap-2
|
|
639
|
+
className: "inline-flex items-center h-8 gap-2 px-3 text-sm font-medium text-imp-destructive transition-colors border border-imp-destructive/30 rounded-md hover:bg-imp-destructive/10",
|
|
640
640
|
children: [isDeleting ? /* @__PURE__ */ jsx(Loader2, { className: "w-3.5 h-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Trash2, { className: "w-3.5 h-3.5" }), "Delete"]
|
|
641
641
|
})]
|
|
642
642
|
})
|
|
@@ -701,7 +701,7 @@ const EditSection = ({ trigger, onSuccess }) => {
|
|
|
701
701
|
})]
|
|
702
702
|
}),
|
|
703
703
|
/* @__PURE__ */ jsxs("div", {
|
|
704
|
-
className: "space-y-3 rounded-lg border
|
|
704
|
+
className: "p-3 space-y-3 border rounded-lg border-border bg-muted/30",
|
|
705
705
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
706
706
|
className: "flex items-center justify-between",
|
|
707
707
|
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
@@ -717,7 +717,7 @@ const EditSection = ({ trigger, onSuccess }) => {
|
|
|
717
717
|
children: /* @__PURE__ */ jsx("span", { className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${hmacEnabled ? "translate-x-4" : "translate-x-0"}` })
|
|
718
718
|
})]
|
|
719
719
|
}), hmacEnabled && /* @__PURE__ */ jsxs("div", {
|
|
720
|
-
className: "space-y-3
|
|
720
|
+
className: "pt-1 space-y-3",
|
|
721
721
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
722
722
|
className: "space-y-1.5",
|
|
723
723
|
children: [/* @__PURE__ */ jsx("label", {
|
|
@@ -807,12 +807,12 @@ const EditSection = ({ trigger, onSuccess }) => {
|
|
|
807
807
|
children: [/* @__PURE__ */ jsx("button", {
|
|
808
808
|
type: "button",
|
|
809
809
|
onClick: onSuccess,
|
|
810
|
-
className: "inline-flex items-center justify-center
|
|
810
|
+
className: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-colors border rounded-md shadow-xs bg-background hover:bg-accent",
|
|
811
811
|
children: "Cancel"
|
|
812
812
|
}), /* @__PURE__ */ jsx("button", {
|
|
813
813
|
type: "submit",
|
|
814
814
|
disabled: !name.trim() || updateMutation.isPending,
|
|
815
|
-
className: "inline-flex items-center justify-center
|
|
815
|
+
className: "inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-colors rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50",
|
|
816
816
|
children: updateMutation.isPending ? "Saving…" : "Save Changes"
|
|
817
817
|
})]
|
|
818
818
|
})
|
|
@@ -1055,7 +1055,7 @@ const WebhooksPage = () => {
|
|
|
1055
1055
|
* Webhooks Frontend Plugin — registers the sidebar item and route
|
|
1056
1056
|
* for webhook management.
|
|
1057
1057
|
*/
|
|
1058
|
-
const
|
|
1058
|
+
const webhooksFrontend = {
|
|
1059
1059
|
id: "webhooks",
|
|
1060
1060
|
name: "Webhooks",
|
|
1061
1061
|
sidebar: [{
|
|
@@ -1169,6 +1169,6 @@ const WebhookTriggerSelector = ({ selectedId, onSelect, flowId, nodeId }) => {
|
|
|
1169
1169
|
});
|
|
1170
1170
|
};
|
|
1171
1171
|
//#endregion
|
|
1172
|
-
export { CopyableField, CreateWebhookModal, WebhookDetailPanel, WebhookTriggerSelector, WebhooksPage, useCreateWebhookTrigger, useDeleteWebhookTrigger, useTestWebhookTrigger, useUpdateWebhookTrigger, useWebhookTrigger, useWebhookTriggerInfo, useWebhookTriggers,
|
|
1172
|
+
export { CopyableField, CreateWebhookModal, WebhookDetailPanel, WebhookTriggerSelector, WebhooksPage, useCreateWebhookTrigger, useDeleteWebhookTrigger, useTestWebhookTrigger, useUpdateWebhookTrigger, useWebhookTrigger, useWebhookTriggerInfo, useWebhookTriggers, webhooksFrontend };
|
|
1173
1173
|
|
|
1174
1174
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["AUTH_MODE_CONFIG","getAuthModeConfig"],"sources":["../../src/frontend/hooks/useWebhookQueries.ts","../../src/frontend/components/CopyableField.tsx","../../src/frontend/components/CreateWebhookModal.tsx","../../src/frontend/components/WebhookDetailPanel.tsx","../../src/frontend/components/WebhooksPage.tsx","../../src/frontend/plugins/webhooksFrontendPlugin.ts","../../src/frontend/components/WebhookTriggerSelector.tsx"],"sourcesContent":["/**\n * React hooks for the webhooks plugin API.\n *\n * Uses @invect/frontend's ApiContext for the base URL.\n */\n\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useApiBaseURL } from '@invect/frontend';\nimport type {\n WebhookTrigger,\n CreateWebhookTriggerInput,\n UpdateWebhookTriggerInput,\n WebhookTriggerInfo,\n} from '../../shared/types';\n\n// ─── API helper ─────────────────────────────────────────────────────\n\nasync function apiFetch<T>(baseUrl: string, path: string, init?: RequestInit): Promise<T> {\n const res = await fetch(`${baseUrl}${path}`, {\n headers: { 'Content-Type': 'application/json', ...init?.headers },\n credentials: 'include',\n ...init,\n });\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error((body as { error?: string }).error || `HTTP ${res.status}`);\n }\n return res.json() as Promise<T>;\n}\n\n// ─── Query Keys ─────────────────────────────────────────────────────\n\nconst keys = {\n all: ['webhooks'] as const,\n list: () => [...keys.all, 'list'] as const,\n detail: (id: string) => [...keys.all, 'detail', id] as const,\n info: (id: string) => [...keys.all, 'info', id] as const,\n};\n\n// ─── Queries ────────────────────────────────────────────────────────\n\nexport function useWebhookTriggers() {\n const baseUrl = useApiBaseURL();\n return useQuery({\n queryKey: keys.list(),\n queryFn: () =>\n apiFetch<{ data: WebhookTrigger[] }>(baseUrl, '/plugins/webhooks/triggers').then(\n (r) => r.data,\n ),\n });\n}\n\nexport function useWebhookTrigger(id: string | undefined) {\n const baseUrl = useApiBaseURL();\n return useQuery({\n queryKey: keys.detail(id ?? ''),\n queryFn: () => apiFetch<WebhookTrigger>(baseUrl, `/plugins/webhooks/triggers/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useWebhookTriggerInfo(id: string | undefined) {\n const baseUrl = useApiBaseURL();\n return useQuery({\n queryKey: keys.info(id ?? ''),\n queryFn: () =>\n apiFetch<WebhookTriggerInfo>(baseUrl, `/plugins/webhooks/triggers/${id}/info`),\n enabled: !!id,\n });\n}\n\n// ─── Mutations ──────────────────────────────────────────────────────\n\nexport function useCreateWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: CreateWebhookTriggerInput) =>\n apiFetch<WebhookTrigger & { fullUrl?: string }>(baseUrl, '/plugins/webhooks/triggers', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => qc.invalidateQueries({ queryKey: keys.list() }),\n });\n}\n\nexport function useUpdateWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...input }: UpdateWebhookTriggerInput & { id: string }) =>\n apiFetch<WebhookTrigger>(baseUrl, `/plugins/webhooks/triggers/${id}`, {\n method: 'PUT',\n body: JSON.stringify(input),\n }),\n onSuccess: (_data, vars) => {\n qc.invalidateQueries({ queryKey: keys.list() });\n qc.invalidateQueries({ queryKey: keys.detail(vars.id) });\n },\n });\n}\n\nexport function useDeleteWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ success: boolean }>(baseUrl, `/plugins/webhooks/triggers/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => qc.invalidateQueries({ queryKey: keys.list() }),\n });\n}\n\nexport function useTestWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n return useMutation({\n mutationFn: ({ id, payload }: { id: string; payload?: unknown }) =>\n apiFetch<{ status: string }>(baseUrl, `/plugins/webhooks/triggers/${id}/test`, {\n method: 'POST',\n body: JSON.stringify(payload ?? { test: true }),\n }),\n });\n}\n","/**\n * CopyableField — Displays a value with copy-to-clipboard and optional masking.\n *\n * Follows the pattern from the Credentials page.\n */\n\nimport { useState, type FC } from 'react';\nimport { Copy, Check, Eye, EyeOff } from 'lucide-react';\n\ninterface CopyableFieldProps {\n value: string;\n masked?: boolean;\n}\n\nexport const CopyableField: FC<CopyableFieldProps> = ({ value, masked = false }) => {\n const [copied, setCopied] = useState(false);\n const [revealed, setRevealed] = useState(!masked);\n\n const copy = async () => {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const displayValue = revealed ? value : '•'.repeat(Math.min(value.length, 32));\n\n return (\n <div className=\"flex items-center gap-1.5\">\n <code className=\"flex-1 truncate rounded bg-muted px-2 py-1.5 font-mono text-[11px]\">\n {displayValue}\n </code>\n {masked && (\n <button\n onClick={() => setRevealed(!revealed)}\n className=\"shrink-0 rounded p-1 hover:bg-muted text-muted-foreground transition-colors\"\n title={revealed ? 'Hide' : 'Reveal'}\n >\n {revealed ? <EyeOff className=\"h-3.5 w-3.5\" /> : <Eye className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n <button\n onClick={copy}\n className=\"shrink-0 rounded p-1 hover:bg-muted text-muted-foreground transition-colors\"\n title=\"Copy to clipboard\"\n >\n {copied ? (\n <Check className=\"h-3.5 w-3.5 text-emerald-500\" />\n ) : (\n <Copy className=\"h-3.5 w-3.5\" />\n )}\n </button>\n </div>\n );\n};\n","/**\n * CreateWebhookModal — Dialog for creating a new webhook trigger.\n *\n * Step 1: Name + endpoint settings\n * Step 2: Success screen with URL + secret to copy\n */\n\nimport { useState, type FC, type RefObject } from 'react';\nimport { Check } from 'lucide-react';\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogDescription,\n} from '@invect/frontend';\nimport { useCreateWebhookTrigger } from '../hooks/useWebhookQueries';\nimport { CopyableField } from './CopyableField';\nimport type { CreateWebhookTriggerInput } from '../../shared/types';\n\n// ─── Component ──────────────────────────────────────────────────────\n\ninterface CreateWebhookModalProps {\n open: boolean;\n onClose: () => void;\n containerRef?: RefObject<HTMLElement | null>;\n /** Pre-fill flowId + nodeId when creating from flow editor */\n flowId?: string;\n nodeId?: string;\n}\n\nexport const CreateWebhookModal: FC<CreateWebhookModalProps> = ({\n open,\n onClose,\n containerRef,\n flowId,\n nodeId,\n}) => {\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [methods, setMethods] = useState('POST');\n const [hmacEnabled, setHmacEnabled] = useState(false);\n const [hmacHeaderName, setHmacHeaderName] = useState('');\n const [hmacSecret, setHmacSecret] = useState('');\n const [allowedIps, setAllowedIps] = useState('');\n const [createdUrl, setCreatedUrl] = useState<string | null>(null);\n\n const createMutation = useCreateWebhookTrigger();\n\n const handleCreate = async () => {\n if (!name.trim()) return;\n\n const input: CreateWebhookTriggerInput = {\n name: name.trim(),\n description: description.trim() || undefined,\n provider: 'generic',\n allowedMethods: methods,\n hmacEnabled,\n hmacHeaderName: hmacEnabled ? hmacHeaderName.trim() || undefined : undefined,\n hmacSecret: hmacEnabled ? hmacSecret.trim() || undefined : undefined,\n allowedIps: allowedIps.trim() || undefined,\n flowId,\n nodeId,\n };\n\n try {\n const result = await createMutation.mutateAsync(input);\n setCreatedUrl(result.fullUrl ?? `/plugins/webhooks/receive/${result.webhookPath}`);\n } catch {\n // Error handled by mutation state\n }\n };\n\n const handleClose = () => {\n setName('');\n setDescription('');\n setMethods('POST');\n setHmacEnabled(false);\n setHmacHeaderName('');\n setHmacSecret('');\n setAllowedIps('');\n setCreatedUrl(null);\n onClose();\n };\n\n return (\n <Dialog open={open} onOpenChange={(v) => { if (!v) handleClose(); }}>\n <DialogContent\n container={containerRef?.current}\n className=\"max-w-md gap-0 p-0 overflow-hidden\"\n showCloseButton\n >\n {/* Header */}\n <div className=\"px-6 pt-6 pb-4\">\n <DialogHeader>\n <DialogTitle className=\"text-base\">\n {createdUrl ? 'Webhook Created' : 'Create Webhook'}\n </DialogTitle>\n <DialogDescription>\n {createdUrl\n ? 'Copy the URL below and configure it in your external service.'\n : 'Set up a generic endpoint to receive webhook events from any external system.'}\n </DialogDescription>\n </DialogHeader>\n </div>\n\n {/* Content */}\n <div className=\"px-6 pb-6 space-y-4\">\n {createdUrl ? (\n /* ── Success ── */\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-2 p-3 text-sm border rounded-lg border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950/30 text-emerald-700 dark:text-emerald-400\">\n <Check className=\"w-4 h-4 shrink-0\" />\n Webhook is ready to receive events.\n </div>\n\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium tracking-wide uppercase text-muted-foreground\">\n Webhook URL\n </label>\n <CopyableField value={createdUrl} />\n </div>\n\n <button\n onClick={handleClose}\n className=\"inline-flex items-center justify-center w-full px-4 text-sm font-medium transition-colors rounded-md h-9 bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n Done\n </button>\n </div>\n ) : (\n /* ── Form ── */\n <>\n {/* Name */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-name\">\n Name *\n </label>\n <input\n id=\"wh-create-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Partner API Events\"\n autoFocus\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n\n {/* Description */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-desc\">\n Description\n </label>\n <input\n id=\"wh-create-desc\"\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional description\"\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Authentication</label>\n <div className=\"space-y-3 rounded-lg border border-border bg-muted/30 p-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">HMAC Verification</div>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Verify requests using an HMAC signature header.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setHmacEnabled(!hmacEnabled)}\n className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${\n hmacEnabled ? 'bg-primary' : 'bg-muted-foreground/30'\n }`}\n >\n <span\n className={`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${\n hmacEnabled ? 'translate-x-4' : 'translate-x-0'\n }`}\n />\n </button>\n </div>\n {hmacEnabled && (\n <div className=\"space-y-3 pt-1\">\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-create-hmac-header\">\n Signature Header Name\n </label>\n <input\n id=\"wh-create-hmac-header\"\n type=\"text\"\n autoComplete=\"off\"\n value={hmacHeaderName}\n onChange={(e) => setHmacHeaderName(e.target.value)}\n placeholder=\"e.g. x-signature\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-create-hmac-secret\">\n Signing Secret\n </label>\n <input\n id=\"wh-create-hmac-secret\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={hmacSecret}\n onChange={(e) => setHmacSecret(e.target.value)}\n placeholder=\"Enter secret key\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* IP Whitelist */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-ips\">\n IP Whitelist\n </label>\n <input\n id=\"wh-create-ips\"\n type=\"text\"\n value={allowedIps}\n onChange={(e) => setAllowedIps(e.target.value)}\n placeholder=\"e.g. 192.168.1.1, 10.0.0.0/24\"\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm font-mono shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n <p className=\"text-xs text-muted-foreground\">\n Leave empty to allow all IPs. Separate multiple addresses with commas.\n </p>\n </div>\n\n {/* HTTP Methods */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-methods\">\n HTTP Methods\n </label>\n <select\n id=\"wh-create-methods\"\n value={methods}\n onChange={(e) => setMethods(e.target.value)}\n className=\"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n >\n <option value=\"POST\">POST only</option>\n <option value=\"POST,PUT\">POST + PUT</option>\n <option value=\"ANY\">Any method</option>\n </select>\n </div>\n\n {/* Error */}\n {createMutation.isError && (\n <p className=\"text-sm text-red-500\">\n {createMutation.error?.message || 'Failed to create webhook'}\n </p>\n )}\n\n {/* Buttons */}\n <div className=\"flex gap-2 pt-2\">\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"inline-flex items-center justify-center flex-1 px-3 text-sm font-medium transition-colors border rounded-md shadow-xs h-9 bg-background hover:bg-accent\"\n >\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!name.trim() || createMutation.isPending}\n className=\"inline-flex items-center justify-center flex-1 px-3 text-sm font-medium transition-colors rounded-md h-9 bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {createMutation.isPending ? 'Creating…' : 'Create Webhook'}\n </button>\n </div>\n </>\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n};\n","/**\n * WebhookDetailPanel — Detail view rendered inside a Dialog.\n *\n * Tabs: Overview | Edit\n * Shows webhook URL, secret, status, linked flow, stats.\n * Allows toggling enabled/disabled, editing, and deleting.\n */\n\nimport { useState, type FC } from 'react';\nimport {\n Globe,\n Trash2,\n ExternalLink,\n Clock,\n Hash,\n ToggleLeft,\n ToggleRight,\n Workflow,\n Loader2,\n} from 'lucide-react';\nimport { DialogHeader, DialogTitle, DialogDescription } from '@invect/frontend';\nimport {\n useUpdateWebhookTrigger,\n useDeleteWebhookTrigger,\n} from '../hooks/useWebhookQueries';\nimport { CopyableField } from './CopyableField';\nimport type { WebhookTrigger, UpdateWebhookTriggerInput } from '../../shared/types';\n\n// ─── Constants ──────────────────────────────────────────────────────\n\nconst AUTH_MODE_CONFIG: Record<string, { label: string; color: string }> = {\n generic: {\n label: 'Unauthenticated',\n color: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800/40 dark:text-zinc-400',\n },\n hmac: {\n label: 'HMAC',\n color: 'bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300',\n },\n ip_whitelist: {\n label: 'IP Whitelist',\n color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300',\n },\n signed: {\n label: 'Signed',\n color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300',\n },\n};\n\nfunction getAuthModeConfig(trigger: WebhookTrigger) {\n if (trigger.provider !== 'generic') {\n return AUTH_MODE_CONFIG.signed;\n }\n if (trigger.hmacEnabled) {\n return AUTH_MODE_CONFIG.hmac;\n }\n if (trigger.allowedIps) {\n return AUTH_MODE_CONFIG.ip_whitelist;\n }\n return AUTH_MODE_CONFIG.generic;\n}\n\nfunction formatFullDate(iso?: string): string {\n if (!iso) return 'Never';\n return new Date(iso).toLocaleString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\n// ─── Component ──────────────────────────────────────────────────────\n\ntype Section = 'overview' | 'edit';\n\ninterface WebhookDetailPanelProps {\n trigger: WebhookTrigger;\n flowName?: string;\n onClose: () => void;\n}\n\nexport const WebhookDetailPanel: FC<WebhookDetailPanelProps> = ({\n trigger,\n flowName,\n onClose,\n}) => {\n const [section, setSection] = useState<Section>('overview');\n const updateMutation = useUpdateWebhookTrigger();\n const deleteMutation = useDeleteWebhookTrigger();\n\n const authModeConfig = getAuthModeConfig(trigger);\n\n const handleToggleEnabled = () => {\n updateMutation.mutate({ id: trigger.id, isEnabled: !trigger.isEnabled });\n };\n\n const handleDelete = () => {\n if (confirm(`Delete webhook \"${trigger.name}\"? This cannot be undone.`)) {\n deleteMutation.mutate(trigger.id, { onSuccess: onClose });\n }\n };\n\n return (\n <>\n {/* Fixed header */}\n <div className=\"px-6 pt-6 pb-0\">\n <DialogHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center justify-center w-10 h-10 rounded-lg bg-muted/60 shrink-0\">\n <Globe className=\"w-5 h-5 text-muted-foreground\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <DialogTitle className=\"text-base\">{trigger.name}</DialogTitle>\n <DialogDescription className=\"flex items-center gap-2 mt-0.5 text-xs\">\n <span\n className={`inline-flex items-center rounded-full border border-transparent px-2 py-0.5 text-[10px] font-medium ${authModeConfig.color}`}\n >\n {authModeConfig.label}\n </span>\n <span\n className={`w-1.5 h-1.5 rounded-full ${\n trigger.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n <span>{trigger.isEnabled ? 'Enabled' : 'Disabled'}</span>\n </DialogDescription>\n </div>\n </div>\n </DialogHeader>\n\n {/* Tab nav */}\n <div className=\"flex gap-1 border-b -mx-6 px-6 mt-4\">\n {([\n { key: 'overview' as const, label: 'Overview' },\n { key: 'edit' as const, label: 'Edit' },\n ]).map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setSection(key)}\n className={`px-3 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${\n section === key\n ? 'border-foreground text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Scrollable content */}\n <div className=\"flex-1 overflow-y-auto px-6 pb-6\">\n {section === 'overview' ? (\n <OverviewSection\n trigger={trigger}\n flowName={flowName}\n onToggleEnabled={handleToggleEnabled}\n onDelete={handleDelete}\n isToggling={updateMutation.isPending}\n isDeleting={deleteMutation.isPending}\n />\n ) : (\n <EditSection\n trigger={trigger}\n onSuccess={() => setSection('overview')}\n />\n )}\n </div>\n </>\n );\n};\n\n// ─── Overview Section ───────────────────────────────────────────────\n\nconst OverviewSection: FC<{\n trigger: WebhookTrigger;\n flowName?: string;\n onToggleEnabled: () => void;\n onDelete: () => void;\n isToggling: boolean;\n isDeleting: boolean;\n}> = ({ trigger, flowName, onToggleEnabled, onDelete, isToggling, isDeleting }) => (\n <div className=\"pt-4 space-y-5\">\n {/* Endpoint URL */}\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n Webhook URL\n </label>\n <CopyableField value={`/plugins/webhooks/receive/${trigger.webhookPath}`} />\n </div>\n\n {/* HMAC Authentication */}\n {trigger.hmacEnabled && trigger.hmacHeaderName && (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n HMAC Authentication\n </label>\n <div className=\"rounded-lg border bg-muted/30 p-3 space-y-1\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">Signature Header</span>\n <span className=\"text-sm font-mono\">{trigger.hmacHeaderName}</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">Secret</span>\n <CopyableField value={trigger.hmacSecret ?? ''} masked />\n </div>\n </div>\n </div>\n )}\n\n {/* IP Whitelist */}\n {trigger.allowedIps && (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n IP Whitelist\n </label>\n <div className=\"rounded-lg border bg-muted/30 p-3\">\n <span className=\"text-sm font-mono break-all\">{trigger.allowedIps}</span>\n </div>\n </div>\n )}\n\n {/* Info grid */}\n <div className=\"grid grid-cols-2 gap-4 py-2\">\n <div>\n <span className=\"text-xs text-muted-foreground block mb-1\">Methods</span>\n <span className=\"text-sm font-mono\">{trigger.allowedMethods}</span>\n </div>\n <div>\n <span className=\"text-xs text-muted-foreground block mb-1\">Authentication</span>\n <span className=\"text-sm\">{getAuthModeConfig(trigger).label}</span>\n </div>\n <div>\n <span className=\"text-xs text-muted-foreground block mb-1\">Created</span>\n <span className=\"text-sm\">{formatFullDate(trigger.createdAt)}</span>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <Hash className=\"w-3 h-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">Triggers:</span>\n <span className=\"text-sm font-medium\">{trigger.triggerCount}</span>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <Clock className=\"w-3 h-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">Last:</span>\n <span className=\"text-sm\">{formatFullDate(trigger.lastTriggeredAt)}</span>\n </div>\n </div>\n\n {/* Linked flow */}\n {trigger.flowId && (\n <div className=\"rounded-lg border bg-muted/30 p-3\">\n <div className=\"flex items-center gap-2\">\n <Workflow className=\"w-4 h-4 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <span className=\"text-xs text-muted-foreground block\">Linked Flow</span>\n <a\n href={`/invect/flow/${trigger.flowId}`}\n className=\"text-sm font-medium text-primary hover:underline inline-flex items-center gap-1\"\n >\n {flowName ?? trigger.flowId}\n <ExternalLink className=\"w-3 h-3\" />\n </a>\n </div>\n </div>\n </div>\n )}\n\n {/* Last payload */}\n {trigger.lastPayload != null && (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n Last Payload\n </label>\n <pre className=\"text-xs font-mono bg-muted rounded-lg p-3 overflow-auto max-h-32\">\n {JSON.stringify(trigger.lastPayload, null, 2)}\n </pre>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-3 border-t\">\n <button\n onClick={onToggleEnabled}\n disabled={isToggling}\n className={`inline-flex items-center gap-2 rounded-md text-sm font-medium h-8 px-3 border transition-colors ${\n trigger.isEnabled\n ? 'border-amber-200 text-amber-700 hover:bg-amber-50 dark:border-amber-800 dark:text-amber-400 dark:hover:bg-amber-950/30'\n : 'border-emerald-200 text-emerald-700 hover:bg-emerald-50 dark:border-emerald-800 dark:text-emerald-400 dark:hover:bg-emerald-950/30'\n }`}\n >\n {isToggling ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : trigger.isEnabled ? (\n <ToggleLeft className=\"w-3.5 h-3.5\" />\n ) : (\n <ToggleRight className=\"w-3.5 h-3.5\" />\n )}\n {trigger.isEnabled ? 'Disable' : 'Enable'}\n </button>\n\n <button\n onClick={onDelete}\n disabled={isDeleting}\n className=\"inline-flex items-center gap-2 rounded-md text-sm font-medium h-8 px-3 border border-red-200 text-red-600 hover:bg-red-50 dark:border-red-800 dark:text-red-400 dark:hover:bg-red-950/30 transition-colors\"\n >\n {isDeleting ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : (\n <Trash2 className=\"w-3.5 h-3.5\" />\n )}\n Delete\n </button>\n </div>\n </div>\n);\n\n// ─── Edit Section ───────────────────────────────────────────────────\n\nconst EditSection: FC<{\n trigger: WebhookTrigger;\n onSuccess: () => void;\n}> = ({ trigger, onSuccess }) => {\n const [name, setName] = useState(trigger.name);\n const [description, setDescription] = useState(trigger.description ?? '');\n const [methods, setMethods] = useState(trigger.allowedMethods);\n const [hmacEnabled, setHmacEnabled] = useState(trigger.hmacEnabled);\n const [hmacHeaderName, setHmacHeaderName] = useState(trigger.hmacHeaderName ?? '');\n const [hmacSecret, setHmacSecret] = useState(trigger.hmacSecret ?? '');\n const [allowedIps, setAllowedIps] = useState(trigger.allowedIps ?? '');\n const updateMutation = useUpdateWebhookTrigger();\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!name.trim()) return;\n\n const input: UpdateWebhookTriggerInput & { id: string } = {\n id: trigger.id,\n name: name.trim(),\n description: description.trim() || undefined,\n allowedMethods: methods,\n hmacEnabled,\n hmacHeaderName: hmacEnabled ? hmacHeaderName.trim() || undefined : undefined,\n hmacSecret: hmacEnabled ? hmacSecret.trim() || undefined : undefined,\n allowedIps: allowedIps.trim() || undefined,\n };\n updateMutation.mutate(input, { onSuccess });\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"pt-4 space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-name\">\n Name *\n </label>\n <input\n id=\"wh-edit-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n required\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-desc\">\n Description\n </label>\n <textarea\n id=\"wh-edit-desc\"\n rows={2}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional description\"\n className=\"w-full min-h-16 rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20 field-sizing-content\"\n />\n </div>\n\n {/* HMAC Authentication */}\n <div className=\"space-y-3 rounded-lg border border-border bg-muted/30 p-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">HMAC Authentication</div>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Verify incoming requests using an HMAC signature header.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setHmacEnabled(!hmacEnabled)}\n className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${\n hmacEnabled ? 'bg-primary' : 'bg-muted-foreground/30'\n }`}\n >\n <span\n className={`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${\n hmacEnabled ? 'translate-x-4' : 'translate-x-0'\n }`}\n />\n </button>\n </div>\n {hmacEnabled && (\n <div className=\"space-y-3 pt-1\">\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-edit-hmac-header\">\n Signature Header Name\n </label>\n <input\n id=\"wh-edit-hmac-header\"\n type=\"text\"\n value={hmacHeaderName}\n onChange={(e) => setHmacHeaderName(e.target.value)}\n placeholder=\"e.g. x-signature\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-edit-hmac-secret\">\n Signing Secret\n </label>\n <input\n id=\"wh-edit-hmac-secret\"\n type=\"password\"\n value={hmacSecret}\n onChange={(e) => setHmacSecret(e.target.value)}\n placeholder=\"Enter secret key\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n </div>\n )}\n </div>\n\n {/* IP Whitelist */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-ips\">\n IP Whitelist\n </label>\n <textarea\n id=\"wh-edit-ips\"\n rows={2}\n value={allowedIps}\n onChange={(e) => setAllowedIps(e.target.value)}\n placeholder=\"Comma-separated IPs, e.g. 192.168.1.1, 10.0.0.0/24\"\n className=\"w-full min-h-16 rounded-md border border-input bg-background px-3 py-2 text-sm font-mono shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20 field-sizing-content\"\n />\n <p className=\"text-xs text-muted-foreground\">\n Leave empty to allow all IPs. Separate multiple addresses with commas.\n </p>\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-methods\">\n HTTP Methods\n </label>\n <select\n id=\"wh-edit-methods\"\n value={methods}\n onChange={(e) => setMethods(e.target.value)}\n className=\"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n >\n <option value=\"POST\">POST only</option>\n <option value=\"POST,PUT\">POST + PUT</option>\n <option value=\"ANY\">Any method</option>\n </select>\n </div>\n\n {updateMutation.isError && (\n <p className=\"text-sm text-red-500\">\n {updateMutation.error?.message || 'Failed to save changes'}\n </p>\n )}\n\n <div className=\"flex justify-end gap-2 pt-2\">\n <button\n type=\"button\"\n onClick={onSuccess}\n className=\"inline-flex items-center justify-center rounded-md text-sm font-medium h-8 px-3 border bg-background shadow-xs hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={!name.trim() || updateMutation.isPending}\n className=\"inline-flex items-center justify-center rounded-md text-sm font-medium h-8 px-3 bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 transition-colors\"\n >\n {updateMutation.isPending ? 'Saving…' : 'Save Changes'}\n </button>\n </div>\n </form>\n );\n};\n","/**\n * WebhooksPage — Main webhook management page.\n *\n * Lists all webhook triggers with status, auth mode, linked flows, and last activity.\n * Click a row to open the detail dialog for editing, toggling, or deleting.\n */\n\nimport { useState, useRef, type FC } from 'react';\nimport {\n Globe,\n Plus,\n Search,\n Clock,\n Hash,\n ChevronRight,\n Loader2,\n Workflow,\n} from 'lucide-react';\nimport {\n PageLayout,\n Dialog,\n DialogContent,\n useFlows,\n} from '@invect/frontend';\nimport { useWebhookTriggers } from '../hooks/useWebhookQueries';\nimport { CreateWebhookModal } from './CreateWebhookModal';\nimport { WebhookDetailPanel } from './WebhookDetailPanel';\nimport type { WebhookTrigger } from '../../shared/types';\n\n// ─── Constants ──────────────────────────────────────────────────────\n\nconst AUTH_MODE_CONFIG: Record<string, { label: string; color: string }> = {\n generic: {\n label: 'Unauthenticated',\n color: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800/40 dark:text-zinc-400',\n },\n hmac: {\n label: 'HMAC',\n color: 'bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300',\n },\n ip_whitelist: {\n label: 'IP Whitelist',\n color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300',\n },\n signed: {\n label: 'Signed',\n color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300',\n },\n};\n\nfunction getAuthModeConfig(trigger: WebhookTrigger) {\n if (trigger.provider !== 'generic') {\n return AUTH_MODE_CONFIG.signed;\n }\n if (trigger.hmacEnabled) {\n return AUTH_MODE_CONFIG.hmac;\n }\n if (trigger.allowedIps) {\n return AUTH_MODE_CONFIG.ip_whitelist;\n }\n return AUTH_MODE_CONFIG.generic;\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────\n\nfunction formatRelativeTime(iso?: string): string {\n if (!iso) return 'Never';\n const diff = Date.now() - new Date(iso).getTime();\n const mins = Math.floor(diff / 60_000);\n if (mins < 1) return 'Just now';\n if (mins < 60) return `${mins}m ago`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 30) return `${days}d ago`;\n return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\n// ─── Webhook Row ────────────────────────────────────────────────────\n\nconst WebhookRow: FC<{\n trigger: WebhookTrigger;\n flowName?: string;\n onClick: () => void;\n}> = ({ trigger, flowName, onClick }) => {\n const authModeConfig = getAuthModeConfig(trigger);\n\n return (\n <button\n className=\"w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-muted/50 transition-colors\"\n onClick={onClick}\n >\n {/* Icon */}\n <div className=\"flex items-center justify-center w-9 h-9 rounded-lg bg-muted/60 shrink-0\">\n <Globe className=\"w-4 h-4 text-muted-foreground\" />\n </div>\n\n {/* Name + subtitle */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium truncate\">{trigger.name}</span>\n <span\n className={`w-1.5 h-1.5 rounded-full shrink-0 ${\n trigger.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n </div>\n <div className=\"flex items-center gap-2 mt-0.5\">\n {flowName ? (\n <span className=\"text-xs text-muted-foreground flex items-center gap-1 truncate\">\n <Workflow className=\"w-3 h-3 shrink-0\" />\n {flowName}\n </span>\n ) : trigger.description ? (\n <span className=\"text-xs text-muted-foreground truncate\">{trigger.description}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/50\">No flow linked</span>\n )}\n </div>\n </div>\n\n {/* Auth badge */}\n <span\n className={`hidden sm:inline-flex items-center rounded-full border border-transparent px-2 py-0.5 text-[10px] font-medium ${authModeConfig.color}`}\n >\n {authModeConfig.label}\n </span>\n\n {/* Stats */}\n <div className=\"hidden md:flex items-center gap-4 text-xs text-muted-foreground shrink-0\">\n <span className=\"flex items-center gap-1\" title=\"Total triggers\">\n <Hash className=\"w-3 h-3\" />\n {trigger.triggerCount}\n </span>\n <span className=\"flex items-center gap-1 w-16 justify-end\" title=\"Last triggered\">\n <Clock className=\"w-3 h-3\" />\n {formatRelativeTime(trigger.lastTriggeredAt)}\n </span>\n </div>\n\n <ChevronRight className=\"w-4 h-4 text-muted-foreground/50 shrink-0\" />\n </button>\n );\n};\n\n// ─── Main Page ──────────────────────────────────────────────────────\n\nexport const WebhooksPage: FC<{ basePath: string }> = () => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [createOpen, setCreateOpen] = useState(false);\n const [selectedTrigger, setSelectedTrigger] = useState<WebhookTrigger | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<'all' | 'enabled' | 'disabled'>('all');\n\n const { data: triggers, isLoading, error } = useWebhookTriggers();\n const { data: flowsResponse } = useFlows();\n\n // Build flow name lookup\n const flowNameMap = new Map<string, string>();\n for (const flow of flowsResponse?.data ?? []) {\n flowNameMap.set(flow.id, flow.name);\n }\n\n // Filter\n const filtered = (triggers ?? []).filter((t) => {\n if (statusFilter === 'enabled' && !t.isEnabled) return false;\n if (statusFilter === 'disabled' && t.isEnabled) return false;\n if (searchQuery) {\n const q = searchQuery.toLowerCase();\n const nameMatch = t.name.toLowerCase().includes(q);\n const flowMatch = t.flowId\n ? (flowNameMap.get(t.flowId) ?? '').toLowerCase().includes(q)\n : false;\n if (!nameMatch && !flowMatch) return false;\n }\n return true;\n });\n\n const enabledCount = (triggers ?? []).filter((t) => t.isEnabled).length;\n const disabledCount = (triggers ?? []).filter((t) => !t.isEnabled).length;\n\n // Keep detail dialog in sync with list data\n const liveTrigger = selectedTrigger\n ? (triggers ?? []).find((t) => t.id === selectedTrigger.id) ?? selectedTrigger\n : null;\n\n return (\n <PageLayout\n title=\"Webhooks\"\n subtitle=\"Receive events from external systems and route them into your flows.\"\n icon={Globe}\n actions={\n <button\n onClick={() => setCreateOpen(true)}\n className=\"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium h-9 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n New Webhook\n </button>\n }\n >\n <div ref={containerRef}>\n {/* Search + Filters */}\n <div className=\"flex flex-col gap-3 mb-4 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1 max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 pointer-events-none text-muted-foreground\" />\n <input\n type=\"text\"\n placeholder=\"Search webhooks…\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-lg border border-border bg-transparent py-2 pl-9 pr-3 text-sm outline-none placeholder:text-muted-foreground focus:border-primary/50\"\n />\n </div>\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {([\n { key: 'all' as const, label: `All (${triggers?.length ?? 0})` },\n { key: 'enabled' as const, label: `Enabled (${enabledCount})` },\n { key: 'disabled' as const, label: `Disabled (${disabledCount})` },\n ]).map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setStatusFilter(key)}\n className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors ${\n statusFilter === key\n ? 'bg-foreground text-background border-foreground'\n : 'bg-card text-muted-foreground border-border hover:border-foreground/30'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Content */}\n {isLoading ? (\n <div className=\"flex items-center justify-center gap-2 py-16 text-sm text-muted-foreground\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n Loading webhooks…\n </div>\n ) : error ? (\n <div className=\"rounded-lg border border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30 p-4 text-sm text-red-600 dark:text-red-400\">\n Failed to load webhooks: {(error as Error).message}\n </div>\n ) : filtered.length === 0 ? (\n <div className=\"flex flex-col items-center py-16 text-center\">\n <div className=\"rounded-full bg-muted p-3 mb-4\">\n <Globe className=\"w-6 h-6 text-muted-foreground\" />\n </div>\n <h3 className=\"text-sm font-semibold mb-1\">\n {triggers?.length === 0 ? 'No webhooks yet' : 'No webhooks match your filter'}\n </h3>\n <p className=\"max-w-sm text-sm text-muted-foreground mb-4\">\n {triggers?.length === 0\n ? 'Create a generic webhook endpoint to receive events from external systems.'\n : 'Try adjusting your search or filter criteria.'}\n </p>\n {triggers?.length === 0 && (\n <button\n onClick={() => setCreateOpen(true)}\n className=\"inline-flex items-center gap-2 rounded-md text-sm font-medium h-9 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n Create Webhook\n </button>\n )}\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-lg border bg-card\">\n <div className=\"divide-y\">\n {filtered.map((trigger) => (\n <WebhookRow\n key={trigger.id}\n trigger={trigger}\n flowName={trigger.flowId ? flowNameMap.get(trigger.flowId) : undefined}\n onClick={() => setSelectedTrigger(trigger)}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Detail Dialog */}\n <Dialog\n open={!!selectedTrigger}\n onOpenChange={(open) => {\n if (!open) setSelectedTrigger(null);\n }}\n >\n <DialogContent\n container={containerRef.current}\n className=\"max-w-2xl h-[32rem] flex flex-col gap-0 p-0 overflow-hidden\"\n showCloseButton\n >\n {liveTrigger && (\n <WebhookDetailPanel\n trigger={liveTrigger}\n flowName={\n liveTrigger.flowId ? flowNameMap.get(liveTrigger.flowId) : undefined\n }\n onClose={() => setSelectedTrigger(null)}\n />\n )}\n </DialogContent>\n </Dialog>\n\n {/* Create Modal */}\n <CreateWebhookModal\n open={createOpen}\n onClose={() => setCreateOpen(false)}\n containerRef={containerRef}\n />\n </PageLayout>\n );\n};\n","/**\n * Webhooks Frontend Plugin — registers the sidebar item and route\n * for webhook management.\n */\n\nimport { Globe } from 'lucide-react';\nimport { WebhooksPage } from '../components/WebhooksPage';\nimport type { InvectFrontendPlugin } from '@invect/frontend';\n\nexport const webhooksFrontendPlugin: InvectFrontendPlugin = {\n id: 'webhooks',\n name: 'Webhooks',\n\n sidebar: [\n {\n label: 'Webhooks',\n icon: Globe,\n path: '/webhooks',\n position: 'top',\n },\n ],\n\n routes: [\n {\n path: '/webhooks',\n component: WebhooksPage,\n },\n ],\n};\n","/**\n * WebhookTriggerSelector — Dropdown to pick an existing webhook trigger\n * or create a new one inline. Used in the trigger.webhook node's config panel.\n */\n\nimport { useState, type FC } from 'react';\nimport { Globe, Plus, ChevronDown, ExternalLink } from 'lucide-react';\nimport { useWebhookTriggers } from '../hooks/useWebhookQueries';\nimport { CreateWebhookModal } from './CreateWebhookModal';\nimport { CopyableField } from './CopyableField';\nimport type { WebhookTrigger } from '../../shared/types';\n\ninterface WebhookTriggerSelectorProps {\n selectedId?: string;\n onSelect: (trigger: WebhookTrigger) => void;\n flowId?: string;\n nodeId?: string;\n}\n\nexport const WebhookTriggerSelector: FC<WebhookTriggerSelectorProps> = ({\n selectedId,\n onSelect,\n flowId,\n nodeId,\n}) => {\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const [createOpen, setCreateOpen] = useState(false);\n const { data: triggers, isLoading } = useWebhookTriggers();\n\n const selected = triggers?.find((t) => t.id === selectedId);\n\n return (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Webhook Trigger</label>\n\n {/* Dropdown */}\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setDropdownOpen(!dropdownOpen)}\n className=\"flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 text-sm shadow-xs hover:bg-accent/50 transition-colors\"\n >\n <span className=\"flex items-center gap-2 truncate\">\n <Globe className=\"h-3.5 w-3.5 text-muted-foreground shrink-0\" />\n {selected ? (\n <>\n <span className=\"truncate\">{selected.name}</span>\n <span\n className={`w-1.5 h-1.5 rounded-full shrink-0 ${\n selected.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n </>\n ) : (\n <span className=\"text-muted-foreground\">\n {isLoading ? 'Loading…' : 'Select a webhook trigger…'}\n </span>\n )}\n </span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground shrink-0\" />\n </button>\n\n {dropdownOpen && (\n <>\n <div className=\"fixed inset-0 z-40\" onClick={() => setDropdownOpen(false)} />\n\n <div className=\"absolute z-50 w-full mt-1 bg-popover border border-border rounded-lg shadow-lg max-h-60 overflow-auto\">\n {/* Create new */}\n <button\n onClick={() => {\n setDropdownOpen(false);\n setCreateOpen(true);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-primary hover:bg-accent/50 border-b border-border transition-colors\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n Create New Webhook\n </button>\n\n {/* Existing triggers */}\n {(triggers ?? []).length === 0 ? (\n <div className=\"px-3 py-4 text-xs text-muted-foreground text-center\">\n No webhook triggers yet\n </div>\n ) : (\n (triggers ?? []).map((trigger) => (\n <button\n key={trigger.id}\n onClick={() => {\n onSelect(trigger);\n setDropdownOpen(false);\n }}\n className={`w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent/50 transition-colors ${\n trigger.id === selectedId ? 'bg-accent' : ''\n }`}\n >\n <span\n className={`w-1.5 h-1.5 rounded-full shrink-0 ${\n trigger.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n <span className=\"truncate\">{trigger.name}</span>\n <span className=\"text-xs text-muted-foreground ml-auto shrink-0\">\n {trigger.provider}\n </span>\n </button>\n ))\n )}\n </div>\n </>\n )}\n </div>\n\n {/* Selected trigger info */}\n {selected && (\n <div className=\"space-y-2 p-3 rounded-lg bg-muted/30 border\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium\">{selected.name}</span>\n <span\n className={`inline-flex items-center rounded-full border border-transparent px-2 py-0.5 text-[10px] font-medium ${\n selected.isEnabled\n ? 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400'\n : 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800/40 dark:text-zinc-400'\n }`}\n >\n {selected.isEnabled ? 'Active' : 'Disabled'}\n </span>\n </div>\n <CopyableField value={`/plugins/webhooks/receive/${selected.webhookPath}`} />\n <a\n href=\"/invect/webhooks\"\n className=\"text-xs text-primary hover:underline inline-flex items-center gap-1\"\n >\n Manage webhooks <ExternalLink className=\"h-3 w-3\" />\n </a>\n </div>\n )}\n\n <CreateWebhookModal\n open={createOpen}\n onClose={() => setCreateOpen(false)}\n flowId={flowId}\n nodeId={nodeId}\n />\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["AUTH_MODE_CONFIG","getAuthModeConfig"],"sources":["../../src/frontend/hooks/useWebhookQueries.ts","../../src/frontend/components/CopyableField.tsx","../../src/frontend/components/CreateWebhookModal.tsx","../../src/frontend/components/WebhookDetailPanel.tsx","../../src/frontend/components/WebhooksPage.tsx","../../src/frontend/plugins/webhooksFrontendPlugin.ts","../../src/frontend/components/WebhookTriggerSelector.tsx"],"sourcesContent":["/**\n * React hooks for the webhooks plugin API.\n *\n * Uses @invect/ui's ApiContext for the base URL.\n */\n\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useApiBaseURL } from '@invect/ui';\nimport type {\n WebhookTrigger,\n CreateWebhookTriggerInput,\n UpdateWebhookTriggerInput,\n WebhookTriggerInfo,\n} from '../../shared/types';\n\n// ─── API helper ─────────────────────────────────────────────────────\n\nasync function apiFetch<T>(baseUrl: string, path: string, init?: RequestInit): Promise<T> {\n const res = await fetch(`${baseUrl}${path}`, {\n headers: { 'Content-Type': 'application/json', ...init?.headers },\n credentials: 'include',\n ...init,\n });\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error((body as { error?: string }).error || `HTTP ${res.status}`);\n }\n return res.json() as Promise<T>;\n}\n\n// ─── Query Keys ─────────────────────────────────────────────────────\n\nconst keys = {\n all: ['webhooks'] as const,\n list: () => [...keys.all, 'list'] as const,\n detail: (id: string) => [...keys.all, 'detail', id] as const,\n info: (id: string) => [...keys.all, 'info', id] as const,\n};\n\n// ─── Queries ────────────────────────────────────────────────────────\n\nexport function useWebhookTriggers() {\n const baseUrl = useApiBaseURL();\n return useQuery({\n queryKey: keys.list(),\n queryFn: () =>\n apiFetch<{ data: WebhookTrigger[] }>(baseUrl, '/plugins/webhooks/triggers').then(\n (r) => r.data,\n ),\n });\n}\n\nexport function useWebhookTrigger(id: string | undefined) {\n const baseUrl = useApiBaseURL();\n return useQuery({\n queryKey: keys.detail(id ?? ''),\n queryFn: () => apiFetch<WebhookTrigger>(baseUrl, `/plugins/webhooks/triggers/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useWebhookTriggerInfo(id: string | undefined) {\n const baseUrl = useApiBaseURL();\n return useQuery({\n queryKey: keys.info(id ?? ''),\n queryFn: () => apiFetch<WebhookTriggerInfo>(baseUrl, `/plugins/webhooks/triggers/${id}/info`),\n enabled: !!id,\n });\n}\n\n// ─── Mutations ──────────────────────────────────────────────────────\n\nexport function useCreateWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: CreateWebhookTriggerInput) =>\n apiFetch<WebhookTrigger & { fullUrl?: string }>(baseUrl, '/plugins/webhooks/triggers', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => qc.invalidateQueries({ queryKey: keys.list() }),\n });\n}\n\nexport function useUpdateWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...input }: UpdateWebhookTriggerInput & { id: string }) =>\n apiFetch<WebhookTrigger>(baseUrl, `/plugins/webhooks/triggers/${id}`, {\n method: 'PUT',\n body: JSON.stringify(input),\n }),\n onSuccess: (_data, vars) => {\n qc.invalidateQueries({ queryKey: keys.list() });\n qc.invalidateQueries({ queryKey: keys.detail(vars.id) });\n },\n });\n}\n\nexport function useDeleteWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ success: boolean }>(baseUrl, `/plugins/webhooks/triggers/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => qc.invalidateQueries({ queryKey: keys.list() }),\n });\n}\n\nexport function useTestWebhookTrigger() {\n const baseUrl = useApiBaseURL();\n return useMutation({\n mutationFn: ({ id, payload }: { id: string; payload?: unknown }) =>\n apiFetch<{ status: string }>(baseUrl, `/plugins/webhooks/triggers/${id}/test`, {\n method: 'POST',\n body: JSON.stringify(payload ?? { test: true }),\n }),\n });\n}\n","/**\n * CopyableField — Displays a value with copy-to-clipboard and optional masking.\n *\n * Follows the pattern from the Credentials page.\n */\n\nimport { useState, type FC } from 'react';\nimport { Copy, Check, Eye, EyeOff } from 'lucide-react';\n\ninterface CopyableFieldProps {\n value: string;\n masked?: boolean;\n}\n\nexport const CopyableField: FC<CopyableFieldProps> = ({ value, masked = false }) => {\n const [copied, setCopied] = useState(false);\n const [revealed, setRevealed] = useState(!masked);\n\n const copy = async () => {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const displayValue = revealed ? value : '•'.repeat(Math.min(value.length, 32));\n\n return (\n <div className=\"flex items-center gap-1.5\">\n <code className=\"flex-1 truncate rounded bg-muted px-2 py-1.5 font-mono text-[11px]\">\n {displayValue}\n </code>\n {masked && (\n <button\n onClick={() => setRevealed(!revealed)}\n className=\"shrink-0 rounded p-1 hover:bg-muted text-muted-foreground transition-colors\"\n title={revealed ? 'Hide' : 'Reveal'}\n >\n {revealed ? <EyeOff className=\"h-3.5 w-3.5\" /> : <Eye className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n <button\n onClick={copy}\n className=\"shrink-0 rounded p-1 hover:bg-muted text-muted-foreground transition-colors\"\n title=\"Copy to clipboard\"\n >\n {copied ? (\n <Check className=\"h-3.5 w-3.5 text-emerald-500\" />\n ) : (\n <Copy className=\"h-3.5 w-3.5\" />\n )}\n </button>\n </div>\n );\n};\n","/**\n * CreateWebhookModal — Dialog for creating a new webhook trigger.\n *\n * Step 1: Name + endpoint settings\n * Step 2: Success screen with URL + secret to copy\n */\n\nimport { useState, type FC, type RefObject } from 'react';\nimport { Check } from 'lucide-react';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@invect/ui';\nimport { useCreateWebhookTrigger } from '../hooks/useWebhookQueries';\nimport { CopyableField } from './CopyableField';\nimport type { CreateWebhookTriggerInput } from '../../shared/types';\n\n// ─── Component ──────────────────────────────────────────────────────\n\ninterface CreateWebhookModalProps {\n open: boolean;\n onClose: () => void;\n containerRef?: RefObject<HTMLElement | null>;\n /** Pre-fill flowId + nodeId when creating from flow editor */\n flowId?: string;\n nodeId?: string;\n}\n\nexport const CreateWebhookModal: FC<CreateWebhookModalProps> = ({\n open,\n onClose,\n containerRef,\n flowId,\n nodeId,\n}) => {\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [methods, setMethods] = useState('POST');\n const [hmacEnabled, setHmacEnabled] = useState(false);\n const [hmacHeaderName, setHmacHeaderName] = useState('');\n const [hmacSecret, setHmacSecret] = useState('');\n const [allowedIps, setAllowedIps] = useState('');\n const [createdUrl, setCreatedUrl] = useState<string | null>(null);\n\n const createMutation = useCreateWebhookTrigger();\n\n const handleCreate = async () => {\n if (!name.trim()) {\n return;\n }\n\n const input: CreateWebhookTriggerInput = {\n name: name.trim(),\n description: description.trim() || undefined,\n provider: 'generic',\n allowedMethods: methods,\n hmacEnabled,\n hmacHeaderName: hmacEnabled ? hmacHeaderName.trim() || undefined : undefined,\n hmacSecret: hmacEnabled ? hmacSecret.trim() || undefined : undefined,\n allowedIps: allowedIps.trim() || undefined,\n flowId,\n nodeId,\n };\n\n try {\n const result = await createMutation.mutateAsync(input);\n setCreatedUrl(result.fullUrl ?? `/plugins/webhooks/receive/${result.webhookPath}`);\n } catch {\n // Error handled by mutation state\n }\n };\n\n const handleClose = () => {\n setName('');\n setDescription('');\n setMethods('POST');\n setHmacEnabled(false);\n setHmacHeaderName('');\n setHmacSecret('');\n setAllowedIps('');\n setCreatedUrl(null);\n onClose();\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(v) => {\n if (!v) {\n handleClose();\n }\n }}\n >\n <DialogContent\n container={containerRef?.current}\n className=\"max-w-md gap-0 p-0 overflow-hidden\"\n showCloseButton\n >\n {/* Header */}\n <div className=\"px-6 pt-6 pb-4\">\n <DialogHeader>\n <DialogTitle className=\"text-base\">\n {createdUrl ? 'Webhook Created' : 'Create Webhook'}\n </DialogTitle>\n <DialogDescription>\n {createdUrl\n ? 'Copy the URL below and configure it in your external service.'\n : 'Set up a generic endpoint to receive webhook events from any external system.'}\n </DialogDescription>\n </DialogHeader>\n </div>\n\n {/* Content */}\n <div className=\"px-6 pb-6 space-y-4\">\n {createdUrl ? (\n /* ── Success ── */\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-2 p-3 text-sm border rounded-lg border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950/30 text-emerald-700 dark:text-emerald-400\">\n <Check className=\"w-4 h-4 shrink-0\" />\n Webhook is ready to receive events.\n </div>\n\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium tracking-wide uppercase text-muted-foreground\">\n Webhook URL\n </label>\n <CopyableField value={createdUrl} />\n </div>\n\n <button\n onClick={handleClose}\n className=\"inline-flex items-center justify-center w-full px-4 text-sm font-medium transition-colors rounded-md h-9 bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n Done\n </button>\n </div>\n ) : (\n /* ── Form ── */\n <>\n {/* Name */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-name\">\n Name *\n </label>\n <input\n id=\"wh-create-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Partner API Events\"\n autoFocus\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n\n {/* Description */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-desc\">\n Description\n </label>\n <input\n id=\"wh-create-desc\"\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional description\"\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Authentication</label>\n <div className=\"space-y-3 rounded-lg border border-border bg-muted/30 p-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">HMAC Verification</div>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Verify requests using an HMAC signature header.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setHmacEnabled(!hmacEnabled)}\n className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${\n hmacEnabled ? 'bg-primary' : 'bg-muted-foreground/30'\n }`}\n >\n <span\n className={`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${\n hmacEnabled ? 'translate-x-4' : 'translate-x-0'\n }`}\n />\n </button>\n </div>\n {hmacEnabled && (\n <div className=\"space-y-3 pt-1\">\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-create-hmac-header\">\n Signature Header Name\n </label>\n <input\n id=\"wh-create-hmac-header\"\n type=\"text\"\n autoComplete=\"off\"\n value={hmacHeaderName}\n onChange={(e) => setHmacHeaderName(e.target.value)}\n placeholder=\"e.g. x-signature\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-create-hmac-secret\">\n Signing Secret\n </label>\n <input\n id=\"wh-create-hmac-secret\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={hmacSecret}\n onChange={(e) => setHmacSecret(e.target.value)}\n placeholder=\"Enter secret key\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* IP Whitelist */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-ips\">\n IP Whitelist\n </label>\n <input\n id=\"wh-create-ips\"\n type=\"text\"\n value={allowedIps}\n onChange={(e) => setAllowedIps(e.target.value)}\n placeholder=\"e.g. 192.168.1.1, 10.0.0.0/24\"\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm font-mono shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n <p className=\"text-xs text-muted-foreground\">\n Leave empty to allow all IPs. Separate multiple addresses with commas.\n </p>\n </div>\n\n {/* HTTP Methods */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-create-methods\">\n HTTP Methods\n </label>\n <select\n id=\"wh-create-methods\"\n value={methods}\n onChange={(e) => setMethods(e.target.value)}\n className=\"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n >\n <option value=\"POST\">POST only</option>\n <option value=\"POST,PUT\">POST + PUT</option>\n <option value=\"ANY\">Any method</option>\n </select>\n </div>\n\n {/* Error */}\n {createMutation.isError && (\n <p className=\"text-sm text-red-500\">\n {createMutation.error?.message || 'Failed to create webhook'}\n </p>\n )}\n\n {/* Buttons */}\n <div className=\"flex gap-2 pt-2\">\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"inline-flex items-center justify-center flex-1 px-3 text-sm font-medium transition-colors border rounded-md shadow-xs h-9 bg-background hover:bg-accent\"\n >\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!name.trim() || createMutation.isPending}\n className=\"inline-flex items-center justify-center flex-1 px-3 text-sm font-medium transition-colors rounded-md h-9 bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {createMutation.isPending ? 'Creating…' : 'Create Webhook'}\n </button>\n </div>\n </>\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n};\n","/**\n * WebhookDetailPanel — Detail view rendered inside a Dialog.\n *\n * Tabs: Overview | Edit\n * Shows webhook URL, secret, status, linked flow, stats.\n * Allows toggling enabled/disabled, editing, and deleting.\n */\n\nimport { useState, type FC } from 'react';\nimport {\n Globe,\n Trash2,\n ExternalLink,\n Clock,\n Hash,\n ToggleLeft,\n ToggleRight,\n Workflow,\n Loader2,\n} from 'lucide-react';\nimport { DialogHeader, DialogTitle, DialogDescription } from '@invect/ui';\nimport { useUpdateWebhookTrigger, useDeleteWebhookTrigger } from '../hooks/useWebhookQueries';\nimport { CopyableField } from './CopyableField';\nimport type { WebhookTrigger, UpdateWebhookTriggerInput } from '../../shared/types';\n\n// ─── Constants ──────────────────────────────────────────────────────\n\nconst AUTH_MODE_CONFIG: Record<string, { label: string; color: string }> = {\n generic: {\n label: 'Unauthenticated',\n color: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800/40 dark:text-zinc-400',\n },\n hmac: {\n label: 'HMAC',\n color: 'bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300',\n },\n ip_whitelist: {\n label: 'IP Whitelist',\n color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300',\n },\n signed: {\n label: 'Signed',\n color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300',\n },\n};\n\nfunction getAuthModeConfig(trigger: WebhookTrigger) {\n if (trigger.provider !== 'generic') {\n return AUTH_MODE_CONFIG.signed;\n }\n if (trigger.hmacEnabled) {\n return AUTH_MODE_CONFIG.hmac;\n }\n if (trigger.allowedIps) {\n return AUTH_MODE_CONFIG.ip_whitelist;\n }\n return AUTH_MODE_CONFIG.generic;\n}\n\nfunction formatFullDate(iso?: string): string {\n if (!iso) {\n return 'Never';\n }\n return new Date(iso).toLocaleString(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\n// ─── Component ──────────────────────────────────────────────────────\n\ntype Section = 'overview' | 'edit';\n\ninterface WebhookDetailPanelProps {\n trigger: WebhookTrigger;\n flowName?: string;\n onClose: () => void;\n}\n\nexport const WebhookDetailPanel: FC<WebhookDetailPanelProps> = ({ trigger, flowName, onClose }) => {\n const [section, setSection] = useState<Section>('overview');\n const updateMutation = useUpdateWebhookTrigger();\n const deleteMutation = useDeleteWebhookTrigger();\n\n const authModeConfig = getAuthModeConfig(trigger);\n\n const handleToggleEnabled = () => {\n updateMutation.mutate({ id: trigger.id, isEnabled: !trigger.isEnabled });\n };\n\n const handleDelete = () => {\n if (confirm(`Delete webhook \"${trigger.name}\"? This cannot be undone.`)) {\n deleteMutation.mutate(trigger.id, { onSuccess: onClose });\n }\n };\n\n return (\n <>\n {/* Fixed header */}\n <div className=\"px-6 pt-6 pb-0\">\n <DialogHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center justify-center w-10 h-10 rounded-lg bg-muted/60 shrink-0\">\n <Globe className=\"w-5 h-5 text-muted-foreground\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <DialogTitle className=\"text-base\">{trigger.name}</DialogTitle>\n <DialogDescription className=\"flex items-center gap-2 mt-0.5 text-xs\">\n <span\n className={`inline-flex items-center rounded-full border border-transparent px-2 py-0.5 text-[10px] font-medium ${authModeConfig.color}`}\n >\n {authModeConfig.label}\n </span>\n <span\n className={`w-1.5 h-1.5 rounded-full ${\n trigger.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n <span>{trigger.isEnabled ? 'Enabled' : 'Disabled'}</span>\n </DialogDescription>\n </div>\n </div>\n </DialogHeader>\n\n {/* Tab nav */}\n <div className=\"flex gap-1 px-6 mt-4 -mx-6 border-b\">\n {[\n { key: 'overview' as const, label: 'Overview' },\n { key: 'edit' as const, label: 'Edit' },\n ].map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setSection(key)}\n className={`px-3 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${\n section === key\n ? 'border-foreground text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Scrollable content */}\n <div className=\"flex-1 px-6 pb-6 overflow-y-auto\">\n {section === 'overview' ? (\n <OverviewSection\n trigger={trigger}\n flowName={flowName}\n onToggleEnabled={handleToggleEnabled}\n onDelete={handleDelete}\n isToggling={updateMutation.isPending}\n isDeleting={deleteMutation.isPending}\n />\n ) : (\n <EditSection trigger={trigger} onSuccess={() => setSection('overview')} />\n )}\n </div>\n </>\n );\n};\n\n// ─── Overview Section ───────────────────────────────────────────────\n\nconst OverviewSection: FC<{\n trigger: WebhookTrigger;\n flowName?: string;\n onToggleEnabled: () => void;\n onDelete: () => void;\n isToggling: boolean;\n isDeleting: boolean;\n}> = ({ trigger, flowName, onToggleEnabled, onDelete, isToggling, isDeleting }) => (\n <div className=\"pt-4 space-y-5\">\n {/* Endpoint URL */}\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium tracking-wide uppercase text-muted-foreground\">\n Webhook URL\n </label>\n <CopyableField value={`/plugins/webhooks/receive/${trigger.webhookPath}`} />\n </div>\n\n {/* HMAC Authentication */}\n {trigger.hmacEnabled && trigger.hmacHeaderName && (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium tracking-wide uppercase text-muted-foreground\">\n HMAC Authentication\n </label>\n <div className=\"p-3 space-y-1 border rounded-lg bg-muted/30\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">Signature Header</span>\n <span className=\"font-mono text-sm\">{trigger.hmacHeaderName}</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">Secret</span>\n <CopyableField value={trigger.hmacSecret ?? ''} masked />\n </div>\n </div>\n </div>\n )}\n\n {/* IP Whitelist */}\n {trigger.allowedIps && (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium tracking-wide uppercase text-muted-foreground\">\n IP Whitelist\n </label>\n <div className=\"p-3 border rounded-lg bg-muted/30\">\n <span className=\"font-mono text-sm break-all\">{trigger.allowedIps}</span>\n </div>\n </div>\n )}\n\n {/* Info grid */}\n <div className=\"grid grid-cols-2 gap-4 py-2\">\n <div>\n <span className=\"block mb-1 text-xs text-muted-foreground\">Methods</span>\n <span className=\"font-mono text-sm\">{trigger.allowedMethods}</span>\n </div>\n <div>\n <span className=\"block mb-1 text-xs text-muted-foreground\">Authentication</span>\n <span className=\"text-sm\">{getAuthModeConfig(trigger).label}</span>\n </div>\n <div>\n <span className=\"block mb-1 text-xs text-muted-foreground\">Created</span>\n <span className=\"text-sm\">{formatFullDate(trigger.createdAt)}</span>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <Hash className=\"w-3 h-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">Triggers:</span>\n <span className=\"text-sm font-medium\">{trigger.triggerCount}</span>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <Clock className=\"w-3 h-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">Last:</span>\n <span className=\"text-sm\">{formatFullDate(trigger.lastTriggeredAt)}</span>\n </div>\n </div>\n\n {/* Linked flow */}\n {trigger.flowId && (\n <div className=\"p-3 border rounded-lg bg-muted/30\">\n <div className=\"flex items-center gap-2\">\n <Workflow className=\"w-4 h-4 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <span className=\"block text-xs text-muted-foreground\">Linked Flow</span>\n <a\n href={`/invect/flow/${trigger.flowId}`}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {flowName ?? trigger.flowId}\n <ExternalLink className=\"w-3 h-3\" />\n </a>\n </div>\n </div>\n </div>\n )}\n\n {/* Last payload */}\n {trigger.lastPayload !== null && trigger.lastPayload !== undefined && (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium tracking-wide uppercase text-muted-foreground\">\n Last Payload\n </label>\n <pre className=\"p-3 overflow-auto font-mono text-xs rounded-lg bg-muted max-h-32\">\n {JSON.stringify(trigger.lastPayload, null, 2)}\n </pre>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-3 border-t\">\n <button\n onClick={onToggleEnabled}\n disabled={isToggling}\n className={`inline-flex items-center gap-2 rounded-md text-sm font-medium h-8 px-3 border transition-colors ${\n trigger.isEnabled\n ? 'border-amber-200 text-amber-700 hover:bg-amber-50 dark:border-amber-800 dark:text-amber-400 dark:hover:bg-amber-950/30'\n : 'border-emerald-200 text-emerald-700 hover:bg-emerald-50 dark:border-emerald-800 dark:text-emerald-400 dark:hover:bg-emerald-950/30'\n }`}\n >\n {isToggling ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : trigger.isEnabled ? (\n <ToggleLeft className=\"w-3.5 h-3.5\" />\n ) : (\n <ToggleRight className=\"w-3.5 h-3.5\" />\n )}\n {trigger.isEnabled ? 'Disable' : 'Enable'}\n </button>\n\n <button\n onClick={onDelete}\n disabled={isDeleting}\n className=\"inline-flex items-center h-8 gap-2 px-3 text-sm font-medium text-imp-destructive transition-colors border border-imp-destructive/30 rounded-md hover:bg-imp-destructive/10\"\n >\n {isDeleting ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : (\n <Trash2 className=\"w-3.5 h-3.5\" />\n )}\n Delete\n </button>\n </div>\n </div>\n);\n\n// ─── Edit Section ───────────────────────────────────────────────────\n\nconst EditSection: FC<{\n trigger: WebhookTrigger;\n onSuccess: () => void;\n}> = ({ trigger, onSuccess }) => {\n const [name, setName] = useState(trigger.name);\n const [description, setDescription] = useState(trigger.description ?? '');\n const [methods, setMethods] = useState(trigger.allowedMethods);\n const [hmacEnabled, setHmacEnabled] = useState(trigger.hmacEnabled);\n const [hmacHeaderName, setHmacHeaderName] = useState(trigger.hmacHeaderName ?? '');\n const [hmacSecret, setHmacSecret] = useState(trigger.hmacSecret ?? '');\n const [allowedIps, setAllowedIps] = useState(trigger.allowedIps ?? '');\n const updateMutation = useUpdateWebhookTrigger();\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!name.trim()) {\n return;\n }\n\n const input: UpdateWebhookTriggerInput & { id: string } = {\n id: trigger.id,\n name: name.trim(),\n description: description.trim() || undefined,\n allowedMethods: methods,\n hmacEnabled,\n hmacHeaderName: hmacEnabled ? hmacHeaderName.trim() || undefined : undefined,\n hmacSecret: hmacEnabled ? hmacSecret.trim() || undefined : undefined,\n allowedIps: allowedIps.trim() || undefined,\n };\n updateMutation.mutate(input, { onSuccess });\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"pt-4 space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-name\">\n Name *\n </label>\n <input\n id=\"wh-edit-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n required\n className=\"h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-desc\">\n Description\n </label>\n <textarea\n id=\"wh-edit-desc\"\n rows={2}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional description\"\n className=\"w-full min-h-16 rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20 field-sizing-content\"\n />\n </div>\n\n {/* HMAC Authentication */}\n <div className=\"p-3 space-y-3 border rounded-lg border-border bg-muted/30\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">HMAC Authentication</div>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Verify incoming requests using an HMAC signature header.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setHmacEnabled(!hmacEnabled)}\n className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${\n hmacEnabled ? 'bg-primary' : 'bg-muted-foreground/30'\n }`}\n >\n <span\n className={`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform ${\n hmacEnabled ? 'translate-x-4' : 'translate-x-0'\n }`}\n />\n </button>\n </div>\n {hmacEnabled && (\n <div className=\"pt-1 space-y-3\">\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-edit-hmac-header\">\n Signature Header Name\n </label>\n <input\n id=\"wh-edit-hmac-header\"\n type=\"text\"\n value={hmacHeaderName}\n onChange={(e) => setHmacHeaderName(e.target.value)}\n placeholder=\"e.g. x-signature\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\" htmlFor=\"wh-edit-hmac-secret\">\n Signing Secret\n </label>\n <input\n id=\"wh-edit-hmac-secret\"\n type=\"password\"\n value={hmacSecret}\n onChange={(e) => setHmacSecret(e.target.value)}\n placeholder=\"Enter secret key\"\n className=\"h-8 w-full rounded-md border border-input bg-background px-2.5 text-sm shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n />\n </div>\n </div>\n )}\n </div>\n\n {/* IP Whitelist */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-ips\">\n IP Whitelist\n </label>\n <textarea\n id=\"wh-edit-ips\"\n rows={2}\n value={allowedIps}\n onChange={(e) => setAllowedIps(e.target.value)}\n placeholder=\"Comma-separated IPs, e.g. 192.168.1.1, 10.0.0.0/24\"\n className=\"w-full min-h-16 rounded-md border border-input bg-background px-3 py-2 text-sm font-mono shadow-xs placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20 field-sizing-content\"\n />\n <p className=\"text-xs text-muted-foreground\">\n Leave empty to allow all IPs. Separate multiple addresses with commas.\n </p>\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor=\"wh-edit-methods\">\n HTTP Methods\n </label>\n <select\n id=\"wh-edit-methods\"\n value={methods}\n onChange={(e) => setMethods(e.target.value)}\n className=\"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n >\n <option value=\"POST\">POST only</option>\n <option value=\"POST,PUT\">POST + PUT</option>\n <option value=\"ANY\">Any method</option>\n </select>\n </div>\n\n {updateMutation.isError && (\n <p className=\"text-sm text-red-500\">\n {updateMutation.error?.message || 'Failed to save changes'}\n </p>\n )}\n\n <div className=\"flex justify-end gap-2 pt-2\">\n <button\n type=\"button\"\n onClick={onSuccess}\n className=\"inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-colors border rounded-md shadow-xs bg-background hover:bg-accent\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={!name.trim() || updateMutation.isPending}\n className=\"inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-colors rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {updateMutation.isPending ? 'Saving…' : 'Save Changes'}\n </button>\n </div>\n </form>\n );\n};\n","/**\n * WebhooksPage — Main webhook management page.\n *\n * Lists all webhook triggers with status, auth mode, linked flows, and last activity.\n * Click a row to open the detail dialog for editing, toggling, or deleting.\n */\n\nimport { useState, useRef, type FC } from 'react';\nimport { Globe, Plus, Search, Clock, Hash, ChevronRight, Loader2, Workflow } from 'lucide-react';\nimport { PageLayout, Dialog, DialogContent, useFlows } from '@invect/ui';\nimport { useWebhookTriggers } from '../hooks/useWebhookQueries';\nimport { CreateWebhookModal } from './CreateWebhookModal';\nimport { WebhookDetailPanel } from './WebhookDetailPanel';\nimport type { WebhookTrigger } from '../../shared/types';\n\n// ─── Constants ──────────────────────────────────────────────────────\n\nconst AUTH_MODE_CONFIG: Record<string, { label: string; color: string }> = {\n generic: {\n label: 'Unauthenticated',\n color: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800/40 dark:text-zinc-400',\n },\n hmac: {\n label: 'HMAC',\n color: 'bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300',\n },\n ip_whitelist: {\n label: 'IP Whitelist',\n color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300',\n },\n signed: {\n label: 'Signed',\n color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300',\n },\n};\n\nfunction getAuthModeConfig(trigger: WebhookTrigger) {\n if (trigger.provider !== 'generic') {\n return AUTH_MODE_CONFIG.signed;\n }\n if (trigger.hmacEnabled) {\n return AUTH_MODE_CONFIG.hmac;\n }\n if (trigger.allowedIps) {\n return AUTH_MODE_CONFIG.ip_whitelist;\n }\n return AUTH_MODE_CONFIG.generic;\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────\n\nfunction formatRelativeTime(iso?: string): string {\n if (!iso) {\n return 'Never';\n }\n const diff = Date.now() - new Date(iso).getTime();\n const mins = Math.floor(diff / 60_000);\n if (mins < 1) {\n return 'Just now';\n }\n if (mins < 60) {\n return `${mins}m ago`;\n }\n const hours = Math.floor(mins / 60);\n if (hours < 24) {\n return `${hours}h ago`;\n }\n const days = Math.floor(hours / 24);\n if (days < 30) {\n return `${days}d ago`;\n }\n return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\n// ─── Webhook Row ────────────────────────────────────────────────────\n\nconst WebhookRow: FC<{\n trigger: WebhookTrigger;\n flowName?: string;\n onClick: () => void;\n}> = ({ trigger, flowName, onClick }) => {\n const authModeConfig = getAuthModeConfig(trigger);\n\n return (\n <button\n className=\"w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-muted/50 transition-colors\"\n onClick={onClick}\n >\n {/* Icon */}\n <div className=\"flex items-center justify-center w-9 h-9 rounded-lg bg-muted/60 shrink-0\">\n <Globe className=\"w-4 h-4 text-muted-foreground\" />\n </div>\n\n {/* Name + subtitle */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium truncate\">{trigger.name}</span>\n <span\n className={`w-1.5 h-1.5 rounded-full shrink-0 ${\n trigger.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n </div>\n <div className=\"flex items-center gap-2 mt-0.5\">\n {flowName ? (\n <span className=\"text-xs text-muted-foreground flex items-center gap-1 truncate\">\n <Workflow className=\"w-3 h-3 shrink-0\" />\n {flowName}\n </span>\n ) : trigger.description ? (\n <span className=\"text-xs text-muted-foreground truncate\">{trigger.description}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/50\">No flow linked</span>\n )}\n </div>\n </div>\n\n {/* Auth badge */}\n <span\n className={`hidden sm:inline-flex items-center rounded-full border border-transparent px-2 py-0.5 text-[10px] font-medium ${authModeConfig.color}`}\n >\n {authModeConfig.label}\n </span>\n\n {/* Stats */}\n <div className=\"hidden md:flex items-center gap-4 text-xs text-muted-foreground shrink-0\">\n <span className=\"flex items-center gap-1\" title=\"Total triggers\">\n <Hash className=\"w-3 h-3\" />\n {trigger.triggerCount}\n </span>\n <span className=\"flex items-center gap-1 w-16 justify-end\" title=\"Last triggered\">\n <Clock className=\"w-3 h-3\" />\n {formatRelativeTime(trigger.lastTriggeredAt)}\n </span>\n </div>\n\n <ChevronRight className=\"w-4 h-4 text-muted-foreground/50 shrink-0\" />\n </button>\n );\n};\n\n// ─── Main Page ──────────────────────────────────────────────────────\n\nexport const WebhooksPage: FC<{ basePath: string }> = () => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [createOpen, setCreateOpen] = useState(false);\n const [selectedTrigger, setSelectedTrigger] = useState<WebhookTrigger | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<'all' | 'enabled' | 'disabled'>('all');\n\n const { data: triggers, isLoading, error } = useWebhookTriggers();\n const { data: flowsResponse } = useFlows();\n\n // Build flow name lookup\n const flowNameMap = new Map<string, string>();\n for (const flow of flowsResponse?.data ?? []) {\n flowNameMap.set(flow.id, flow.name);\n }\n\n // Filter\n const filtered = (triggers ?? []).filter((t) => {\n if (statusFilter === 'enabled' && !t.isEnabled) {\n return false;\n }\n if (statusFilter === 'disabled' && t.isEnabled) {\n return false;\n }\n if (searchQuery) {\n const q = searchQuery.toLowerCase();\n const nameMatch = t.name.toLowerCase().includes(q);\n const flowMatch = t.flowId\n ? (flowNameMap.get(t.flowId) ?? '').toLowerCase().includes(q)\n : false;\n if (!nameMatch && !flowMatch) {\n return false;\n }\n }\n return true;\n });\n\n const enabledCount = (triggers ?? []).filter((t) => t.isEnabled).length;\n const disabledCount = (triggers ?? []).filter((t) => !t.isEnabled).length;\n\n // Keep detail dialog in sync with list data\n const liveTrigger = selectedTrigger\n ? ((triggers ?? []).find((t) => t.id === selectedTrigger.id) ?? selectedTrigger)\n : null;\n\n return (\n <PageLayout\n title=\"Webhooks\"\n subtitle=\"Receive events from external systems and route them into your flows.\"\n icon={Globe}\n actions={\n <button\n onClick={() => setCreateOpen(true)}\n className=\"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium h-9 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n New Webhook\n </button>\n }\n >\n <div ref={containerRef}>\n {/* Search + Filters */}\n <div className=\"flex flex-col gap-3 mb-4 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1 max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 pointer-events-none text-muted-foreground\" />\n <input\n type=\"text\"\n placeholder=\"Search webhooks…\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-lg border border-border bg-transparent py-2 pl-9 pr-3 text-sm outline-none placeholder:text-muted-foreground focus:border-primary/50\"\n />\n </div>\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {[\n { key: 'all' as const, label: `All (${triggers?.length ?? 0})` },\n { key: 'enabled' as const, label: `Enabled (${enabledCount})` },\n { key: 'disabled' as const, label: `Disabled (${disabledCount})` },\n ].map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setStatusFilter(key)}\n className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors ${\n statusFilter === key\n ? 'bg-foreground text-background border-foreground'\n : 'bg-card text-muted-foreground border-border hover:border-foreground/30'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Content */}\n {isLoading ? (\n <div className=\"flex items-center justify-center gap-2 py-16 text-sm text-muted-foreground\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n Loading webhooks…\n </div>\n ) : error ? (\n <div className=\"rounded-lg border border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30 p-4 text-sm text-red-600 dark:text-red-400\">\n Failed to load webhooks: {(error as Error).message}\n </div>\n ) : filtered.length === 0 ? (\n <div className=\"flex flex-col items-center py-16 text-center\">\n <div className=\"rounded-full bg-muted p-3 mb-4\">\n <Globe className=\"w-6 h-6 text-muted-foreground\" />\n </div>\n <h3 className=\"text-sm font-semibold mb-1\">\n {triggers?.length === 0 ? 'No webhooks yet' : 'No webhooks match your filter'}\n </h3>\n <p className=\"max-w-sm text-sm text-muted-foreground mb-4\">\n {triggers?.length === 0\n ? 'Create a generic webhook endpoint to receive events from external systems.'\n : 'Try adjusting your search or filter criteria.'}\n </p>\n {triggers?.length === 0 && (\n <button\n onClick={() => setCreateOpen(true)}\n className=\"inline-flex items-center gap-2 rounded-md text-sm font-medium h-9 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n Create Webhook\n </button>\n )}\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-lg border bg-card\">\n <div className=\"divide-y\">\n {filtered.map((trigger) => (\n <WebhookRow\n key={trigger.id}\n trigger={trigger}\n flowName={trigger.flowId ? flowNameMap.get(trigger.flowId) : undefined}\n onClick={() => setSelectedTrigger(trigger)}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Detail Dialog */}\n <Dialog\n open={!!selectedTrigger}\n onOpenChange={(open) => {\n if (!open) {\n setSelectedTrigger(null);\n }\n }}\n >\n <DialogContent\n container={containerRef.current}\n className=\"max-w-2xl h-[32rem] flex flex-col gap-0 p-0 overflow-hidden\"\n showCloseButton\n >\n {liveTrigger && (\n <WebhookDetailPanel\n trigger={liveTrigger}\n flowName={liveTrigger.flowId ? flowNameMap.get(liveTrigger.flowId) : undefined}\n onClose={() => setSelectedTrigger(null)}\n />\n )}\n </DialogContent>\n </Dialog>\n\n {/* Create Modal */}\n <CreateWebhookModal\n open={createOpen}\n onClose={() => setCreateOpen(false)}\n containerRef={containerRef}\n />\n </PageLayout>\n );\n};\n","/**\n * Webhooks Frontend Plugin — registers the sidebar item and route\n * for webhook management.\n */\n\nimport { Globe } from 'lucide-react';\nimport { WebhooksPage } from '../components/WebhooksPage';\nimport type { InvectFrontendPlugin } from '@invect/ui';\n\nexport const webhooksFrontend: InvectFrontendPlugin = {\n id: 'webhooks',\n name: 'Webhooks',\n\n sidebar: [\n {\n label: 'Webhooks',\n icon: Globe,\n path: '/webhooks',\n position: 'top',\n },\n ],\n\n routes: [\n {\n path: '/webhooks',\n component: WebhooksPage,\n },\n ],\n};\n","/**\n * WebhookTriggerSelector — Dropdown to pick an existing webhook trigger\n * or create a new one inline. Used in the trigger.webhook node's config panel.\n */\n\nimport { useState, type FC } from 'react';\nimport { Globe, Plus, ChevronDown, ExternalLink } from 'lucide-react';\nimport { useWebhookTriggers } from '../hooks/useWebhookQueries';\nimport { CreateWebhookModal } from './CreateWebhookModal';\nimport { CopyableField } from './CopyableField';\nimport type { WebhookTrigger } from '../../shared/types';\n\ninterface WebhookTriggerSelectorProps {\n selectedId?: string;\n onSelect: (trigger: WebhookTrigger) => void;\n flowId?: string;\n nodeId?: string;\n}\n\nexport const WebhookTriggerSelector: FC<WebhookTriggerSelectorProps> = ({\n selectedId,\n onSelect,\n flowId,\n nodeId,\n}) => {\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const [createOpen, setCreateOpen] = useState(false);\n const { data: triggers, isLoading } = useWebhookTriggers();\n\n const selected = triggers?.find((t) => t.id === selectedId);\n\n return (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Webhook Trigger</label>\n\n {/* Dropdown */}\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setDropdownOpen(!dropdownOpen)}\n className=\"flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 text-sm shadow-xs hover:bg-accent/50 transition-colors\"\n >\n <span className=\"flex items-center gap-2 truncate\">\n <Globe className=\"h-3.5 w-3.5 text-muted-foreground shrink-0\" />\n {selected ? (\n <>\n <span className=\"truncate\">{selected.name}</span>\n <span\n className={`w-1.5 h-1.5 rounded-full shrink-0 ${\n selected.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n </>\n ) : (\n <span className=\"text-muted-foreground\">\n {isLoading ? 'Loading…' : 'Select a webhook trigger…'}\n </span>\n )}\n </span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground shrink-0\" />\n </button>\n\n {dropdownOpen && (\n <>\n <div className=\"fixed inset-0 z-40\" onClick={() => setDropdownOpen(false)} />\n\n <div className=\"absolute z-50 w-full mt-1 bg-popover border border-border rounded-lg shadow-lg max-h-60 overflow-auto\">\n {/* Create new */}\n <button\n onClick={() => {\n setDropdownOpen(false);\n setCreateOpen(true);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-primary hover:bg-accent/50 border-b border-border transition-colors\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n Create New Webhook\n </button>\n\n {/* Existing triggers */}\n {(triggers ?? []).length === 0 ? (\n <div className=\"px-3 py-4 text-xs text-muted-foreground text-center\">\n No webhook triggers yet\n </div>\n ) : (\n (triggers ?? []).map((trigger) => (\n <button\n key={trigger.id}\n onClick={() => {\n onSelect(trigger);\n setDropdownOpen(false);\n }}\n className={`w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent/50 transition-colors ${\n trigger.id === selectedId ? 'bg-accent' : ''\n }`}\n >\n <span\n className={`w-1.5 h-1.5 rounded-full shrink-0 ${\n trigger.isEnabled ? 'bg-emerald-500' : 'bg-muted-foreground/40'\n }`}\n />\n <span className=\"truncate\">{trigger.name}</span>\n <span className=\"text-xs text-muted-foreground ml-auto shrink-0\">\n {trigger.provider}\n </span>\n </button>\n ))\n )}\n </div>\n </>\n )}\n </div>\n\n {/* Selected trigger info */}\n {selected && (\n <div className=\"space-y-2 p-3 rounded-lg bg-muted/30 border\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium\">{selected.name}</span>\n <span\n className={`inline-flex items-center rounded-full border border-transparent px-2 py-0.5 text-[10px] font-medium ${\n selected.isEnabled\n ? 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400'\n : 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800/40 dark:text-zinc-400'\n }`}\n >\n {selected.isEnabled ? 'Active' : 'Disabled'}\n </span>\n </div>\n <CopyableField value={`/plugins/webhooks/receive/${selected.webhookPath}`} />\n <a\n href=\"/invect/webhooks\"\n className=\"text-xs text-primary hover:underline inline-flex items-center gap-1\"\n >\n Manage webhooks <ExternalLink className=\"h-3 w-3\" />\n </a>\n </div>\n )}\n\n <CreateWebhookModal\n open={createOpen}\n onClose={() => setCreateOpen(false)}\n flowId={flowId}\n nodeId={nodeId}\n />\n </div>\n );\n};\n"],"mappings":"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"}
|